refactor: soft-refresh via SecurityContextRepository decorator instead of filter#24495
Closed
netroms wants to merge 2 commits into
Closed
refactor: soft-refresh via SecurityContextRepository decorator instead of filter#24495netroms wants to merge 2 commits into
netroms wants to merge 2 commits into
Conversation
Replace role/user-driven mass SessionRegistry.expireNow with a JDBC-backed
two-level invalidation scheme:
- authz_version table holds per-user ('user', <uid>) and per-role
('role', <uid>) generation stamps plus a single global epoch row; every
bump advances the epoch in the same transaction as the entity change,
so readers can never observe a stamp without its data. A schema-only
JPA mapping (AuthzVersion) lets H2 test contexts generate the table;
production schema stays Flyway-managed (V2_44_16) and validated at
startup.
- UserDetailsSoftRefreshFilter (session-bound auth only: form + OIDC,
never JWT/PAT/stateless, never during impersonation) checks one epoch
read per request; on epoch movement it compares the principal's
effective generation and lazily rebuilds an immutable UserDetails
snapshot, replacing the Authentication with an explicit
SecurityContextRepository save. No logout, no cookie change.
- AuthzService memoizes snapshots per username keyed by a pre-read epoch
(stamp-before-build invariant) with striped single-flight rebuilds;
JWT and PAT auth paths share the same epoch-validated cache.
- Role authority/restriction edits and role deletion bump one role key,
O(1) regardless of member count. User role/org-unit changes and group
membership deltas (import hook owning side + service paths) bump only
affected users.
- Gen bumps are update-first with a dialect-branched first-insert
(Postgres ON CONFLICT DO NOTHING; plain INSERT on H2, which has no
ON CONFLICT support).
- Password change, disable, lock, and expiry keep hard session
invalidation.
…d of filter Decorating the HttpSession delegate of the standard repository pair makes the refresh session-only by construction: JWT, PAT, and stateless authentications never load through HttpSessionSecurityContextRepository, so no token-type conversion or accidental session creation is possible, and the filter-ordering concern disappears. Wrapping DeferredSecurityContext runs the freshness check only when a request actually accesses its authentication. Under requireExplicitSave the refresh persists itself via the session attribute (SecurityContextHolderFilter never saves). Same decision flow, gates, and OIDC rebuild as the removed filter; tests ported to load-through-repository semantics plus laziness and caching cases.
netroms
force-pushed
the
feat/userdetails-soft-refresh-v2
branch
from
July 18, 2026 20:07
df3f015 to
9dfed6e
Compare
Contributor
Author
|
Folded into #24493 per review preference for a single readable PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #24493 (base is that PR's branch, so this diff shows only the restructure — same behavior, one commit).
UserDetailsSoftRefreshFilterwithSoftRefreshSecurityContextRepository, decorating theHttpSessiondelegate of the standardDelegatingSecurityContextRepositorypair.HttpSessionSecurityContextRepository, so token-type conversion or accidental session creation is impossible by construction, and the filter-ordering concern disappears.DeferredSecurityContextwrapping runs the freshness check only when a request actually accesses its authentication; underrequireExplicitSavethe refresh persists itself via the session attribute (SecurityContextHolderFilternever saves — verified against Spring Security 6.5.10 sources).Test plan
SoftRefreshSecurityContextRepositoryTest(9: PAT/impersonation skip, epoch fast path, gen refresh + self-persistence, OIDC rebuild, deferred laziness, get() caching)UserControllerTest52/52,AuthzSoftRefreshH2CompatTest3/3,MeControllerTest28/28AI Assisted