1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Move Authority Propagation Into Filters

Given that the filters are the level at which the
SecurityContextHolder is consulted, this commit moves
the operation that ProviderManager was doing into each
authentication filter.

Issue gh-17862
This commit is contained in:
Josh Cummings
2025-08-29 13:14:21 -06:00
parent a0fe6a5fee
commit 3f774548d2
17 changed files with 60 additions and 138 deletions
@@ -248,6 +248,12 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
// return immediately as subclass has indicated that it hasn't completed
return;
}
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
authenticationResult = authenticationResult.toBuilder()
.authorities((a) -> a.addAll(current.getAuthorities()))
.build();
}
this.sessionStrategy.onAuthentication(authenticationResult, request, response);
// Authentication success
if (this.continueChainBeforeSuccessfulAuthentication) {
@@ -184,6 +184,12 @@ public class AuthenticationFilter extends OncePerRequestFilter {
filterChain.doFilter(request, response);
return;
}
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
authenticationResult = authenticationResult.toBuilder()
.authorities((a) -> a.addAll(current.getAuthorities()))
.build();
}
HttpSession session = request.getSession(false);
if (session != null) {
request.changeSessionId();
@@ -204,6 +204,12 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
principal, credentials);
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
authenticationResult = authenticationResult.toBuilder()
.authorities((a) -> a.addAll(current.getAuthorities()))
.build();
}
successfulAuthentication(request, response, authenticationResult);
}
catch (AuthenticationException ex) {
@@ -186,6 +186,10 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter {
this.logger.trace(LogMessage.format("Found username '%s' in Basic Authorization header", username));
if (authenticationIsRequired(username)) {
Authentication authResult = this.authenticationManager.authenticate(authRequest);
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
authResult = authResult.toBuilder().authorities((a) -> a.addAll(current.getAuthorities())).build();
}
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
context.setAuthentication(authResult);
this.securityContextHolderStrategy.setContext(context);
@@ -122,12 +122,26 @@ public class AuthenticationWebFilter implements WebFilter {
.flatMap((authenticationManager) -> authenticationManager.authenticate(token))
.switchIfEmpty(Mono
.defer(() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass()))))
.flatMap(this::applyCurrentAuthenication)
.flatMap(
(authentication) -> onAuthenticationSuccess(authentication, new WebFilterExchange(exchange, chain)))
.doOnError(AuthenticationException.class,
(ex) -> logger.debug(LogMessage.format("Authentication failed: %s", ex.getMessage()), ex));
}
private Mono<Authentication> applyCurrentAuthenication(Authentication result) {
return ReactiveSecurityContextHolder.getContext().map((context) -> {
Authentication current = context.getAuthentication();
if (current == null) {
return result;
}
if (!current.isAuthenticated()) {
return result;
}
return result.toBuilder().authorities((a) -> a.addAll(current.getAuthorities())).build();
}).switchIfEmpty(Mono.just(result));
}
protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {
ServerWebExchange exchange = webFilterExchange.getExchange();
SecurityContextImpl securityContext = new SecurityContextImpl();
@@ -144,6 +144,7 @@ public class AuthenticationFilterTests {
this.authenticationConverter);
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl());
given(strategy.getContext()).willReturn(new SecurityContextImpl());
filter.setSecurityContextHolderStrategy(strategy);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
MockHttpServletResponse response = new MockHttpServletResponse();