login.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. redirect, err := authn.SaveUserAuthenticated(w, r, u.Config(), storedUser)
  56. if err != nil {
  57. u.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  58. return
  59. }
  60. if redirect != "" {
  61. http.Redirect(w, r, redirect, http.StatusFound)
  62. return
  63. }
  64. u.WriteResult(w, r, storedUser.ToUserType())
  65. }
  66. // checkUserRestrictions checks login restrictions specified by environment variables on the
  67. // Porter instance.
  68. func checkUserRestrictions(
  69. serverConf *env.ServerConf,
  70. reqEmail string,
  71. ) error {
  72. // if the admin user env var is specified, only allow admin user email
  73. if adminEmail := serverConf.AdminEmail; adminEmail != "" && adminEmail != reqEmail {
  74. return fmt.Errorf("email not allowed")
  75. }
  76. return nil
  77. }