Resolve compromised password detection on password change

What does this MR do and why?

Resolve any unresolved CompromisedPasswordDetection records associated with a user when their password is changed.

References

Follow-up from !191112 (merged)

2nd split MR from !188723 (closed)

Part of work towards https://gitlab.com/gitlab-org/gitlab/-/issues/535207

How to set up and validate locally

  1. In rails console enable the feature flag
    Feature.enable(:notify_compromised_passwords)
  2. Make sure your GDK is EE and simulating SaaS/GitLab.com
  3. Go to the login page
  4. Copy the session ID and CSRF token
  5. Use below curl command replacing session, CSRF token, username and password to simulate the presence of the header
    curl 'http://gdk.test:3000/users/sign_in' \
      -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
      -H 'Accept-Language: en-US,en;q=0.9' \
      -H 'Cache-Control: max-age=0' \
      -H 'Connection: keep-alive' \
      -H 'Content-Type: application/x-www-form-urlencoded' \
      -b 'preferred_language=en; _gitlab_session=SESSIONCOOKIEHERE; perf_bar_enabled=true' \
      -H 'Exposed-Credential-Check: 1' \
      -H 'Origin: http://gdk.test:3000' \
      -H 'Referer: http://gdk.test:3000/users/sign_in' \
      -H 'Upgrade-Insecure-Requests: 1' \
      -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36' \
      --data-raw 'authenticity_token=CSRFTOKENHERE&user%5Blogin%5D=USERNAMEHERE&user%5Bpassword%5D=PASSWORDHERE' \
      --insecure
  6. Open a GDK rails console
  7. Verify that a record was created:
    > Users::CompromisedPasswordDetection.last
    => #<Users::CompromisedPasswordDetection:0x000000034c812ed8 id: 1, created_at: Tue, 13 May 2025 04:50:37.943996000 UTC +00:00, updated_at: Tue, 13 May 2025 04:50:37.943996000 UTC +00:00, user_id: 1, resolved_at: nil>
  8. Sign back in as the user and change your password: http://gdk.test:3000/-/user_settings/password/edit
    • This could also happen by changing the user's password as an admin
  9. Verify that the previously created record was updated to set resolved_at and the user no longer has unresolved compromised password detections:
    > Users::CompromisedPasswordDetection.last
    => #<Users::CompromisedPasswordDetection:0x000000031e5bbf50
     id: 1,
     created_at: Fri, 16 May 2025 00:58:50.237071000 UTC +00:00,
     updated_at: Fri, 16 May 2025 01:00:16.946386000 UTC +00:00,
     resolved_at: Fri, 16 May 2025 01:00:16.946101000 UTC +00:00,
     user_id: 1>
    > User.find(1).compromised_password_detections.unresolved.exists?
    => false

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Merge request reports

Loading