3636import com .nimbusds .jose .crypto .RSASSASigner ;
3737import com .nimbusds .jose .jwk .JWKSet ;
3838import com .nimbusds .jose .jwk .RSAKey ;
39+ import com .nimbusds .jose .util .JSONObjectUtils ;
3940import jakarta .servlet .http .HttpServletRequest ;
4041import net .minidev .json .JSONObject ;
4142import okhttp3 .mockwebserver .MockResponse ;
5758import org .springframework .beans .factory .xml .BeanDefinitionParserDelegate ;
5859import org .springframework .beans .factory .xml .ParserContext ;
5960import org .springframework .beans .factory .xml .XmlReaderContext ;
61+ import org .springframework .core .ParameterizedTypeReference ;
6062import org .springframework .core .convert .converter .Converter ;
6163import org .springframework .core .io .ClassPathResource ;
6264import org .springframework .http .HttpHeaders ;
8486import org .springframework .security .oauth2 .jwt .TestJwts ;
8587import org .springframework .security .oauth2 .server .resource .authentication .BearerTokenAuthenticationToken ;
8688import org .springframework .security .oauth2 .server .resource .authentication .JwtAuthenticationToken ;
87- import org .springframework .security .oauth2 .server .resource .introspection .NimbusOpaqueTokenIntrospector ;
8889import org .springframework .security .oauth2 .server .resource .introspection .OpaqueTokenAuthenticationConverter ;
8990import org .springframework .security .oauth2 .server .resource .introspection .OpaqueTokenIntrospector ;
91+ import org .springframework .security .oauth2 .server .resource .introspection .SpringOpaqueTokenIntrospector ;
9092import org .springframework .security .oauth2 .server .resource .web .BearerTokenResolver ;
9193import org .springframework .security .test .context .annotation .SecurityTestExecutionListeners ;
9294import org .springframework .security .web .authentication .AuthenticationConverter ;
@@ -139,7 +141,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
139141 @ Test
140142 public void getWhenValidBearerTokenThenAcceptsRequest () throws Exception {
141143 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
142- mockRestOperations (jwks ("Default" ));
144+ mockJwksRestOperations (jwks ("Default" ));
143145 String token = this .token ("ValidNoScopes" );
144146 // @formatter:off
145147 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -150,7 +152,7 @@ public void getWhenValidBearerTokenThenAcceptsRequest() throws Exception {
150152 @ Test
151153 public void getWhenCustomSecurityContextHolderStrategyThenUses () throws Exception {
152154 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("JwtCustomSecurityContextHolderStrategy" )).autowire ();
153- mockRestOperations (jwks ("Default" ));
155+ mockJwksRestOperations (jwks ("Default" ));
154156 String token = this .token ("ValidNoScopes" );
155157 // @formatter:off
156158 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -175,7 +177,7 @@ public void getWhenUsingJwkSetUriThenAcceptsRequest() throws Exception {
175177 @ Test
176178 public void getWhenExpiredBearerTokenThenInvalidToken () throws Exception {
177179 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
178- mockRestOperations (jwks ("Default" ));
180+ mockJwksRestOperations (jwks ("Default" ));
179181 String token = this .token ("Expired" );
180182 // @formatter:off
181183 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -187,7 +189,7 @@ public void getWhenExpiredBearerTokenThenInvalidToken() throws Exception {
187189 @ Test
188190 public void getWhenBadJwkEndpointThen500 () throws Exception {
189191 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
190- mockRestOperations ("malformed" );
192+ mockJwksRestOperations ("malformed" );
191193 String token = this .token ("ValidNoScopes" );
192194 // @formatter:off
193195 assertThatExceptionOfType (AuthenticationServiceException .class )
@@ -219,7 +221,7 @@ public void getWhenMalformedBearerTokenThenInvalidToken() throws Exception {
219221 @ Test
220222 public void getWhenMalformedPayloadThenInvalidToken () throws Exception {
221223 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
222- mockRestOperations (jwks ("Default" ));
224+ mockJwksRestOperations (jwks ("Default" ));
223225 String token = this .token ("MalformedPayload" );
224226 // @formatter:off
225227 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -242,7 +244,7 @@ public void getWhenUnsignedBearerTokenThenInvalidToken() throws Exception {
242244 @ Test
243245 public void getWhenBearerTokenBeforeNotBeforeThenInvalidToken () throws Exception {
244246 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
245- this .mockRestOperations (jwks ("Default" ));
247+ this .mockJwksRestOperations (jwks ("Default" ));
246248 String token = this .token ("TooEarly" );
247249 // @formatter:off
248250 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -299,7 +301,7 @@ public void getWhenNoBearerTokenThenUnauthorized() throws Exception {
299301 @ Test
300302 public void getWhenSufficientlyScopedBearerTokenThenAcceptsRequest () throws Exception {
301303 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
302- mockRestOperations (jwks ("Default" ));
304+ mockJwksRestOperations (jwks ("Default" ));
303305 String token = this .token ("ValidMessageReadScope" );
304306 // @formatter:off
305307 this .mvc .perform (get ("/requires-read-scope" ).header ("Authorization" , "Bearer " + token ))
@@ -310,7 +312,7 @@ public void getWhenSufficientlyScopedBearerTokenThenAcceptsRequest() throws Exce
310312 @ Test
311313 public void getWhenInsufficientScopeThenInsufficientScopeError () throws Exception {
312314 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
313- mockRestOperations (jwks ("Default" ));
315+ mockJwksRestOperations (jwks ("Default" ));
314316 String token = this .token ("ValidNoScopes" );
315317 // @formatter:off
316318 this .mvc .perform (get ("/requires-read-scope" ).header ("Authorization" , "Bearer " + token ))
@@ -322,7 +324,7 @@ public void getWhenInsufficientScopeThenInsufficientScopeError() throws Exceptio
322324 @ Test
323325 public void getWhenInsufficientScpThenInsufficientScopeError () throws Exception {
324326 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
325- mockRestOperations (jwks ("Default" ));
327+ mockJwksRestOperations (jwks ("Default" ));
326328 String token = this .token ("ValidMessageWriteScp" );
327329 // @formatter:off
328330 this .mvc .perform (get ("/requires-read-scope" ).header ("Authorization" , "Bearer " + token ))
@@ -334,7 +336,7 @@ public void getWhenInsufficientScpThenInsufficientScopeError() throws Exception
334336 @ Test
335337 public void getWhenAuthorizationServerHasNoMatchingKeyThenInvalidToken () throws Exception {
336338 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
337- mockRestOperations (jwks ("Empty" ));
339+ mockJwksRestOperations (jwks ("Empty" ));
338340 String token = this .token ("ValidNoScopes" );
339341 // @formatter:off
340342 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -346,7 +348,7 @@ public void getWhenAuthorizationServerHasNoMatchingKeyThenInvalidToken() throws
346348 @ Test
347349 public void getWhenAuthorizationServerHasMultipleMatchingKeysThenOk () throws Exception {
348350 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
349- mockRestOperations (jwks ("TwoKeys" ));
351+ mockJwksRestOperations (jwks ("TwoKeys" ));
350352 String token = this .token ("ValidNoScopes" );
351353 // @formatter:off
352354 this .mvc .perform (get ("/authenticated" ).header ("Authorization" , "Bearer " + token ))
@@ -357,7 +359,7 @@ public void getWhenAuthorizationServerHasMultipleMatchingKeysThenOk() throws Exc
357359 @ Test
358360 public void getWhenKeyMatchesByKidThenOk () throws Exception {
359361 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
360- mockRestOperations (jwks ("TwoKeys" ));
362+ mockJwksRestOperations (jwks ("TwoKeys" ));
361363 String token = this .token ("Kid" );
362364 // @formatter:off
363365 this .mvc .perform (get ("/authenticated" ).header ("Authorization" , "Bearer " + token ))
@@ -368,7 +370,7 @@ public void getWhenKeyMatchesByKidThenOk() throws Exception {
368370 @ Test
369371 public void postWhenValidBearerTokenAndNoCsrfTokenThenOk () throws Exception {
370372 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
371- mockRestOperations (jwks ("Default" ));
373+ mockJwksRestOperations (jwks ("Default" ));
372374 String token = this .token ("ValidNoScopes" );
373375 // @formatter:off
374376 this .mvc .perform (post ("/authenticated" ).header ("Authorization" , "Bearer " + token ))
@@ -390,7 +392,7 @@ public void postWhenNoBearerTokenThenCsrfDenies() throws Exception {
390392 @ Test
391393 public void postWhenExpiredBearerTokenAndNoCsrfThenInvalidToken () throws Exception {
392394 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
393- mockRestOperations (jwks ("Default" ));
395+ mockJwksRestOperations (jwks ("Default" ));
394396 String token = this .token ("Expired" );
395397 // @formatter:off
396398 this .mvc .perform (post ("/authenticated" ).header ("Authorization" , "Bearer " + token ))
@@ -402,7 +404,7 @@ public void postWhenExpiredBearerTokenAndNoCsrfThenInvalidToken() throws Excepti
402404 @ Test
403405 public void requestWhenJwtThenSessionIsNotCreated () throws Exception {
404406 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("Jwt" )).autowire ();
405- mockRestOperations (jwks ("Default" ));
407+ mockJwksRestOperations (jwks ("Default" ));
406408 String token = this .token ("ValidNoScopes" );
407409 // @formatter:off
408410 MvcResult result = this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -438,7 +440,7 @@ public void requestWhenNoBearerTokenThenSessionIsCreated() throws Exception {
438440 @ Test
439441 public void requestWhenSessionManagementConfiguredThenUses () throws Exception {
440442 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("AlwaysSessionCreation" )).autowire ();
441- mockRestOperations (jwks ("Default" ));
443+ mockJwksRestOperations (jwks ("Default" ));
442444 String token = this .token ("ValidNoScopes" );
443445 // @formatter:off
444446 MvcResult result = this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -587,7 +589,7 @@ public void requestWhenRealmNameConfiguredThenUsesOnAccessDenied() throws Except
587589 @ Test
588590 public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage () throws Exception {
589591 this .spring .configLocations (xml ("MockJwtValidator" ), xml ("Jwt" )).autowire ();
590- mockRestOperations (jwks ("Default" ));
592+ mockJwksRestOperations (jwks ("Default" ));
591593 String token = this .token ("ValidNoScopes" );
592594 OAuth2TokenValidator <Jwt > jwtValidator = this .spring .getContext ().getBean (OAuth2TokenValidator .class );
593595 OAuth2Error error = new OAuth2Error ("custom-error" , "custom-description" , "custom-uri" );
@@ -602,7 +604,7 @@ public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage() th
602604 @ Test
603605 public void requestWhenClockSkewSetThenTimestampWindowRelaxedAccordingly () throws Exception {
604606 this .spring .configLocations (xml ("UnexpiredJwtClockSkew" ), xml ("Jwt" )).autowire ();
605- mockRestOperations (jwks ("Default" ));
607+ mockJwksRestOperations (jwks ("Default" ));
606608 String token = this .token ("ExpiresAt4687177990" );
607609 // @formatter:off
608610 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -613,7 +615,7 @@ public void requestWhenClockSkewSetThenTimestampWindowRelaxedAccordingly() throw
613615 @ Test
614616 public void requestWhenClockSkewSetButJwtStillTooLateThenReportsExpired () throws Exception {
615617 this .spring .configLocations (xml ("ExpiredJwtClockSkew" ), xml ("Jwt" )).autowire ();
616- mockRestOperations (jwks ("Default" ));
618+ mockJwksRestOperations (jwks ("Default" ));
617619 String token = this .token ("ExpiresAt4687177990" );
618620 // @formatter:off
619621 this .mvc .perform (get ("/" ).header ("Authorization" , "Bearer " + token ))
@@ -675,7 +677,7 @@ public void requestWhenUsingPublicKeyAlgorithmDoesNotMatchThenReturnsInvalidToke
675677 @ Test
676678 public void getWhenIntrospectingThenOk () throws Exception {
677679 this .spring .configLocations (xml ("OpaqueTokenRestOperations" ), xml ("OpaqueToken" )).autowire ();
678- mockRestOperations (json ("Active" ));
680+ mockJsonRestOperations (json ("Active" ));
679681 // @formatter:off
680682 this .mvc .perform (get ("/authenticated" ).header ("Authorization" , "Bearer token" ))
681683 .andExpect (status ().isNotFound ());
@@ -686,7 +688,7 @@ public void getWhenIntrospectingThenOk() throws Exception {
686688 public void configureWhenIntrospectingWithAuthenticationConverterThenUses () throws Exception {
687689 this .spring .configLocations (xml ("OpaqueTokenRestOperations" ), xml ("OpaqueTokenAndAuthenticationConverter" ))
688690 .autowire ();
689- mockRestOperations (json ("Active" ));
691+ mockJsonRestOperations (json ("Active" ));
690692 OpaqueTokenAuthenticationConverter converter = bean (OpaqueTokenAuthenticationConverter .class );
691693 given (converter .convert (any (), any ())).willReturn (new TestingAuthenticationToken ("user" , "pass" , "app" ));
692694 // @formatter:off
@@ -699,7 +701,7 @@ public void configureWhenIntrospectingWithAuthenticationConverterThenUses() thro
699701 @ Test
700702 public void getWhenIntrospectionFailsThenUnauthorized () throws Exception {
701703 this .spring .configLocations (xml ("OpaqueTokenRestOperations" ), xml ("OpaqueToken" )).autowire ();
702- mockRestOperations (json ("Inactive" ));
704+ mockJsonRestOperations (json ("Inactive" ));
703705 // @formatter:off
704706 MockHttpServletRequestBuilder request = get ("/" )
705707 .header ("Authorization" , "Bearer token" );
@@ -712,7 +714,7 @@ public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
712714 @ Test
713715 public void getWhenIntrospectionLacksScopeThenForbidden () throws Exception {
714716 this .spring .configLocations (xml ("OpaqueTokenRestOperations" ), xml ("OpaqueToken" )).autowire ();
715- mockRestOperations (json ("ActiveNoScopes" ));
717+ mockJsonRestOperations (json ("ActiveNoScopes" ));
716718 // @formatter:off
717719 this .mvc .perform (get ("/requires-read-scope" ).header ("Authorization" , "Bearer token" ))
718720 .andExpect (status ().isForbidden ())
@@ -818,7 +820,7 @@ public void requestWhenFormLoginAndResourceServerEntryPointsThenSessionCreatedBy
818820 @ Test
819821 public void getWhenAlsoUsingHttpBasicThenCorrectProviderEngages () throws Exception {
820822 this .spring .configLocations (xml ("JwtRestOperations" ), xml ("BasicAndResourceServer" )).autowire ();
821- mockRestOperations (jwks ("Default" ));
823+ mockJwksRestOperations (jwks ("Default" ));
822824 String token = this .token ("ValidNoScopes" );
823825 // @formatter:off
824826 this .mvc .perform (get ("/authenticated" ).header ("Authorization" , "Bearer " + token ))
@@ -963,14 +965,29 @@ private void mockWebServer(String response) {
963965 .setBody (response ));
964966 }
965967
966- private void mockRestOperations (String response ) {
968+ private void mockJwksRestOperations (String response ) {
967969 RestOperations rest = this .spring .getContext ().getBean (RestOperations .class );
968970 HttpHeaders headers = new HttpHeaders ();
969971 headers .setContentType (MediaType .APPLICATION_JSON );
970972 ResponseEntity <String > entity = new ResponseEntity <>(response , headers , HttpStatus .OK );
971973 given (rest .exchange (any (RequestEntity .class ), eq (String .class ))).willReturn (entity );
972974 }
973975
976+ private void mockJsonRestOperations (String response ) {
977+ try {
978+ RestOperations rest = this .spring .getContext ().getBean (RestOperations .class );
979+ HttpHeaders headers = new HttpHeaders ();
980+ headers .setContentType (MediaType .APPLICATION_JSON );
981+ ResponseEntity <Map <String , Object >> entity = new ResponseEntity <>(JSONObjectUtils .parse (response ), headers ,
982+ HttpStatus .OK );
983+ given (rest .exchange (any (RequestEntity .class ), eq (new ParameterizedTypeReference <Map <String , Object >>() {
984+ }))).willReturn (entity );
985+ }
986+ catch (Exception ex ) {
987+ throw new IllegalArgumentException (ex );
988+ }
989+ }
990+
974991 private String json (String name ) throws IOException {
975992 return resource (name + ".json" );
976993 }
@@ -1047,7 +1064,7 @@ static class OpaqueTokenIntrospectorFactoryBean implements FactoryBean<OpaqueTok
10471064
10481065 @ Override
10491066 public OpaqueTokenIntrospector getObject () throws Exception {
1050- return new NimbusOpaqueTokenIntrospector ("https://idp.example.org" , this .rest );
1067+ return new SpringOpaqueTokenIntrospector ("https://idp.example.org" , this .rest );
10511068 }
10521069
10531070 @ Override
0 commit comments