Skip to content

Do not 500 when resetting password for account with an unconfirmed email address that has since been confirmed by another account#6042

Merged
mitchellhenke merged 3 commits intomainfrom
mitchellhenke/reset-password-500
Mar 9, 2022
Merged

Do not 500 when resetting password for account with an unconfirmed email address that has since been confirmed by another account#6042
mitchellhenke merged 3 commits intomainfrom
mitchellhenke/reset-password-500

Conversation

@mitchellhenke
Copy link
Contributor

@mitchellhenke mitchellhenke commented Mar 8, 2022

Kind of circuitous, but very possible way to get a 500 (NewRelic)

  1. Register with EMAIL1 (do not confirm)
  2. Reset password on EMAIL1
  3. Register with EMAIL2
  4. Confirm EMAIL2 via email received
  5. Add 2FA
  6. Go to account page logged in as EMAIL2
  7. Click add email
  8. Add EMAIL1
  9. Open the recently received EMAIL1 confirmation email sent on behalf of EMAIL2
  10. Log out
  11. Open reset password email received in step 2
  12. Enter new password and submit
  13. 500

The index collision happens because we only allow one record with a given email address to be confirmed. The reset password token is generated for the first account which hasn't yet confirmed the email address. In the meantime, a second account is created that adds and confirms the same email address. When the first account opens the password reset email, and enters a password, we attempt to update the email address as being confirmed (and correctly fail).

@mitchellhenke mitchellhenke force-pushed the mitchellhenke/reset-password-500 branch from 8f7927b to e3bae65 Compare March 8, 2022 22:46
@mitchellhenke mitchellhenke changed the title Add failing test Do not 500 when resetting password for account with an unconfirmed email address that has since been confirmed by another account Mar 9, 2022
@mitchellhenke mitchellhenke force-pushed the mitchellhenke/reset-password-500 branch 2 times, most recently from 0e2ee75 to 5609e02 Compare March 9, 2022 16:56
@mitchellhenke mitchellhenke marked this pull request as ready for review March 9, 2022 17:00
Copy link
Contributor

@zachmargolis zachmargolis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! nice find!

This reminds me of another duplicate error we'd seen in our logs: https://cm-jira.usa.gov/browse/LG-5171, I wonder if a similar case of multiple accounts is what's causing that bug

Comment on lines 69 to 72
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add a unit test for this method/failure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm comfortable with the test in https://github.com/18F/identity-idp/pull/6042/files#diff-6169030eddc977e1ae39fe9c01f51f38bf4c8dfbec994c3539a8c10d5340b8caR154-R169 covering the expected behavior. Is there an aspect or edge case missing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for odd model joins like this, that doing a unit tests is clearer than an acceptance test, but I don't feel that strongly, the overall behavior is covered by the one you linked

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it helps, there isn't a join and could probably be simplified to just be user.email_addresses.first since an unconfirmed account should only ever have one email address

@mitchellhenke mitchellhenke force-pushed the mitchellhenke/reset-password-500 branch from 0a9a28b to 123a5d2 Compare March 9, 2022 19:12
Mitchell Henke and others added 3 commits March 9, 2022 13:13
changelog: Bug Fixes, Reset Password, Fix 500 error when resetting password for account with email confirmed by another account
Co-authored-by: Zach Margolis <zachmargolis@users.noreply.github.com>
@mitchellhenke mitchellhenke force-pushed the mitchellhenke/reset-password-500 branch from 123a5d2 to bbd9bb7 Compare March 9, 2022 19:13
# their token failed
errors.add(:reset_password_token, 'invalid_token', type: :invalid_token)
elsif !user.reset_password_period_valid?
elsif !user.reset_password_period_valid? || invalid_account?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also worth noting that this should resolve the vast vast majority of cases, but the chance still exists that the two accounts could end up in a race condition where they both try to confirm the email address at the same time in the window of time between the SELECT here and the UPDATE that follows.

@mitchellhenke mitchellhenke merged commit df64e43 into main Mar 9, 2022
@mitchellhenke mitchellhenke deleted the mitchellhenke/reset-password-500 branch March 9, 2022 22:01
@aduth aduth mentioned this pull request Mar 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants