Skip to content

Commit de5347a

Browse files
committed
Improve brittle tests using opaque token introspection
The tests that went through opaque token introspection rely on mocking a specific method in the RestOperations interface which is very brittle and hampers the ability to refactor internals. They are changed to instead make actual HTTP requests to a MockWebServer instead allowing refactoring changes. This is necessary to allow the implementation to be swapped from NimbusOpaqueTokenIntrospector to SpringOpaqueTokenIntrospector because the latter uses RestOperations#exchange(String, ParameterizedType) instead of RestOperations#exchange(String, String) of the former. Signed-off-by: Andreas Svanberg <[email protected]>
1 parent d5f38dc commit de5347a

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

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

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.springframework.context.EnvironmentAware;
6262
import org.springframework.context.annotation.Bean;
6363
import org.springframework.context.annotation.Configuration;
64+
import org.springframework.context.annotation.Import;
6465
import org.springframework.context.support.GenericApplicationContext;
6566
import org.springframework.core.convert.converter.Converter;
6667
import org.springframework.core.env.ConfigurableEnvironment;
@@ -146,6 +147,7 @@
146147
import org.springframework.web.bind.annotation.RequestMethod;
147148
import org.springframework.web.bind.annotation.RestController;
148149
import org.springframework.web.client.RestOperations;
150+
import org.springframework.web.client.RestTemplate;
149151
import org.springframework.web.context.support.GenericWebApplicationContext;
150152
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
151153

@@ -618,8 +620,8 @@ public void requestWhenDefaultConfiguredThenSessionIsNotCreated() throws Excepti
618620

619621
@Test
620622
public void requestWhenIntrospectionConfiguredThenSessionIsNotCreated() throws Exception {
621-
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
622-
mockRestOperations(json("Active"));
623+
this.spring.register(OpaqueTokenConfig.class, BasicController.class).autowire();
624+
mockWebServer(json("Active"));
623625
// @formatter:off
624626
MvcResult result = this.mvc.perform(get("/authenticated").with(bearerToken("token")))
625627
.andExpect(status().isOk())
@@ -1060,8 +1062,8 @@ public void getWhenDefaultAndCustomJwtAuthenticationManagerThenCustomUsed() thro
10601062

10611063
@Test
10621064
public void getWhenIntrospectingThenOk() throws Exception {
1063-
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
1064-
mockRestOperations(json("Active"));
1065+
this.spring.register(OpaqueTokenConfig.class, BasicController.class).autowire();
1066+
mockWebServer(json("Active"));
10651067
// @formatter:off
10661068
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
10671069
.andExpect(status().isOk())
@@ -1071,9 +1073,8 @@ public void getWhenIntrospectingThenOk() throws Exception {
10711073

10721074
@Test
10731075
public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception {
1074-
this.spring.register(RestOperationsConfig.class, OpaqueTokenInLambdaConfig.class, BasicController.class)
1075-
.autowire();
1076-
mockRestOperations(json("Active"));
1076+
this.spring.register(OpaqueTokenInLambdaConfig.class, BasicController.class).autowire();
1077+
mockWebServer(json("Active"));
10771078
// @formatter:off
10781079
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
10791080
.andExpect(status().isOk())
@@ -1083,8 +1084,8 @@ public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception
10831084

10841085
@Test
10851086
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
1086-
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
1087-
mockRestOperations(json("Inactive"));
1087+
this.spring.register(OpaqueTokenConfig.class).autowire();
1088+
mockWebServer(json("Inactive"));
10881089
// @formatter:off
10891090
this.mvc.perform(get("/").with(bearerToken("token")))
10901091
.andExpect(status().isUnauthorized())
@@ -1094,8 +1095,8 @@ public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
10941095

10951096
@Test
10961097
public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception {
1097-
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
1098-
mockRestOperations(json("ActiveNoScopes"));
1098+
this.spring.register(OpaqueTokenConfig.class).autowire();
1099+
mockWebServer(json("ActiveNoScopes"));
10991100
// @formatter:off
11001101
this.mvc.perform(get("/requires-read-scope").with(bearerToken("token")))
11011102
.andExpect(status().isForbidden())
@@ -1400,13 +1401,11 @@ public void getJwtAuthenticationConverterWhenDuplicateConverterBeansThenThrowsEx
14001401

14011402
@Test
14021403
public void getWhenCustomAuthenticationConverterThenUsed() throws Exception {
1403-
this.spring
1404-
.register(RestOperationsConfig.class, OpaqueTokenAuthenticationConverterConfig.class, BasicController.class)
1405-
.autowire();
1404+
this.spring.register(OpaqueTokenAuthenticationConverterConfig.class, BasicController.class).autowire();
14061405
OpaqueTokenAuthenticationConverter authenticationConverter = bean(OpaqueTokenAuthenticationConverter.class);
14071406
given(authenticationConverter.convert(anyString(), any(OAuth2AuthenticatedPrincipal.class)))
14081407
.willReturn(new TestingAuthenticationToken("jdoe", null, Collections.emptyList()));
1409-
mockRestOperations(json("Active"));
1408+
mockWebServer(json("Active"));
14101409
// @formatter:off
14111410
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
14121411
.andExpect(status().isOk())
@@ -2343,6 +2342,7 @@ AuthenticationEventPublisher authenticationEventPublisher() {
23432342
@Configuration
23442343
@EnableWebSecurity
23452344
@EnableWebMvc
2345+
@Import(OpaqueTokenIntrospectorConfig.class)
23462346
static class OpaqueTokenConfig {
23472347

23482348
@Bean
@@ -2364,6 +2364,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
23642364
@Configuration
23652365
@EnableWebSecurity
23662366
@EnableWebMvc
2367+
@Import(OpaqueTokenIntrospectorConfig.class)
23672368
static class OpaqueTokenInLambdaConfig {
23682369

23692370
@Bean
@@ -2387,6 +2388,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
23872388

23882389
@Configuration
23892390
@EnableWebSecurity
2391+
@Import(OpaqueTokenIntrospectorConfig.class)
23902392
static class OpaqueTokenAuthenticationManagerConfig {
23912393

23922394
@Bean
@@ -2559,6 +2561,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
25592561
@Configuration
25602562
@EnableWebSecurity
25612563
@EnableWebMvc
2564+
@Import(OpaqueTokenIntrospectorConfig.class)
25622565
static class OpaqueTokenAuthenticationConverterConfig {
25632566

25642567
@Bean
@@ -2583,6 +2586,20 @@ OpaqueTokenAuthenticationConverter authenticationConverter() {
25832586

25842587
}
25852588

2589+
@Configuration
2590+
@Import(WebServerConfig.class)
2591+
static class OpaqueTokenIntrospectorConfig {
2592+
2593+
@Value("${mockwebserver.url:https://example.org}")
2594+
String introspectUri;
2595+
2596+
@Bean
2597+
NimbusOpaqueTokenIntrospector introspector() {
2598+
return new NimbusOpaqueTokenIntrospector(this.introspectUri, new RestTemplate());
2599+
}
2600+
2601+
}
2602+
25862603
@Configuration
25872604
static class JwtDecoderConfig {
25882605

@@ -2694,11 +2711,6 @@ NimbusJwtDecoder jwtDecoder() {
26942711
.build();
26952712
}
26962713

2697-
@Bean
2698-
NimbusOpaqueTokenIntrospector tokenIntrospectionClient() {
2699-
return new NimbusOpaqueTokenIntrospector("https://example.org/introspect", this.rest);
2700-
}
2701-
27022714
}
27032715

27042716
private static class BearerTokenRequestPostProcessor implements RequestPostProcessor {

0 commit comments

Comments
 (0)