diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java index 49b887c5..2cdf451a 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java @@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -31,15 +30,17 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; import org.springframework.security.config.test.SpringTestRule; import org.springframework.security.oauth2.jose.TestJwks; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; import org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter; import org.springframework.test.web.servlet.MockMvc; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -51,8 +52,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Florian Berthe */ public class JwkSetTests { - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static ProviderSettings providerSettings; @@ -64,19 +63,11 @@ public class JwkSetTests { @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); providerSettings = new ProviderSettings().jwkSetEndpoint("/test/jwks"); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenJwkSetThenReturnKeys() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); @@ -105,13 +96,20 @@ public class JwkSetTests { static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java index d4ec8db6..8f9d602c 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java @@ -15,6 +15,7 @@ */ package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -28,11 +29,9 @@ import java.util.stream.Collectors; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; -import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -62,12 +61,16 @@ import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtEncoder; import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -86,14 +89,6 @@ import org.springframework.web.util.UriComponentsBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -114,9 +109,8 @@ public class OAuth2AuthorizationCodeGrantTests { private static final String S256_CODE_CHALLENGE = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"; private static final String AUTHORITIES_CLAIM = "authorities"; private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.CODE); + private static final OAuth2TokenType STATE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.STATE); - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static NimbusJwsEncoder jwtEncoder; private static ProviderSettings providerSettings; @@ -130,13 +124,17 @@ public class OAuth2AuthorizationCodeGrantTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + + @Autowired + private OAuth2AuthorizationService authorizationService; + @Autowired private JwtDecoder jwtDecoder; @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); jwtEncoder = new NimbusJwsEncoder(jwkSource); @@ -145,27 +143,29 @@ public class OAuth2AuthorizationCodeGrantTests { .tokenEndpoint("/test/token"); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenAuthorizationRequestNotAuthenticatedThenUnauthorized() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) .params(getAuthorizationRequestParameters(registeredClient))) .andExpect(status().isUnauthorized()) .andReturn(); + } - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verifyNoInteractions(authorizationService); + @Test + public void requestWhenRegisteredClientMissingThenBadRequest() throws Exception { + this.spring.register(AuthorizationServerConfiguration.class).autowire(); + + RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + + this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) + .params(getAuthorizationRequestParameters(registeredClient))) + .andExpect(status().isBadRequest()) + .andReturn(); } @Test @@ -184,18 +184,20 @@ public class OAuth2AuthorizationCodeGrantTests { private void assertAuthorizationRequestRedirectsToClient(String authorizationEndpointUri) throws Exception { RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); MvcResult mvcResult = this.mvc.perform(get(authorizationEndpointUri) .params(getAuthorizationRequestParameters(registeredClient)) .with(user("user"))) .andExpect(status().is3xxRedirection()) .andReturn(); - assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state"); + String redirectedUrl = mvcResult.getResponse().getRedirectedUrl(); + assertThat(redirectedUrl).matches("https://example.com\\?code=.{15,}&state=state"); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).save(any()); + String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code"); + OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE); + assertThat(authorization).isNotNull(); + assertThat(authorization.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); } @Test @@ -203,14 +205,10 @@ public class OAuth2AuthorizationCodeGrantTests { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); - when(authorizationService.findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE))) - .thenReturn(authorization); + this.authorizationService.save(authorization); OAuth2AccessTokenResponse accessTokenResponse = assertTokenRequestReturnsAccessTokenResponse( registeredClient, authorization, OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI); @@ -230,14 +228,10 @@ public class OAuth2AuthorizationCodeGrantTests { this.spring.register(AuthorizationServerConfigurationCustomEndpoints.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); - when(authorizationService.findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE))) - .thenReturn(authorization); + this.authorizationService.save(authorization); assertTokenRequestReturnsAccessTokenResponse( registeredClient, authorization, providerSettings.tokenEndpoint()); @@ -258,11 +252,14 @@ public class OAuth2AuthorizationCodeGrantTests { .andExpect(jsonPath("$.scope").isNotEmpty()) .andReturn(); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE)); - verify(authorizationService).save(any()); + OAuth2Authorization accessTokenAuthorization = this.authorizationService.findById(authorization.getId()); + assertThat(accessTokenAuthorization).isNotNull(); + assertThat(accessTokenAuthorization.getAccessToken()).isNotNull(); + assertThat(accessTokenAuthorization.getRefreshToken()).isNotNull(); + + OAuth2Authorization.Token authorizationCodeToken = accessTokenAuthorization.getToken(OAuth2AuthorizationCode.class); + assertThat(authorizationCodeToken).isNotNull(); + assertThat(authorizationCodeToken.getMetadata().get(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME)).isEqualTo(true); MockHttpServletResponse servletResponse = mvcResult.getResponse(); MockClientHttpResponse httpResponse = new MockClientHttpResponse( @@ -275,8 +272,7 @@ public class OAuth2AuthorizationCodeGrantTests { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); MvcResult mvcResult = this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) .params(getAuthorizationRequestParameters(registeredClient)) @@ -285,21 +281,16 @@ public class OAuth2AuthorizationCodeGrantTests { .with(user("user"))) .andExpect(status().is3xxRedirection()) .andReturn(); - assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state"); - - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); + String redirectedUrl = mvcResult.getResponse().getRedirectedUrl(); + assertThat(redirectedUrl).matches("https://example.com\\?code=.{15,}&state=state"); - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - OAuth2Authorization authorization = authorizationCaptor.getValue(); - - when(authorizationService.findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE))) - .thenReturn(authorization); + String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code"); + OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE); + assertThat(authorizationCodeAuthorization).isNotNull(); + assertThat(authorizationCodeAuthorization.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) - .params(getTokenRequestParameters(registeredClient, authorization)) + .params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization)) .param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()) .param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER)) .andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store"))) @@ -311,11 +302,13 @@ public class OAuth2AuthorizationCodeGrantTests { .andExpect(jsonPath("$.refresh_token").doesNotExist()) .andExpect(jsonPath("$.scope").isNotEmpty()); - verify(registeredClientRepository, times(2)).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService, times(2)).findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE)); - verify(authorizationService, times(2)).save(any()); + OAuth2Authorization accessTokenAuthorization = this.authorizationService.findById(authorizationCodeAuthorization.getId()); + assertThat(accessTokenAuthorization).isNotNull(); + assertThat(accessTokenAuthorization.getAccessToken()).isNotNull(); + + OAuth2Authorization.Token authorizationCodeToken = accessTokenAuthorization.getToken(OAuth2AuthorizationCode.class); + assertThat(authorizationCodeToken).isNotNull(); + assertThat(authorizationCodeToken.getMetadata().get(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME)).isEqualTo(true); } @Test @@ -323,14 +316,10 @@ public class OAuth2AuthorizationCodeGrantTests { this.spring.register(AuthorizationServerConfigurationWithJwtEncoder.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); - when(authorizationService.findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE))) - .thenReturn(authorization); + this.authorizationService.save(authorization); this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .params(getTokenRequestParameters(registeredClient, authorization)) @@ -349,8 +338,7 @@ public class OAuth2AuthorizationCodeGrantTests { }) .clientSettings(settings -> settings.requireUserConsent(true)) .build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); String consentPage = this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) .params(getAuthorizationRequestParameters(registeredClient)) @@ -377,36 +365,28 @@ public class OAuth2AuthorizationCodeGrantTests { }) .clientSettings(settings -> settings.requireUserConsent(true)) .build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); + OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient) .principalName("user") .build(); - - final String stateParameter = "state"; - - when(authorizationService.findByToken( - eq(stateParameter), eq(new OAuth2TokenType(OAuth2ParameterNames.STATE)))) - .thenReturn(authorization); + this.authorizationService.save(authorization); MvcResult mvcResult = this.mvc.perform(post(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) .param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()) .param(OAuth2ParameterNames.SCOPE, "message.read") .param(OAuth2ParameterNames.SCOPE, "message.write") - .param(OAuth2ParameterNames.STATE, stateParameter) + .param(OAuth2ParameterNames.STATE, "state") .param("consent_action", "approve") .with(user("user"))) .andExpect(status().is3xxRedirection()) .andReturn(); - assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state"); - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - OAuth2Authorization authorizationCodeAuthorization = authorizationCaptor.getValue(); - when(authorizationService.findByToken( - eq(authorizationCodeAuthorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE))) - .thenReturn(authorizationCodeAuthorization); + String redirectedUrl = mvcResult.getResponse().getRedirectedUrl(); + assertThat(redirectedUrl).matches("https://example.com\\?code=.{15,}&state=state"); + + String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code"); + OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE); this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization)) @@ -434,27 +414,27 @@ public class OAuth2AuthorizationCodeGrantTests { }) .clientSettings(settings -> settings.requireUserConsent(true)) .build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); MvcResult mvcResult = this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) .params(getAuthorizationRequestParameters(registeredClient)) .with(user("user"))) .andExpect(status().is3xxRedirection()) .andReturn(); + String redirectedUrl = mvcResult.getResponse().getRedirectedUrl(); + assertThat(redirectedUrl).matches("/oauth2/consent\\?scope=.+&client_id=.+&state=.+"); - String locationHeader = URLDecoder.decode(mvcResult.getResponse().getRedirectedUrl(), StandardCharsets.UTF_8.name()); - UriComponents redirectedUrl = UriComponentsBuilder.fromUriString(locationHeader).build(); - MultiValueMap redirectQueryParams = redirectedUrl.getQueryParams(); + String locationHeader = URLDecoder.decode(redirectedUrl, StandardCharsets.UTF_8.name()); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build(); + MultiValueMap redirectQueryParams = uriComponents.getQueryParams(); - assertThat(redirectedUrl.getPath()).isEqualTo(consentPage); + assertThat(uriComponents.getPath()).isEqualTo(consentPage); assertThat(redirectQueryParams.getFirst(OAuth2ParameterNames.SCOPE)).isEqualTo("message.read message.write"); assertThat(redirectQueryParams.getFirst(OAuth2ParameterNames.CLIENT_ID)).isEqualTo(registeredClient.getClientId()); - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - OAuth2Authorization authorization = authorizationCaptor.getValue(); - assertThat(redirectQueryParams.getFirst(OAuth2ParameterNames.STATE)).isEqualTo(authorization.getAttribute(OAuth2ParameterNames.STATE)); + String state = extractParameterFromRedirectUri(redirectedUrl, "state"); + OAuth2Authorization authorization = this.authorizationService.findByToken(state, STATE_TOKEN_TYPE); + assertThat(authorization).isNotNull(); } private static MultiValueMap getAuthorizationRequestParameters(RegisteredClient registeredClient) { @@ -494,18 +474,36 @@ public class OAuth2AuthorizationCodeGrantTests { ); } + private String extractParameterFromRedirectUri(String redirectUri, String param) throws UnsupportedEncodingException { + String locationHeader = URLDecoder.decode(redirectUri, StandardCharsets.UTF_8.name()); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build(); + return uriComponents.getQueryParams().getFirst(param); + } + @EnableWebSecurity @Import(OAuth2AuthorizationServerConfiguration.class) static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerMetadataTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerMetadataTests.java index a2ae28c8..9073dfd5 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerMetadataTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerMetadataTests.java @@ -29,12 +29,14 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; import org.springframework.security.config.test.SpringTestRule; import org.springframework.security.oauth2.jose.TestJwks; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter; import org.springframework.test.web.servlet.MockMvc; -import static org.mockito.Mockito.mock; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -76,7 +78,8 @@ public class OAuth2AuthorizationServerMetadataTests { @Bean RegisteredClientRepository registeredClientRepository() { - return mock(RegisteredClientRepository.class); + RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + return new InMemoryRegisteredClientRepository(registeredClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java index 3111b2c6..4ec2e23a 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java @@ -44,12 +44,16 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.jose.TestJwks; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -67,7 +71,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -80,8 +83,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Joe Grandja */ public class OAuth2ClientCredentialsGrantTests { - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static OAuth2TokenCustomizer jwtCustomizer; private static AuthenticationConverter accessTokenRequestConverter; @@ -95,10 +96,11 @@ public class OAuth2ClientCredentialsGrantTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); jwtCustomizer = mock(OAuth2TokenCustomizer.class); @@ -112,8 +114,6 @@ public class OAuth2ClientCredentialsGrantTests { @Before public void setup() { reset(jwtCustomizer); - reset(registeredClientRepository); - reset(authorizationService); } @Test @@ -123,9 +123,6 @@ public class OAuth2ClientCredentialsGrantTests { this.mvc.perform(MockMvcRequestBuilders.post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())) .andExpect(status().isUnauthorized()); - - verifyNoInteractions(registeredClientRepository); - verifyNoInteractions(authorizationService); } @Test @@ -133,8 +130,7 @@ public class OAuth2ClientCredentialsGrantTests { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()) @@ -146,8 +142,6 @@ public class OAuth2ClientCredentialsGrantTests { .andExpect(jsonPath("$.scope").value("scope1 scope2")); verify(jwtCustomizer).customize(any()); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).save(any()); } @Test @@ -155,8 +149,7 @@ public class OAuth2ClientCredentialsGrantTests { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()) @@ -168,8 +161,6 @@ public class OAuth2ClientCredentialsGrantTests { .andExpect(jsonPath("$.scope").value("scope1 scope2")); verify(jwtCustomizer).customize(any()); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).save(any()); } @Test @@ -177,8 +168,7 @@ public class OAuth2ClientCredentialsGrantTests { this.spring.register(AuthorizationServerConfigurationCustomTokenEndpoint.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient); OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication = @@ -217,13 +207,25 @@ public class OAuth2ClientCredentialsGrantTests { static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java index 8fdf8ecd..f3247b07 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java @@ -26,7 +26,6 @@ import java.util.stream.Collectors; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -47,7 +46,6 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.AuthorizationGrantType; -import org.springframework.security.oauth2.core.OAuth2TokenType; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; @@ -55,11 +53,15 @@ import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -71,12 +73,6 @@ import org.springframework.util.MultiValueMap; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -90,8 +86,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. */ public class OAuth2RefreshTokenGrantTests { private static final String AUTHORITIES_CLAIM = "authorities"; - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static NimbusJwtDecoder jwtDecoder; private static HttpMessageConverter accessTokenHttpResponseConverter = @@ -103,34 +97,28 @@ public class OAuth2RefreshTokenGrantTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + + @Autowired + private OAuth2AuthorizationService authorizationService; + @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); jwtDecoder = NimbusJwtDecoder.withPublicKey(TestKeys.DEFAULT_PUBLIC_KEY).build(); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenRefreshTokenRequestValidThenReturnAccessTokenResponse() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); - when(authorizationService.findByToken( - eq(authorization.getRefreshToken().getToken().getTokenValue()), - eq(OAuth2TokenType.REFRESH_TOKEN))) - .thenReturn(authorization); + this.authorizationService.save(authorization); MvcResult mvcResult = this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .params(getRefreshTokenRequestParameters(authorization)) @@ -146,12 +134,6 @@ public class OAuth2RefreshTokenGrantTests { .andExpect(jsonPath("$.scope").isNotEmpty()) .andReturn(); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).findByToken( - eq(authorization.getRefreshToken().getToken().getTokenValue()), - eq(OAuth2TokenType.REFRESH_TOKEN)); - verify(authorizationService).save(any()); - MockHttpServletResponse servletResponse = mvcResult.getResponse(); MockClientHttpResponse httpResponse = new MockClientHttpResponse( servletResponse.getContentAsByteArray(), HttpStatus.valueOf(servletResponse.getStatus())); @@ -188,13 +170,25 @@ public class OAuth2RefreshTokenGrantTests { static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java index e26993c5..f454e02a 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java @@ -23,7 +23,6 @@ import java.util.HashSet; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -50,9 +49,13 @@ import org.springframework.security.oauth2.core.http.converter.OAuth2TokenIntros import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.TestJwtClaimsSets; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -63,12 +66,6 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -80,8 +77,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Joe Grandja */ public class OAuth2TokenIntrospectionTests { - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static ProviderSettings providerSettings; private final HttpMessageConverter tokenIntrospectionHttpResponseConverter = @@ -93,28 +88,26 @@ public class OAuth2TokenIntrospectionTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + + @Autowired + private OAuth2AuthorizationService authorizationService; + @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); providerSettings = new ProviderSettings().tokenIntrospectionEndpoint("/test/introspect"); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenIntrospectValidAccessTokenThenActive() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); - RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2().build(); - when(registeredClientRepository.findByClientId(eq(introspectRegisteredClient.getClientId()))) - .thenReturn(introspectRegisteredClient); + RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2() + .clientSecret("secret-2").build(); + this.registeredClientRepository.save(introspectRegisteredClient); RegisteredClient authorizedRegisteredClient = TestRegisteredClients.registeredClient().build(); Instant issuedAt = Instant.now(); @@ -126,10 +119,8 @@ public class OAuth2TokenIntrospectionTests { OAuth2Authorization authorization = TestOAuth2Authorizations .authorization(authorizedRegisteredClient, accessToken, tokenClaims.getClaims()) .build(); - when(authorizationService.findByToken(eq(accessToken.getTokenValue()), isNull())) - .thenReturn(authorization); - when(registeredClientRepository.findById(eq(authorizedRegisteredClient.getId()))) - .thenReturn(authorizedRegisteredClient); + this.registeredClientRepository.save(authorizedRegisteredClient); + this.authorizationService.save(authorization); // @formatter:off MvcResult mvcResult = this.mvc.perform(post(providerSettings.tokenIntrospectionEndpoint()) @@ -139,10 +130,6 @@ public class OAuth2TokenIntrospectionTests { .andReturn(); // @formatter:on - verify(registeredClientRepository).findByClientId(eq(introspectRegisteredClient.getClientId())); - verify(authorizationService).findByToken(eq(accessToken.getTokenValue()), isNull()); - verify(registeredClientRepository).findById(eq(authorizedRegisteredClient.getId())); - OAuth2TokenIntrospection tokenIntrospectionResponse = readTokenIntrospectionResponse(mvcResult); assertThat(tokenIntrospectionResponse.isActive()).isTrue(); assertThat(tokenIntrospectionResponse.getClientId()).isEqualTo(authorizedRegisteredClient.getClientId()); @@ -165,17 +152,15 @@ public class OAuth2TokenIntrospectionTests { public void requestWhenIntrospectValidRefreshTokenThenActive() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); - RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2().build(); - when(registeredClientRepository.findByClientId(eq(introspectRegisteredClient.getClientId()))) - .thenReturn(introspectRegisteredClient); + RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2() + .clientSecret("secret-2").build(); + this.registeredClientRepository.save(introspectRegisteredClient); RegisteredClient authorizedRegisteredClient = TestRegisteredClients.registeredClient().build(); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(authorizedRegisteredClient).build(); OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken(); - when(authorizationService.findByToken(eq(refreshToken.getTokenValue()), isNull())) - .thenReturn(authorization); - when(registeredClientRepository.findById(eq(authorizedRegisteredClient.getId()))) - .thenReturn(authorizedRegisteredClient); + this.registeredClientRepository.save(authorizedRegisteredClient); + this.authorizationService.save(authorization); // @formatter:off MvcResult mvcResult = this.mvc.perform(post(providerSettings.tokenIntrospectionEndpoint()) @@ -185,10 +170,6 @@ public class OAuth2TokenIntrospectionTests { .andReturn(); // @formatter:on - verify(registeredClientRepository).findByClientId(eq(introspectRegisteredClient.getClientId())); - verify(authorizationService).findByToken(eq(refreshToken.getTokenValue()), isNull()); - verify(registeredClientRepository).findById(eq(authorizedRegisteredClient.getId())); - OAuth2TokenIntrospection tokenIntrospectionResponse = readTokenIntrospectionResponse(mvcResult); assertThat(tokenIntrospectionResponse.isActive()).isTrue(); assertThat(tokenIntrospectionResponse.getClientId()).isEqualTo(authorizedRegisteredClient.getClientId()); @@ -226,13 +207,25 @@ public class OAuth2TokenIntrospectionTests { static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java index 06d9c261..cb7dd0ed 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java @@ -22,11 +22,9 @@ import java.util.Base64; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; -import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -43,9 +41,13 @@ import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.OAuth2TokenType; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames2; import org.springframework.security.oauth2.jose.TestJwks; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -56,12 +58,6 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -71,8 +67,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Joe Grandja */ public class OAuth2TokenRevocationTests { - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static ProviderSettings providerSettings; @@ -82,33 +76,30 @@ public class OAuth2TokenRevocationTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + + @Autowired + private OAuth2AuthorizationService authorizationService; + @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); providerSettings = new ProviderSettings().tokenRevocationEndpoint("/test/revoke"); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenRevokeRefreshTokenThenRevoked() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); OAuth2RefreshToken token = authorization.getRefreshToken().getToken(); OAuth2TokenType tokenType = OAuth2TokenType.REFRESH_TOKEN; - when(authorizationService.findByToken(eq(token.getTokenValue()), isNull())).thenReturn(authorization); + this.authorizationService.save(authorization); this.mvc.perform(post(OAuth2TokenRevocationEndpointFilter.DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI) .params(getTokenRevocationRequestParameters(token, tokenType)) @@ -116,13 +107,7 @@ public class OAuth2TokenRevocationTests { registeredClient.getClientId(), registeredClient.getClientSecret()))) .andExpect(status().isOk()); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).findByToken(eq(token.getTokenValue()), isNull()); - - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - - OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue(); + OAuth2Authorization updatedAuthorization = this.authorizationService.findById(authorization.getId()); OAuth2Authorization.Token refreshToken = updatedAuthorization.getRefreshToken(); assertThat(refreshToken.isInvalidated()).isTrue(); OAuth2Authorization.Token accessToken = updatedAuthorization.getAccessToken(); @@ -145,13 +130,12 @@ public class OAuth2TokenRevocationTests { private void assertRevokeAccessTokenThenRevoked(String tokenRevocationEndpointUri) throws Exception { RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build(); OAuth2AccessToken token = authorization.getAccessToken().getToken(); OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN; - when(authorizationService.findByToken(eq(token.getTokenValue()), isNull())).thenReturn(authorization); + this.authorizationService.save(authorization); this.mvc.perform(post(tokenRevocationEndpointUri) .params(getTokenRevocationRequestParameters(token, tokenType)) @@ -159,13 +143,7 @@ public class OAuth2TokenRevocationTests { registeredClient.getClientId(), registeredClient.getClientSecret()))) .andExpect(status().isOk()); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).findByToken(eq(token.getTokenValue()), isNull()); - - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - - OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue(); + OAuth2Authorization updatedAuthorization = this.authorizationService.findById(authorization.getId()); OAuth2Authorization.Token accessToken = updatedAuthorization.getAccessToken(); assertThat(accessToken.isInvalidated()).isTrue(); OAuth2Authorization.Token refreshToken = updatedAuthorization.getRefreshToken(); @@ -192,13 +170,25 @@ public class OAuth2TokenRevocationTests { static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java index dead12e1..4049cc2f 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java @@ -22,11 +22,9 @@ import java.util.Base64; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; -import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -46,7 +44,6 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.security.oauth2.core.OAuth2TokenType; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; @@ -55,8 +52,11 @@ import org.springframework.security.oauth2.core.oidc.OidcClientRegistration; import org.springframework.security.oauth2.core.oidc.http.converter.OidcClientRegistrationHttpMessageConverter; import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; -import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -67,13 +67,6 @@ import org.springframework.test.web.servlet.MvcResult; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -90,8 +83,6 @@ public class OidcClientRegistrationTests { new OAuth2AccessTokenResponseHttpMessageConverter(); private static final HttpMessageConverter clientRegistrationHttpMessageConverter = new OidcClientRegistrationHttpMessageConverter(); - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; @Rule @@ -100,20 +91,18 @@ public class OidcClientRegistrationTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + + @Autowired + private OAuth2AuthorizationService authorizationService; + @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenClientRegistrationRequestAuthorizedThenClientRegistrationResponse() throws Exception { this.spring.register(AuthorizationServerConfiguration.class).autowire(); @@ -124,8 +113,7 @@ public class OidcClientRegistrationTests { RegisteredClient registeredClient = TestRegisteredClients.registeredClient2() .scope(clientRegistrationScope) .build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); MvcResult mvcResult = this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()) @@ -139,17 +127,8 @@ public class OidcClientRegistrationTests { OAuth2AccessToken accessToken = readAccessTokenResponse(mvcResult.getResponse()).getAccessToken(); - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - OAuth2Authorization authorization = authorizationCaptor.getValue(); - // ***** (2) Register the client - when(authorizationService.findByToken(eq(accessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN))) - .thenReturn(authorization); - doNothing().when(registeredClientRepository).save(any(RegisteredClient.class)); - // @formatter:off OidcClientRegistration clientRegistration = OidcClientRegistration.builder() .clientName("client-name") @@ -225,13 +204,25 @@ public class OidcClientRegistrationTests { static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java index 2da8337f..88db0de7 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java @@ -15,6 +15,8 @@ */ package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.Principal; @@ -26,11 +28,9 @@ import java.util.stream.Collectors; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; -import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -58,11 +58,15 @@ import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -75,17 +79,12 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -102,8 +101,6 @@ public class OidcTests { private static final String ISSUER_URL = "https://example.com/issuer1"; private static final String AUTHORITIES_CLAIM = "authorities"; private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.CODE); - private static RegisteredClientRepository registeredClientRepository; - private static OAuth2AuthorizationService authorizationService; private static JWKSource jwkSource; private static HttpMessageConverter accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter(); @@ -114,23 +111,21 @@ public class OidcTests { @Autowired private MockMvc mvc; + @Autowired + private RegisteredClientRepository registeredClientRepository; + + @Autowired + private OAuth2AuthorizationService authorizationService; + @Autowired private JwtDecoder jwtDecoder; @BeforeClass public static void init() { - registeredClientRepository = mock(RegisteredClientRepository.class); - authorizationService = mock(OAuth2AuthorizationService.class); JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); } - @Before - public void setup() { - reset(registeredClientRepository); - reset(authorizationService); - } - @Test public void requestWhenConfigurationRequestAndIssuerSetThenReturnConfigurationResponse() throws Exception { this.spring.register(AuthorizationServerConfigurationWithIssuer.class).autowire(); @@ -159,26 +154,18 @@ public class OidcTests { this.spring.register(AuthorizationServerConfiguration.class).autowire(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().scope(OidcScopes.OPENID).build(); - when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId()))) - .thenReturn(registeredClient); + this.registeredClientRepository.save(registeredClient); MvcResult mvcResult = this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI) .params(getAuthorizationRequestParameters(registeredClient)) .with(user("user").roles("A", "B"))) .andExpect(status().is3xxRedirection()) .andReturn(); - assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state"); - - verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId())); + String redirectedUrl = mvcResult.getResponse().getRedirectedUrl(); + assertThat(redirectedUrl).matches("https://example.com\\?code=.{15,}&state=state"); - ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); - verify(authorizationService).save(authorizationCaptor.capture()); - OAuth2Authorization authorization = authorizationCaptor.getValue(); - - when(authorizationService.findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE))) - .thenReturn(authorization); + String authorizationCode = extractParameterFromRedirectUri(redirectedUrl, "code"); + OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE); mvcResult = this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI) .params(getTokenRequestParameters(registeredClient, authorization)) @@ -195,12 +182,6 @@ public class OidcTests { .andExpect(jsonPath("$.id_token").isNotEmpty()) .andReturn(); - verify(registeredClientRepository, times(2)).findByClientId(eq(registeredClient.getClientId())); - verify(authorizationService).findByToken( - eq(authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue()), - eq(AUTHORIZATION_CODE_TOKEN_TYPE)); - verify(authorizationService, times(2)).save(any()); - MockHttpServletResponse servletResponse = mvcResult.getResponse(); MockClientHttpResponse httpResponse = new MockClientHttpResponse( servletResponse.getContentAsByteArray(), HttpStatus.valueOf(servletResponse.getStatus())); @@ -244,18 +225,36 @@ public class OidcTests { return new String(encodedBytes, StandardCharsets.UTF_8); } + private String extractParameterFromRedirectUri(String redirectUri, String param) throws UnsupportedEncodingException { + String locationHeader = URLDecoder.decode(redirectUri, StandardCharsets.UTF_8.name()); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build(); + return uriComponents.getQueryParams().getFirst(param); + } + @EnableWebSecurity @Import(OAuth2AuthorizationServerConfiguration.class) static class AuthorizationServerConfiguration { @Bean - RegisteredClientRepository registeredClientRepository() { - return registeredClientRepository; + OAuth2AuthorizationService authorizationService() { + return new InMemoryOAuth2AuthorizationService(); } @Bean - OAuth2AuthorizationService authorizationService() { - return authorizationService; + OAuth2AuthorizationConsentService authorizationConsentService() { + return new InMemoryOAuth2AuthorizationConsentService(); + } + + @Bean + RegisteredClientRepository registeredClientRepository() { + // @formatter:off + RegisteredClient dummyClient = TestRegisteredClients.registeredClient() + .id("dummy-client") + .clientId("dummy-client") + .clientSecret("dummy-secret") + .build(); + // @formatter:on + return new InMemoryRegisteredClientRepository(dummyClient); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/TestOAuth2Authorizations.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/TestOAuth2Authorizations.java index fa5da747..c15ebecf 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/TestOAuth2Authorizations.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/TestOAuth2Authorizations.java @@ -28,6 +28,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.OAuth2RefreshToken2; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; import org.springframework.util.CollectionUtils; @@ -80,6 +81,7 @@ public class TestOAuth2Authorizations { .token(authorizationCode) .token(accessToken, (metadata) -> metadata.putAll(tokenMetadata(accessTokenClaims))) .refreshToken(refreshToken) + .attribute(OAuth2ParameterNames.STATE, "state") .attribute(OAuth2AuthorizationRequest.class.getName(), authorizationRequest) .attribute(Principal.class.getName(), new TestingAuthenticationToken("principal", null, "ROLE_A", "ROLE_B")) diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson2/TestingAuthenticationTokenMixin.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson2/TestingAuthenticationTokenMixin.java new file mode 100644 index 00000000..dbba290e --- /dev/null +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson2/TestingAuthenticationTokenMixin.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.server.authorization.jackson2; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + +/** + * This mixin class is used to serialize/deserialize {@link TestingAuthenticationToken}. + * + * @author Steve Riesenberg + * @since 0.1.2 + * @see TestingAuthenticationToken + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE) +@JsonIgnoreProperties(value = { "authenticated" }, ignoreUnknown = true) +public class TestingAuthenticationTokenMixin { + + @JsonCreator + TestingAuthenticationTokenMixin(@JsonProperty("principal") Object principal, + @JsonProperty("credentials") Object credentials, + @JsonProperty("authorities") List authorities) { + } + +}