diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index 50ae85c9c3..62d1c20d49 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -39,6 +39,7 @@ import com.nimbusds.jose.Payload; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.util.JSONObjectUtils; import jakarta.annotation.PreDestroy; import jakarta.servlet.http.HttpServletRequest; import net.minidev.json.JSONObject; @@ -62,6 +63,7 @@ import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.convert.converter.Converter; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; @@ -217,7 +219,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithValidBearerTokenThenAcceptsRequest() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -232,7 +234,7 @@ public class OAuth2ResourceServerConfigurerTests { .register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class, SecurityContextChangedListenerConfig.class) .autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -248,7 +250,7 @@ public class OAuth2ResourceServerConfigurerTests { .register(RestOperationsConfig.class, DefaultConfig.class, SecurityContextChangedListenerConfig.class, BasicController.class) .autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -261,7 +263,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsInLambdaWithValidBearerTokenThenAcceptsRequest() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultInLambdaConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -297,7 +299,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithExpiredBearerTokenThenInvalidToken() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("Expired"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -341,7 +343,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithMalformedPayloadThenInvalidToken() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("MalformedPayload"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -364,7 +366,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithBearerTokenBeforeNotBeforeThenInvalidToken() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire(); - this.mockRestOperations(jwks("Default")); + this.mockJwksRestOperations(jwks("Default")); String token = this.token("TooEarly"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -421,7 +423,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenAnonymousDisabledThenAllows() throws Exception { this.spring.register(RestOperationsConfig.class, AnonymousDisabledConfig.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken(token))) @@ -442,7 +444,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithSufficientlyScopedBearerTokenThenAcceptsRequest() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageReadScope"); // @formatter:off this.mvc.perform(get("/requires-read-scope").with(bearerToken(token))) @@ -454,7 +456,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithInsufficientScopeThenInsufficientScopeError() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/requires-read-scope").with(bearerToken(token))) @@ -466,7 +468,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsWithInsufficientScpThenInsufficientScopeError() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageWriteScp"); // @formatter:off this.mvc.perform(get("/requires-read-scope").with(bearerToken(token))) @@ -478,7 +480,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsAndAuthorizationServerHasNoMatchingKeyThenInvalidToken() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire(); - mockRestOperations(jwks("Empty")); + mockJwksRestOperations(jwks("Empty")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -490,7 +492,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsAndAuthorizationServerHasMultipleMatchingKeysThenOk() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("TwoKeys")); + mockJwksRestOperations(jwks("TwoKeys")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken(token))) @@ -502,7 +504,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingDefaultsAndKeyMatchesByKidThenOk() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("TwoKeys")); + mockJwksRestOperations(jwks("TwoKeys")); String token = this.token("Kid"); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken(token))) @@ -514,7 +516,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingMethodSecurityWithValidBearerTokenThenAcceptsRequest() throws Exception { this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageReadScope"); // @formatter:off this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))) @@ -526,7 +528,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingMethodSecurityWithValidBearerTokenHavingScpAttributeThenAcceptsRequest() throws Exception { this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageReadScp"); // @formatter:off this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))) @@ -538,7 +540,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingMethodSecurityWithInsufficientScopeThenInsufficientScopeError() throws Exception { this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))) @@ -550,7 +552,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingMethodSecurityWithInsufficientScpThenInsufficientScopeError() throws Exception { this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageWriteScp"); // @formatter:off this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))) @@ -562,7 +564,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenUsingMethodSecurityWithDenyAllThenInsufficientScopeError() throws Exception { this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageReadScope"); // @formatter:off this.mvc.perform(get("/ms-deny").with(bearerToken(token))) @@ -574,7 +576,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void postWhenUsingDefaultsWithValidBearerTokenAndNoCsrfTokenThenOk() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(post("/authenticated").header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE).with(bearerToken(token))) @@ -596,7 +598,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void postWhenUsingDefaultsWithExpiredBearerTokenAndNoCsrfThenInvalidToken() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("Expired"); // @formatter:off this.mvc.perform(post("/authenticated").header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE).with(bearerToken(token))) @@ -608,7 +610,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void requestWhenDefaultConfiguredThenSessionIsNotCreated() throws Exception { this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off MvcResult result = this.mvc.perform(get("/").with(bearerToken(token))) @@ -621,7 +623,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void requestWhenIntrospectionConfiguredThenSessionIsNotCreated() throws Exception { this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire(); - mockRestOperations(json("Active")); + mockJsonRestOperations(json("Active")); // @formatter:off MvcResult result = this.mvc.perform(get("/authenticated").with(bearerToken("token"))) .andExpect(status().isOk()) @@ -646,7 +648,7 @@ public class OAuth2ResourceServerConfigurerTests { public void requestWhenSessionManagementConfiguredThenUserConfigurationOverrides() throws Exception { this.spring.register(RestOperationsConfig.class, AlwaysSessionCreationConfig.class, BasicController.class) .autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off MvcResult result = this.mvc.perform(get("/").with(bearerToken(token))) @@ -917,7 +919,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage() throws Exception { this.spring.register(RestOperationsConfig.class, CustomJwtValidatorConfig.class).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); OAuth2TokenValidator jwtValidator = this.spring.getContext() .getBean(CustomJwtValidatorConfig.class) @@ -935,7 +937,7 @@ public class OAuth2ResourceServerConfigurerTests { public void requestWhenClockSkewSetThenTimestampWindowRelaxedAccordingly() throws Exception { this.spring.register(RestOperationsConfig.class, UnexpiredJwtClockSkewConfig.class, BasicController.class) .autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ExpiresAt4687177990"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -947,7 +949,7 @@ public class OAuth2ResourceServerConfigurerTests { public void requestWhenClockSkewSetButJwtStillTooLateThenReportsExpired() throws Exception { this.spring.register(RestOperationsConfig.class, ExpiredJwtClockSkewConfig.class, BasicController.class) .autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ExpiresAt4687177990"); // @formatter:off this.mvc.perform(get("/").with(bearerToken(token))) @@ -1061,7 +1063,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenIntrospectingThenOk() throws Exception { this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire(); - mockRestOperations(json("Active")); + mockJsonRestOperations(json("Active")); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken("token"))) .andExpect(status().isOk()) @@ -1073,7 +1075,7 @@ public class OAuth2ResourceServerConfigurerTests { public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception { this.spring.register(RestOperationsConfig.class, OpaqueTokenInLambdaConfig.class, BasicController.class) .autowire(); - mockRestOperations(json("Active")); + mockJsonRestOperations(json("Active")); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken("token"))) .andExpect(status().isOk()) @@ -1084,7 +1086,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenIntrospectionFailsThenUnauthorized() throws Exception { this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire(); - mockRestOperations(json("Inactive")); + mockJsonRestOperations(json("Inactive")); // @formatter:off this.mvc.perform(get("/").with(bearerToken("token"))) .andExpect(status().isUnauthorized()) @@ -1095,7 +1097,7 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception { this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire(); - mockRestOperations(json("ActiveNoScopes")); + mockJsonRestOperations(json("ActiveNoScopes")); // @formatter:off this.mvc.perform(get("/requires-read-scope").with(bearerToken("token"))) .andExpect(status().isForbidden()) @@ -1252,7 +1254,7 @@ public class OAuth2ResourceServerConfigurerTests { public void getWhenAlsoUsingHttpBasicThenCorrectProviderEngages() throws Exception { this.spring.register(RestOperationsConfig.class, BasicAndResourceServerConfig.class, BasicController.class) .autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken(token))) @@ -1408,7 +1410,7 @@ public class OAuth2ResourceServerConfigurerTests { OpaqueTokenAuthenticationConverter authenticationConverter = bean(OpaqueTokenAuthenticationConverter.class); given(authenticationConverter.convert(anyString(), any(OAuth2AuthenticatedPrincipal.class))) .willReturn(new TestingAuthenticationToken("jdoe", null, Collections.emptyList())); - mockRestOperations(json("Active")); + mockJsonRestOperations(json("Active")); // @formatter:off this.mvc.perform(get("/authenticated").with(bearerToken("token"))) .andExpect(status().isOk()) @@ -1515,6 +1517,29 @@ public class OAuth2ResourceServerConfigurerTests { given(rest.exchange(any(RequestEntity.class), eq(String.class))).willReturn(entity); } + private void mockJwksRestOperations(String response) { + RestOperations rest = this.spring.getContext().getBean(RestOperations.class); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + ResponseEntity entity = new ResponseEntity<>(response, headers, HttpStatus.OK); + given(rest.exchange(any(RequestEntity.class), eq(String.class))).willReturn(entity); + } + + private void mockJsonRestOperations(String response) { + try { + RestOperations rest = this.spring.getContext().getBean(RestOperations.class); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + ResponseEntity> entity = new ResponseEntity<>(JSONObjectUtils.parse(response), headers, + HttpStatus.OK); + given(rest.exchange(any(RequestEntity.class), eq(new ParameterizedTypeReference>() { + }))).willReturn(entity); + } + catch (Exception ex) { + throw new IllegalArgumentException(ex); + } + } + private T bean(Class beanClass) { return this.spring.getContext().getBean(beanClass); } diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java index 400ff28613..4a6af4fc81 100644 --- a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java @@ -36,6 +36,7 @@ import com.nimbusds.jose.Payload; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.util.JSONObjectUtils; import jakarta.servlet.http.HttpServletRequest; import net.minidev.json.JSONObject; import okhttp3.mockwebserver.MockResponse; @@ -57,6 +58,7 @@ import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.XmlReaderContext; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.convert.converter.Converter; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpHeaders; @@ -139,7 +141,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenValidBearerTokenThenAcceptsRequest() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -150,7 +152,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenCustomSecurityContextHolderStrategyThenUses() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("JwtCustomSecurityContextHolderStrategy")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -175,7 +177,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenExpiredBearerTokenThenInvalidToken() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("Expired"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -187,7 +189,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenBadJwkEndpointThen500() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations("malformed"); + mockJwksRestOperations("malformed"); String token = this.token("ValidNoScopes"); // @formatter:off assertThatExceptionOfType(AuthenticationServiceException.class) @@ -219,7 +221,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenMalformedPayloadThenInvalidToken() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("MalformedPayload"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -242,7 +244,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenBearerTokenBeforeNotBeforeThenInvalidToken() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - this.mockRestOperations(jwks("Default")); + this.mockJwksRestOperations(jwks("Default")); String token = this.token("TooEarly"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -299,7 +301,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenSufficientlyScopedBearerTokenThenAcceptsRequest() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageReadScope"); // @formatter:off this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token)) @@ -310,7 +312,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenInsufficientScopeThenInsufficientScopeError() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token)) @@ -322,7 +324,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenInsufficientScpThenInsufficientScopeError() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidMessageWriteScp"); // @formatter:off this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token)) @@ -334,7 +336,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenAuthorizationServerHasNoMatchingKeyThenInvalidToken() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Empty")); + mockJwksRestOperations(jwks("Empty")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -346,7 +348,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenAuthorizationServerHasMultipleMatchingKeysThenOk() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("TwoKeys")); + mockJwksRestOperations(jwks("TwoKeys")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token)) @@ -357,7 +359,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenKeyMatchesByKidThenOk() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("TwoKeys")); + mockJwksRestOperations(jwks("TwoKeys")); String token = this.token("Kid"); // @formatter:off this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token)) @@ -368,7 +370,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void postWhenValidBearerTokenAndNoCsrfTokenThenOk() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token)) @@ -390,7 +392,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void postWhenExpiredBearerTokenAndNoCsrfThenInvalidToken() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("Expired"); // @formatter:off this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token)) @@ -402,7 +404,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void requestWhenJwtThenSessionIsNotCreated() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off MvcResult result = this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -438,7 +440,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void requestWhenSessionManagementConfiguredThenUses() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("AlwaysSessionCreation")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off MvcResult result = this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -587,7 +589,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage() throws Exception { this.spring.configLocations(xml("MockJwtValidator"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); OAuth2TokenValidator jwtValidator = this.spring.getContext().getBean(OAuth2TokenValidator.class); OAuth2Error error = new OAuth2Error("custom-error", "custom-description", "custom-uri"); @@ -602,7 +604,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void requestWhenClockSkewSetThenTimestampWindowRelaxedAccordingly() throws Exception { this.spring.configLocations(xml("UnexpiredJwtClockSkew"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ExpiresAt4687177990"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -613,7 +615,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void requestWhenClockSkewSetButJwtStillTooLateThenReportsExpired() throws Exception { this.spring.configLocations(xml("ExpiredJwtClockSkew"), xml("Jwt")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ExpiresAt4687177990"); // @formatter:off this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) @@ -675,7 +677,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenIntrospectingThenOk() throws Exception { this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire(); - mockRestOperations(json("Active")); + mockJsonRestOperations(json("Active")); // @formatter:off this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) .andExpect(status().isNotFound()); @@ -686,7 +688,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { public void configureWhenIntrospectingWithAuthenticationConverterThenUses() throws Exception { this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueTokenAndAuthenticationConverter")) .autowire(); - mockRestOperations(json("Active")); + mockJsonRestOperations(json("Active")); OpaqueTokenAuthenticationConverter converter = bean(OpaqueTokenAuthenticationConverter.class); given(converter.convert(any(), any())).willReturn(new TestingAuthenticationToken("user", "pass", "app")); // @formatter:off @@ -699,7 +701,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenIntrospectionFailsThenUnauthorized() throws Exception { this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire(); - mockRestOperations(json("Inactive")); + mockJsonRestOperations(json("Inactive")); // @formatter:off MockHttpServletRequestBuilder request = get("/") .header("Authorization", "Bearer token"); @@ -712,7 +714,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception { this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire(); - mockRestOperations(json("ActiveNoScopes")); + mockJsonRestOperations(json("ActiveNoScopes")); // @formatter:off this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer token")) .andExpect(status().isForbidden()) @@ -818,7 +820,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { @Test public void getWhenAlsoUsingHttpBasicThenCorrectProviderEngages() throws Exception { this.spring.configLocations(xml("JwtRestOperations"), xml("BasicAndResourceServer")).autowire(); - mockRestOperations(jwks("Default")); + mockJwksRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); // @formatter:off this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token)) @@ -963,7 +965,7 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { .setBody(response)); } - private void mockRestOperations(String response) { + private void mockJwksRestOperations(String response) { RestOperations rest = this.spring.getContext().getBean(RestOperations.class); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -971,6 +973,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { given(rest.exchange(any(RequestEntity.class), eq(String.class))).willReturn(entity); } + private void mockJsonRestOperations(String response) { + try { + RestOperations rest = this.spring.getContext().getBean(RestOperations.class); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + ResponseEntity> entity = new ResponseEntity<>(JSONObjectUtils.parse(response), headers, + HttpStatus.OK); + given(rest.exchange(any(RequestEntity.class), eq(new ParameterizedTypeReference>() { + }))).willReturn(entity); + } + catch (Exception ex) { + throw new IllegalArgumentException(ex); + } + } + private String json(String name) throws IOException { return resource(name + ".json"); }