From 30577bd291781d34b4550404872cfba657278edc Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Fri, 11 Apr 2025 15:36:23 +0300 Subject: [PATCH] Add Additional Tests To BearerTokenAuthenticationFilterTests Issue gh-14750 Signed-off-by: Max Batischev --- .../BearerTokenAuthenticationFilterTests.java | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java index 465b5261c6..b64a29f762 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java @@ -52,6 +52,7 @@ import org.springframework.security.oauth2.server.resource.authentication.Bearer import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; @@ -74,6 +75,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) public class BearerTokenAuthenticationFilterTests { + private static final String TEST_TOKEN = "token"; + @Mock AuthenticationEntryPoint authenticationEntryPoint; @@ -92,6 +95,9 @@ public class BearerTokenAuthenticationFilterTests { @Mock AuthenticationDetailsSource authenticationDetailsSource; + @Mock + AuthenticationConverter authenticationConverter; + MockHttpServletRequest request; MockHttpServletResponse response; @@ -321,6 +327,171 @@ public class BearerTokenAuthenticationFilterTests { // @formatter:on } + @Test + public void doFilterWhenBearerTokenPresentAndConverterSetThenAuthenticates() throws ServletException, IOException { + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + filter.doFilter(this.request, this.response, this.filterChain); + + ArgumentCaptor captor = ArgumentCaptor + .forClass(BearerTokenAuthenticationToken.class); + verify(this.authenticationManager).authenticate(captor.capture()); + assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); + assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME)) + .isNotNull(); + } + + @Test + public void doFilterWhenSecurityContextRepositoryAndConverterSetThenSaves() throws ServletException, IOException { + SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("test", "password"); + given(this.authenticationManager.authenticate(any())).willReturn(expectedAuthentication); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.setSecurityContextRepository(securityContextRepository); + + filter.doFilter(this.request, this.response, this.filterChain); + + ArgumentCaptor captor = ArgumentCaptor + .forClass(BearerTokenAuthenticationToken.class); + verify(this.authenticationManager).authenticate(captor.capture()); + assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); + ArgumentCaptor contextArg = ArgumentCaptor.forClass(SecurityContext.class); + verify(securityContextRepository).saveContext(contextArg.capture(), eq(this.request), eq(this.response)); + assertThat(contextArg.getValue().getAuthentication().getName()).isEqualTo(expectedAuthentication.getName()); + } + + @Test + public void doFilterWhenUsingAuthenticationManagerResolverAndConverterSetThenAuthenticates() throws Exception { + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManagerResolver)); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManagerResolver.resolve(any())).willReturn(this.authenticationManager); + + filter.doFilter(this.request, this.response, this.filterChain); + + ArgumentCaptor captor = ArgumentCaptor + .forClass(BearerTokenAuthenticationToken.class); + verify(this.authenticationManager).authenticate(captor.capture()); + assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); + assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME)) + .isNotNull(); + } + + @Test + public void doFilterWhenNoBearerTokenPresentAndConverterSetThenDoesNotAuthenticate() + throws ServletException, IOException { + given(this.authenticationConverter.convert(this.request)).willReturn(null); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + filter.doFilter(this.request, this.response, this.filterChain); + + verifyNoMoreInteractions(this.authenticationManager); + } + + @Test + public void doFilterWhenMalformedBearerTokenAndConverterSetThenPropagatesError() + throws ServletException, IOException { + BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, HttpStatus.BAD_REQUEST, + "description", "uri"); + OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); + given(this.authenticationConverter.convert(this.request)).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.doFilter(this.request, this.response, this.filterChain); + + verifyNoMoreInteractions(this.authenticationManager); + verify(this.authenticationEntryPoint).commence(this.request, this.response, exception); + } + + @Test + public void doFilterWhenAuthenticationFailsWithDefaultHandlerAndConverterSetThenPropagatesError() + throws ServletException, IOException { + BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED, + "description", "uri"); + OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(this.authenticationEntryPoint).commence(this.request, this.response, exception); + } + + @Test + public void doFilterWhenAuthenticationFailsWithCustomHandlerAndConverterSetThenPropagatesError() + throws ServletException, IOException { + BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED, + "description", "uri"); + OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.setAuthenticationFailureHandler(this.authenticationFailureHandler); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(this.authenticationFailureHandler).onAuthenticationFailure(this.request, this.response, exception); + } + + @Test + public void doFilterWhenConverterSetAndAuthenticationServiceExceptionThenRethrows() { + AuthenticationServiceException exception = new AuthenticationServiceException("message"); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any())).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain)); + } + + @Test + public void doFilterWhenConverterSetAndCustomEntryPointAndAuthenticationErrorThenUses() + throws ServletException, IOException { + AuthenticationException exception = new InvalidBearerTokenException("message"); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any())).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + AuthenticationEntryPoint entrypoint = mock(AuthenticationEntryPoint.class); + filter.setAuthenticationEntryPoint(entrypoint); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(entrypoint).commence(any(), any(), any(InvalidBearerTokenException.class)); + } + + @Test + public void doFilterWhenConverterSetCustomSecurityContextHolderStrategyThenUses() + throws ServletException, IOException { + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class); + given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl()); + filter.setSecurityContextHolderStrategy(strategy); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(strategy).setContext(any()); + } + private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) { filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); filter.setBearerTokenResolver(this.bearerTokenResolver); @@ -335,4 +506,10 @@ public class BearerTokenAuthenticationFilterTests { verifyNoMoreInteractions(this.authenticationManager); } + private BearerTokenAuthenticationFilter addMocksWithConverter(BearerTokenAuthenticationFilter filter) { + filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); + filter.setAuthenticationConverter(this.authenticationConverter); + return filter; + } + }