|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright 2020-2021 the original author or authors.
|
|
|
|
|
|
+ * Copyright 2020-2022 the original author or authors.
|
|
*
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -15,10 +15,16 @@
|
|
*/
|
|
*/
|
|
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
|
|
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
|
|
|
|
|
|
|
|
+import java.net.URLEncoder;
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
import java.time.Duration;
|
|
import java.time.Duration;
|
|
import java.time.Instant;
|
|
import java.time.Instant;
|
|
|
|
+import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
|
+import java.util.Base64;
|
|
|
|
+import java.util.Collections;
|
|
import java.util.HashSet;
|
|
import java.util.HashSet;
|
|
|
|
+import java.util.List;
|
|
|
|
|
|
import com.nimbusds.jose.jwk.JWKSet;
|
|
import com.nimbusds.jose.jwk.JWKSet;
|
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
|
@@ -28,10 +34,12 @@ import org.junit.AfterClass;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.Rule;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.Test;
|
|
|
|
+import org.mockito.ArgumentCaptor;
|
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Import;
|
|
import org.springframework.context.annotation.Import;
|
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.http.converter.HttpMessageConverter;
|
|
import org.springframework.http.converter.HttpMessageConverter;
|
|
import org.springframework.jdbc.core.JdbcOperations;
|
|
import org.springframework.jdbc.core.JdbcOperations;
|
|
@@ -48,18 +56,26 @@ import org.springframework.security.config.test.SpringTestRule;
|
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
|
|
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
|
|
|
|
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
|
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
|
|
|
+import org.springframework.security.oauth2.core.OAuth2AuthorizationCode;
|
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
|
|
|
+import org.springframework.security.oauth2.core.OAuth2TokenClaimsSet;
|
|
|
|
+import org.springframework.security.oauth2.core.OAuth2TokenFormat;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenIntrospection;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenIntrospection;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
|
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.endpoint.OAuth2ParameterNames;
|
|
|
|
+import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
|
import org.springframework.security.oauth2.core.http.converter.OAuth2TokenIntrospectionHttpMessageConverter;
|
|
import org.springframework.security.oauth2.core.http.converter.OAuth2TokenIntrospectionHttpMessageConverter;
|
|
import org.springframework.security.oauth2.jose.TestJwks;
|
|
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.JdbcOAuth2AuthorizationConsentService;
|
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
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.OAuth2AuthorizationService;
|
|
|
|
+import org.springframework.security.oauth2.server.authorization.OAuth2TokenClaimsContext;
|
|
|
|
+import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
|
|
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
|
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
|
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
|
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
|
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository.RegisteredClientParametersMapper;
|
|
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository.RegisteredClientParametersMapper;
|
|
@@ -67,6 +83,7 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
|
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
|
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.client.TestRegisteredClients;
|
|
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
|
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
|
|
|
+import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
|
import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin;
|
|
import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
import org.springframework.test.web.servlet.MvcResult;
|
|
import org.springframework.test.web.servlet.MvcResult;
|
|
@@ -74,7 +91,8 @@ import org.springframework.util.LinkedMultiValueMap;
|
|
import org.springframework.util.MultiValueMap;
|
|
import org.springframework.util.MultiValueMap;
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
|
|
|
|
|
|
+import static org.mockito.Mockito.mock;
|
|
|
|
+import static org.mockito.Mockito.verify;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
|
|
|
|
@@ -88,8 +106,11 @@ public class OAuth2TokenIntrospectionTests {
|
|
private static EmbeddedDatabase db;
|
|
private static EmbeddedDatabase db;
|
|
private static JWKSource<SecurityContext> jwkSource;
|
|
private static JWKSource<SecurityContext> jwkSource;
|
|
private static ProviderSettings providerSettings;
|
|
private static ProviderSettings providerSettings;
|
|
- private final HttpMessageConverter<OAuth2TokenIntrospection> tokenIntrospectionHttpResponseConverter =
|
|
|
|
|
|
+ private static OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer;
|
|
|
|
+ private static final HttpMessageConverter<OAuth2TokenIntrospection> tokenIntrospectionHttpResponseConverter =
|
|
new OAuth2TokenIntrospectionHttpMessageConverter();
|
|
new OAuth2TokenIntrospectionHttpMessageConverter();
|
|
|
|
+ private static final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
|
|
|
+ new OAuth2AccessTokenResponseHttpMessageConverter();
|
|
|
|
|
|
@Rule
|
|
@Rule
|
|
public final SpringTestRule spring = new SpringTestRule();
|
|
public final SpringTestRule spring = new SpringTestRule();
|
|
@@ -111,6 +132,7 @@ public class OAuth2TokenIntrospectionTests {
|
|
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
|
|
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
|
|
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
|
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
|
providerSettings = ProviderSettings.builder().tokenIntrospectionEndpoint("/test/introspect").build();
|
|
providerSettings = ProviderSettings.builder().tokenIntrospectionEndpoint("/test/introspect").build();
|
|
|
|
+ accessTokenCustomizer = mock(OAuth2TokenCustomizer.class);
|
|
db = new EmbeddedDatabaseBuilder()
|
|
db = new EmbeddedDatabaseBuilder()
|
|
.generateUniqueName(true)
|
|
.generateUniqueName(true)
|
|
.setType(EmbeddedDatabaseType.HSQL)
|
|
.setType(EmbeddedDatabaseType.HSQL)
|
|
@@ -145,9 +167,19 @@ public class OAuth2TokenIntrospectionTests {
|
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
|
OAuth2AccessToken.TokenType.BEARER, "access-token", issuedAt, expiresAt,
|
|
OAuth2AccessToken.TokenType.BEARER, "access-token", issuedAt, expiresAt,
|
|
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
|
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
|
- JwtClaimsSet tokenClaims = TestJwtClaimsSets.jwtClaimsSet().build();
|
|
|
|
|
|
+ // @formatter:off
|
|
|
|
+ OAuth2TokenClaimsSet accessTokenClaims = OAuth2TokenClaimsSet.builder()
|
|
|
|
+ .issuer("https://provider.com")
|
|
|
|
+ .subject("subject")
|
|
|
|
+ .audience(Collections.singletonList(authorizedRegisteredClient.getClientId()))
|
|
|
|
+ .issuedAt(issuedAt)
|
|
|
|
+ .notBefore(issuedAt)
|
|
|
|
+ .expiresAt(expiresAt)
|
|
|
|
+ .id("id")
|
|
|
|
+ .build();
|
|
|
|
+ // @formatter:on
|
|
OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
OAuth2Authorization authorization = TestOAuth2Authorizations
|
|
- .authorization(authorizedRegisteredClient, accessToken, tokenClaims.getClaims())
|
|
|
|
|
|
+ .authorization(authorizedRegisteredClient, accessToken, accessTokenClaims.getClaims())
|
|
.build();
|
|
.build();
|
|
this.registeredClientRepository.save(authorizedRegisteredClient);
|
|
this.registeredClientRepository.save(authorizedRegisteredClient);
|
|
this.authorizationService.save(authorization);
|
|
this.authorizationService.save(authorization);
|
|
@@ -155,7 +187,7 @@ public class OAuth2TokenIntrospectionTests {
|
|
// @formatter:off
|
|
// @formatter:off
|
|
MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
|
|
MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
|
|
.params(getTokenIntrospectionRequestParameters(accessToken, OAuth2TokenType.ACCESS_TOKEN))
|
|
.params(getTokenIntrospectionRequestParameters(accessToken, OAuth2TokenType.ACCESS_TOKEN))
|
|
- .with(httpBasic(introspectRegisteredClient.getClientId(), introspectRegisteredClient.getClientSecret())))
|
|
|
|
|
|
+ .header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(introspectRegisteredClient)))
|
|
.andExpect(status().isOk())
|
|
.andExpect(status().isOk())
|
|
.andReturn();
|
|
.andReturn();
|
|
// @formatter:on
|
|
// @formatter:on
|
|
@@ -165,17 +197,17 @@ public class OAuth2TokenIntrospectionTests {
|
|
assertThat(tokenIntrospectionResponse.getClientId()).isEqualTo(authorizedRegisteredClient.getClientId());
|
|
assertThat(tokenIntrospectionResponse.getClientId()).isEqualTo(authorizedRegisteredClient.getClientId());
|
|
assertThat(tokenIntrospectionResponse.getUsername()).isNull();
|
|
assertThat(tokenIntrospectionResponse.getUsername()).isNull();
|
|
assertThat(tokenIntrospectionResponse.getIssuedAt()).isBetween(
|
|
assertThat(tokenIntrospectionResponse.getIssuedAt()).isBetween(
|
|
- accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
|
|
|
|
|
+ accessTokenClaims.getIssuedAt().minusSeconds(1), accessTokenClaims.getIssuedAt().plusSeconds(1));
|
|
assertThat(tokenIntrospectionResponse.getExpiresAt()).isBetween(
|
|
assertThat(tokenIntrospectionResponse.getExpiresAt()).isBetween(
|
|
- accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
|
|
|
|
|
+ accessTokenClaims.getExpiresAt().minusSeconds(1), accessTokenClaims.getExpiresAt().plusSeconds(1));
|
|
assertThat(tokenIntrospectionResponse.getScopes()).containsExactlyInAnyOrderElementsOf(accessToken.getScopes());
|
|
assertThat(tokenIntrospectionResponse.getScopes()).containsExactlyInAnyOrderElementsOf(accessToken.getScopes());
|
|
assertThat(tokenIntrospectionResponse.getTokenType()).isEqualTo(accessToken.getTokenType().getValue());
|
|
assertThat(tokenIntrospectionResponse.getTokenType()).isEqualTo(accessToken.getTokenType().getValue());
|
|
assertThat(tokenIntrospectionResponse.getNotBefore()).isBetween(
|
|
assertThat(tokenIntrospectionResponse.getNotBefore()).isBetween(
|
|
- tokenClaims.getNotBefore().minusSeconds(1), tokenClaims.getNotBefore().plusSeconds(1));
|
|
|
|
- assertThat(tokenIntrospectionResponse.getSubject()).isEqualTo(tokenClaims.getSubject());
|
|
|
|
- assertThat(tokenIntrospectionResponse.getAudience()).containsExactlyInAnyOrderElementsOf(tokenClaims.getAudience());
|
|
|
|
- assertThat(tokenIntrospectionResponse.getIssuer()).isEqualTo(tokenClaims.getIssuer());
|
|
|
|
- assertThat(tokenIntrospectionResponse.getId()).isEqualTo(tokenClaims.getId());
|
|
|
|
|
|
+ accessTokenClaims.getNotBefore().minusSeconds(1), accessTokenClaims.getNotBefore().plusSeconds(1));
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getSubject()).isEqualTo(accessTokenClaims.getSubject());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getAudience()).containsExactlyInAnyOrderElementsOf(accessTokenClaims.getAudience());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getIssuer()).isEqualTo(accessTokenClaims.getIssuer());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getId()).isEqualTo(accessTokenClaims.getId());
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
@@ -195,7 +227,7 @@ public class OAuth2TokenIntrospectionTests {
|
|
// @formatter:off
|
|
// @formatter:off
|
|
MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
|
|
MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
|
|
.params(getTokenIntrospectionRequestParameters(refreshToken, OAuth2TokenType.REFRESH_TOKEN))
|
|
.params(getTokenIntrospectionRequestParameters(refreshToken, OAuth2TokenType.REFRESH_TOKEN))
|
|
- .with(httpBasic(introspectRegisteredClient.getClientId(), introspectRegisteredClient.getClientSecret())))
|
|
|
|
|
|
+ .header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(introspectRegisteredClient)))
|
|
.andExpect(status().isOk())
|
|
.andExpect(status().isOk())
|
|
.andReturn();
|
|
.andReturn();
|
|
// @formatter:on
|
|
// @formatter:on
|
|
@@ -217,6 +249,71 @@ public class OAuth2TokenIntrospectionTests {
|
|
assertThat(tokenIntrospectionResponse.getId()).isNull();
|
|
assertThat(tokenIntrospectionResponse.getId()).isNull();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void requestWhenObtainReferenceAccessTokenAndIntrospectThenActive() throws Exception {
|
|
|
|
+ this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
|
|
|
+
|
|
|
|
+ // @formatter:off
|
|
|
|
+ TokenSettings tokenSettings = TokenSettings.builder()
|
|
|
|
+ .accessTokenFormat(OAuth2TokenFormat.REFERENCE)
|
|
|
|
+ .build();
|
|
|
|
+ RegisteredClient authorizedRegisteredClient = TestRegisteredClients.registeredClient()
|
|
|
|
+ .tokenSettings(tokenSettings)
|
|
|
|
+ .build();
|
|
|
|
+ // @formatter:on
|
|
|
|
+ this.registeredClientRepository.save(authorizedRegisteredClient);
|
|
|
|
+
|
|
|
|
+ OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(authorizedRegisteredClient).build();
|
|
|
|
+ this.authorizationService.save(authorization);
|
|
|
|
+
|
|
|
|
+ // @formatter:off
|
|
|
|
+ MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenEndpoint())
|
|
|
|
+ .params(getAuthorizationCodeTokenRequestParameters(authorizedRegisteredClient, authorization))
|
|
|
|
+ .header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(authorizedRegisteredClient)))
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
+ .andReturn();
|
|
|
|
+ // @formatter:on
|
|
|
|
+
|
|
|
|
+ OAuth2AccessTokenResponse accessTokenResponse = readAccessTokenResponse(mvcResult);
|
|
|
|
+ OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
|
|
|
|
+
|
|
|
|
+ RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2().build();
|
|
|
|
+ this.registeredClientRepository.save(introspectRegisteredClient);
|
|
|
|
+
|
|
|
|
+ // @formatter:off
|
|
|
|
+ mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
|
|
|
|
+ .params(getTokenIntrospectionRequestParameters(accessToken, OAuth2TokenType.ACCESS_TOKEN))
|
|
|
|
+ .header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(introspectRegisteredClient)))
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
+ .andReturn();
|
|
|
|
+ // @formatter:on
|
|
|
|
+
|
|
|
|
+ OAuth2TokenIntrospection tokenIntrospectionResponse = readTokenIntrospectionResponse(mvcResult);
|
|
|
|
+
|
|
|
|
+ ArgumentCaptor<OAuth2TokenClaimsContext> accessTokenClaimsContextCaptor = ArgumentCaptor.forClass(OAuth2TokenClaimsContext.class);
|
|
|
|
+ verify(accessTokenCustomizer).customize(accessTokenClaimsContextCaptor.capture());
|
|
|
|
+
|
|
|
|
+ OAuth2TokenClaimsContext accessTokenClaimsContext = accessTokenClaimsContextCaptor.getValue();
|
|
|
|
+ OAuth2TokenClaimsSet accessTokenClaims = accessTokenClaimsContext.getClaims().build();
|
|
|
|
+
|
|
|
|
+ assertThat(tokenIntrospectionResponse.isActive()).isTrue();
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getClientId()).isEqualTo(authorizedRegisteredClient.getClientId());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getUsername()).isNull();
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getIssuedAt()).isBetween(
|
|
|
|
+ accessTokenClaims.getIssuedAt().minusSeconds(1), accessTokenClaims.getIssuedAt().plusSeconds(1));
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getExpiresAt()).isBetween(
|
|
|
|
+ accessTokenClaims.getExpiresAt().minusSeconds(1), accessTokenClaims.getExpiresAt().plusSeconds(1));
|
|
|
|
+ List<String> scopes = new ArrayList<>(accessTokenClaims.getClaim(OAuth2ParameterNames.SCOPE));
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getScopes()).containsExactlyInAnyOrderElementsOf(scopes);
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getTokenType()).isEqualTo(accessToken.getTokenType().getValue());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getNotBefore()).isBetween(
|
|
|
|
+ accessTokenClaims.getNotBefore().minusSeconds(1), accessTokenClaims.getNotBefore().plusSeconds(1));
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getSubject()).isEqualTo(accessTokenClaims.getSubject());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getAudience()).containsExactlyInAnyOrderElementsOf(accessTokenClaims.getAudience());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getIssuer()).isEqualTo(accessTokenClaims.getIssuer());
|
|
|
|
+ assertThat(tokenIntrospectionResponse.getId()).isEqualTo(accessTokenClaims.getId());
|
|
|
|
+ }
|
|
|
|
+
|
|
private static MultiValueMap<String, String> getTokenIntrospectionRequestParameters(AbstractOAuth2Token token,
|
|
private static MultiValueMap<String, String> getTokenIntrospectionRequestParameters(AbstractOAuth2Token token,
|
|
OAuth2TokenType tokenType) {
|
|
OAuth2TokenType tokenType) {
|
|
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
|
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
|
@@ -225,11 +322,37 @@ public class OAuth2TokenIntrospectionTests {
|
|
return parameters;
|
|
return parameters;
|
|
}
|
|
}
|
|
|
|
|
|
- private OAuth2TokenIntrospection readTokenIntrospectionResponse(MvcResult mvcResult) throws Exception {
|
|
|
|
|
|
+ private static OAuth2TokenIntrospection readTokenIntrospectionResponse(MvcResult mvcResult) throws Exception {
|
|
|
|
+ MockHttpServletResponse servletResponse = mvcResult.getResponse();
|
|
|
|
+ MockClientHttpResponse httpResponse = new MockClientHttpResponse(
|
|
|
|
+ servletResponse.getContentAsByteArray(), HttpStatus.valueOf(servletResponse.getStatus()));
|
|
|
|
+ return tokenIntrospectionHttpResponseConverter.read(OAuth2TokenIntrospection.class, httpResponse);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static MultiValueMap<String, String> getAuthorizationCodeTokenRequestParameters(RegisteredClient registeredClient,
|
|
|
|
+ OAuth2Authorization authorization) {
|
|
|
|
+ MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
|
|
|
+ parameters.set(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
|
|
|
+ parameters.set(OAuth2ParameterNames.CODE, authorization.getToken(OAuth2AuthorizationCode.class).getToken().getTokenValue());
|
|
|
|
+ parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
|
|
|
|
+ return parameters;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static OAuth2AccessTokenResponse readAccessTokenResponse(MvcResult mvcResult) throws Exception {
|
|
MockHttpServletResponse servletResponse = mvcResult.getResponse();
|
|
MockHttpServletResponse servletResponse = mvcResult.getResponse();
|
|
MockClientHttpResponse httpResponse = new MockClientHttpResponse(
|
|
MockClientHttpResponse httpResponse = new MockClientHttpResponse(
|
|
servletResponse.getContentAsByteArray(), HttpStatus.valueOf(servletResponse.getStatus()));
|
|
servletResponse.getContentAsByteArray(), HttpStatus.valueOf(servletResponse.getStatus()));
|
|
- return this.tokenIntrospectionHttpResponseConverter.read(OAuth2TokenIntrospection.class, httpResponse);
|
|
|
|
|
|
+ return accessTokenHttpResponseConverter.read(OAuth2AccessTokenResponse.class, httpResponse);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static String getAuthorizationHeader(RegisteredClient registeredClient) throws Exception {
|
|
|
|
+ String clientId = registeredClient.getClientId();
|
|
|
|
+ String clientSecret = registeredClient.getClientSecret();
|
|
|
|
+ clientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8.name());
|
|
|
|
+ clientSecret = URLEncoder.encode(clientSecret, StandardCharsets.UTF_8.name());
|
|
|
|
+ String credentialsString = clientId + ":" + clientSecret;
|
|
|
|
+ byte[] encodedBytes = Base64.getEncoder().encode(credentialsString.getBytes(StandardCharsets.UTF_8));
|
|
|
|
+ return "Basic " + new String(encodedBytes, StandardCharsets.UTF_8);
|
|
}
|
|
}
|
|
|
|
|
|
@EnableWebSecurity
|
|
@EnableWebSecurity
|
|
@@ -244,6 +367,11 @@ public class OAuth2TokenIntrospectionTests {
|
|
return authorizationService;
|
|
return authorizationService;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Bean
|
|
|
|
+ OAuth2AuthorizationConsentService authorizationConsentService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) {
|
|
|
|
+ return new JdbcOAuth2AuthorizationConsentService(jdbcOperations, registeredClientRepository);
|
|
|
|
+ }
|
|
|
|
+
|
|
@Bean
|
|
@Bean
|
|
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations, PasswordEncoder passwordEncoder) {
|
|
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations, PasswordEncoder passwordEncoder) {
|
|
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(jdbcOperations);
|
|
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(jdbcOperations);
|
|
@@ -259,13 +387,13 @@ public class OAuth2TokenIntrospectionTests {
|
|
}
|
|
}
|
|
|
|
|
|
@Bean
|
|
@Bean
|
|
- JWKSource<SecurityContext> jwkSource() {
|
|
|
|
- return jwkSource;
|
|
|
|
|
|
+ ProviderSettings providerSettings() {
|
|
|
|
+ return providerSettings;
|
|
}
|
|
}
|
|
|
|
|
|
@Bean
|
|
@Bean
|
|
- ProviderSettings providerSettings() {
|
|
|
|
- return providerSettings;
|
|
|
|
|
|
+ OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer() {
|
|
|
|
+ return accessTokenCustomizer;
|
|
}
|
|
}
|
|
|
|
|
|
@Bean
|
|
@Bean
|