Skip to content

fix(oauth2): Apply default token exp if nil #1353 - #1616

Open
millionsouls wants to merge 5 commits into
openstack-experimental:mainfrom
millionsouls:expiry2
Open

millionsouls wants to merge 5 commits into
openstack-experimental:mainfrom
millionsouls:expiry2

Conversation

@millionsouls

Copy link
Copy Markdown
Contributor

Summary

Use configured access token lifetime if the subject or app cred token have no expiry. Caps exp at credential expiry that is present, reject any lifetime that is not postive, and send result to expires_in. Removed prior MissingSubjectTokenExpiry error, and changed the respective test function to instead test for applying default expiration lifetime.

Test plan

cargo test -p openstack-keystone-core oauth2_client::token_exchange::tests Expiry rules
cargo test -p openstack-keystone api::v4::oauth2::token::token_exchange::tests Endpoint and response
cargo check -p openstack-keystone --message-format=short Compiling
cargo fmt --check Formatting

Security review checklist

Required if this diff touches authentication, scope, delegation, tokens,
credentials, EC2, trusts, application credentials, or OPA policy input.

Delete this section entirely if it doesn't apply. See
doc/src/contributor/security-model.md
§7 for the full context behind each item.

  • Does any delegation/authorization decision read the scope
    (project_id, ScopeInfo) where it should read the chain
    (authentication_context(), delegation object)? (I1/I2)
  • New delegation-sensitive policy rule? Is the fact it needs projected
    onto Credentials from the chain, and does the rule anchor on
    delegated_project_id + carry the scope-drift tripwire? (I2/I3)
  • New scope shape or redemption path for a delegated auth? Are effective
    roles still bounded by the delegation? Added a test that a restricted
    delegation cannot exceed its roles via the new path? (I4)
  • New ScopeInfo variant or auth method? Updated
    validate_scope_boundaries(), calculate_effective_roles(),
    fully_resolved(), and Credentials::try_from — all without adding a
    wildcard _ => arm? (I5, Gate J)
  • New lookup by a client-derivable key (like sha256(access))? Does it
    re-assert type/shape after fetch? (I6)
  • Does any new data reaching OPA include secrets/decrypted blobs? (I7,
    Gate I)
  • New list/collection endpoint? Does it re-check each item with the
    per-item read policy? (I8)
  • Same endpoint: can an unprivileged caller request the whole collection
    and leave the per-item pass to sort it out? Is the value the
    collection policy gates on the same one the driver actually filters
    by? (I8a)
  • Does the change let a narrow auth method be broadened by a
    request-supplied scope? (I5)
  • Are there negative tests proving the escape is blocked, not just
    positive tests proving the happy path works?
  • Does the test drive ValidatedSecurityContext::new_for_scope()
    end-to-end, not just the inner helper (calculate_effective_roles,
    validate_scope_boundaries) in isolation?

@millionsouls
millionsouls marked this pull request as ready for review November 5, 2026 00:10
@millionsouls
millionsouls force-pushed the expiry2 branch 6 times, most recently from a776693 to 7609a87 Compare November 9, 2026 15:30
@millionsouls
millionsouls force-pushed the expiry2 branch 3 times, most recently from 53f88d0 to 6798a66 Compare November 12, 2026 14:43
@millionsouls
millionsouls marked this pull request as draft November 12, 2026 14:43
@millionsouls
millionsouls force-pushed the expiry2 branch 3 times, most recently from 995911f to 5b083c7 Compare November 13, 2026 14:40
@millionsouls
millionsouls marked this pull request as ready for review November 14, 2026 19:09
)

Use configured access token lifetime if the subject or app cred
token have no expiry. Caps exp at credential expiry that is present,
reject any lifetime that is not postive, and send result to
expires_in.

Assisted-by: Claude <noreply@anthropic.com>

Signed-off-by: Kevin <36448536+millionsouls@users.noreply.github.com>
Assert that token exchange uses configured default when validated cred
expiries are later, and that expires_in matches exp-iat. Returns
invalid_request for expired or invalid subject credentials.

Assisted-by: Claude <noreply@anthropic.com>

Signed-off-by: Kevin <36448536+millionsouls@users.noreply.github.com>
Signed-off-by: Kevin <36448536+millionsouls@users.noreply.github.com>
Route claim building failures to the shared exchange_error mapper
instead of a partial inline mapping.

Signed-off-by: Kevin <36448536+millionsouls@users.noreply.github.com>
Feeds client side TokenExchangeError through exchange_error and
asserts each maps to 400 invalid_request.

Signed-off-by: Kevin <36448536+millionsouls@users.noreply.github.com>

This branch has not been deployed

No deployments
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