Skip to content

Commit ccb3b02

Browse files
committed
Bearer Token Server-side Errors Return 500
Closes gh-9395
1 parent ca5e303 commit ccb3b02

File tree

4 files changed

+45
-30
lines changed

4 files changed

+45
-30
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

Lines changed: 11 additions & 13 deletions
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-2021 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.
@@ -78,6 +78,7 @@
7878
import org.springframework.security.authentication.AuthenticationManager;
7979
import org.springframework.security.authentication.AuthenticationManagerResolver;
8080
import org.springframework.security.authentication.AuthenticationProvider;
81+
import org.springframework.security.authentication.AuthenticationServiceException;
8182
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
8283
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
8384
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -104,7 +105,6 @@
104105
import org.springframework.security.oauth2.jwt.Jwt;
105106
import org.springframework.security.oauth2.jwt.JwtClaimNames;
106107
import org.springframework.security.oauth2.jwt.JwtDecoder;
107-
import org.springframework.security.oauth2.jwt.JwtException;
108108
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
109109
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
110110
import org.springframework.security.oauth2.jwt.TestJwts;
@@ -260,26 +260,24 @@ public void getWhenUsingDefaultsWithExpiredBearerTokenThenInvalidToken() throws
260260
}
261261

262262
@Test
263-
public void getWhenUsingDefaultsWithBadJwkEndpointThenInvalidToken() throws Exception {
263+
public void getWhenUsingDefaultsWithBadJwkEndpointThen500() throws Exception {
264264
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
265265
mockRestOperations("malformed");
266266
String token = this.token("ValidNoScopes");
267267
// @formatter:off
268-
this.mvc.perform(get("/").with(bearerToken(token)))
269-
.andExpect(status().isUnauthorized())
270-
.andExpect(header().string("WWW-Authenticate", "Bearer"));
268+
assertThatExceptionOfType(AuthenticationServiceException.class)
269+
.isThrownBy(() -> this.mvc.perform(get("/").with(bearerToken(token))));
271270
// @formatter:on
272271
}
273272

274273
@Test
275-
public void getWhenUsingDefaultsWithUnavailableJwkEndpointThenInvalidToken() throws Exception {
274+
public void getWhenUsingDefaultsWithUnavailableJwkEndpointThen500() throws Exception {
276275
this.spring.register(WebServerConfig.class, JwkSetUriConfig.class).autowire();
277276
this.web.shutdown();
278277
String token = this.token("ValidNoScopes");
279278
// @formatter:off
280-
this.mvc.perform(get("/").with(bearerToken(token)))
281-
.andExpect(status().isUnauthorized())
282-
.andExpect(header().string("WWW-Authenticate", "Bearer"));
279+
assertThatExceptionOfType(AuthenticationServiceException.class)
280+
.isThrownBy(() -> this.mvc.perform(get("/").with(bearerToken(token))));
283281
// @formatter:on
284282
}
285283

@@ -825,7 +823,7 @@ public void getJwtDecoderWhenTwoJwtDecoderBeansThenThrowsException() {
825823
public void requestWhenRealmNameConfiguredThenUsesOnUnauthenticated() throws Exception {
826824
this.spring.register(RealmNameConfiguredOnEntryPoint.class, JwtDecoderConfig.class).autowire();
827825
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
828-
given(decoder.decode(anyString())).willThrow(JwtException.class);
826+
given(decoder.decode(anyString())).willThrow(BadJwtException.class);
829827
// @formatter:off
830828
this.mvc.perform(get("/authenticated").with(bearerToken("invalid_token")))
831829
.andExpect(status().isUnauthorized())
@@ -1092,7 +1090,7 @@ public void getIntrospectionClientWhenDslAndBeanWiredThenDslTakesPrecedence() {
10921090
public void requestWhenBasicAndResourceServerEntryPointsThenMatchedByRequest() throws Exception {
10931091
this.spring.register(BasicAndResourceServerConfig.class, JwtDecoderConfig.class).autowire();
10941092
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
1095-
given(decoder.decode(anyString())).willThrow(JwtException.class);
1093+
given(decoder.decode(anyString())).willThrow(BadJwtException.class);
10961094
// @formatter:off
10971095
this.mvc.perform(get("/authenticated").with(httpBasic("some", "user")))
10981096
.andExpect(status().isUnauthorized())
@@ -1110,7 +1108,7 @@ public void requestWhenBasicAndResourceServerEntryPointsThenMatchedByRequest() t
11101108
public void requestWhenFormLoginAndResourceServerEntryPointsThenSessionCreatedByRequest() throws Exception {
11111109
this.spring.register(FormAndResourceServerConfig.class, JwtDecoderConfig.class).autowire();
11121110
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
1113-
given(decoder.decode(anyString())).willThrow(JwtException.class);
1111+
given(decoder.decode(anyString())).willThrow(BadJwtException.class);
11141112
// @formatter:off
11151113
MvcResult result = this.mvc.perform(get("/authenticated")
11161114
.header("Accept", "text/html"))

config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java

Lines changed: 12 additions & 13 deletions
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-2021 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.
@@ -69,17 +69,18 @@
6969
import org.springframework.http.RequestEntity;
7070
import org.springframework.http.ResponseEntity;
7171
import org.springframework.security.authentication.AuthenticationManagerResolver;
72+
import org.springframework.security.authentication.AuthenticationServiceException;
7273
import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.JwtBeanDefinitionParser;
7374
import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.OpaqueTokenBeanDefinitionParser;
7475
import org.springframework.security.config.test.SpringTestRule;
7576
import org.springframework.security.oauth2.core.OAuth2Error;
7677
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
7778
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
7879
import org.springframework.security.oauth2.jose.TestKeys;
80+
import org.springframework.security.oauth2.jwt.BadJwtException;
7981
import org.springframework.security.oauth2.jwt.Jwt;
8082
import org.springframework.security.oauth2.jwt.JwtClaimNames;
8183
import org.springframework.security.oauth2.jwt.JwtDecoder;
82-
import org.springframework.security.oauth2.jwt.JwtException;
8384
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
8485
import org.springframework.security.oauth2.jwt.TestJwts;
8586
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
@@ -168,26 +169,24 @@ public void getWhenExpiredBearerTokenThenInvalidToken() throws Exception {
168169
}
169170

170171
@Test
171-
public void getWhenBadJwkEndpointThenInvalidToken() throws Exception {
172+
public void getWhenBadJwkEndpointThen500() throws Exception {
172173
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
173174
mockRestOperations("malformed");
174175
String token = this.token("ValidNoScopes");
175176
// @formatter:off
176-
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
177-
.andExpect(status().isUnauthorized())
178-
.andExpect(header().string("WWW-Authenticate", "Bearer"));
177+
assertThatExceptionOfType(AuthenticationServiceException.class)
178+
.isThrownBy(() -> this.mvc.perform(get("/").header("Authorization", "Bearer " + token)));
179179
// @formatter:on
180180
}
181181

182182
@Test
183-
public void getWhenUnavailableJwkEndpointThenInvalidToken() throws Exception {
183+
public void getWhenUnavailableJwkEndpointThen500() throws Exception {
184184
this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire();
185185
this.web.shutdown();
186186
String token = this.token("ValidNoScopes");
187187
// @formatter:off
188-
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
189-
.andExpect(status().isUnauthorized())
190-
.andExpect(header().string("WWW-Authenticate", "Bearer"));
188+
assertThatExceptionOfType(AuthenticationServiceException.class)
189+
.isThrownBy(() -> this.mvc.perform(get("/").header("Authorization", "Bearer " + token)));
191190
// @formatter:on
192191
}
193192

@@ -529,7 +528,7 @@ public void configureWhenDecoderAndJwkSetUriThenException() {
529528
public void requestWhenRealmNameConfiguredThenUsesOnUnauthenticated() throws Exception {
530529
this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire();
531530
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
532-
Mockito.when(decoder.decode(anyString())).thenThrow(JwtException.class);
531+
Mockito.when(decoder.decode(anyString())).thenThrow(BadJwtException.class);
533532
// @formatter:off
534533
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token"))
535534
.andExpect(status().isUnauthorized())
@@ -736,7 +735,7 @@ public void requestWhenBasicAndResourceServerEntryPointsThenBearerTokenPresides(
736735
// different from DSL
737736
this.spring.configLocations(xml("MockJwtDecoder"), xml("BasicAndResourceServer")).autowire();
738737
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
739-
given(decoder.decode(anyString())).willThrow(JwtException.class);
738+
given(decoder.decode(anyString())).willThrow(BadJwtException.class);
740739
// @formatter:off
741740
this.mvc.perform(get("/authenticated").with(httpBasic("some", "user")))
742741
.andExpect(status().isUnauthorized())
@@ -755,7 +754,7 @@ public void requestWhenFormLoginAndResourceServerEntryPointsThenSessionCreatedBy
755754
// different from DSL
756755
this.spring.configLocations(xml("MockJwtDecoder"), xml("FormAndResourceServer")).autowire();
757756
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
758-
given(decoder.decode(anyString())).willThrow(JwtException.class);
757+
given(decoder.decode(anyString())).willThrow(BadJwtException.class);
759758
MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized()).andReturn();
760759
assertThat(result.getRequest().getSession(false)).isNotNull();
761760
// @formatter:off

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 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.AuthenticationDetailsSource;
2828
import org.springframework.security.authentication.AuthenticationManager;
2929
import org.springframework.security.authentication.AuthenticationManagerResolver;
30+
import org.springframework.security.authentication.AuthenticationServiceException;
3031
import org.springframework.security.core.Authentication;
3132
import org.springframework.security.core.AuthenticationException;
3233
import org.springframework.security.core.context.SecurityContext;
@@ -66,8 +67,12 @@ public final class BearerTokenAuthenticationFilter extends OncePerRequestFilter
6667

6768
private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();
6869

69-
private AuthenticationFailureHandler authenticationFailureHandler = (request, response,
70-
exception) -> this.authenticationEntryPoint.commence(request, response, exception);
70+
private AuthenticationFailureHandler authenticationFailureHandler = (request, response, exception) -> {
71+
if (exception instanceof AuthenticationServiceException) {
72+
throw exception;
73+
}
74+
this.authenticationEntryPoint.commence(request, response, exception);
75+
};
7176

7277
/**
7378
* Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s)

oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilterTests.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -34,6 +34,7 @@
3434
import org.springframework.mock.web.MockHttpServletResponse;
3535
import org.springframework.security.authentication.AuthenticationManager;
3636
import org.springframework.security.authentication.AuthenticationManagerResolver;
37+
import org.springframework.security.authentication.AuthenticationServiceException;
3738
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
3839
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
3940
import org.springframework.security.oauth2.server.resource.BearerTokenError;
@@ -42,6 +43,7 @@
4243
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
4344

4445
import static org.assertj.core.api.Assertions.assertThat;
46+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
4547
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
4648
import static org.mockito.ArgumentMatchers.any;
4749
import static org.mockito.BDDMockito.given;
@@ -154,6 +156,17 @@ public void doFilterWhenAuthenticationFailsWithCustomHandlerThenPropagatesError(
154156
verify(this.authenticationFailureHandler).onAuthenticationFailure(this.request, this.response, exception);
155157
}
156158

159+
@Test
160+
public void doFilterWhenAuthenticationServiceExceptionThenRethrows() {
161+
AuthenticationServiceException exception = new AuthenticationServiceException("message");
162+
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
163+
given(this.authenticationManager.authenticate(any())).willThrow(exception);
164+
BearerTokenAuthenticationFilter filter = addMocks(
165+
new BearerTokenAuthenticationFilter(this.authenticationManager));
166+
assertThatExceptionOfType(AuthenticationServiceException.class)
167+
.isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain));
168+
}
169+
157170
@Test
158171
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
159172
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);

0 commit comments

Comments
 (0)