4747import org .springframework .security .oauth2 .server .resource .authentication .BearerTokenAuthenticationToken ;
4848import org .springframework .security .oauth2 .server .resource .web .BearerTokenResolver ;
4949import org .springframework .security .web .AuthenticationEntryPoint ;
50+ import org .springframework .security .web .authentication .AuthenticationConverter ;
5051import org .springframework .security .web .authentication .AuthenticationFailureHandler ;
5152import org .springframework .security .web .context .RequestAttributeSecurityContextRepository ;
5253import org .springframework .security .web .context .SecurityContextRepository ;
6970@ ExtendWith (MockitoExtension .class )
7071public class BearerTokenAuthenticationFilterTests {
7172
73+ private static final String TEST_TOKEN = "token" ;
74+
7275 @ Mock
7376 AuthenticationEntryPoint authenticationEntryPoint ;
7477
@@ -87,6 +90,9 @@ public class BearerTokenAuthenticationFilterTests {
8790 @ Mock
8891 AuthenticationDetailsSource <HttpServletRequest , ?> authenticationDetailsSource ;
8992
93+ @ Mock
94+ AuthenticationConverter authenticationConverter ;
95+
9096 MockHttpServletRequest request ;
9197
9298 MockHttpServletResponse response ;
@@ -297,6 +303,171 @@ public void constructorWhenNullAuthenticationManagerResolverThenThrowsException(
297303 // @formatter:on
298304 }
299305
306+ @ Test
307+ public void doFilterWhenBearerTokenPresentAndConverterSetThenAuthenticates () throws ServletException , IOException {
308+ given (this .authenticationConverter .convert (this .request ))
309+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
310+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
311+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
312+
313+ filter .doFilter (this .request , this .response , this .filterChain );
314+
315+ ArgumentCaptor <BearerTokenAuthenticationToken > captor = ArgumentCaptor
316+ .forClass (BearerTokenAuthenticationToken .class );
317+ verify (this .authenticationManager ).authenticate (captor .capture ());
318+ assertThat (captor .getValue ().getPrincipal ()).isEqualTo (TEST_TOKEN );
319+ assertThat (this .request .getAttribute (RequestAttributeSecurityContextRepository .DEFAULT_REQUEST_ATTR_NAME ))
320+ .isNotNull ();
321+ }
322+
323+ @ Test
324+ public void doFilterWhenSecurityContextRepositoryAndConverterSetThenSaves () throws ServletException , IOException {
325+ SecurityContextRepository securityContextRepository = mock (SecurityContextRepository .class );
326+ given (this .authenticationConverter .convert (this .request ))
327+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
328+ TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken ("test" , "password" );
329+ given (this .authenticationManager .authenticate (any ())).willReturn (expectedAuthentication );
330+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
331+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
332+ filter .setSecurityContextRepository (securityContextRepository );
333+
334+ filter .doFilter (this .request , this .response , this .filterChain );
335+
336+ ArgumentCaptor <BearerTokenAuthenticationToken > captor = ArgumentCaptor
337+ .forClass (BearerTokenAuthenticationToken .class );
338+ verify (this .authenticationManager ).authenticate (captor .capture ());
339+ assertThat (captor .getValue ().getPrincipal ()).isEqualTo (TEST_TOKEN );
340+ ArgumentCaptor <SecurityContext > contextArg = ArgumentCaptor .forClass (SecurityContext .class );
341+ verify (securityContextRepository ).saveContext (contextArg .capture (), eq (this .request ), eq (this .response ));
342+ assertThat (contextArg .getValue ().getAuthentication ().getName ()).isEqualTo (expectedAuthentication .getName ());
343+ }
344+
345+ @ Test
346+ public void doFilterWhenUsingAuthenticationManagerResolverAndConverterSetThenAuthenticates () throws Exception {
347+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
348+ new BearerTokenAuthenticationFilter (this .authenticationManagerResolver ));
349+ given (this .authenticationConverter .convert (this .request ))
350+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
351+ given (this .authenticationManagerResolver .resolve (any ())).willReturn (this .authenticationManager );
352+
353+ filter .doFilter (this .request , this .response , this .filterChain );
354+
355+ ArgumentCaptor <BearerTokenAuthenticationToken > captor = ArgumentCaptor
356+ .forClass (BearerTokenAuthenticationToken .class );
357+ verify (this .authenticationManager ).authenticate (captor .capture ());
358+ assertThat (captor .getValue ().getPrincipal ()).isEqualTo (TEST_TOKEN );
359+ assertThat (this .request .getAttribute (RequestAttributeSecurityContextRepository .DEFAULT_REQUEST_ATTR_NAME ))
360+ .isNotNull ();
361+ }
362+
363+ @ Test
364+ public void doFilterWhenNoBearerTokenPresentAndConverterSetThenDoesNotAuthenticate ()
365+ throws ServletException , IOException {
366+ given (this .authenticationConverter .convert (this .request )).willReturn (null );
367+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
368+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
369+
370+ filter .doFilter (this .request , this .response , this .filterChain );
371+
372+ verifyNoMoreInteractions (this .authenticationManager );
373+ }
374+
375+ @ Test
376+ public void doFilterWhenMalformedBearerTokenAndConverterSetThenPropagatesError ()
377+ throws ServletException , IOException {
378+ BearerTokenError error = new BearerTokenError (BearerTokenErrorCodes .INVALID_REQUEST , HttpStatus .BAD_REQUEST ,
379+ "description" , "uri" );
380+ OAuth2AuthenticationException exception = new OAuth2AuthenticationException (error );
381+ given (this .authenticationConverter .convert (this .request )).willThrow (exception );
382+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
383+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
384+ filter .doFilter (this .request , this .response , this .filterChain );
385+
386+ verifyNoMoreInteractions (this .authenticationManager );
387+ verify (this .authenticationEntryPoint ).commence (this .request , this .response , exception );
388+ }
389+
390+ @ Test
391+ public void doFilterWhenAuthenticationFailsWithDefaultHandlerAndConverterSetThenPropagatesError ()
392+ throws ServletException , IOException {
393+ BearerTokenError error = new BearerTokenError (BearerTokenErrorCodes .INVALID_TOKEN , HttpStatus .UNAUTHORIZED ,
394+ "description" , "uri" );
395+ OAuth2AuthenticationException exception = new OAuth2AuthenticationException (error );
396+ given (this .authenticationConverter .convert (this .request ))
397+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
398+ given (this .authenticationManager .authenticate (any (BearerTokenAuthenticationToken .class ))).willThrow (exception );
399+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
400+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
401+
402+ filter .doFilter (this .request , this .response , this .filterChain );
403+
404+ verify (this .authenticationEntryPoint ).commence (this .request , this .response , exception );
405+ }
406+
407+ @ Test
408+ public void doFilterWhenAuthenticationFailsWithCustomHandlerAndConverterSetThenPropagatesError ()
409+ throws ServletException , IOException {
410+ BearerTokenError error = new BearerTokenError (BearerTokenErrorCodes .INVALID_TOKEN , HttpStatus .UNAUTHORIZED ,
411+ "description" , "uri" );
412+ OAuth2AuthenticationException exception = new OAuth2AuthenticationException (error );
413+ given (this .authenticationConverter .convert (this .request ))
414+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
415+ given (this .authenticationManager .authenticate (any (BearerTokenAuthenticationToken .class ))).willThrow (exception );
416+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
417+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
418+ filter .setAuthenticationFailureHandler (this .authenticationFailureHandler );
419+
420+ filter .doFilter (this .request , this .response , this .filterChain );
421+
422+ verify (this .authenticationFailureHandler ).onAuthenticationFailure (this .request , this .response , exception );
423+ }
424+
425+ @ Test
426+ public void doFilterWhenConverterSetAndAuthenticationServiceExceptionThenRethrows () {
427+ AuthenticationServiceException exception = new AuthenticationServiceException ("message" );
428+ given (this .authenticationConverter .convert (this .request ))
429+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
430+ given (this .authenticationManager .authenticate (any ())).willThrow (exception );
431+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
432+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
433+
434+ assertThatExceptionOfType (AuthenticationServiceException .class )
435+ .isThrownBy (() -> filter .doFilter (this .request , this .response , this .filterChain ));
436+ }
437+
438+ @ Test
439+ public void doFilterWhenConverterSetAndCustomEntryPointAndAuthenticationErrorThenUses ()
440+ throws ServletException , IOException {
441+ AuthenticationException exception = new InvalidBearerTokenException ("message" );
442+ given (this .authenticationConverter .convert (this .request ))
443+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
444+ given (this .authenticationManager .authenticate (any ())).willThrow (exception );
445+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
446+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
447+ AuthenticationEntryPoint entrypoint = mock (AuthenticationEntryPoint .class );
448+ filter .setAuthenticationEntryPoint (entrypoint );
449+
450+ filter .doFilter (this .request , this .response , this .filterChain );
451+
452+ verify (entrypoint ).commence (any (), any (), any (InvalidBearerTokenException .class ));
453+ }
454+
455+ @ Test
456+ public void doFilterWhenConverterSetCustomSecurityContextHolderStrategyThenUses ()
457+ throws ServletException , IOException {
458+ given (this .authenticationConverter .convert (this .request ))
459+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
460+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
461+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
462+ SecurityContextHolderStrategy strategy = mock (SecurityContextHolderStrategy .class );
463+ given (strategy .createEmptyContext ()).willReturn (new SecurityContextImpl ());
464+ filter .setSecurityContextHolderStrategy (strategy );
465+
466+ filter .doFilter (this .request , this .response , this .filterChain );
467+
468+ verify (strategy ).setContext (any ());
469+ }
470+
300471 private BearerTokenAuthenticationFilter addMocks (BearerTokenAuthenticationFilter filter ) {
301472 filter .setAuthenticationEntryPoint (this .authenticationEntryPoint );
302473 filter .setBearerTokenResolver (this .bearerTokenResolver );
@@ -311,4 +482,10 @@ private void dontAuthenticate() throws ServletException, IOException {
311482 verifyNoMoreInteractions (this .authenticationManager );
312483 }
313484
485+ private BearerTokenAuthenticationFilter addMocksWithConverter (BearerTokenAuthenticationFilter filter ) {
486+ filter .setAuthenticationEntryPoint (this .authenticationEntryPoint );
487+ filter .setAuthenticationConverter (this .authenticationConverter );
488+ return filter ;
489+ }
490+
314491}
0 commit comments