ResourceOwnerPasswordGrant implements the password grant type flow
(ctx context.Context, w http.ResponseWriter, r *http.Request)
| 69 | |
| 70 | // ResourceOwnerPasswordGrant implements the password grant type flow |
| 71 | func (a *API) ResourceOwnerPasswordGrant(ctx context.Context, w http.ResponseWriter, r *http.Request) error { |
| 72 | db := a.db.WithContext(ctx) |
| 73 | |
| 74 | params := &PasswordGrantParams{} |
| 75 | if err := retrieveRequestParams(r, params); err != nil { |
| 76 | return err |
| 77 | } |
| 78 | |
| 79 | aud := a.requestAud(ctx, r) |
| 80 | config := a.config |
| 81 | |
| 82 | if params.Email != "" && params.Phone != "" { |
| 83 | return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Only an email address or phone number should be provided on login.") |
| 84 | } |
| 85 | var user *models.User |
| 86 | var grantParams models.GrantParams |
| 87 | var provider string |
| 88 | var err error |
| 89 | |
| 90 | grantParams.FillGrantParams(r) |
| 91 | |
| 92 | if params.Email != "" { |
| 93 | provider = "email" |
| 94 | if !config.External.Email.Enabled { |
| 95 | return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeEmailProviderDisabled, "Email logins are disabled") |
| 96 | } |
| 97 | user, err = models.FindUserByEmailAndAudience(db, params.Email, aud) |
| 98 | } else if params.Phone != "" { |
| 99 | provider = "phone" |
| 100 | if !config.External.Phone.Enabled { |
| 101 | return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodePhoneProviderDisabled, "Phone logins are disabled") |
| 102 | } |
| 103 | params.Phone = formatPhoneNumber(params.Phone) |
| 104 | user, err = models.FindUserByPhoneAndAudience(db, params.Phone, aud) |
| 105 | } else { |
| 106 | return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "missing email or phone") |
| 107 | } |
| 108 | |
| 109 | if err != nil { |
| 110 | if models.IsNotFoundError(err) { |
| 111 | return apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, InvalidLoginMessage) |
| 112 | } |
| 113 | return apierrors.NewInternalServerError("Database error querying schema").WithInternalError(err) |
| 114 | } |
| 115 | |
| 116 | if !user.HasPassword() { |
| 117 | return apierrors.NewBadRequestError(apierrors.ErrorCodeInvalidCredentials, InvalidLoginMessage) |
| 118 | } |
| 119 | |
| 120 | if user.IsBanned() { |
| 121 | return apierrors.NewBadRequestError(apierrors.ErrorCodeUserBanned, "User is banned") |
| 122 | } |
| 123 | |
| 124 | isValidPassword, shouldReEncrypt, err := user.Authenticate(ctx, db, params.Password, config.Security.DBEncryption.DecryptionKeys, config.Security.DBEncryption.Encrypt, config.Security.DBEncryption.EncryptionKeyID) |
| 125 | if err != nil { |
| 126 | return err |
| 127 | } |
| 128 |
nothing calls this directly
no test coverage detected