Skip to content

Commit eb30ff9

Browse files
committed
Provide Authentication to AuthenticationExceptions
Issue gh-16444
1 parent a3e7cbe commit eb30ff9

File tree

8 files changed

+55
-23
lines changed

8 files changed

+55
-23
lines changed

core/src/main/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManager.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626
import reactor.core.publisher.Mono;
2727

2828
import org.springframework.security.core.Authentication;
29+
import org.springframework.security.core.AuthenticationException;
2930
import org.springframework.util.Assert;
3031

3132
/**
@@ -58,6 +59,7 @@ public DelegatingReactiveAuthenticationManager(List<ReactiveAuthenticationManage
5859
public Mono<Authentication> authenticate(Authentication authentication) {
5960
Flux<ReactiveAuthenticationManager> result = Flux.fromIterable(this.delegates);
6061
Function<ReactiveAuthenticationManager, Mono<Authentication>> logging = (m) -> m.authenticate(authentication)
62+
.doOnError(AuthenticationException.class, (ex) -> ex.setAuthenticationRequest(authentication))
6163
.doOnError(this.logger::debug);
6264

6365
return ((this.continueOnError) ? result.concatMapDelayError(logging) : result.concatMap(logging)).next();

core/src/main/java/org/springframework/security/authentication/ProviderManager.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -202,6 +202,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
202202
throw ex;
203203
}
204204
catch (AuthenticationException ex) {
205+
ex.setAuthenticationRequest(authentication);
205206
logger.debug(LogMessage.format("Authentication failed with provider %s since %s",
206207
provider.getClass().getSimpleName(), ex.getMessage()));
207208
lastException = ex;
@@ -265,6 +266,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
265266

266267
@SuppressWarnings("deprecation")
267268
private void prepareException(AuthenticationException ex, Authentication auth) {
269+
ex.setAuthenticationRequest(auth);
268270
this.eventPublisher.publishAuthenticationFailure(ex, auth);
269271
}
270272

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -176,7 +176,9 @@ public Authentication authenticate(Authentication authentication) throws Authent
176176
String issuer = this.issuerConverter.convert(token);
177177
AuthenticationManager authenticationManager = this.issuerAuthenticationManagerResolver.resolve(issuer);
178178
if (authenticationManager == null) {
179-
throw new InvalidBearerTokenException("Invalid issuer");
179+
AuthenticationException ex = new InvalidBearerTokenException("Invalid issuer");
180+
ex.setAuthenticationRequest(authentication);
181+
throw ex;
180182
}
181183
return authenticationManager.authenticate(authentication);
182184
}
@@ -194,10 +196,14 @@ public String convert(@NonNull BearerTokenAuthenticationToken authentication) {
194196
return issuer;
195197
}
196198
}
197-
catch (Exception ex) {
198-
throw new InvalidBearerTokenException(ex.getMessage(), ex);
199+
catch (Exception cause) {
200+
AuthenticationException ex = new InvalidBearerTokenException(cause.getMessage(), cause);
201+
ex.setAuthenticationRequest(authentication);
202+
throw ex;
199203
}
200-
throw new InvalidBearerTokenException("Missing issuer");
204+
AuthenticationException ex = new InvalidBearerTokenException("Missing issuer");
205+
ex.setAuthenticationRequest(authentication);
206+
throw ex;
201207
}
202208

203209
}

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java

+16-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
3636
import org.springframework.security.authentication.ReactiveAuthenticationManager;
3737
import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;
3838
import org.springframework.security.core.Authentication;
39+
import org.springframework.security.core.AuthenticationException;
3940
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
4041
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
4142
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
@@ -181,7 +182,11 @@ public Mono<Authentication> authenticate(Authentication authentication) {
181182
BearerTokenAuthenticationToken token = (BearerTokenAuthenticationToken) authentication;
182183
return this.issuerConverter.convert(token)
183184
.flatMap((issuer) -> this.issuerAuthenticationManagerResolver.resolve(issuer)
184-
.switchIfEmpty(Mono.error(() -> new InvalidBearerTokenException("Invalid issuer " + issuer))))
185+
.switchIfEmpty(Mono.error(() -> {
186+
AuthenticationException ex = new InvalidBearerTokenException("Invalid issuer " + issuer);
187+
ex.setAuthenticationRequest(authentication);
188+
return ex;
189+
})))
185190
.flatMap((manager) -> manager.authenticate(authentication));
186191
}
187192

@@ -194,12 +199,18 @@ public Mono<String> convert(@NonNull BearerTokenAuthenticationToken token) {
194199
try {
195200
String issuer = JWTParser.parse(token.getToken()).getJWTClaimsSet().getIssuer();
196201
if (issuer == null) {
197-
throw new InvalidBearerTokenException("Missing issuer");
202+
AuthenticationException ex = new InvalidBearerTokenException("Missing issuer");
203+
ex.setAuthenticationRequest(token);
204+
throw ex;
198205
}
199206
return Mono.just(issuer);
200207
}
201-
catch (Exception ex) {
202-
return Mono.error(() -> new InvalidBearerTokenException(ex.getMessage(), ex));
208+
catch (Exception cause) {
209+
return Mono.error(() -> {
210+
AuthenticationException ex = new InvalidBearerTokenException(cause.getMessage(), cause);
211+
ex.setAuthenticationRequest(token);
212+
return ex;
213+
});
203214
}
204215
}
205216

web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2004-2022 the original author or authors.
2+
* Copyright 2004-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -194,10 +194,11 @@ private void handleAccessDeniedException(HttpServletRequest request, HttpServlet
194194
logger.trace(LogMessage.format("Sending %s to authentication entry point since access is denied",
195195
authentication), exception);
196196
}
197-
sendStartAuthentication(request, response, chain,
198-
new InsufficientAuthenticationException(
199-
this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication",
200-
"Full authentication is required to access this resource")));
197+
AuthenticationException ex = new InsufficientAuthenticationException(
198+
this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication",
199+
"Full authentication is required to access this resource"));
200+
ex.setAuthenticationRequest(authentication);
201+
sendStartAuthentication(request, response, chain, ex);
201202
}
202203
else {
203204
if (logger.isTraceEnabled()) {

web/src/main/java/org/springframework/security/web/authentication/RequestMatcherDelegatingAuthenticationManagerResolver.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
2727
import org.springframework.security.authentication.AuthenticationManagerResolver;
2828
import org.springframework.security.authentication.AuthenticationServiceException;
2929
import org.springframework.security.authorization.AuthorizationManager;
30+
import org.springframework.security.core.AuthenticationException;
3031
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
3132
import org.springframework.security.web.util.matcher.RequestMatcher;
3233
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
@@ -46,7 +47,9 @@ public final class RequestMatcherDelegatingAuthenticationManagerResolver
4647
private final List<RequestMatcherEntry<AuthenticationManager>> authenticationManagers;
4748

4849
private AuthenticationManager defaultAuthenticationManager = (authentication) -> {
49-
throw new AuthenticationServiceException("Cannot authenticate " + authentication);
50+
AuthenticationException ex = new AuthenticationServiceException("Cannot authenticate " + authentication);
51+
ex.setAuthenticationRequest(authentication);
52+
throw ex;
5053
};
5154

5255
/**

web/src/main/java/org/springframework/security/web/server/authentication/ServerWebExchangeDelegatingReactiveAuthenticationManagerResolver.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626
import org.springframework.security.authentication.AuthenticationServiceException;
2727
import org.springframework.security.authentication.ReactiveAuthenticationManager;
2828
import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;
29+
import org.springframework.security.core.AuthenticationException;
2930
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
3031
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
3132
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcherEntry;
@@ -46,8 +47,11 @@ public final class ServerWebExchangeDelegatingReactiveAuthenticationManagerResol
4647

4748
private final List<ServerWebExchangeMatcherEntry<ReactiveAuthenticationManager>> authenticationManagers;
4849

49-
private ReactiveAuthenticationManager defaultAuthenticationManager = (authentication) -> Mono
50-
.error(new AuthenticationServiceException("Cannot authenticate " + authentication));
50+
private ReactiveAuthenticationManager defaultAuthenticationManager = (authentication) -> {
51+
AuthenticationException ex = new AuthenticationServiceException("Cannot authenticate " + authentication);
52+
ex.setAuthenticationRequest(authentication);
53+
return Mono.error(ex);
54+
};
5155

5256
/**
5357
* Construct an

web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -93,6 +93,9 @@ public void setAuthenticationTrustResolver(AuthenticationTrustResolver authentic
9393
}
9494

9595
private <T> Mono<T> commenceAuthentication(ServerWebExchange exchange, AuthenticationException denied) {
96+
if (exchange.getPrincipal() instanceof Authentication authentication) {
97+
denied.setAuthenticationRequest(authentication);
98+
}
9699
return this.authenticationEntryPoint
97100
.commence(exchange, new AuthenticationCredentialsNotFoundException("Not Authenticated", denied))
98101
.then(Mono.empty());

0 commit comments

Comments
 (0)