Repository navigation
feat(oauth2): Add jti replay cache for external assertions - #1640
thinhphucnguyen wants to merge 1 commit into
Conversation
Signed-off-by: Thinh Phuc Nguyen <nguyenthinhphuc1901@gmail.com>
gtema
left a comment
There was a problem hiding this comment.
Here we come to the dirty reality. You add a in-process cache which only protects a single node, but the request landing on the other node would work. The WebAuthn has similar issue where a short-living auth state must be shared across all cluster instances. This is done through the Raft storage as the 'ephemeral' value (kept in logs for replay, but not stored in the DB). Here we have a pretty similar usecase.
It doesn't make the PR useless, but first we need to think further on how this should be integrated with each other. One option is to introduce the SingleUseStore trait and have few implementations for it: local and cluster/raft. This PR would then define the trait and implement it for ReplayCache while in the next PR we can add a raft based implementation.
I need to think on this deeper, so for now I would suggest you focus on something else. I will make it a draft for now to signal work in progress
|
the foundation work is layed in PR 1641. Once it lands you can do following (after rebase):
|
External IdP assertions can be presented to the token endpoint more than
once while they are valid. This adds the cache that remembers the
jtiofaccepted assertions so the exchange handler can refuse a second use.
What changed:
replay.rs: the bounded(scope, id)cache fromDpopReplayCache,generalised so the caller passes the expiry. Same rules as before: bounded
per scope and in total, and a live entry is never evicted to make room.
dpop_replay.rs:DpopReplayCacheis now a thin wrapper around it. PublicAPI and
DpopReplayErrorare unchanged, and I did not touch its tests.assertion_replay.rs:AssertionReplayCache, keyed by (domain, issuer,jti). An entry lives untilexpplus the profile's clock skew, the lastmoment the token can still pass
verify_subject_token_jwt. It reads theskew from the profile constant, so the two cannot drift apart (the only
change in
verify.rsispub(crate)on that constant).Nothing calls the new cache yet. Wiring and config limits come after.
Tested with the new unit tests plus the existing DPoP ones, run one test per
process the way nextest does.