Skip to content

Commit

Permalink
Don't alarm on "Email in use" response from Identity /guest endpoint (
Browse files Browse the repository at this point in the history
#6745)

Sometimes POST /guest returns "Email in use" even though we already
checked whether the user existed by looking them up with GET /user
passing their email address. According to identity occasionally users
get into a weird state and this is a result of that. I think this should
still result in a 500 (it's not related to something the user has done)
but we don't want to alarm on it.
  • Loading branch information
tjmw authored Jan 30, 2025
1 parent 7f3e6f2 commit a95112e
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 1 deletion.
1 change: 1 addition & 0 deletions support-frontend/app/actions/CustomActionBuilders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class CustomActionBuilders(
emailProviderRejectedCode,
invalidEmailAddressCode,
recaptchaFailedCode,
emailAddressAlreadyTakenCode,
)
if (result.header.status == 500) {
if (!ignoreList.contains(result.header.reasonPhrase.getOrElse(""))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,14 @@ class CreateSubscriptionController(
)
}

private def mapIdentityErrorToCreateSubscriptionError(identityError: IdentityError) =
private def mapIdentityErrorToCreateSubscriptionError(identityError: IdentityError): CreateSubscriptionError =
identityError match {
case EmailProviderRejected(_) => RequestValidationError(emailProviderRejectedCode)
case InvalidEmailAddress(_) => RequestValidationError(invalidEmailAddressCode)
// We're mapping this to a ServerError because it shouldn't ever happen, but sometimes does. Even though we
// asked identity (in getOrCreateIdentityUser) whether the user exists first, sometimes we get an answer of no
// back but then attempting to create returns this error.
case EmailAddressAlreadyTaken(_) => ServerError(emailAddressAlreadyTakenCode)
case OtherIdentityError(message, description, endpoint) =>
endpoint match {
case Some(GuestEndpoint) => ServerError(s"Identity error calling /guest: $message; $description")
Expand Down Expand Up @@ -345,6 +349,14 @@ class CreateSubscriptionController(
),
body = writeable.toEntity(err.message),
)
case ServerError(code) if code == emailAddressAlreadyTakenCode =>
Result(
header = new ResponseHeader(
status = INTERNAL_SERVER_ERROR,
reasonPhrase = Some(emailAddressAlreadyTakenCode),
),
body = writeable.toEntity(emailAddressAlreadyTakenCode),
)
case _: ServerError =>
InternalServerError
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ object IdentityErrorResponse {
implicit val reads: Reads[IdentityErrorResponse] = Json.reads[IdentityErrorResponse]
val emailProviderRejectedCode = "email_provider_rejected"
val invalidEmailAddressCode = "invalid_email_address"
val emailAddressAlreadyTakenCode = "email_address_already_taken"

sealed trait IdentityError {
def endpoint: Option[IdentityEndpoint]
def setEndpoint(e: IdentityEndpoint): IdentityError = {
this match {
case EmailProviderRejected(_) => EmailProviderRejected(Some(e))
case InvalidEmailAddress(_) => InvalidEmailAddress(Some(e))
case EmailAddressAlreadyTaken(_) => EmailAddressAlreadyTaken(Some(e))
case OtherIdentityError(m, d, _endpoint) => OtherIdentityError(m, d, endpoint = Some(e))
}
}
Expand All @@ -46,6 +48,9 @@ object IdentityErrorResponse {
/** The email address is invalid. */
case class InvalidEmailAddress(endpoint: Option[IdentityEndpoint]) extends IdentityError

/** The email address is already associated with an existing account. */
case class EmailAddressAlreadyTaken(endpoint: Option[IdentityEndpoint]) extends IdentityError

/** Some other error occurred. */
case class OtherIdentityError(message: String, description: String, endpoint: Option[IdentityEndpoint])
extends IdentityError
Expand All @@ -65,6 +70,8 @@ object IdentityErrorResponse {
EmailProviderRejected(endpoint = None)
} else if (message == "Invalid emailAddress:" && description == "Please enter a valid email address") {
InvalidEmailAddress(endpoint = None)
} else if (message == "Email in use" && description == "This email has already been taken") {
EmailAddressAlreadyTaken(endpoint = None)
} else {
OtherIdentityError(message, description, endpoint = None)
}
Expand Down

0 comments on commit a95112e

Please sign in to comment.