5252import org .springframework .security .oauth2 .server .resource .authentication .JwtAuthenticationToken ;
5353import org .springframework .security .oauth2 .server .resource .web .BearerTokenResolver ;
5454import org .springframework .security .web .AuthenticationEntryPoint ;
55+ import org .springframework .security .web .authentication .AuthenticationConverter ;
5556import org .springframework .security .web .authentication .AuthenticationFailureHandler ;
5657import org .springframework .security .web .context .RequestAttributeSecurityContextRepository ;
5758import org .springframework .security .web .context .SecurityContextRepository ;
7475@ ExtendWith (MockitoExtension .class )
7576public class BearerTokenAuthenticationFilterTests {
7677
78+ private static final String TEST_TOKEN = "token" ;
79+
7780 @ Mock
7881 AuthenticationEntryPoint authenticationEntryPoint ;
7982
@@ -92,6 +95,9 @@ public class BearerTokenAuthenticationFilterTests {
9295 @ Mock
9396 AuthenticationDetailsSource <HttpServletRequest , ?> authenticationDetailsSource ;
9497
98+ @ Mock
99+ AuthenticationConverter authenticationConverter ;
100+
95101 MockHttpServletRequest request ;
96102
97103 MockHttpServletResponse response ;
@@ -321,6 +327,171 @@ public void constructorWhenNullAuthenticationManagerResolverThenThrowsException(
321327 // @formatter:on
322328 }
323329
330+ @ Test
331+ public void doFilterWhenBearerTokenPresentAndConverterSetThenAuthenticates () throws ServletException , IOException {
332+ given (this .authenticationConverter .convert (this .request ))
333+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
334+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
335+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
336+
337+ filter .doFilter (this .request , this .response , this .filterChain );
338+
339+ ArgumentCaptor <BearerTokenAuthenticationToken > captor = ArgumentCaptor
340+ .forClass (BearerTokenAuthenticationToken .class );
341+ verify (this .authenticationManager ).authenticate (captor .capture ());
342+ assertThat (captor .getValue ().getPrincipal ()).isEqualTo (TEST_TOKEN );
343+ assertThat (this .request .getAttribute (RequestAttributeSecurityContextRepository .DEFAULT_REQUEST_ATTR_NAME ))
344+ .isNotNull ();
345+ }
346+
347+ @ Test
348+ public void doFilterWhenSecurityContextRepositoryAndConverterSetThenSaves () throws ServletException , IOException {
349+ SecurityContextRepository securityContextRepository = mock (SecurityContextRepository .class );
350+ given (this .authenticationConverter .convert (this .request ))
351+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
352+ TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken ("test" , "password" );
353+ given (this .authenticationManager .authenticate (any ())).willReturn (expectedAuthentication );
354+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
355+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
356+ filter .setSecurityContextRepository (securityContextRepository );
357+
358+ filter .doFilter (this .request , this .response , this .filterChain );
359+
360+ ArgumentCaptor <BearerTokenAuthenticationToken > captor = ArgumentCaptor
361+ .forClass (BearerTokenAuthenticationToken .class );
362+ verify (this .authenticationManager ).authenticate (captor .capture ());
363+ assertThat (captor .getValue ().getPrincipal ()).isEqualTo (TEST_TOKEN );
364+ ArgumentCaptor <SecurityContext > contextArg = ArgumentCaptor .forClass (SecurityContext .class );
365+ verify (securityContextRepository ).saveContext (contextArg .capture (), eq (this .request ), eq (this .response ));
366+ assertThat (contextArg .getValue ().getAuthentication ().getName ()).isEqualTo (expectedAuthentication .getName ());
367+ }
368+
369+ @ Test
370+ public void doFilterWhenUsingAuthenticationManagerResolverAndConverterSetThenAuthenticates () throws Exception {
371+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
372+ new BearerTokenAuthenticationFilter (this .authenticationManagerResolver ));
373+ given (this .authenticationConverter .convert (this .request ))
374+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
375+ given (this .authenticationManagerResolver .resolve (any ())).willReturn (this .authenticationManager );
376+
377+ filter .doFilter (this .request , this .response , this .filterChain );
378+
379+ ArgumentCaptor <BearerTokenAuthenticationToken > captor = ArgumentCaptor
380+ .forClass (BearerTokenAuthenticationToken .class );
381+ verify (this .authenticationManager ).authenticate (captor .capture ());
382+ assertThat (captor .getValue ().getPrincipal ()).isEqualTo (TEST_TOKEN );
383+ assertThat (this .request .getAttribute (RequestAttributeSecurityContextRepository .DEFAULT_REQUEST_ATTR_NAME ))
384+ .isNotNull ();
385+ }
386+
387+ @ Test
388+ public void doFilterWhenNoBearerTokenPresentAndConverterSetThenDoesNotAuthenticate ()
389+ throws ServletException , IOException {
390+ given (this .authenticationConverter .convert (this .request )).willReturn (null );
391+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
392+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
393+
394+ filter .doFilter (this .request , this .response , this .filterChain );
395+
396+ verifyNoMoreInteractions (this .authenticationManager );
397+ }
398+
399+ @ Test
400+ public void doFilterWhenMalformedBearerTokenAndConverterSetThenPropagatesError ()
401+ throws ServletException , IOException {
402+ BearerTokenError error = new BearerTokenError (BearerTokenErrorCodes .INVALID_REQUEST , HttpStatus .BAD_REQUEST ,
403+ "description" , "uri" );
404+ OAuth2AuthenticationException exception = new OAuth2AuthenticationException (error );
405+ given (this .authenticationConverter .convert (this .request )).willThrow (exception );
406+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
407+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
408+ filter .doFilter (this .request , this .response , this .filterChain );
409+
410+ verifyNoMoreInteractions (this .authenticationManager );
411+ verify (this .authenticationEntryPoint ).commence (this .request , this .response , exception );
412+ }
413+
414+ @ Test
415+ public void doFilterWhenAuthenticationFailsWithDefaultHandlerAndConverterSetThenPropagatesError ()
416+ throws ServletException , IOException {
417+ BearerTokenError error = new BearerTokenError (BearerTokenErrorCodes .INVALID_TOKEN , HttpStatus .UNAUTHORIZED ,
418+ "description" , "uri" );
419+ OAuth2AuthenticationException exception = new OAuth2AuthenticationException (error );
420+ given (this .authenticationConverter .convert (this .request ))
421+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
422+ given (this .authenticationManager .authenticate (any (BearerTokenAuthenticationToken .class ))).willThrow (exception );
423+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
424+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
425+
426+ filter .doFilter (this .request , this .response , this .filterChain );
427+
428+ verify (this .authenticationEntryPoint ).commence (this .request , this .response , exception );
429+ }
430+
431+ @ Test
432+ public void doFilterWhenAuthenticationFailsWithCustomHandlerAndConverterSetThenPropagatesError ()
433+ throws ServletException , IOException {
434+ BearerTokenError error = new BearerTokenError (BearerTokenErrorCodes .INVALID_TOKEN , HttpStatus .UNAUTHORIZED ,
435+ "description" , "uri" );
436+ OAuth2AuthenticationException exception = new OAuth2AuthenticationException (error );
437+ given (this .authenticationConverter .convert (this .request ))
438+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
439+ given (this .authenticationManager .authenticate (any (BearerTokenAuthenticationToken .class ))).willThrow (exception );
440+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
441+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
442+ filter .setAuthenticationFailureHandler (this .authenticationFailureHandler );
443+
444+ filter .doFilter (this .request , this .response , this .filterChain );
445+
446+ verify (this .authenticationFailureHandler ).onAuthenticationFailure (this .request , this .response , exception );
447+ }
448+
449+ @ Test
450+ public void doFilterWhenConverterSetAndAuthenticationServiceExceptionThenRethrows () {
451+ AuthenticationServiceException exception = new AuthenticationServiceException ("message" );
452+ given (this .authenticationConverter .convert (this .request ))
453+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
454+ given (this .authenticationManager .authenticate (any ())).willThrow (exception );
455+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
456+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
457+
458+ assertThatExceptionOfType (AuthenticationServiceException .class )
459+ .isThrownBy (() -> filter .doFilter (this .request , this .response , this .filterChain ));
460+ }
461+
462+ @ Test
463+ public void doFilterWhenConverterSetAndCustomEntryPointAndAuthenticationErrorThenUses ()
464+ throws ServletException , IOException {
465+ AuthenticationException exception = new InvalidBearerTokenException ("message" );
466+ given (this .authenticationConverter .convert (this .request ))
467+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
468+ given (this .authenticationManager .authenticate (any ())).willThrow (exception );
469+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
470+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
471+ AuthenticationEntryPoint entrypoint = mock (AuthenticationEntryPoint .class );
472+ filter .setAuthenticationEntryPoint (entrypoint );
473+
474+ filter .doFilter (this .request , this .response , this .filterChain );
475+
476+ verify (entrypoint ).commence (any (), any (), any (InvalidBearerTokenException .class ));
477+ }
478+
479+ @ Test
480+ public void doFilterWhenConverterSetCustomSecurityContextHolderStrategyThenUses ()
481+ throws ServletException , IOException {
482+ given (this .authenticationConverter .convert (this .request ))
483+ .willReturn (new BearerTokenAuthenticationToken (TEST_TOKEN ));
484+ BearerTokenAuthenticationFilter filter = addMocksWithConverter (
485+ new BearerTokenAuthenticationFilter (this .authenticationManager ));
486+ SecurityContextHolderStrategy strategy = mock (SecurityContextHolderStrategy .class );
487+ given (strategy .createEmptyContext ()).willReturn (new SecurityContextImpl ());
488+ filter .setSecurityContextHolderStrategy (strategy );
489+
490+ filter .doFilter (this .request , this .response , this .filterChain );
491+
492+ verify (strategy ).setContext (any ());
493+ }
494+
324495 private BearerTokenAuthenticationFilter addMocks (BearerTokenAuthenticationFilter filter ) {
325496 filter .setAuthenticationEntryPoint (this .authenticationEntryPoint );
326497 filter .setBearerTokenResolver (this .bearerTokenResolver );
@@ -335,4 +506,10 @@ private void dontAuthenticate() throws ServletException, IOException {
335506 verifyNoMoreInteractions (this .authenticationManager );
336507 }
337508
509+ private BearerTokenAuthenticationFilter addMocksWithConverter (BearerTokenAuthenticationFilter filter ) {
510+ filter .setAuthenticationEntryPoint (this .authenticationEntryPoint );
511+ filter .setAuthenticationConverter (this .authenticationConverter );
512+ return filter ;
513+ }
514+
338515}
0 commit comments