login.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package user
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "github.com/porter-dev/porter/api/server/authn"
  7. "github.com/porter-dev/porter/api/server/handlers"
  8. "github.com/porter-dev/porter/api/server/shared"
  9. "github.com/porter-dev/porter/api/server/shared/apierrors"
  10. "github.com/porter-dev/porter/api/server/shared/config"
  11. "github.com/porter-dev/porter/api/server/shared/config/env"
  12. "github.com/porter-dev/porter/api/types"
  13. "golang.org/x/crypto/bcrypt"
  14. "gorm.io/gorm"
  15. )
  16. type UserLoginHandler struct {
  17. handlers.PorterHandlerReadWriter
  18. }
  19. func NewUserLoginHandler(
  20. config *config.Config,
  21. decoderValidator shared.RequestDecoderValidator,
  22. writer shared.ResultWriter,
  23. ) *UserLoginHandler {
  24. return &UserLoginHandler{
  25. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  26. }
  27. }
  28. func (u *UserLoginHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  29. request := &types.LoginUserRequest{}
  30. if ok := u.DecodeAndValidate(w, r, request); !ok {
  31. return
  32. }
  33. if err := checkUserRestrictions(u.Config().ServerConf, request.Email); err != nil {
  34. u.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
  35. return
  36. }
  37. // check that passwords match
  38. storedUser, err := u.Repo().User().ReadUserByEmail(request.Email)
  39. // case on user not existing, send forbidden error if not exist
  40. if err != nil {
  41. if targetErr := gorm.ErrRecordNotFound; errors.Is(err, targetErr) {
  42. u.HandleAPIError(w, r, apierrors.NewErrForbidden(err))
  43. return
  44. } else {
  45. u.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  46. return
  47. }
  48. }
  49. if err := bcrypt.CompareHashAndPassword([]byte(storedUser.Password), []byte(request.Password)); err != nil {
  50. reqErr := apierrors.NewErrPassThroughToClient(fmt.Errorf("incorrect password"), http.StatusUnauthorized)
  51. u.HandleAPIError(w, r, reqErr)
  52. return
  53. }
  54. // save the user as authenticated in the session
  55. if err := authn.SaveUserAuthenticated(w, r, u.Config(), storedUser); err != nil {
  56. u.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  57. return
  58. }
  59. u.WriteResult(w, r, storedUser.ToUserType())
  60. }
  61. // checkUserRestrictions checks login restrictions specified by environment variables on the
  62. // Porter instance.
  63. func checkUserRestrictions(
  64. serverConf *env.ServerConf,
  65. reqEmail string,
  66. ) error {
  67. // if the admin user env var is specified, only allow admin user email
  68. if adminEmail := serverConf.AdminEmail; adminEmail != "" && adminEmail != reqEmail {
  69. return fmt.Errorf("email not allowed")
  70. }
  71. return nil
  72. }