Skip to content

Conversation

@thabofletcher
Copy link
Contributor

@thabofletcher thabofletcher commented Aug 29, 2025

Closes ENG-681

Description Of Changes

This is to re-implement ENG-681, which was reverted due to its impact on FidesPlus/unit tests. This has been refactored to not require the changes the the OAuth client test fixture.

Code Changes

Invalidates exisitng sessions for a user when their password has been reset

Steps to Confirm

  1. Login as a user
  2. Change the pw for that user
  3. Watch the session get invalidated

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Add a db-migration This indicates that a change includes a database migration label to the entry if your change includes a DB migration
    • Add a high-risk This issue suggests changes that have a high-probability of breaking existing code label to the entry if your change includes a high-risk change (i.e. potential for performance impact or unexpected regression) that should be flagged
    • Updates unreleased work already in Changelog, no new entry necessary
  • Followup issues:
    • Followup issues created
    • No followup issues
  • Database migrations:
    • Ensure that your downrev is up to date with the latest revision on main
    • Ensure that your downgrade() migration is correct and works
      • If a downgrade migration is not possible for this change, please call this out in the PR description!
    • No migrations
  • Documentation:
    • Documentation complete, PR opened in fidesdocs
    • Documentation issue created in fidesdocs
    • If there are any new client scopes created as part of the pull request, remember to update public-facing documentation that references our scope registry
    • No documentation updates required

@vercel
Copy link

vercel bot commented Aug 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
fides-plus-nightly Ignored Ignored Preview Sep 3, 2025 0:09am
fides-privacy-center Ignored Ignored Sep 3, 2025 0:09am

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR implements comprehensive session invalidation logic to address the security vulnerability CVE-2025-57766. When a user's password is reset or updated, all existing authentication sessions are immediately invalidated to prevent unauthorized access from potentially compromised tokens.

The implementation operates at multiple layers:

Backend Authentication Layer: A new is_token_invalidated() function in oauth/utils.py checks if tokens were issued before the user's most recent password reset by comparing token timestamps against the password_reset_at field. This function is integrated into the token extraction process to automatically reject outdated tokens with HTTP 403 responses.

OAuth Client Management: During password resets, the user's associated OAuth client is deleted entirely in both user-initiated (update_user_password) and admin-forced (force_update_password) scenarios. This provides an additional layer of session invalidation beyond timestamp checking.

Frontend Session Management: Both password update modals (UpdatePasswordModal and NewPasswordModal) now implement proper logout flows when users change their own passwords. This includes clearing localStorage, dispatching logout actions, and redirecting to the login page to ensure client-side state remains consistent with server-side invalidation.

Model Relationships: A circular import issue between ClientDetail and FidesUser models was resolved using TYPE_CHECKING blocks to maintain the relationship needed for password reset timestamp validation.

The changes are thoroughly tested with a new test case that verifies old tokens become invalid immediately after password resets. This security enhancement ensures that password changes - whether due to compromise, security incidents, or routine updates - immediately terminate all existing sessions, forcing users to re-authenticate with their new credentials.

PR Description Notes:

  • The description sections ("Description Of Changes", "Code Changes", "Steps to Confirm") are marked as "TBD" and should be completed before merge

Important Files Changed

Files Changed
Filename Score Overview
CHANGELOG.md 5/5 Documents the security fix with CVE reference and cleans up duplicate section headers
src/fides/api/oauth/utils.py 4/5 Core implementation of token invalidation logic with timestamp checking
clients/admin-ui/src/features/user-management/NewPasswordModal.tsx 4/5 Adds logout flow when admin resets their own password
src/fides/api/api/v1/endpoints/user_endpoints.py 4/5 Implements OAuth client deletion during password resets
src/fides/api/models/client.py 5/5 Resolves circular import issue for user relationship access
tests/ops/api/v1/endpoints/test_user_endpoints.py 4/5 Adds comprehensive test coverage for session invalidation
clients/admin-ui/src/features/user-management/UpdatePasswordModal.tsx 4/5 Implements logout flow after successful password updates

Confidence score: 4/5

  • This PR implements critical security functionality with multiple layers of protection and comprehensive testing
  • Score reflects well-structured implementation with proper error handling, but complexity across multiple components requires careful validation
  • Pay close attention to the OAuth token validation logic in utils.py and ensure all password reset flows properly trigger session invalidation

Sequence Diagram

sequenceDiagram
    participant User
    participant AdminUI as Admin UI
    participant API as Fides API
    participant DB as Database
    participant Auth as Auth System

    Note over User, Auth: Password Reset Session Invalidation Flow

    User->>AdminUI: Click "Reset password" button
    AdminUI->>AdminUI: Open NewPasswordModal
    User->>AdminUI: Enter new password details
    AdminUI->>API: POST /api/v1/user/{id}/force-reset-password
    
    API->>DB: Validate user exists
    DB-->>API: User found
    
    API->>API: Hash new password
    API->>DB: Update user password
    API->>DB: Set password_reset_at timestamp
    
    Note over API, DB: Session Invalidation Logic
    API->>DB: Find user's OAuth client
    API->>DB: Delete OAuth client (invalidates all sessions)
    
    DB-->>API: Password updated, client deleted
    API-->>AdminUI: Success response
    
    AdminUI->>AdminUI: Check if admin reset own password
    alt Admin reset own password
        AdminUI->>AdminUI: Clear localStorage
        AdminUI->>Auth: Dispatch logout()
        AdminUI->>AdminUI: Redirect to login page
    else Admin reset other user's password
        AdminUI->>AdminUI: Show success toast
    end

    Note over User, Auth: Token Validation on Subsequent Requests
    User->>API: Make request with old token
    API->>Auth: Extract token and load client
    Auth->>DB: Load client by ID
    DB-->>Auth: Client not found (deleted)
    Auth-->>API: Authorization error
    API-->>User: 403 Forbidden

    alt User tries with valid new session
        User->>AdminUI: Login with new password
        AdminUI->>API: POST /api/v1/login
        API->>DB: Create new OAuth client
        API-->>AdminUI: New token
        AdminUI->>API: Make request with new token
        API->>Auth: Validate token
        Auth-->>API: Valid
        API-->>AdminUI: Success
    end
Loading

Context used:

Rule - Review the entire PR not just the last commits (link)

7 files reviewed, 2 comments

Edit Code Review Bot Settings | Greptile

Comment on lines +217 to +219
"Unable to delete user client during password reset for user {}: {}",
current_user.id,
exc,
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Using bare Exception catch is overly broad. Consider catching more specific exceptions like database errors to avoid masking unexpected issues

@codecov
Copy link

codecov bot commented Aug 29, 2025

Codecov Report

❌ Patch coverage is 56.00000% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.64%. Comparing base (f2df9a2) to head (da5ad56).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/fides/api/api/v1/endpoints/user_endpoints.py 40.00% 4 Missing and 2 partials ⚠️
src/fides/api/oauth/utils.py 64.28% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6526      +/-   ##
==========================================
- Coverage   87.66%   87.64%   -0.03%     
==========================================
  Files         483      483              
  Lines       30908    30931      +23     
  Branches     3482     3486       +4     
==========================================
+ Hits        27096    27108      +12     
- Misses       3067     3074       +7     
- Partials      745      749       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@thabofletcher thabofletcher force-pushed the ENG-681-pw-reset-session-invalidation branch from 7316e8d to 421be70 Compare August 30, 2025 03:20
@thabofletcher thabofletcher changed the title ENG-681 Re implement pw reset session invalidation ENG-861 Re implement pw reset session invalidation Sep 2, 2025
@thabofletcher thabofletcher changed the title ENG-861 Re implement pw reset session invalidation ENG-681 Re implement pw reset session invalidation Sep 2, 2025
Copy link
Contributor

@erosselli erosselli left a comment

Choose a reason for hiding this comment

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

I'm approving, thanks for making the changes. I think we should ticket a follow-up to look at the timezone comparison thing a bit more in depth as it feels like it might be kind of fragile? though not as bad as the original security vuln.

Also let's make sure we get proper coverage :)

Comment on lines +2199 to +2200
from fides.config import CONFIG
from tests.conftest import _generate_auth_header
Copy link
Contributor

Choose a reason for hiding this comment

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

this is cursor being annoying with the local imports, can we move them top-level? I have an item in my to-do list to add a rule to fides so it doesn't do this

Comment on lines +1288 to +1289
assert resp_reset.status_code == HTTP_200_OK
# Exception is handled and request succeeds; log assertion not required for coverage
Copy link
Contributor

Choose a reason for hiding this comment

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

log assertion is not required but we could add it at very little cost right ? since it's the only "evidence" that we're hitting the exception code path, and codecov's reporting we aren't ... so it might be a good sanity check to leave in place , you can use the loguru_caplog fixture

@thabofletcher thabofletcher merged commit e7ca762 into main Sep 3, 2025
24 checks passed
@thabofletcher thabofletcher deleted the ENG-681-pw-reset-session-invalidation branch September 3, 2025 00:13
@cypress
Copy link

cypress bot commented Sep 3, 2025

fides    Run #13317

Run Properties:  status check passed Passed #13317  •  git commit e7ca762281: ENG-681 Re implement pw reset session invalidation (#6526)
Project fides
Branch Review main
Run status status check passed Passed #13317
Run duration 00m 55s
Commit git commit e7ca762281: ENG-681 Re implement pw reset session invalidation (#6526)
Committer Thabo Fletcher
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 5
View all changes introduced in this branch ↗︎

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.

4 participants