diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index c36a2712b6..e7c7de2cd8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,6 +78,7 @@ import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManagerResolver; import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -104,7 +105,6 @@ import org.springframework.security.oauth2.jwt.BadJwtException; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.JwtTimestampValidator; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.oauth2.jwt.TestJwts; @@ -260,26 +260,24 @@ public class OAuth2ResourceServerConfigurerTests { } @Test - public void getWhenUsingDefaultsWithBadJwkEndpointThenInvalidToken() throws Exception { + public void getWhenUsingDefaultsWithBadJwkEndpointThen500() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire(); mockRestOperations("malformed"); String token = this.token("ValidNoScopes"); // @formatter:off - this.mvc.perform(get("/").with(bearerToken(token))) - .andExpect(status().isUnauthorized()) - .andExpect(header().string("WWW-Authenticate", "Bearer")); + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> this.mvc.perform(get("/").with(bearerToken(token)))); // @formatter:on } @Test - public void getWhenUsingDefaultsWithUnavailableJwkEndpointThenInvalidToken() throws Exception { + public void getWhenUsingDefaultsWithUnavailableJwkEndpointThen500() throws Exception { this.spring.register(WebServerConfig.class, JwkSetUriConfig.class).autowire(); this.web.shutdown(); String token = this.token("ValidNoScopes"); // @formatter:off - this.mvc.perform(get("/").with(bearerToken(token))) - .andExpect(status().isUnauthorized()) - .andExpect(header().string("WWW-Authenticate", "Bearer")); + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> this.mvc.perform(get("/").with(bearerToken(token)))); // @formatter:on } @@ -825,7 +823,7 @@ public class OAuth2ResourceServerConfigurerTests { public void requestWhenRealmNameConfiguredThenUsesOnUnauthenticated() throws Exception { this.spring.register(RealmNameConfiguredOnEntryPoint.class, JwtDecoderConfig.class).autowire(); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); - given(decoder.decode(anyString())).willThrow(JwtException.class); + given(decoder.decode(anyString())).willThrow(BadJwtException.class); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken("invalid_token"))) .andExpect(status().isUnauthorized()) @@ -1092,7 +1090,7 @@ public class OAuth2ResourceServerConfigurerTests { public void requestWhenBasicAndResourceServerEntryPointsThenMatchedByRequest() throws Exception { this.spring.register(BasicAndResourceServerConfig.class, JwtDecoderConfig.class).autowire(); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); - given(decoder.decode(anyString())).willThrow(JwtException.class); + given(decoder.decode(anyString())).willThrow(BadJwtException.class); // @formatter:off this.mvc.perform(get("/authenticated").with(httpBasic("some", "user"))) .andExpect(status().isUnauthorized()) @@ -1110,7 +1108,7 @@ public class OAuth2ResourceServerConfigurerTests { public void requestWhenFormLoginAndResourceServerEntryPointsThenSessionCreatedByRequest() throws Exception { this.spring.register(FormAndResourceServerConfig.class, JwtDecoderConfig.class).autowire(); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); - given(decoder.decode(anyString())).willThrow(JwtException.class); + given(decoder.decode(anyString())).willThrow(BadJwtException.class); // @formatter:off MvcResult result = this.mvc.perform(get("/authenticated") .header("Accept", "text/html")) diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java index 498d8f80be..d0529ae17d 100644 --- a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,6 +69,7 @@ import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManagerResolver; +import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.JwtBeanDefinitionParser; import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.OpaqueTokenBeanDefinitionParser; import org.springframework.security.config.test.SpringTestRule; @@ -76,10 +77,10 @@ import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2TokenValidator; import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; import org.springframework.security.oauth2.jose.TestKeys; +import org.springframework.security.oauth2.jwt.BadJwtException; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.oauth2.jwt.TestJwts; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; @@ -168,26 +169,24 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { } @Test - public void getWhenBadJwkEndpointThenInvalidToken() throws Exception { + public void getWhenBadJwkEndpointThen500() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); mockRestOperations("malformed"); String token = this.token("ValidNoScopes"); // @formatter:off - this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) - .andExpect(status().isUnauthorized()) - .andExpect(header().string("WWW-Authenticate", "Bearer")); + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> this.mvc.perform(get("/").header("Authorization", "Bearer " + token))); // @formatter:on } @Test - public void getWhenUnavailableJwkEndpointThenInvalidToken() throws Exception { + public void getWhenUnavailableJwkEndpointThen500() throws Exception { this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire(); this.web.shutdown(); String token = this.token("ValidNoScopes"); // @formatter:off - this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) - .andExpect(status().isUnauthorized()) - .andExpect(header().string("WWW-Authenticate", "Bearer")); + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> this.mvc.perform(get("/").header("Authorization", "Bearer " + token))); // @formatter:on } @@ -529,7 +528,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { public void requestWhenRealmNameConfiguredThenUsesOnUnauthenticated() throws Exception { this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire(); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); - Mockito.when(decoder.decode(anyString())).thenThrow(JwtException.class); + Mockito.when(decoder.decode(anyString())).thenThrow(BadJwtException.class); // @formatter:off this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token")) .andExpect(status().isUnauthorized()) @@ -736,7 +735,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { // different from DSL this.spring.configLocations(xml("MockJwtDecoder"), xml("BasicAndResourceServer")).autowire(); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); - given(decoder.decode(anyString())).willThrow(JwtException.class); + given(decoder.decode(anyString())).willThrow(BadJwtException.class); // @formatter:off this.mvc.perform(get("/authenticated").with(httpBasic("some", "user"))) .andExpect(status().isUnauthorized()) @@ -755,7 +754,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { // different from DSL this.spring.configLocations(xml("MockJwtDecoder"), xml("FormAndResourceServer")).autowire(); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); - given(decoder.decode(anyString())).willThrow(JwtException.class); + given(decoder.decode(anyString())).willThrow(BadJwtException.class); MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized()).andReturn(); assertThat(result.getRequest().getSession(false)).isNotNull(); // @formatter:off diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.java index 02e1d42d4b..551101d0ef 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import org.springframework.core.log.LogMessage; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManagerResolver; +import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContext; @@ -66,8 +67,12 @@ public final class BearerTokenAuthenticationFilter extends OncePerRequestFilter private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint(); - private AuthenticationFailureHandler authenticationFailureHandler = (request, response, - exception) -> this.authenticationEntryPoint.commence(request, response, exception); + private AuthenticationFailureHandler authenticationFailureHandler = (request, response, exception) -> { + if (exception instanceof AuthenticationServiceException) { + throw exception; + } + this.authenticationEntryPoint.commence(request, response, exception); + }; /** * Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s) diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilterTests.java index 90a04ac322..3882f73f72 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManagerResolver; +import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.BearerTokenError; @@ -42,6 +43,7 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @@ -154,6 +156,17 @@ public class BearerTokenAuthenticationFilterTests { verify(this.authenticationFailureHandler).onAuthenticationFailure(this.request, this.response, exception); } + @Test + public void doFilterWhenAuthenticationServiceExceptionThenRethrows() { + AuthenticationServiceException exception = new AuthenticationServiceException("message"); + given(this.bearerTokenResolver.resolve(this.request)).willReturn("token"); + given(this.authenticationManager.authenticate(any())).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocks( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain)); + } + @Test public void setAuthenticationEntryPointWhenNullThenThrowsException() { BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);