Skip to content

Commit bbb3f82

Browse files
Fix mock for Spring(Reactive)OpaqueTokenIntrospector
Signed-off-by: Tran Ngoc Nhan <[email protected]>
1 parent 7c1e4cd commit bbb3f82

File tree

2 files changed

+100
-58
lines changed

2 files changed

+100
-58
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.nimbusds.jose.crypto.RSASSASigner;
4040
import com.nimbusds.jose.jwk.JWKSet;
4141
import com.nimbusds.jose.jwk.RSAKey;
42+
import com.nimbusds.jose.util.JSONObjectUtils;
4243
import jakarta.annotation.PreDestroy;
4344
import jakarta.servlet.http.HttpServletRequest;
4445
import net.minidev.json.JSONObject;
@@ -62,6 +63,7 @@
6263
import org.springframework.context.annotation.Bean;
6364
import org.springframework.context.annotation.Configuration;
6465
import org.springframework.context.support.GenericApplicationContext;
66+
import org.springframework.core.ParameterizedTypeReference;
6567
import org.springframework.core.convert.converter.Converter;
6668
import org.springframework.core.env.ConfigurableEnvironment;
6769
import org.springframework.core.env.Environment;
@@ -217,7 +219,7 @@ public class OAuth2ResourceServerConfigurerTests {
217219
@Test
218220
public void getWhenUsingDefaultsWithValidBearerTokenThenAcceptsRequest() throws Exception {
219221
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
220-
mockRestOperations(jwks("Default"));
222+
mockJwksRestOperations(jwks("Default"));
221223
String token = this.token("ValidNoScopes");
222224
// @formatter:off
223225
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -232,7 +234,7 @@ public void getWhenCustomSecurityContextHolderStrategyThenUses() throws Exceptio
232234
.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class,
233235
SecurityContextChangedListenerConfig.class)
234236
.autowire();
235-
mockRestOperations(jwks("Default"));
237+
mockJwksRestOperations(jwks("Default"));
236238
String token = this.token("ValidNoScopes");
237239
// @formatter:off
238240
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -248,7 +250,7 @@ public void getWhenSecurityContextHolderStrategyThenUses() throws Exception {
248250
.register(RestOperationsConfig.class, DefaultConfig.class, SecurityContextChangedListenerConfig.class,
249251
BasicController.class)
250252
.autowire();
251-
mockRestOperations(jwks("Default"));
253+
mockJwksRestOperations(jwks("Default"));
252254
String token = this.token("ValidNoScopes");
253255
// @formatter:off
254256
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -261,7 +263,7 @@ public void getWhenSecurityContextHolderStrategyThenUses() throws Exception {
261263
@Test
262264
public void getWhenUsingDefaultsInLambdaWithValidBearerTokenThenAcceptsRequest() throws Exception {
263265
this.spring.register(RestOperationsConfig.class, DefaultInLambdaConfig.class, BasicController.class).autowire();
264-
mockRestOperations(jwks("Default"));
266+
mockJwksRestOperations(jwks("Default"));
265267
String token = this.token("ValidNoScopes");
266268
// @formatter:off
267269
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -297,7 +299,7 @@ public void getWhenUsingJwkSetUriInLambdaThenAcceptsRequest() throws Exception {
297299
@Test
298300
public void getWhenUsingDefaultsWithExpiredBearerTokenThenInvalidToken() throws Exception {
299301
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
300-
mockRestOperations(jwks("Default"));
302+
mockJwksRestOperations(jwks("Default"));
301303
String token = this.token("Expired");
302304
// @formatter:off
303305
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -341,7 +343,7 @@ public void getWhenUsingDefaultsWithMalformedBearerTokenThenInvalidToken() throw
341343
@Test
342344
public void getWhenUsingDefaultsWithMalformedPayloadThenInvalidToken() throws Exception {
343345
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
344-
mockRestOperations(jwks("Default"));
346+
mockJwksRestOperations(jwks("Default"));
345347
String token = this.token("MalformedPayload");
346348
// @formatter:off
347349
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -364,7 +366,7 @@ public void getWhenUsingDefaultsWithUnsignedBearerTokenThenInvalidToken() throws
364366
@Test
365367
public void getWhenUsingDefaultsWithBearerTokenBeforeNotBeforeThenInvalidToken() throws Exception {
366368
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
367-
this.mockRestOperations(jwks("Default"));
369+
this.mockJwksRestOperations(jwks("Default"));
368370
String token = this.token("TooEarly");
369371
// @formatter:off
370372
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -421,7 +423,7 @@ public void postWhenCsrfDisabledWithBearerTokenAsFormParameterThenIgnoresToken()
421423
@Test
422424
public void getWhenAnonymousDisabledThenAllows() throws Exception {
423425
this.spring.register(RestOperationsConfig.class, AnonymousDisabledConfig.class).autowire();
424-
mockRestOperations(jwks("Default"));
426+
mockJwksRestOperations(jwks("Default"));
425427
String token = token("ValidNoScopes");
426428
// @formatter:off
427429
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
@@ -442,7 +444,7 @@ public void getWhenUsingDefaultsWithNoBearerTokenThenUnauthorized() throws Excep
442444
@Test
443445
public void getWhenUsingDefaultsWithSufficientlyScopedBearerTokenThenAcceptsRequest() throws Exception {
444446
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
445-
mockRestOperations(jwks("Default"));
447+
mockJwksRestOperations(jwks("Default"));
446448
String token = this.token("ValidMessageReadScope");
447449
// @formatter:off
448450
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token)))
@@ -454,7 +456,7 @@ public void getWhenUsingDefaultsWithSufficientlyScopedBearerTokenThenAcceptsRequ
454456
@Test
455457
public void getWhenUsingDefaultsWithInsufficientScopeThenInsufficientScopeError() throws Exception {
456458
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
457-
mockRestOperations(jwks("Default"));
459+
mockJwksRestOperations(jwks("Default"));
458460
String token = this.token("ValidNoScopes");
459461
// @formatter:off
460462
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token)))
@@ -466,7 +468,7 @@ public void getWhenUsingDefaultsWithInsufficientScopeThenInsufficientScopeError(
466468
@Test
467469
public void getWhenUsingDefaultsWithInsufficientScpThenInsufficientScopeError() throws Exception {
468470
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
469-
mockRestOperations(jwks("Default"));
471+
mockJwksRestOperations(jwks("Default"));
470472
String token = this.token("ValidMessageWriteScp");
471473
// @formatter:off
472474
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token)))
@@ -478,7 +480,7 @@ public void getWhenUsingDefaultsWithInsufficientScpThenInsufficientScopeError()
478480
@Test
479481
public void getWhenUsingDefaultsAndAuthorizationServerHasNoMatchingKeyThenInvalidToken() throws Exception {
480482
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
481-
mockRestOperations(jwks("Empty"));
483+
mockJwksRestOperations(jwks("Empty"));
482484
String token = this.token("ValidNoScopes");
483485
// @formatter:off
484486
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -490,7 +492,7 @@ public void getWhenUsingDefaultsAndAuthorizationServerHasNoMatchingKeyThenInvali
490492
@Test
491493
public void getWhenUsingDefaultsAndAuthorizationServerHasMultipleMatchingKeysThenOk() throws Exception {
492494
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
493-
mockRestOperations(jwks("TwoKeys"));
495+
mockJwksRestOperations(jwks("TwoKeys"));
494496
String token = this.token("ValidNoScopes");
495497
// @formatter:off
496498
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
@@ -502,7 +504,7 @@ public void getWhenUsingDefaultsAndAuthorizationServerHasMultipleMatchingKeysThe
502504
@Test
503505
public void getWhenUsingDefaultsAndKeyMatchesByKidThenOk() throws Exception {
504506
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
505-
mockRestOperations(jwks("TwoKeys"));
507+
mockJwksRestOperations(jwks("TwoKeys"));
506508
String token = this.token("Kid");
507509
// @formatter:off
508510
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
@@ -514,7 +516,7 @@ public void getWhenUsingDefaultsAndKeyMatchesByKidThenOk() throws Exception {
514516
@Test
515517
public void getWhenUsingMethodSecurityWithValidBearerTokenThenAcceptsRequest() throws Exception {
516518
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
517-
mockRestOperations(jwks("Default"));
519+
mockJwksRestOperations(jwks("Default"));
518520
String token = this.token("ValidMessageReadScope");
519521
// @formatter:off
520522
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
@@ -526,7 +528,7 @@ public void getWhenUsingMethodSecurityWithValidBearerTokenThenAcceptsRequest() t
526528
@Test
527529
public void getWhenUsingMethodSecurityWithValidBearerTokenHavingScpAttributeThenAcceptsRequest() throws Exception {
528530
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
529-
mockRestOperations(jwks("Default"));
531+
mockJwksRestOperations(jwks("Default"));
530532
String token = this.token("ValidMessageReadScp");
531533
// @formatter:off
532534
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
@@ -538,7 +540,7 @@ public void getWhenUsingMethodSecurityWithValidBearerTokenHavingScpAttributeThen
538540
@Test
539541
public void getWhenUsingMethodSecurityWithInsufficientScopeThenInsufficientScopeError() throws Exception {
540542
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
541-
mockRestOperations(jwks("Default"));
543+
mockJwksRestOperations(jwks("Default"));
542544
String token = this.token("ValidNoScopes");
543545
// @formatter:off
544546
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
@@ -550,7 +552,7 @@ public void getWhenUsingMethodSecurityWithInsufficientScopeThenInsufficientScope
550552
@Test
551553
public void getWhenUsingMethodSecurityWithInsufficientScpThenInsufficientScopeError() throws Exception {
552554
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
553-
mockRestOperations(jwks("Default"));
555+
mockJwksRestOperations(jwks("Default"));
554556
String token = this.token("ValidMessageWriteScp");
555557
// @formatter:off
556558
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
@@ -562,7 +564,7 @@ public void getWhenUsingMethodSecurityWithInsufficientScpThenInsufficientScopeEr
562564
@Test
563565
public void getWhenUsingMethodSecurityWithDenyAllThenInsufficientScopeError() throws Exception {
564566
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
565-
mockRestOperations(jwks("Default"));
567+
mockJwksRestOperations(jwks("Default"));
566568
String token = this.token("ValidMessageReadScope");
567569
// @formatter:off
568570
this.mvc.perform(get("/ms-deny").with(bearerToken(token)))
@@ -574,7 +576,7 @@ public void getWhenUsingMethodSecurityWithDenyAllThenInsufficientScopeError() th
574576
@Test
575577
public void postWhenUsingDefaultsWithValidBearerTokenAndNoCsrfTokenThenOk() throws Exception {
576578
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
577-
mockRestOperations(jwks("Default"));
579+
mockJwksRestOperations(jwks("Default"));
578580
String token = this.token("ValidNoScopes");
579581
// @formatter:off
580582
this.mvc.perform(post("/authenticated").header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE).with(bearerToken(token)))
@@ -596,7 +598,7 @@ public void postWhenUsingDefaultsWithNoBearerTokenThenCsrfDenies() throws Except
596598
@Test
597599
public void postWhenUsingDefaultsWithExpiredBearerTokenAndNoCsrfThenInvalidToken() throws Exception {
598600
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
599-
mockRestOperations(jwks("Default"));
601+
mockJwksRestOperations(jwks("Default"));
600602
String token = this.token("Expired");
601603
// @formatter:off
602604
this.mvc.perform(post("/authenticated").header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE).with(bearerToken(token)))
@@ -608,7 +610,7 @@ public void postWhenUsingDefaultsWithExpiredBearerTokenAndNoCsrfThenInvalidToken
608610
@Test
609611
public void requestWhenDefaultConfiguredThenSessionIsNotCreated() throws Exception {
610612
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
611-
mockRestOperations(jwks("Default"));
613+
mockJwksRestOperations(jwks("Default"));
612614
String token = this.token("ValidNoScopes");
613615
// @formatter:off
614616
MvcResult result = this.mvc.perform(get("/").with(bearerToken(token)))
@@ -621,7 +623,7 @@ public void requestWhenDefaultConfiguredThenSessionIsNotCreated() throws Excepti
621623
@Test
622624
public void requestWhenIntrospectionConfiguredThenSessionIsNotCreated() throws Exception {
623625
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
624-
mockRestOperations(json("Active"));
626+
mockJsonRestOperations(json("Active"));
625627
// @formatter:off
626628
MvcResult result = this.mvc.perform(get("/authenticated").with(bearerToken("token")))
627629
.andExpect(status().isOk())
@@ -646,7 +648,7 @@ public void requestWhenUsingDefaultsAndNoBearerTokenThenSessionIsCreated() throw
646648
public void requestWhenSessionManagementConfiguredThenUserConfigurationOverrides() throws Exception {
647649
this.spring.register(RestOperationsConfig.class, AlwaysSessionCreationConfig.class, BasicController.class)
648650
.autowire();
649-
mockRestOperations(jwks("Default"));
651+
mockJwksRestOperations(jwks("Default"));
650652
String token = this.token("ValidNoScopes");
651653
// @formatter:off
652654
MvcResult result = this.mvc.perform(get("/").with(bearerToken(token)))
@@ -917,7 +919,7 @@ public void accessDeniedHandlerWhenGivenNullThenThrowsException() {
917919
@Test
918920
public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage() throws Exception {
919921
this.spring.register(RestOperationsConfig.class, CustomJwtValidatorConfig.class).autowire();
920-
mockRestOperations(jwks("Default"));
922+
mockJwksRestOperations(jwks("Default"));
921923
String token = this.token("ValidNoScopes");
922924
OAuth2TokenValidator<Jwt> jwtValidator = this.spring.getContext()
923925
.getBean(CustomJwtValidatorConfig.class)
@@ -935,7 +937,7 @@ public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage() th
935937
public void requestWhenClockSkewSetThenTimestampWindowRelaxedAccordingly() throws Exception {
936938
this.spring.register(RestOperationsConfig.class, UnexpiredJwtClockSkewConfig.class, BasicController.class)
937939
.autowire();
938-
mockRestOperations(jwks("Default"));
940+
mockJwksRestOperations(jwks("Default"));
939941
String token = this.token("ExpiresAt4687177990");
940942
// @formatter:off
941943
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -947,7 +949,7 @@ public void requestWhenClockSkewSetThenTimestampWindowRelaxedAccordingly() throw
947949
public void requestWhenClockSkewSetButJwtStillTooLateThenReportsExpired() throws Exception {
948950
this.spring.register(RestOperationsConfig.class, ExpiredJwtClockSkewConfig.class, BasicController.class)
949951
.autowire();
950-
mockRestOperations(jwks("Default"));
952+
mockJwksRestOperations(jwks("Default"));
951953
String token = this.token("ExpiresAt4687177990");
952954
// @formatter:off
953955
this.mvc.perform(get("/").with(bearerToken(token)))
@@ -1061,7 +1063,7 @@ public void getWhenDefaultAndCustomJwtAuthenticationManagerThenCustomUsed() thro
10611063
@Test
10621064
public void getWhenIntrospectingThenOk() throws Exception {
10631065
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
1064-
mockRestOperations(json("Active"));
1066+
mockJsonRestOperations(json("Active"));
10651067
// @formatter:off
10661068
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
10671069
.andExpect(status().isOk())
@@ -1073,7 +1075,7 @@ public void getWhenIntrospectingThenOk() throws Exception {
10731075
public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception {
10741076
this.spring.register(RestOperationsConfig.class, OpaqueTokenInLambdaConfig.class, BasicController.class)
10751077
.autowire();
1076-
mockRestOperations(json("Active"));
1078+
mockJsonRestOperations(json("Active"));
10771079
// @formatter:off
10781080
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
10791081
.andExpect(status().isOk())
@@ -1084,7 +1086,7 @@ public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception
10841086
@Test
10851087
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
10861088
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
1087-
mockRestOperations(json("Inactive"));
1089+
mockJsonRestOperations(json("Inactive"));
10881090
// @formatter:off
10891091
this.mvc.perform(get("/").with(bearerToken("token")))
10901092
.andExpect(status().isUnauthorized())
@@ -1095,7 +1097,7 @@ public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
10951097
@Test
10961098
public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception {
10971099
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
1098-
mockRestOperations(json("ActiveNoScopes"));
1100+
mockJsonRestOperations(json("ActiveNoScopes"));
10991101
// @formatter:off
11001102
this.mvc.perform(get("/requires-read-scope").with(bearerToken("token")))
11011103
.andExpect(status().isForbidden())
@@ -1252,7 +1254,7 @@ public void requestWhenDefaultAndResourceServerAccessDeniedHandlersThenMatchedBy
12521254
public void getWhenAlsoUsingHttpBasicThenCorrectProviderEngages() throws Exception {
12531255
this.spring.register(RestOperationsConfig.class, BasicAndResourceServerConfig.class, BasicController.class)
12541256
.autowire();
1255-
mockRestOperations(jwks("Default"));
1257+
mockJwksRestOperations(jwks("Default"));
12561258
String token = this.token("ValidNoScopes");
12571259
// @formatter:off
12581260
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
@@ -1408,7 +1410,7 @@ public void getWhenCustomAuthenticationConverterThenUsed() throws Exception {
14081410
OpaqueTokenAuthenticationConverter authenticationConverter = bean(OpaqueTokenAuthenticationConverter.class);
14091411
given(authenticationConverter.convert(anyString(), any(OAuth2AuthenticatedPrincipal.class)))
14101412
.willReturn(new TestingAuthenticationToken("jdoe", null, Collections.emptyList()));
1411-
mockRestOperations(json("Active"));
1413+
mockJsonRestOperations(json("Active"));
14121414
// @formatter:off
14131415
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
14141416
.andExpect(status().isOk())
@@ -1515,6 +1517,29 @@ private void mockRestOperations(String response) {
15151517
given(rest.exchange(any(RequestEntity.class), eq(String.class))).willReturn(entity);
15161518
}
15171519

1520+
private void mockJwksRestOperations(String response) {
1521+
RestOperations rest = this.spring.getContext().getBean(RestOperations.class);
1522+
HttpHeaders headers = new HttpHeaders();
1523+
headers.setContentType(MediaType.APPLICATION_JSON);
1524+
ResponseEntity<String> entity = new ResponseEntity<>(response, headers, HttpStatus.OK);
1525+
given(rest.exchange(any(RequestEntity.class), eq(String.class))).willReturn(entity);
1526+
}
1527+
1528+
private void mockJsonRestOperations(String response) {
1529+
try {
1530+
RestOperations rest = this.spring.getContext().getBean(RestOperations.class);
1531+
HttpHeaders headers = new HttpHeaders();
1532+
headers.setContentType(MediaType.APPLICATION_JSON);
1533+
ResponseEntity<Map<String, Object>> entity = new ResponseEntity<>(JSONObjectUtils.parse(response), headers,
1534+
HttpStatus.OK);
1535+
given(rest.exchange(any(RequestEntity.class), eq(new ParameterizedTypeReference<Map<String, Object>>() {
1536+
}))).willReturn(entity);
1537+
}
1538+
catch (Exception ex) {
1539+
throw new IllegalArgumentException(ex);
1540+
}
1541+
}
1542+
15181543
private <T> T bean(Class<T> beanClass) {
15191544
return this.spring.getContext().getBean(beanClass);
15201545
}

0 commit comments

Comments
 (0)