Skip to content

oauth2-session raft driver: add user/client/domain and expiry indexes for refresh families and device grants #1255

Closed

Description

@gtema

Roadmap step 1 (M1). Audit findings F-A3, prerequisite for F-F1.

Current state

crates/oauth2-session-driver-raft/src/lib.rs:44-70 defines only primary keys plus one family index:

oauth2:session:v1:<session_id>
oauth2:code:v1:<code>
oauth2:refresh:v1:<sha256(bearer)>
oauth2:refresh_family_idx:v1:<family_id>:<token_id>
oauth2:device_code:v1:<device_code>
oauth2:device_user_code:v1:<user_code>

Nothing maps a user_id, client_id, or domain_id to its refresh families, and nothing orders records by expires_at. Every revocation and sweep use case is a full scan.

What must be done

  • Add secondary index keys written in the same Raft transaction as the primary record:
    • oauth2:refresh_user_idx:v1:<domain_id>:<user_id>:<family_id>
    • oauth2:refresh_client_idx:v1:<client_id>:<family_id>
    • oauth2:refresh_domain_idx:v1:<domain_id>:<family_id> (can be derived from user idx prefix; keep explicit for domain-wide revoke)
    • oauth2:expiry_idx:v1:<expires_at zero-padded i64>:<kind>:<primary_key> for pre-auth sessions, authorization codes, device grants, and refresh tokens. Rewrite the expiry entry on refresh rotation (old removed, new added).
  • Extend Oauth2SessionBackend (crates/core/src/oauth2_session/backend.rs) with:
    • list_refresh_families_by_user(domain_id, user_id) -> Vec<String>
    • list_refresh_families_by_client(client_id) -> Vec<String>
    • list_refresh_families_by_domain(domain_id) -> Vec<String>
    • list_expired(before: i64, limit: usize) -> Vec<(kind, key)>
  • Keep index and primary writes atomic via StorageApi::transaction (mirror create_refresh_token_impl at lib.rs:255-283, which already writes the family index this way).
  • Update MockOauth2SessionBackend users in crates/core and crates/keystone tests.
  • Raft driver unit tests: index round-trip for each new index, prefix scan returns only matching families, expiry scan honours before and limit.
  • Bump nothing on-disk-incompatible: existing v1 records without indexes must still be readable; document that pre-existing refresh families are not indexed until first rotation (or add a one-shot backfill in keystone-manage).

Acceptance

cargo test -p openstack_keystone_oauth2_session_driver_raft green; cargo nextest run -p test_integration --profile raft green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions