Apply Spring formatting to 1.3.x
Issue gh-1616
This commit is contained in:
@@ -48,23 +48,23 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
@Test
|
||||
public void buildWhenAllClaimsProvidedThenCreated() {
|
||||
OAuth2AuthorizationServerMetadata authorizationServerMetadata = OAuth2AuthorizationServerMetadata.builder()
|
||||
.issuer("https://example.com")
|
||||
.authorizationEndpoint("https://example.com/oauth2/authorize")
|
||||
.tokenEndpoint("https://example.com/oauth2/token")
|
||||
.tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
|
||||
.jwkSetUrl("https://example.com/oauth2/jwks")
|
||||
.scope("openid")
|
||||
.responseType("code")
|
||||
.grantType("authorization_code")
|
||||
.grantType("client_credentials")
|
||||
.tokenRevocationEndpoint("https://example.com/oauth2/revoke")
|
||||
.tokenRevocationEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
|
||||
.tokenIntrospectionEndpoint("https://example.com/oauth2/introspect")
|
||||
.tokenIntrospectionEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
|
||||
.codeChallengeMethod("S256")
|
||||
.tlsClientCertificateBoundAccessTokens(true)
|
||||
.claim("a-claim", "a-value")
|
||||
.build();
|
||||
.issuer("https://example.com")
|
||||
.authorizationEndpoint("https://example.com/oauth2/authorize")
|
||||
.tokenEndpoint("https://example.com/oauth2/token")
|
||||
.tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
|
||||
.jwkSetUrl("https://example.com/oauth2/jwks")
|
||||
.scope("openid")
|
||||
.responseType("code")
|
||||
.grantType("authorization_code")
|
||||
.grantType("client_credentials")
|
||||
.tokenRevocationEndpoint("https://example.com/oauth2/revoke")
|
||||
.tokenRevocationEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
|
||||
.tokenIntrospectionEndpoint("https://example.com/oauth2/introspect")
|
||||
.tokenIntrospectionEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
|
||||
.codeChallengeMethod("S256")
|
||||
.tlsClientCertificateBoundAccessTokens(true)
|
||||
.claim("a-claim", "a-value")
|
||||
.build();
|
||||
|
||||
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(url("https://example.com"));
|
||||
assertThat(authorizationServerMetadata.getAuthorizationEndpoint())
|
||||
|
||||
@@ -92,8 +92,8 @@ public class TestOAuth2Authorizations {
|
||||
.attribute(Principal.class.getName(),
|
||||
new TestingAuthenticationToken("principal", null, "ROLE_A", "ROLE_B"));
|
||||
if (accessToken != null) {
|
||||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(
|
||||
"refresh-token", Instant.now(), Instant.now().plus(1, ChronoUnit.HOURS));
|
||||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", Instant.now(),
|
||||
Instant.now().plus(1, ChronoUnit.HOURS));
|
||||
builder
|
||||
.token(accessToken, (metadata) -> metadata.putAll(tokenMetadata(registeredClient, accessTokenClaims)))
|
||||
.refreshToken(refreshToken);
|
||||
@@ -102,7 +102,8 @@ public class TestOAuth2Authorizations {
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static Map<String, Object> tokenMetadata(RegisteredClient registeredClient, Map<String, Object> tokenClaims) {
|
||||
private static Map<String, Object> tokenMetadata(RegisteredClient registeredClient,
|
||||
Map<String, Object> tokenClaims) {
|
||||
Map<String, Object> tokenMetadata = new HashMap<>();
|
||||
OAuth2TokenFormat accessTokenFormat = registeredClient.getTokenSettings().getAccessTokenFormat();
|
||||
tokenMetadata.put(OAuth2TokenFormat.class.getName(), accessTokenFormat.getValue());
|
||||
|
||||
@@ -34,39 +34,43 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
* @author Dmitriy Dubson
|
||||
*/
|
||||
public class OAuth2AccessTokenAuthenticationContextTests {
|
||||
|
||||
private final RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
private final OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(this.registeredClient).build();
|
||||
private OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, this.registeredClient.getClientSecret());
|
||||
private final OAuth2AccessTokenAuthenticationToken accessTokenAuthenticationToken =
|
||||
new OAuth2AccessTokenAuthenticationToken(this.registeredClient, this.clientPrincipal,
|
||||
this.authorization.getAccessToken().getToken(), this.authorization.getRefreshToken().getToken());
|
||||
|
||||
private final OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(this.registeredClient)
|
||||
.build();
|
||||
|
||||
private OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, this.registeredClient.getClientSecret());
|
||||
|
||||
private final OAuth2AccessTokenAuthenticationToken accessTokenAuthenticationToken = new OAuth2AccessTokenAuthenticationToken(
|
||||
this.registeredClient, this.clientPrincipal, this.authorization.getAccessToken().getToken(),
|
||||
this.authorization.getRefreshToken().getToken());
|
||||
|
||||
@Test
|
||||
public void withWhenAuthenticationNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> OAuth2AccessTokenAuthenticationContext.with(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authentication cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authentication cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setWhenValueNullThenThrowIllegalArgumentException() {
|
||||
OAuth2AccessTokenAuthenticationContext.Builder builder =
|
||||
OAuth2AccessTokenAuthenticationContext.with(this.accessTokenAuthenticationToken);
|
||||
OAuth2AccessTokenAuthenticationContext.Builder builder = OAuth2AccessTokenAuthenticationContext
|
||||
.with(this.accessTokenAuthenticationToken);
|
||||
|
||||
assertThatThrownBy(() -> builder.accessTokenResponse(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("value cannot be null");
|
||||
assertThatThrownBy(() -> builder.accessTokenResponse(null)).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("value cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAllValuesProvidedThenAllValuesAreSet() {
|
||||
OAuth2AccessTokenResponse.Builder accessTokenResponseBuilder =
|
||||
OAuth2AccessTokenResponse.withToken(this.accessTokenAuthenticationToken.getAccessToken().getTokenValue());
|
||||
OAuth2AccessTokenAuthenticationContext context =
|
||||
OAuth2AccessTokenAuthenticationContext.with(this.accessTokenAuthenticationToken)
|
||||
.accessTokenResponse(accessTokenResponseBuilder)
|
||||
.build();
|
||||
OAuth2AccessTokenResponse.Builder accessTokenResponseBuilder = OAuth2AccessTokenResponse
|
||||
.withToken(this.accessTokenAuthenticationToken.getAccessToken().getTokenValue());
|
||||
OAuth2AccessTokenAuthenticationContext context = OAuth2AccessTokenAuthenticationContext
|
||||
.with(this.accessTokenAuthenticationToken)
|
||||
.accessTokenResponse(accessTokenResponseBuilder)
|
||||
.build();
|
||||
|
||||
assertThat(context.<Authentication>getAuthentication()).isEqualTo(this.accessTokenAuthenticationToken);
|
||||
assertThat(context.getAccessTokenResponse()).isEqualTo(accessTokenResponseBuilder);
|
||||
|
||||
@@ -146,8 +146,8 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
|
||||
@Test
|
||||
public void setAuthorizationConsentRequiredWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.authenticationProvider.setAuthorizationConsentRequired(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authorizationConsentRequired cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authorizationConsentRequired cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -486,23 +486,24 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthorizationConsentRequiredThenUsed() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Predicate<OAuth2AuthorizationCodeRequestAuthenticationContext> authorizationConsentRequired = mock(Predicate.class);
|
||||
Predicate<OAuth2AuthorizationCodeRequestAuthenticationContext> authorizationConsentRequired = mock(
|
||||
Predicate.class);
|
||||
this.authenticationProvider.setAuthorizationConsentRequired(authorizationConsentRequired);
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
String redirectUri = registeredClient.getRedirectUris().toArray(new String[0])[1];
|
||||
OAuth2AuthorizationCodeRequestAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeRequestAuthenticationToken(
|
||||
AUTHORIZATION_URI, registeredClient.getClientId(), principal,
|
||||
redirectUri, STATE, registeredClient.getScopes(), null);
|
||||
OAuth2AuthorizationCodeRequestAuthenticationToken authentication = new OAuth2AuthorizationCodeRequestAuthenticationToken(
|
||||
AUTHORIZATION_URI, registeredClient.getClientId(), principal, redirectUri, STATE,
|
||||
registeredClient.getScopes(), null);
|
||||
|
||||
OAuth2AuthorizationCodeRequestAuthenticationToken authenticationResult =
|
||||
(OAuth2AuthorizationCodeRequestAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2AuthorizationCodeRequestAuthenticationToken authenticationResult = (OAuth2AuthorizationCodeRequestAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
|
||||
assertAuthorizationCodeRequestWithAuthorizationCodeResult(registeredClient, authentication, authenticationResult);
|
||||
assertAuthorizationCodeRequestWithAuthorizationCodeResult(registeredClient, authentication,
|
||||
authenticationResult);
|
||||
|
||||
verify(authorizationConsentRequired).test(any());
|
||||
}
|
||||
|
||||
@@ -145,8 +145,8 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
|
||||
@Test
|
||||
public void setAuthenticationValidatorWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.authenticationProvider.setAuthenticationValidator(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authenticationValidator cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authenticationValidator cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -325,10 +325,10 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthenticationValidatorThenUsed() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2ClientCredentialsAuthenticationToken authentication =
|
||||
new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, registeredClient.getScopes(), null);
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2ClientCredentialsAuthenticationToken authentication = new OAuth2ClientCredentialsAuthenticationToken(
|
||||
clientPrincipal, registeredClient.getScopes(), null);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<OAuth2ClientCredentialsAuthenticationContext> authenticationValidator = mock(Consumer.class);
|
||||
|
||||
@@ -70,15 +70,24 @@ import static org.mockito.Mockito.when;
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
private static final Set<String> RESOURCES = Set.of("https://mydomain.com/resource1", "https://mydomain.com/resource2");
|
||||
|
||||
private static final Set<String> RESOURCES = Set.of("https://mydomain.com/resource1",
|
||||
"https://mydomain.com/resource2");
|
||||
|
||||
private static final Set<String> AUDIENCES = Set.of("audience1", "audience2");
|
||||
|
||||
private static final String SUBJECT_TOKEN = "EfYu_0jEL";
|
||||
|
||||
private static final String ACTOR_TOKEN = "JlNE_xR1f";
|
||||
|
||||
private static final String ACCESS_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:access_token";
|
||||
|
||||
private static final String JWT_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:jwt";
|
||||
|
||||
private OAuth2AuthorizationService authorizationService;
|
||||
|
||||
private OAuth2TokenGenerator<OAuth2Token> tokenGenerator;
|
||||
|
||||
private OAuth2TokenExchangeAuthenticationProvider authenticationProvider;
|
||||
|
||||
@BeforeEach
|
||||
@@ -168,7 +177,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenSubjectTokenNotFoundThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(null);
|
||||
// @formatter:off
|
||||
@@ -187,10 +197,12 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenSubjectTokenNotActiveThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createExpiredAccessToken(SUBJECT_TOKEN)).build();
|
||||
.token(createExpiredAccessToken(SUBJECT_TOKEN))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(authorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
@@ -208,10 +220,12 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenSubjectTokenTypeJwtAndSubjectTokenFormatReferenceThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createJwtRequest(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN), withTokenFormat(OAuth2TokenFormat.REFERENCE)).build();
|
||||
.token(createAccessToken(SUBJECT_TOKEN), withTokenFormat(OAuth2TokenFormat.REFERENCE))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(authorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
@@ -229,7 +243,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenSubjectPrincipalNullThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
// @formatter:off
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
@@ -254,12 +269,14 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenActorTokenNotFoundThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, (OAuth2Authorization) null);
|
||||
.token(createAccessToken(SUBJECT_TOKEN))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, (OAuth2Authorization) null);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -277,14 +294,17 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenActorTokenNotActiveThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN)).build();
|
||||
.token(createAccessToken(SUBJECT_TOKEN))
|
||||
.build();
|
||||
OAuth2Authorization actorAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createExpiredAccessToken(ACTOR_TOKEN)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
.token(createExpiredAccessToken(ACTOR_TOKEN))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -302,14 +322,17 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenActorTokenTypeJwtAndActorTokenFormatReferenceThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createJwtRequest(registeredClient);
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN), withTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)).build();
|
||||
.token(createAccessToken(SUBJECT_TOKEN), withTokenFormat(OAuth2TokenFormat.SELF_CONTAINED))
|
||||
.build();
|
||||
OAuth2Authorization actorAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(ACTOR_TOKEN), withTokenFormat(OAuth2TokenFormat.REFERENCE)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
.token(createAccessToken(ACTOR_TOKEN), withTokenFormat(OAuth2TokenFormat.REFERENCE))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -327,7 +350,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenMayActAndActorIssClaimNotAuthorizedThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
Map<String, String> authorizedActorClaims = Map.of(OAuth2TokenClaimNames.ISS, "issuer",
|
||||
OAuth2TokenClaimNames.SUB, "actor");
|
||||
@@ -339,9 +363,10 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
Map<String, Object> actorTokenClaims = Map.of(OAuth2TokenClaimNames.ISS, "invalid-issuer",
|
||||
OAuth2TokenClaimNames.SUB, "actor");
|
||||
OAuth2Authorization actorAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(ACTOR_TOKEN), withClaims(actorTokenClaims)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
.token(createAccessToken(ACTOR_TOKEN), withClaims(actorTokenClaims))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -359,7 +384,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenMayActAndActorSubClaimNotAuthorizedThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
Map<String, String> authorizedActorClaims = Map.of(OAuth2TokenClaimNames.ISS, "issuer",
|
||||
OAuth2TokenClaimNames.SUB, "actor");
|
||||
@@ -371,9 +397,10 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
Map<String, Object> actorTokenClaims = Map.of(OAuth2TokenClaimNames.ISS, "issuer", OAuth2TokenClaimNames.SUB,
|
||||
"invalid-actor");
|
||||
OAuth2Authorization actorAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(ACTOR_TOKEN), withClaims(actorTokenClaims)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
.token(createAccessToken(ACTOR_TOKEN), withClaims(actorTokenClaims))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -391,7 +418,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenMayActAndImpersonationThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createImpersonationRequest(registeredClient);
|
||||
Map<String, String> authorizedActorClaims = Map.of(OAuth2TokenClaimNames.ISS, "issuer",
|
||||
OAuth2TokenClaimNames.SUB, "actor");
|
||||
@@ -400,8 +428,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
.token(createAccessToken(SUBJECT_TOKEN), withClaims(Map.of("may_act", authorizedActorClaims)))
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization);
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -418,15 +446,18 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenInvalidScopeInRequestThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient,
|
||||
Set.of("invalid"));
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN)).build();
|
||||
.token(createAccessToken(SUBJECT_TOKEN))
|
||||
.build();
|
||||
OAuth2Authorization actorAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(ACTOR_TOKEN)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
.token(createAccessToken(ACTOR_TOKEN))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -444,14 +475,18 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenInvalidScopeInSubjectAuthorizationThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient, Set.of());
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN)).authorizedScopes(Set.of("invalid")).build();
|
||||
.token(createAccessToken(SUBJECT_TOKEN))
|
||||
.authorizedScopes(Set.of("invalid"))
|
||||
.build();
|
||||
OAuth2Authorization actorAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(ACTOR_TOKEN)).build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
.token(createAccessToken(ACTOR_TOKEN))
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
@@ -469,7 +504,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenNoActorTokenAndValidTokenExchangeThenReturnAccessTokenForImpersonation() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createImpersonationRequest(registeredClient);
|
||||
TestingAuthenticationToken userPrincipal = new TestingAuthenticationToken("user", null, "ROLE_USER");
|
||||
// @formatter:off
|
||||
@@ -478,19 +514,19 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
.attribute(Principal.class.getName(), userPrincipal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization);
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization);
|
||||
OAuth2AccessToken accessToken = createAccessToken("token-value");
|
||||
when(this.tokenGenerator.generate(any(OAuth2TokenContext.class))).thenReturn(accessToken);
|
||||
OAuth2AccessTokenAuthenticationToken authenticationResult =
|
||||
(OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2AccessTokenAuthenticationToken authenticationResult = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
assertThat(authenticationResult.getPrincipal()).isEqualTo(authentication.getPrincipal());
|
||||
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
|
||||
assertThat(authenticationResult.getRefreshToken()).isNull();
|
||||
assertThat(authenticationResult.getAdditionalParameters()).hasSize(1);
|
||||
assertThat(authenticationResult.getAdditionalParameters().get(OAuth2ParameterNames.ISSUED_TOKEN_TYPE))
|
||||
.isEqualTo(JWT_TOKEN_TYPE_VALUE);
|
||||
.isEqualTo(JWT_TOKEN_TYPE_VALUE);
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
ArgumentCaptor<OAuth2TokenContext> tokenContextCaptor = ArgumentCaptor.forClass(OAuth2TokenContext.class);
|
||||
@@ -521,32 +557,33 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenNoActorTokenAndPreviousActorThenReturnAccessTokenForImpersonation() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createImpersonationRequest(registeredClient);
|
||||
TestingAuthenticationToken userPrincipal = new TestingAuthenticationToken("user", null, "ROLE_USER");
|
||||
OAuth2TokenExchangeActor previousActor = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS, "issuer1",
|
||||
OAuth2TokenClaimNames.SUB, "actor"));
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken subjectPrincipal =
|
||||
new OAuth2TokenExchangeCompositeAuthenticationToken(userPrincipal, List.of(previousActor));
|
||||
OAuth2TokenExchangeActor previousActor = new OAuth2TokenExchangeActor(
|
||||
Map.of(OAuth2TokenClaimNames.ISS, "issuer1", OAuth2TokenClaimNames.SUB, "actor"));
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken subjectPrincipal = new OAuth2TokenExchangeCompositeAuthenticationToken(
|
||||
userPrincipal, List.of(previousActor));
|
||||
// @formatter:off
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN))
|
||||
.attribute(Principal.class.getName(), subjectPrincipal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization);
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization);
|
||||
OAuth2AccessToken accessToken = createAccessToken("token-value");
|
||||
when(this.tokenGenerator.generate(any(OAuth2TokenContext.class))).thenReturn(accessToken);
|
||||
OAuth2AccessTokenAuthenticationToken authenticationResult =
|
||||
(OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2AccessTokenAuthenticationToken authenticationResult = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
assertThat(authenticationResult.getPrincipal()).isEqualTo(authentication.getPrincipal());
|
||||
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
|
||||
assertThat(authenticationResult.getRefreshToken()).isNull();
|
||||
assertThat(authenticationResult.getAdditionalParameters()).hasSize(1);
|
||||
assertThat(authenticationResult.getAdditionalParameters().get(OAuth2ParameterNames.ISSUED_TOKEN_TYPE))
|
||||
.isEqualTo(JWT_TOKEN_TYPE_VALUE);
|
||||
.isEqualTo(JWT_TOKEN_TYPE_VALUE);
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
ArgumentCaptor<OAuth2TokenContext> tokenContextCaptor = ArgumentCaptor.forClass(OAuth2TokenContext.class);
|
||||
@@ -577,15 +614,16 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenActorTokenAndValidTokenExchangeThenReturnAccessTokenForDelegation() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = createDelegationRequest(registeredClient);
|
||||
TestingAuthenticationToken userPrincipal = new TestingAuthenticationToken("user", null, "ROLE_USER");
|
||||
OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS, "issuer1",
|
||||
OAuth2TokenClaimNames.SUB, "actor1"));
|
||||
OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS, "issuer2",
|
||||
OAuth2TokenClaimNames.SUB, "actor2"));
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken subjectPrincipal =
|
||||
new OAuth2TokenExchangeCompositeAuthenticationToken(userPrincipal, List.of(actor1));
|
||||
OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(
|
||||
Map.of(OAuth2TokenClaimNames.ISS, "issuer1", OAuth2TokenClaimNames.SUB, "actor1"));
|
||||
OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(
|
||||
Map.of(OAuth2TokenClaimNames.ISS, "issuer2", OAuth2TokenClaimNames.SUB, "actor2"));
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken subjectPrincipal = new OAuth2TokenExchangeCompositeAuthenticationToken(
|
||||
userPrincipal, List.of(actor1));
|
||||
// @formatter:off
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.token(createAccessToken(SUBJECT_TOKEN), withClaims(Map.of("may_act", actor2.getClaims())))
|
||||
@@ -596,19 +634,19 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
.token(createAccessToken(ACTOR_TOKEN), withClaims(actor2.getClaims()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class))).thenReturn(
|
||||
subjectAuthorization, actorAuthorization);
|
||||
when(this.authorizationService.findByToken(anyString(), any(OAuth2TokenType.class)))
|
||||
.thenReturn(subjectAuthorization, actorAuthorization);
|
||||
OAuth2AccessToken accessToken = createAccessToken("token-value");
|
||||
when(this.tokenGenerator.generate(any(OAuth2TokenContext.class))).thenReturn(accessToken);
|
||||
OAuth2AccessTokenAuthenticationToken authenticationResult =
|
||||
(OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2AccessTokenAuthenticationToken authenticationResult = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
assertThat(authenticationResult.getPrincipal()).isEqualTo(authentication.getPrincipal());
|
||||
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
|
||||
assertThat(authenticationResult.getRefreshToken()).isNull();
|
||||
assertThat(authenticationResult.getAdditionalParameters()).hasSize(1);
|
||||
assertThat(authenticationResult.getAdditionalParameters().get(OAuth2ParameterNames.ISSUED_TOKEN_TYPE))
|
||||
.isEqualTo(JWT_TOKEN_TYPE_VALUE);
|
||||
.isEqualTo(JWT_TOKEN_TYPE_VALUE);
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
ArgumentCaptor<OAuth2TokenContext> tokenContextCaptor = ArgumentCaptor.forClass(OAuth2TokenContext.class);
|
||||
@@ -638,8 +676,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
assertThat(authorization.getAccessToken().getToken()).isEqualTo(accessToken);
|
||||
assertThat(authorization.getRefreshToken()).isNull();
|
||||
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken authorizationPrincipal =
|
||||
authorization.getAttribute(Principal.class.getName());
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken authorizationPrincipal = authorization
|
||||
.getAttribute(Principal.class.getName());
|
||||
assertThat(authorizationPrincipal).isNotNull();
|
||||
assertThat(authorizationPrincipal.getSubject()).isSameAs(subjectPrincipal.getSubject());
|
||||
assertThat(authorizationPrincipal.getActors()).containsExactly(actor2, actor1);
|
||||
@@ -664,7 +702,8 @@ public class OAuth2TokenExchangeAuthenticationProviderTests {
|
||||
clientPrincipal, ACTOR_TOKEN, ACCESS_TOKEN_TYPE_VALUE, RESOURCES, AUDIENCES, requestedScopes, null);
|
||||
}
|
||||
|
||||
private static OAuth2TokenExchangeAuthenticationToken createImpersonationRequest(RegisteredClient registeredClient) {
|
||||
private static OAuth2TokenExchangeAuthenticationToken createImpersonationRequest(
|
||||
RegisteredClient registeredClient) {
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, null);
|
||||
return new OAuth2TokenExchangeAuthenticationToken(JWT_TOKEN_TYPE_VALUE, SUBJECT_TOKEN, ACCESS_TOKEN_TYPE_VALUE,
|
||||
|
||||
@@ -35,17 +35,27 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class OAuth2TokenExchangeAuthenticationTokenTests {
|
||||
private static final Set<String> RESOURCES = Set.of("https://mydomain.com/resource1", "https://mydomain.com/resource2");
|
||||
|
||||
private static final Set<String> RESOURCES = Set.of("https://mydomain.com/resource1",
|
||||
"https://mydomain.com/resource2");
|
||||
|
||||
private static final Set<String> AUDIENCES = Set.of("audience1", "audience2");
|
||||
|
||||
private static final String SUBJECT_TOKEN = "EfYu_0jEL";
|
||||
|
||||
private static final String ACTOR_TOKEN = "JlNE_xR1f";
|
||||
|
||||
private static final String ACCESS_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:access_token";
|
||||
|
||||
private static final String JWT_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:jwt";
|
||||
|
||||
private RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
private OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, this.registeredClient.getClientSecret());
|
||||
|
||||
private OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, this.registeredClient.getClientSecret());
|
||||
|
||||
private Set<String> scopes = Collections.singleton("scope1");
|
||||
|
||||
private Map<String, Object> additionalParameters = Collections.singletonMap("param1", "value1");
|
||||
|
||||
@Test
|
||||
|
||||
@@ -57,8 +57,8 @@ public class OAuth2TokenExchangeCompositeAuthenticationTokenTests {
|
||||
OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(Map.of("claim1", "value1"));
|
||||
OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(Map.of("claim2", "value2"));
|
||||
List<OAuth2TokenExchangeActor> actors = List.of(actor1, actor2);
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken authentication =
|
||||
new OAuth2TokenExchangeCompositeAuthenticationToken(subject, actors);
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken authentication = new OAuth2TokenExchangeCompositeAuthenticationToken(
|
||||
subject, actors);
|
||||
assertThat(authentication.getSubject()).isEqualTo(subject);
|
||||
assertThat(authentication.getActors()).isEqualTo(actors);
|
||||
}
|
||||
|
||||
@@ -65,18 +65,27 @@ import static org.mockito.Mockito.when;
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class X509ClientCertificateAuthenticationProviderTests {
|
||||
// See RFC 7636: Appendix B. Example for the S256 code_challenge_method
|
||||
|
||||
// See RFC 7636: Appendix B. Example for the S256 code_challenge_method
|
||||
// https://tools.ietf.org/html/rfc7636#appendix-B
|
||||
private static final String S256_CODE_VERIFIER = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
|
||||
|
||||
private static final String S256_CODE_CHALLENGE = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM";
|
||||
|
||||
private static final String AUTHORIZATION_CODE = "code";
|
||||
|
||||
private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.CODE);
|
||||
|
||||
private JWKSet selfSignedCertificateJwkSet;
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String clientJwkSetUrl;
|
||||
|
||||
private RegisteredClientRepository registeredClientRepository;
|
||||
|
||||
private OAuth2AuthorizationService authorizationService;
|
||||
|
||||
private X509ClientCertificateAuthenticationProvider authenticationProvider;
|
||||
|
||||
@BeforeEach
|
||||
@@ -102,8 +111,8 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
|
||||
this.registeredClientRepository = mock(RegisteredClientRepository.class);
|
||||
this.authorizationService = mock(OAuth2AuthorizationService.class);
|
||||
this.authenticationProvider = new X509ClientCertificateAuthenticationProvider(
|
||||
this.registeredClientRepository, this.authorizationService);
|
||||
this.authenticationProvider = new X509ClientCertificateAuthenticationProvider(this.registeredClientRepository,
|
||||
this.authorizationService);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -114,22 +123,22 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
@Test
|
||||
public void constructorWhenRegisteredClientRepositoryNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new X509ClientCertificateAuthenticationProvider(null, this.authorizationService))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("registeredClientRepository cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("registeredClientRepository cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenAuthorizationServiceNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new X509ClientCertificateAuthenticationProvider(this.registeredClientRepository, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authorizationService cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authorizationService cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCertificateVerifierWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.authenticationProvider.setCertificateVerifier(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("certificateVerifier cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("certificateVerifier cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -145,36 +154,36 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId() + "-invalid", ClientAuthenticationMethod.TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains(OAuth2ParameterNames.CLIENT_ID);
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains(OAuth2ParameterNames.CLIENT_ID);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenUnsupportedClientAuthenticationMethodThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("authentication_method");
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("authentication_method");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -185,17 +194,17 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.TLS_CLIENT_AUTH, null, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("credentials");
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("credentials");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -211,18 +220,18 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("x509_certificate_subject_dn");
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("x509_certificate_subject_dn");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -238,20 +247,21 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, null);
|
||||
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2ClientAuthenticationToken authenticationResult = (OAuth2ClientAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isEqualTo(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
assertThat(authenticationResult.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.TLS_CLIENT_AUTH);
|
||||
assertThat(authenticationResult.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.TLS_CLIENT_AUTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -267,18 +277,19 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
// PKI Certificate will have different issuer
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, null); // PKI Certificate will have different issuer
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("x509_certificate_issuer");
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("x509_certificate_issuer");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -289,18 +300,18 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("client_jwk_set_url");
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("client_jwk_set_url");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -316,18 +327,18 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("jwk_set_uri");
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains("jwk_set_uri");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -352,7 +363,8 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSelfSignedX509CertificateJwkSetResponseNoMatchingKeysThenThrowOAuth2AuthenticationException() throws Exception {
|
||||
public void authenticateWhenSelfSignedX509CertificateJwkSetResponseNoMatchingKeysThenThrowOAuth2AuthenticationException()
|
||||
throws Exception {
|
||||
// @formatter:off
|
||||
X509Certificate pkiCertificate = TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE[0];
|
||||
RSAKey pkiRSAKey = new RSAKey.Builder((RSAPublicKey) pkiCertificate.getPublicKey())
|
||||
@@ -396,18 +408,18 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains(expectedErrorDescription);
|
||||
});
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.satisfies(error -> {
|
||||
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
assertThat(error.getDescription()).contains(expectedErrorDescription);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -423,20 +435,22 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE, null);
|
||||
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2ClientAuthenticationToken authenticationResult = (OAuth2ClientAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isEqualTo(TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE);
|
||||
assertThat(authenticationResult.getCredentials())
|
||||
.isEqualTo(TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
assertThat(authenticationResult.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH);
|
||||
assertThat(authenticationResult.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -452,13 +466,13 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
.build();
|
||||
// @formatter:on
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersS256())
|
||||
.build();
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersS256())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE)))
|
||||
.thenReturn(authorization);
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(S256_CODE_VERIFIER);
|
||||
|
||||
@@ -466,15 +480,16 @@ public class X509ClientCertificateAuthenticationProviderTests {
|
||||
registeredClient.getClientId(), ClientAuthenticationMethod.TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE, parameters);
|
||||
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
OAuth2ClientAuthenticationToken authenticationResult = (OAuth2ClientAuthenticationToken) this.authenticationProvider
|
||||
.authenticate(authentication);
|
||||
|
||||
verify(this.authorizationService).findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE));
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isEqualTo(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
assertThat(authenticationResult.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.TLS_CLIENT_AUTH);
|
||||
assertThat(authenticationResult.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.TLS_CLIENT_AUTH);
|
||||
}
|
||||
|
||||
private static Map<String, Object> createPkceAuthorizationParametersS256() {
|
||||
|
||||
@@ -37,10 +37,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
class AuthorizationServerContextFilterTests {
|
||||
|
||||
private static final String SCHEME = "https";
|
||||
|
||||
private static final String HOST = "example.com";
|
||||
|
||||
private static final int PORT = 8443;
|
||||
|
||||
private static final String DEFAULT_ISSUER = SCHEME + "://" + HOST + ":" + PORT;
|
||||
|
||||
private AuthorizationServerContextFilter filter;
|
||||
|
||||
@Test
|
||||
@@ -60,17 +65,17 @@ class AuthorizationServerContextFilterTests {
|
||||
@Test
|
||||
public void doFilterWhenCustomEndpointsThenIssuerResolved() throws Exception {
|
||||
AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder()
|
||||
.authorizationEndpoint("/oauth2/v1/authorize")
|
||||
.deviceAuthorizationEndpoint("/oauth2/v1/device_authorization")
|
||||
.deviceVerificationEndpoint("/oauth2/v1/device_verification")
|
||||
.tokenEndpoint("/oauth2/v1/token")
|
||||
.jwkSetEndpoint("/oauth2/v1/jwks")
|
||||
.tokenRevocationEndpoint("/oauth2/v1/revoke")
|
||||
.tokenIntrospectionEndpoint("/oauth2/v1/introspect")
|
||||
.oidcClientRegistrationEndpoint("/connect/v1/register")
|
||||
.oidcUserInfoEndpoint("/v1/userinfo")
|
||||
.oidcLogoutEndpoint("/connect/v1/logout")
|
||||
.build();
|
||||
.authorizationEndpoint("/oauth2/v1/authorize")
|
||||
.deviceAuthorizationEndpoint("/oauth2/v1/device_authorization")
|
||||
.deviceVerificationEndpoint("/oauth2/v1/device_verification")
|
||||
.tokenEndpoint("/oauth2/v1/token")
|
||||
.jwkSetEndpoint("/oauth2/v1/jwks")
|
||||
.tokenRevocationEndpoint("/oauth2/v1/revoke")
|
||||
.tokenIntrospectionEndpoint("/oauth2/v1/introspect")
|
||||
.oidcClientRegistrationEndpoint("/connect/v1/register")
|
||||
.oidcUserInfoEndpoint("/v1/userinfo")
|
||||
.oidcLogoutEndpoint("/connect/v1/logout")
|
||||
.build();
|
||||
this.filter = new AuthorizationServerContextFilter(authorizationServerSettings);
|
||||
|
||||
String issuerPath = "/issuer2";
|
||||
@@ -101,8 +106,8 @@ class AuthorizationServerContextFilterTests {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
AtomicReference<String> resolvedIssuer = new AtomicReference<>();
|
||||
FilterChain filterChain = (req, resp) ->
|
||||
resolvedIssuer.set(AuthorizationServerContextHolder.getContext().getIssuer());
|
||||
FilterChain filterChain = (req, resp) -> resolvedIssuer
|
||||
.set(AuthorizationServerContextHolder.getContext().getIssuer());
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
|
||||
@@ -55,9 +55,13 @@ import static org.mockito.Mockito.when;
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
class DefaultOAuth2TokenCustomizersTests {
|
||||
|
||||
private static final String ISSUER_1 = "issuer-1";
|
||||
|
||||
private static final String ISSUER_2 = "issuer-2";
|
||||
|
||||
private JwsHeader.Builder jwsHeaderBuilder;
|
||||
|
||||
private JwtClaimsSet.Builder jwtClaimsBuilder;
|
||||
|
||||
@BeforeEach
|
||||
@@ -131,10 +135,10 @@ class DefaultOAuth2TokenCustomizersTests {
|
||||
when(tokenExchangeAuthentication.getAudiences()).thenReturn(Collections.emptySet());
|
||||
|
||||
Authentication subject = new TestingAuthenticationToken("subject", null);
|
||||
OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(Map.of(JwtClaimNames.ISS, ISSUER_1,
|
||||
JwtClaimNames.SUB, "actor1"));
|
||||
OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(Map.of(JwtClaimNames.ISS, ISSUER_2,
|
||||
JwtClaimNames.SUB, "actor2"));
|
||||
OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(
|
||||
Map.of(JwtClaimNames.ISS, ISSUER_1, JwtClaimNames.SUB, "actor1"));
|
||||
OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(
|
||||
Map.of(JwtClaimNames.ISS, ISSUER_2, JwtClaimNames.SUB, "actor2"));
|
||||
OAuth2TokenExchangeCompositeAuthenticationToken principal = new OAuth2TokenExchangeCompositeAuthenticationToken(
|
||||
subject, List.of(actor1, actor2));
|
||||
|
||||
@@ -177,11 +181,10 @@ class DefaultOAuth2TokenCustomizersTests {
|
||||
)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
|
||||
new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, null, null);
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient,
|
||||
ClientAuthenticationMethod.TLS_CLIENT_AUTH, TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication = new OAuth2ClientCredentialsAuthenticationToken(
|
||||
clientPrincipal, null, null);
|
||||
// @formatter:off
|
||||
JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
|
||||
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||
@@ -215,11 +218,11 @@ class DefaultOAuth2TokenCustomizersTests {
|
||||
)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient,
|
||||
ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
|
||||
TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE);
|
||||
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
|
||||
new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, null, null);
|
||||
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication = new OAuth2ClientCredentialsAuthenticationToken(
|
||||
clientPrincipal, null, null);
|
||||
// @formatter:off
|
||||
JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
|
||||
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||
|
||||
@@ -82,13 +82,13 @@ public class JwkSetTests {
|
||||
public static void init() {
|
||||
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
|
||||
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
||||
db = new EmbeddedDatabaseBuilder()
|
||||
.generateUniqueName(true)
|
||||
.setType(EmbeddedDatabaseType.HSQL)
|
||||
.setScriptEncoding("UTF-8")
|
||||
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql")
|
||||
.addScript("org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql")
|
||||
.build();
|
||||
db = new EmbeddedDatabaseBuilder().generateUniqueName(true)
|
||||
.setType(EmbeddedDatabaseType.HSQL)
|
||||
.setScriptEncoding("UTF-8")
|
||||
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql")
|
||||
.addScript(
|
||||
"org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql")
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -188,7 +188,10 @@ public class JwkSetTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().jwkSetEndpoint("/test/jwks").multipleIssuersAllowed(true).build();
|
||||
return AuthorizationServerSettings.builder()
|
||||
.jwkSetEndpoint("/test/jwks")
|
||||
.multipleIssuersAllowed(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -918,30 +918,33 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
MvcResult mvcResult = this.mvc.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI))
|
||||
.queryParams(getAuthorizationRequestParameters(registeredClient))
|
||||
.queryParam(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE)
|
||||
.queryParam(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256")
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
MvcResult mvcResult = this.mvc
|
||||
.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI))
|
||||
.queryParams(getAuthorizationRequestParameters(registeredClient))
|
||||
.queryParam(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE)
|
||||
.queryParam(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256")
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
|
||||
String authorizationCode = extractParameterFromRedirectUri(mvcResult.getResponse().getRedirectedUrl(), "code");
|
||||
OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
|
||||
OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode,
|
||||
AUTHORIZATION_CODE_TOKEN_TYPE);
|
||||
|
||||
this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
this.mvc
|
||||
.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.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")))
|
||||
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.token_type").isNotEmpty())
|
||||
.andExpect(jsonPath("$.expires_in").isNotEmpty())
|
||||
.andExpect(jsonPath("$.refresh_token").doesNotExist())
|
||||
.andExpect(jsonPath("$.scope").isNotEmpty())
|
||||
.andReturn();
|
||||
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
|
||||
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.token_type").isNotEmpty())
|
||||
.andExpect(jsonPath("$.expires_in").isNotEmpty())
|
||||
.andExpect(jsonPath("$.refresh_token").doesNotExist())
|
||||
.andExpect(jsonPath("$.scope").isNotEmpty())
|
||||
.andReturn();
|
||||
|
||||
ArgumentCaptor<OAuth2TokenContext> tokenContextCaptor = ArgumentCaptor.forClass(OAuth2TokenContext.class);
|
||||
verify(tokenGenerator).generate(tokenContextCaptor.capture());
|
||||
@@ -1333,7 +1336,8 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
|
||||
@EnableWebSecurity
|
||||
@Import(OAuth2AuthorizationServerConfiguration.class)
|
||||
static class AuthorizationServerConfigurationWithMultipleIssuersAllowed extends AuthorizationServerConfigurationWithTokenGenerator {
|
||||
static class AuthorizationServerConfigurationWithMultipleIssuersAllowed
|
||||
extends AuthorizationServerConfigurationWithTokenGenerator {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
|
||||
@@ -110,13 +110,14 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(ISSUER))
|
||||
.andReturn();
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(ISSUER))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenAuthorizationServerMetadataRequestIncludesIssuerPathThenMetadataResponseHasIssuerPath() throws Exception {
|
||||
public void requestWhenAuthorizationServerMetadataRequestIncludesIssuerPathThenMetadataResponseHasIssuerPath()
|
||||
throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithMultipleIssuersAllowed.class).autowire();
|
||||
|
||||
String host = "https://example.com:8443";
|
||||
@@ -124,23 +125,23 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
String issuerPath = "/issuer1";
|
||||
String issuer = host.concat(issuerPath);
|
||||
this.mvc.perform(get(host.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI).concat(issuerPath)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
|
||||
issuerPath = "/path1/issuer2";
|
||||
issuer = host.concat(issuerPath);
|
||||
this.mvc.perform(get(host.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI).concat(issuerPath)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
|
||||
issuerPath = "/path1/path2/issuer3";
|
||||
issuer = host.concat(issuerPath);
|
||||
this.mvc.perform(get(host.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI).concat(issuerPath)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
// gh-616
|
||||
@@ -150,9 +151,9 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
this.spring.register(AuthorizationServerConfigurationWithMetadataCustomizer.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED,
|
||||
hasItems("scope1", "scope2")));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED,
|
||||
hasItems("scope1", "scope2")));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
|
||||
@@ -298,14 +298,14 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
// @formatter:on
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
|
||||
.with(x509(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE))
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
|
||||
this.mvc
|
||||
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI).with(x509(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE))
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
|
||||
|
||||
verify(jwtCustomizer).customize(any());
|
||||
}
|
||||
@@ -344,13 +344,12 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
.forClass(List.class);
|
||||
verify(authenticationConvertersConsumer).accept(authenticationConvertersCaptor.capture());
|
||||
List<AuthenticationConverter> authenticationConverters = authenticationConvertersCaptor.getValue();
|
||||
assertThat(authenticationConverters).allMatch((converter) ->
|
||||
converter == authenticationConverter ||
|
||||
converter instanceof OAuth2AuthorizationCodeAuthenticationConverter ||
|
||||
converter instanceof OAuth2RefreshTokenAuthenticationConverter ||
|
||||
converter instanceof OAuth2ClientCredentialsAuthenticationConverter ||
|
||||
converter instanceof OAuth2DeviceCodeAuthenticationConverter ||
|
||||
converter instanceof OAuth2TokenExchangeAuthenticationConverter);
|
||||
assertThat(authenticationConverters).allMatch((converter) -> converter == authenticationConverter
|
||||
|| converter instanceof OAuth2AuthorizationCodeAuthenticationConverter
|
||||
|| converter instanceof OAuth2RefreshTokenAuthenticationConverter
|
||||
|| converter instanceof OAuth2ClientCredentialsAuthenticationConverter
|
||||
|| converter instanceof OAuth2DeviceCodeAuthenticationConverter
|
||||
|| converter instanceof OAuth2TokenExchangeAuthenticationConverter);
|
||||
|
||||
verify(authenticationProvider).authenticate(eq(clientCredentialsAuthentication));
|
||||
|
||||
@@ -359,13 +358,12 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
.forClass(List.class);
|
||||
verify(authenticationProvidersConsumer).accept(authenticationProvidersCaptor.capture());
|
||||
List<AuthenticationProvider> authenticationProviders = authenticationProvidersCaptor.getValue();
|
||||
assertThat(authenticationProviders).allMatch((provider) ->
|
||||
provider == authenticationProvider ||
|
||||
provider instanceof OAuth2AuthorizationCodeAuthenticationProvider ||
|
||||
provider instanceof OAuth2RefreshTokenAuthenticationProvider ||
|
||||
provider instanceof OAuth2ClientCredentialsAuthenticationProvider ||
|
||||
provider instanceof OAuth2DeviceCodeAuthenticationProvider ||
|
||||
provider instanceof OAuth2TokenExchangeAuthenticationProvider);
|
||||
assertThat(authenticationProviders).allMatch((provider) -> provider == authenticationProvider
|
||||
|| provider instanceof OAuth2AuthorizationCodeAuthenticationProvider
|
||||
|| provider instanceof OAuth2RefreshTokenAuthenticationProvider
|
||||
|| provider instanceof OAuth2ClientCredentialsAuthenticationProvider
|
||||
|| provider instanceof OAuth2DeviceCodeAuthenticationProvider
|
||||
|| provider instanceof OAuth2TokenExchangeAuthenticationProvider);
|
||||
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(accessTokenAuthentication));
|
||||
}
|
||||
@@ -395,13 +393,12 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
.forClass(List.class);
|
||||
verify(authenticationConvertersConsumer).accept(authenticationConvertersCaptor.capture());
|
||||
List<AuthenticationConverter> authenticationConverters = authenticationConvertersCaptor.getValue();
|
||||
assertThat(authenticationConverters).allMatch((converter) ->
|
||||
converter == authenticationConverter ||
|
||||
converter instanceof JwtClientAssertionAuthenticationConverter ||
|
||||
converter instanceof X509ClientCertificateAuthenticationConverter ||
|
||||
converter instanceof ClientSecretBasicAuthenticationConverter ||
|
||||
converter instanceof ClientSecretPostAuthenticationConverter ||
|
||||
converter instanceof PublicClientAuthenticationConverter);
|
||||
assertThat(authenticationConverters).allMatch((converter) -> converter == authenticationConverter
|
||||
|| converter instanceof JwtClientAssertionAuthenticationConverter
|
||||
|| converter instanceof X509ClientCertificateAuthenticationConverter
|
||||
|| converter instanceof ClientSecretBasicAuthenticationConverter
|
||||
|| converter instanceof ClientSecretPostAuthenticationConverter
|
||||
|| converter instanceof PublicClientAuthenticationConverter);
|
||||
|
||||
verify(authenticationProvider).authenticate(eq(clientPrincipal));
|
||||
|
||||
@@ -410,12 +407,11 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
.forClass(List.class);
|
||||
verify(authenticationProvidersConsumer).accept(authenticationProvidersCaptor.capture());
|
||||
List<AuthenticationProvider> authenticationProviders = authenticationProvidersCaptor.getValue();
|
||||
assertThat(authenticationProviders).allMatch((provider) ->
|
||||
provider == authenticationProvider ||
|
||||
provider instanceof JwtClientAssertionAuthenticationProvider ||
|
||||
provider instanceof X509ClientCertificateAuthenticationProvider ||
|
||||
provider instanceof ClientSecretAuthenticationProvider ||
|
||||
provider instanceof PublicClientAuthenticationProvider);
|
||||
assertThat(authenticationProviders).allMatch((provider) -> provider == authenticationProvider
|
||||
|| provider instanceof JwtClientAssertionAuthenticationProvider
|
||||
|| provider instanceof X509ClientCertificateAuthenticationProvider
|
||||
|| provider instanceof ClientSecretAuthenticationProvider
|
||||
|| provider instanceof PublicClientAuthenticationProvider);
|
||||
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(clientPrincipal));
|
||||
}
|
||||
@@ -429,14 +425,15 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
|
||||
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
|
||||
this.mvc
|
||||
.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
|
||||
.header(HttpHeaders.AUTHORIZATION,
|
||||
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
|
||||
|
||||
ArgumentCaptor<JwtEncodingContext> jwtEncodingContextCaptor = ArgumentCaptor.forClass(JwtEncodingContext.class);
|
||||
verify(jwtCustomizer).customize(jwtEncodingContextCaptor.capture());
|
||||
|
||||
@@ -247,9 +247,9 @@ public class OAuth2DeviceCodeGrantTests {
|
||||
String userCode = deviceAuthorizationResponse.getUserCode().getTokenValue();
|
||||
assertThat(userCode).matches("[A-Z]{4}-[A-Z]{4}");
|
||||
assertThat(deviceAuthorizationResponse.getVerificationUri())
|
||||
.isEqualTo("https://example.com:8443/oauth2/device_verification");
|
||||
.isEqualTo("https://example.com:8443/oauth2/device_verification");
|
||||
assertThat(deviceAuthorizationResponse.getVerificationUriComplete())
|
||||
.isEqualTo("https://example.com:8443/oauth2/device_verification?user_code=" + userCode);
|
||||
.isEqualTo("https://example.com:8443/oauth2/device_verification?user_code=" + userCode);
|
||||
|
||||
String deviceCode = deviceAuthorizationResponse.getDeviceCode().getTokenValue();
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(deviceCode, DEVICE_CODE_TOKEN_TYPE);
|
||||
|
||||
@@ -94,18 +94,24 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class OAuth2TokenExchangeGrantTests {
|
||||
|
||||
private static final String DEFAULT_TOKEN_ENDPOINT_URI = "/oauth2/token";
|
||||
|
||||
private static final String RESOURCE = "https://mydomain.com/resource";
|
||||
|
||||
private static final String AUDIENCE = "audience";
|
||||
|
||||
private static final String SUBJECT_TOKEN = "EfYu_0jEL";
|
||||
|
||||
private static final String ACTOR_TOKEN = "JlNE_xR1f";
|
||||
|
||||
private static final String ACCESS_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:access_token";
|
||||
|
||||
private static final String JWT_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:jwt";
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext();
|
||||
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenResponseHttpMessageConverter =
|
||||
new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@@ -152,7 +158,8 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
@@ -168,23 +175,27 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenAccessTokenRequestValidAndNoActorTokenThenReturnAccessTokenResponseForImpersonation() throws Exception {
|
||||
public void requestWhenAccessTokenRequestValidAndNoActorTokenThenReturnAccessTokenResponseForImpersonation()
|
||||
throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
UsernamePasswordAuthenticationToken userPrincipal = createUserPrincipal("user");
|
||||
OAuth2Authorization subjectAuthorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.attribute(Principal.class.getName(), userPrincipal).build();
|
||||
.attribute(Principal.class.getName(), userPrincipal)
|
||||
.build();
|
||||
this.authorizationService.save(subjectAuthorization);
|
||||
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.TOKEN_EXCHANGE.getValue());
|
||||
parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
|
||||
parameters.set(OAuth2ParameterNames.REQUESTED_TOKEN_TYPE, JWT_TOKEN_TYPE_VALUE);
|
||||
parameters.set(OAuth2ParameterNames.SUBJECT_TOKEN, subjectAuthorization.getAccessToken().getToken().getTokenValue());
|
||||
parameters.set(OAuth2ParameterNames.SUBJECT_TOKEN,
|
||||
subjectAuthorization.getAccessToken().getToken().getTokenValue());
|
||||
parameters.set(OAuth2ParameterNames.SUBJECT_TOKEN_TYPE, JWT_TOKEN_TYPE_VALUE);
|
||||
parameters.set(OAuth2ParameterNames.RESOURCE, RESOURCE);
|
||||
parameters.set(OAuth2ParameterNames.AUDIENCE, AUDIENCE);
|
||||
@@ -208,8 +219,8 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
MockHttpServletResponse servletResponse = mvcResult.getResponse();
|
||||
MockClientHttpResponse httpResponse = new MockClientHttpResponse(servletResponse.getContentAsByteArray(),
|
||||
HttpStatus.OK);
|
||||
OAuth2AccessTokenResponse accessTokenResponse =
|
||||
this.accessTokenResponseHttpMessageConverter.read(OAuth2AccessTokenResponse.class, httpResponse);
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.accessTokenResponseHttpMessageConverter
|
||||
.read(OAuth2AccessTokenResponse.class, httpResponse);
|
||||
|
||||
String accessToken = accessTokenResponse.getAccessToken().getTokenValue();
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(accessToken,
|
||||
@@ -217,19 +228,22 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
assertThat(authorization).isNotNull();
|
||||
assertThat(authorization.getAccessToken()).isNotNull();
|
||||
assertThat(authorization.getAccessToken().getClaims()).isNotNull();
|
||||
// We do not populate claims (e.g. `aud`) based on the resource or audience parameters
|
||||
// We do not populate claims (e.g. `aud`) based on the resource or audience
|
||||
// parameters
|
||||
assertThat(authorization.getAccessToken().getClaims().get(OAuth2TokenClaimNames.AUD))
|
||||
.isEqualTo(List.of(registeredClient.getClientId()));
|
||||
.isEqualTo(List.of(registeredClient.getClientId()));
|
||||
assertThat(authorization.getRefreshToken()).isNull();
|
||||
assertThat(authorization.<Authentication>getAttribute(Principal.class.getName())).isEqualTo(userPrincipal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenAccessTokenRequestValidAndActorTokenThenReturnAccessTokenResponseForDelegation() throws Exception {
|
||||
public void requestWhenAccessTokenRequestValidAndActorTokenThenReturnAccessTokenResponseForDelegation()
|
||||
throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
UsernamePasswordAuthenticationToken userPrincipal = createUserPrincipal("user");
|
||||
@@ -284,8 +298,8 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
MockHttpServletResponse servletResponse = mvcResult.getResponse();
|
||||
MockClientHttpResponse httpResponse = new MockClientHttpResponse(servletResponse.getContentAsByteArray(),
|
||||
HttpStatus.OK);
|
||||
OAuth2AccessTokenResponse accessTokenResponse =
|
||||
this.accessTokenResponseHttpMessageConverter.read(OAuth2AccessTokenResponse.class, httpResponse);
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.accessTokenResponseHttpMessageConverter
|
||||
.read(OAuth2AccessTokenResponse.class, httpResponse);
|
||||
|
||||
String accessToken = accessTokenResponse.getAccessToken().getTokenValue();
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(accessToken,
|
||||
@@ -296,7 +310,7 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
assertThat(authorization.getAccessToken().getClaims().get("act")).isNotNull();
|
||||
assertThat(authorization.getRefreshToken()).isNull();
|
||||
assertThat(authorization.<Authentication>getAttribute(Principal.class.getName()))
|
||||
.isInstanceOf(OAuth2TokenExchangeCompositeAuthenticationToken.class);
|
||||
.isInstanceOf(OAuth2TokenExchangeCompositeAuthenticationToken.class);
|
||||
}
|
||||
|
||||
private static OAuth2AccessToken createAccessToken(String tokenValue) {
|
||||
@@ -363,6 +377,7 @@ public class OAuth2TokenExchangeGrantTests {
|
||||
PasswordEncoder passwordEncoder() {
|
||||
return NoOpPasswordEncoder.getInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -437,11 +437,10 @@ public class OAuth2TokenIntrospectionTests {
|
||||
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
introspectRegisteredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, introspectRegisteredClient.getClientSecret());
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, null, null);
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(introspectRegisteredClient,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, introspectRegisteredClient.getClientSecret());
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication = new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, null, null);
|
||||
|
||||
when(authenticationConverter.convert(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
when(authenticationProvider.supports(eq(OAuth2TokenIntrospectionAuthenticationToken.class))).thenReturn(true);
|
||||
@@ -600,10 +599,12 @@ public class OAuth2TokenIntrospectionTests {
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
|
||||
@Override
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().multipleIssuersAllowed(true).tokenIntrospectionEndpoint("/test/introspect").build();
|
||||
return AuthorizationServerSettings.builder()
|
||||
.multipleIssuersAllowed(true)
|
||||
.tokenIntrospectionEndpoint("/test/introspect")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -387,7 +387,8 @@ public class OidcClientRegistrationTests {
|
||||
when(authenticationProvider.authenticate(any())).thenThrow(new OAuth2AuthenticationException("error"));
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, "invalid").with(jwt()));
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, "invalid")
|
||||
.with(jwt()));
|
||||
|
||||
verify(authenticationFailureHandler).onAuthenticationFailure(any(), any(), any());
|
||||
verifyNoInteractions(authenticationSuccessHandler);
|
||||
@@ -411,14 +412,16 @@ public class OidcClientRegistrationTests {
|
||||
|
||||
OidcClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
|
||||
|
||||
this.mvc.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1")
|
||||
.with(httpBasic(clientRegistrationResponse.getClientId(), clientRegistrationResponse.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1"))
|
||||
.andReturn();
|
||||
this.mvc
|
||||
.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1")
|
||||
.with(httpBasic(clientRegistrationResponse.getClientId(),
|
||||
clientRegistrationResponse.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1"))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
// gh-1344
|
||||
@@ -445,12 +448,12 @@ public class OidcClientRegistrationTests {
|
||||
Instant issuedAt = Instant.now();
|
||||
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
|
||||
JwtClaimsSet jwtClaimsSet = JwtClaimsSet.builder()
|
||||
.issuer(clientRegistrationResponse.getClientId())
|
||||
.subject(clientRegistrationResponse.getClientId())
|
||||
.audience(Collections.singletonList(asUrl(ISSUER, this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.build();
|
||||
.issuer(clientRegistrationResponse.getClientId())
|
||||
.subject(clientRegistrationResponse.getClientId())
|
||||
.audience(Collections.singletonList(asUrl(ISSUER, this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.build();
|
||||
|
||||
JWKSet jwkSet = new JWKSet(
|
||||
TestJwks.jwk(new SecretKeySpec(clientRegistrationResponse.getClientSecret().getBytes(), "HS256"))
|
||||
@@ -460,15 +463,17 @@ public class OidcClientRegistrationTests {
|
||||
|
||||
Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet));
|
||||
|
||||
this.mvc.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1")
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION, jwtAssertion.getTokenValue())
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, clientRegistrationResponse.getClientId()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1"));
|
||||
this.mvc
|
||||
.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1")
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE,
|
||||
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION, jwtAssertion.getTokenValue())
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, clientRegistrationResponse.getClientId()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -533,7 +538,8 @@ public class OidcClientRegistrationTests {
|
||||
// @formatter:on
|
||||
Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet));
|
||||
|
||||
MvcResult mvcResult = this.mvc.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
MvcResult mvcResult = this.mvc
|
||||
.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE,
|
||||
@@ -553,8 +559,8 @@ public class OidcClientRegistrationTests {
|
||||
httpHeaders.setBearerAuth(accessToken.getTokenValue());
|
||||
|
||||
// Register the client
|
||||
mvcResult = this.mvc.perform(post(ISSUER.concat(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI))
|
||||
.headers(httpHeaders)
|
||||
mvcResult = this.mvc
|
||||
.perform(post(ISSUER.concat(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)).headers(httpHeaders)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(getClientRegistrationRequestContent(clientRegistration)))
|
||||
.andExpect(status().isCreated())
|
||||
@@ -569,11 +575,11 @@ public class OidcClientRegistrationTests {
|
||||
Instant issuedAt = Instant.now();
|
||||
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
|
||||
return JwtClaimsSet.builder()
|
||||
.issuer(registeredClient.getClientId())
|
||||
.subject(registeredClient.getClientId())
|
||||
.audience(Collections.singletonList(asUrl(ISSUER, this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt);
|
||||
.issuer(registeredClient.getClientId())
|
||||
.subject(registeredClient.getClientId())
|
||||
.audience(Collections.singletonList(asUrl(ISSUER, this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt);
|
||||
}
|
||||
|
||||
private static String asUrl(String uri, String path) {
|
||||
@@ -753,9 +759,7 @@ public class OidcClientRegistrationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.multipleIssuersAllowed(true)
|
||||
.build();
|
||||
return AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -80,28 +80,29 @@ public class OidcProviderConfigurationTests {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenConfigurationRequestIncludesIssuerPathThenConfigurationResponseHasIssuerPath() throws Exception {
|
||||
public void requestWhenConfigurationRequestIncludesIssuerPathThenConfigurationResponseHasIssuerPath()
|
||||
throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithMultipleIssuersAllowed.class).autowire();
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
|
||||
issuer = "https://example.com:8443/path1/issuer2";
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
|
||||
issuer = "https://example.com:8443/path1/path2/issuer3";
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
}
|
||||
|
||||
// gh-632
|
||||
@@ -109,10 +110,9 @@ public class OidcProviderConfigurationTests {
|
||||
public void requestWhenConfigurationRequestAndUserAuthenticatedThenReturnConfigurationResponse() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI))
|
||||
.with(user("user")))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER));
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)).with(user("user")))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER));
|
||||
}
|
||||
|
||||
// gh-616
|
||||
@@ -122,9 +122,9 @@ public class OidcProviderConfigurationTests {
|
||||
this.spring.register(AuthorizationServerConfigurationWithProviderConfigurationCustomizer.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED,
|
||||
hasItems(OidcScopes.OPENID, OidcScopes.PROFILE, OidcScopes.EMAIL)));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED,
|
||||
hasItems(OidcScopes.OPENID, OidcScopes.PROFILE, OidcScopes.EMAIL)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -133,9 +133,10 @@ public class OidcProviderConfigurationTests {
|
||||
this.spring.register(AuthorizationServerConfigurationWithClientRegistrationEnabled.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER))
|
||||
.andExpect(jsonPath("$.registration_endpoint").value(ISSUER.concat(this.authorizationServerSettings.getOidcClientRegistrationEndpoint())));
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER))
|
||||
.andExpect(jsonPath("$.registration_endpoint")
|
||||
.value(ISSUER.concat(this.authorizationServerSettings.getOidcClientRegistrationEndpoint())));
|
||||
}
|
||||
|
||||
private ResultMatcher[] defaultConfigurationMatchers(String issuer) {
|
||||
@@ -235,9 +236,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.issuer(ISSUER)
|
||||
.build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -248,9 +247,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.multipleIssuersAllowed(true)
|
||||
.build();
|
||||
return AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -324,12 +324,13 @@ public class OidcTests {
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
// Login
|
||||
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(registeredClient);
|
||||
MvcResult mvcResult = this.mvc.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI))
|
||||
.queryParams(authorizationRequestParameters)
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(
|
||||
registeredClient);
|
||||
MvcResult mvcResult = this.mvc
|
||||
.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI)).queryParams(authorizationRequestParameters)
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
|
||||
MockHttpSession session = (MockHttpSession) mvcResult.getRequest().getSession();
|
||||
assertThat(session.isNew()).isTrue();
|
||||
@@ -340,12 +341,13 @@ public class OidcTests {
|
||||
AUTHORIZATION_CODE_TOKEN_TYPE);
|
||||
|
||||
// Get ID Token
|
||||
mvcResult = this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.params(getTokenRequestParameters(registeredClient, authorization))
|
||||
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
mvcResult = this.mvc
|
||||
.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.params(getTokenRequestParameters(registeredClient, authorization))
|
||||
.header(HttpHeaders.AUTHORIZATION,
|
||||
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
MockHttpServletResponse servletResponse = mvcResult.getResponse();
|
||||
MockClientHttpResponse httpResponse = new MockClientHttpResponse(servletResponse.getContentAsByteArray(),
|
||||
@@ -356,11 +358,11 @@ public class OidcTests {
|
||||
String idToken = (String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN);
|
||||
|
||||
// Logout
|
||||
mvcResult = this.mvc.perform(post(issuer.concat(DEFAULT_OIDC_LOGOUT_ENDPOINT_URI))
|
||||
.param("id_token_hint", idToken)
|
||||
.session(session))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
mvcResult = this.mvc
|
||||
.perform(post(issuer.concat(DEFAULT_OIDC_LOGOUT_ENDPOINT_URI)).param("id_token_hint", idToken)
|
||||
.session(session))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
|
||||
|
||||
assertThat(redirectedUrl).matches("/");
|
||||
|
||||
@@ -526,9 +526,7 @@ public class OidcUserInfoTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.multipleIssuersAllowed(true)
|
||||
.build();
|
||||
return AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ public class OidcProviderConfigurationEndpointFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNotConfigurationRequestThenNotProcessed() throws Exception {
|
||||
AuthorizationServerContextHolder.setContext(
|
||||
new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
AuthorizationServerContextHolder
|
||||
.setContext(new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
|
||||
String requestUri = "/path";
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||
@@ -79,8 +79,8 @@ public class OidcProviderConfigurationEndpointFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterWhenConfigurationRequestPostThenNotProcessed() throws Exception {
|
||||
AuthorizationServerContextHolder.setContext(
|
||||
new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
AuthorizationServerContextHolder
|
||||
.setContext(new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
|
||||
String requestUri = DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
|
||||
@@ -137,18 +137,25 @@ public class OidcProviderConfigurationEndpointFilterTests {
|
||||
assertThat(providerConfigurationResponse).contains("\"jwks_uri\":\"https://example.com/oauth2/v1/jwks\"");
|
||||
assertThat(providerConfigurationResponse).contains("\"scopes_supported\":[\"openid\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"response_types_supported\":[\"code\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\",\"urn:ietf:params:oauth:grant-type:device_code\",\"urn:ietf:params:oauth:grant-type:token-exchange\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"revocation_endpoint\":\"https://example.com/oauth2/v1/revoke\"");
|
||||
assertThat(providerConfigurationResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"introspection_endpoint\":\"https://example.com/oauth2/v1/introspect\"");
|
||||
assertThat(providerConfigurationResponse).contains("\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(providerConfigurationResponse).contains(
|
||||
"\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\",\"urn:ietf:params:oauth:grant-type:device_code\",\"urn:ietf:params:oauth:grant-type:token-exchange\"]");
|
||||
assertThat(providerConfigurationResponse)
|
||||
.contains("\"revocation_endpoint\":\"https://example.com/oauth2/v1/revoke\"");
|
||||
assertThat(providerConfigurationResponse).contains(
|
||||
"\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(providerConfigurationResponse)
|
||||
.contains("\"introspection_endpoint\":\"https://example.com/oauth2/v1/introspect\"");
|
||||
assertThat(providerConfigurationResponse).contains(
|
||||
"\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"code_challenge_methods_supported\":[\"S256\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"tls_client_certificate_bound_access_tokens\":true");
|
||||
assertThat(providerConfigurationResponse).contains("\"subject_types_supported\":[\"public\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"id_token_signing_alg_values_supported\":[\"RS256\"]");
|
||||
assertThat(providerConfigurationResponse).contains("\"userinfo_endpoint\":\"https://example.com/userinfo\"");
|
||||
assertThat(providerConfigurationResponse).contains("\"end_session_endpoint\":\"https://example.com/connect/logout\"");
|
||||
assertThat(providerConfigurationResponse).contains("\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(providerConfigurationResponse)
|
||||
.contains("\"end_session_endpoint\":\"https://example.com/connect/logout\"");
|
||||
assertThat(providerConfigurationResponse).contains(
|
||||
"\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -86,13 +86,16 @@ public class AuthorizationServerSettingsTests {
|
||||
public void buildWhenIssuerSetAndMultipleIssuersAllowedTrueThenThrowIllegalArgumentException() {
|
||||
String issuer = "https://example.com:9000";
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> AuthorizationServerSettings.builder().issuer(issuer).multipleIssuersAllowed(true).build())
|
||||
.withMessage("The issuer identifier (" + issuer + ") cannot be set when isMultipleIssuersAllowed() is true.");
|
||||
.isThrownBy(() -> AuthorizationServerSettings.builder().issuer(issuer).multipleIssuersAllowed(true).build())
|
||||
.withMessage(
|
||||
"The issuer identifier (" + issuer + ") cannot be set when isMultipleIssuersAllowed() is true.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenIssuerNotSetAndMultipleIssuersAllowedTrueThenDefaultsAreSet() {
|
||||
AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build();
|
||||
AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder()
|
||||
.multipleIssuersAllowed(true)
|
||||
.build();
|
||||
|
||||
assertThat(authorizationServerSettings.getIssuer()).isNull();
|
||||
assertThat(authorizationServerSettings.isMultipleIssuersAllowed()).isTrue();
|
||||
|
||||
@@ -65,9 +65,10 @@ public class ClientSettingsTests {
|
||||
@Test
|
||||
public void x509CertificateSubjectDNWhenProvidedThenSet() {
|
||||
ClientSettings clientSettings = ClientSettings.builder()
|
||||
.x509CertificateSubjectDN("CN=demo-client-sample, OU=Spring Samples, O=Spring, C=US")
|
||||
.build();
|
||||
assertThat(clientSettings.getX509CertificateSubjectDN()).isEqualTo("CN=demo-client-sample, OU=Spring Samples, O=Spring, C=US");
|
||||
.x509CertificateSubjectDN("CN=demo-client-sample, OU=Spring Samples, O=Spring, C=US")
|
||||
.build();
|
||||
assertThat(clientSettings.getX509CertificateSubjectDN())
|
||||
.isEqualTo("CN=demo-client-sample, OU=Spring Samples, O=Spring, C=US");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -153,18 +153,16 @@ public class TokenSettingsTests {
|
||||
|
||||
@Test
|
||||
public void x509CertificateBoundAccessTokensWhenTrueThenSet() {
|
||||
TokenSettings tokenSettings = TokenSettings.builder()
|
||||
.x509CertificateBoundAccessTokens(true)
|
||||
.build();
|
||||
TokenSettings tokenSettings = TokenSettings.builder().x509CertificateBoundAccessTokens(true).build();
|
||||
assertThat(tokenSettings.isX509CertificateBoundAccessTokens()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingWhenCustomThenSet() {
|
||||
TokenSettings tokenSettings = TokenSettings.builder()
|
||||
.setting("name1", "value1")
|
||||
.settings(settings -> settings.put("name2", "value2"))
|
||||
.build();
|
||||
.setting("name1", "value1")
|
||||
.settings(settings -> settings.put("name2", "value2"))
|
||||
.build();
|
||||
assertThat(tokenSettings.getSettings()).hasSize(10);
|
||||
assertThat(tokenSettings.<String>getSetting("name1")).isEqualTo("value1");
|
||||
assertThat(tokenSettings.<String>getSetting("name2")).isEqualTo("value2");
|
||||
|
||||
@@ -29,22 +29,25 @@ public final class TestX509Certificates {
|
||||
// Generate the Root certificate (Trust Anchor or most-trusted CA)
|
||||
KeyPair rootKeyPair = X509CertificateUtils.generateRSAKeyPair();
|
||||
String distinguishedName = "CN=spring-samples-trusted-ca, OU=Spring Samples, O=Spring, C=US";
|
||||
X509Certificate rootCertificate = X509CertificateUtils.createTrustAnchorCertificate(rootKeyPair, distinguishedName);
|
||||
X509Certificate rootCertificate = X509CertificateUtils.createTrustAnchorCertificate(rootKeyPair,
|
||||
distinguishedName);
|
||||
|
||||
// Generate the CA (intermediary) certificate
|
||||
KeyPair caKeyPair = X509CertificateUtils.generateRSAKeyPair();
|
||||
distinguishedName = "CN=spring-samples-ca, OU=Spring Samples, O=Spring, C=US";
|
||||
X509Certificate caCertificate = X509CertificateUtils.createCACertificate(
|
||||
rootCertificate, rootKeyPair.getPrivate(), caKeyPair.getPublic(), distinguishedName);
|
||||
X509Certificate caCertificate = X509CertificateUtils.createCACertificate(rootCertificate,
|
||||
rootKeyPair.getPrivate(), caKeyPair.getPublic(), distinguishedName);
|
||||
|
||||
// Generate certificate for demo-client-sample
|
||||
KeyPair demoClientKeyPair = X509CertificateUtils.generateRSAKeyPair();
|
||||
distinguishedName = "CN=demo-client-sample, OU=Spring Samples, O=Spring, C=US";
|
||||
X509Certificate demoClientCertificate = X509CertificateUtils.createEndEntityCertificate(
|
||||
caCertificate, caKeyPair.getPrivate(), demoClientKeyPair.getPublic(), distinguishedName);
|
||||
X509Certificate demoClientCertificate = X509CertificateUtils.createEndEntityCertificate(caCertificate,
|
||||
caKeyPair.getPrivate(), demoClientKeyPair.getPublic(), distinguishedName);
|
||||
|
||||
DEMO_CLIENT_PKI_CERTIFICATE = new X509Certificate[] { demoClientCertificate, caCertificate, rootCertificate };
|
||||
} catch (Exception ex) {
|
||||
DEMO_CLIENT_PKI_CERTIFICATE = new X509Certificate[] { demoClientCertificate, caCertificate,
|
||||
rootCertificate };
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
@@ -55,10 +58,12 @@ public final class TestX509Certificates {
|
||||
// Generate self-signed certificate for demo-client-sample
|
||||
KeyPair keyPair = X509CertificateUtils.generateRSAKeyPair();
|
||||
String distinguishedName = "CN=demo-client-sample, OU=Spring Samples, O=Spring, C=US";
|
||||
X509Certificate demoClientSelfSignedCertificate = X509CertificateUtils.createTrustAnchorCertificate(keyPair, distinguishedName);
|
||||
X509Certificate demoClientSelfSignedCertificate = X509CertificateUtils.createTrustAnchorCertificate(keyPair,
|
||||
distinguishedName);
|
||||
|
||||
DEMO_CLIENT_SELF_SIGNED_CERTIFICATE = new X509Certificate[] { demoClientSelfSignedCertificate };
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,15 +44,20 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public final class X509CertificateUtils {
|
||||
|
||||
private static final String BC_PROVIDER = "BC";
|
||||
|
||||
private static final String SHA256_RSA_SIGNATURE_ALGORITHM = "SHA256withRSA";
|
||||
|
||||
private static final Date DEFAULT_START_DATE;
|
||||
|
||||
private static final Date DEFAULT_END_DATE;
|
||||
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
// Setup default certificate start date to yesterday and end date for 1 year validity
|
||||
// Setup default certificate start date to yesterday and end date for 1 year
|
||||
// validity
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.DATE, -1);
|
||||
DEFAULT_START_DATE = calendar.getTime();
|
||||
@@ -69,34 +74,31 @@ public final class X509CertificateUtils {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", BC_PROVIDER);
|
||||
keyPairGenerator.initialize(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4));
|
||||
keyPair = keyPairGenerator.generateKeyPair();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
public static X509Certificate createTrustAnchorCertificate(KeyPair keyPair, String distinguishedName) throws Exception {
|
||||
public static X509Certificate createTrustAnchorCertificate(KeyPair keyPair, String distinguishedName)
|
||||
throws Exception {
|
||||
X500Principal subject = new X500Principal(distinguishedName);
|
||||
BigInteger serialNum = new BigInteger(Long.toString(new SecureRandom().nextLong()));
|
||||
|
||||
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
|
||||
subject,
|
||||
serialNum,
|
||||
DEFAULT_START_DATE,
|
||||
DEFAULT_END_DATE,
|
||||
subject,
|
||||
keyPair.getPublic());
|
||||
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(subject, serialNum, DEFAULT_START_DATE,
|
||||
DEFAULT_END_DATE, subject, keyPair.getPublic());
|
||||
|
||||
// Add Extensions
|
||||
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
|
||||
certBuilder
|
||||
// A BasicConstraints to mark root certificate as CA certificate
|
||||
.addExtension(Extension.basicConstraints, true, new BasicConstraints(true))
|
||||
.addExtension(Extension.subjectKeyIdentifier, false,
|
||||
extensionUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
|
||||
// A BasicConstraints to mark root certificate as CA certificate
|
||||
.addExtension(Extension.basicConstraints, true, new BasicConstraints(true))
|
||||
.addExtension(Extension.subjectKeyIdentifier, false,
|
||||
extensionUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder(SHA256_RSA_SIGNATURE_ALGORITHM)
|
||||
.setProvider(BC_PROVIDER).build(keyPair.getPrivate());
|
||||
ContentSigner signer = new JcaContentSignerBuilder(SHA256_RSA_SIGNATURE_ALGORITHM).setProvider(BC_PROVIDER)
|
||||
.build(keyPair.getPrivate());
|
||||
|
||||
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BC_PROVIDER);
|
||||
|
||||
@@ -109,32 +111,26 @@ public final class X509CertificateUtils {
|
||||
X500Principal subject = new X500Principal(distinguishedName);
|
||||
BigInteger serialNum = new BigInteger(Long.toString(new SecureRandom().nextLong()));
|
||||
|
||||
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
|
||||
signerCert.getSubjectX500Principal(),
|
||||
serialNum,
|
||||
DEFAULT_START_DATE,
|
||||
DEFAULT_END_DATE,
|
||||
subject,
|
||||
certKey);
|
||||
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(signerCert.getSubjectX500Principal(),
|
||||
serialNum, DEFAULT_START_DATE, DEFAULT_END_DATE, subject, certKey);
|
||||
|
||||
// Add Extensions
|
||||
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
|
||||
certBuilder
|
||||
// A BasicConstraints to mark as CA certificate and how many CA certificates can follow it in the chain
|
||||
// (with 0 meaning the chain ends with the next certificate in the chain).
|
||||
.addExtension(Extension.basicConstraints, true, new BasicConstraints(0))
|
||||
// KeyUsage specifies what the public key in the certificate can be used for.
|
||||
// In this case, it can be used for signing other certificates and/or
|
||||
// signing Certificate Revocation Lists (CRLs).
|
||||
.addExtension(Extension.keyUsage, true,
|
||||
new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign))
|
||||
.addExtension(Extension.authorityKeyIdentifier, false,
|
||||
extensionUtils.createAuthorityKeyIdentifier(signerCert))
|
||||
.addExtension(Extension.subjectKeyIdentifier, false,
|
||||
extensionUtils.createSubjectKeyIdentifier(certKey));
|
||||
// A BasicConstraints to mark as CA certificate and how many CA certificates
|
||||
// can follow it in the chain
|
||||
// (with 0 meaning the chain ends with the next certificate in the chain).
|
||||
.addExtension(Extension.basicConstraints, true, new BasicConstraints(0))
|
||||
// KeyUsage specifies what the public key in the certificate can be used for.
|
||||
// In this case, it can be used for signing other certificates and/or
|
||||
// signing Certificate Revocation Lists (CRLs).
|
||||
.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign))
|
||||
.addExtension(Extension.authorityKeyIdentifier, false,
|
||||
extensionUtils.createAuthorityKeyIdentifier(signerCert))
|
||||
.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(certKey));
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder(SHA256_RSA_SIGNATURE_ALGORITHM)
|
||||
.setProvider(BC_PROVIDER).build(signerKey);
|
||||
ContentSigner signer = new JcaContentSignerBuilder(SHA256_RSA_SIGNATURE_ALGORITHM).setProvider(BC_PROVIDER)
|
||||
.build(signerKey);
|
||||
|
||||
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BC_PROVIDER);
|
||||
|
||||
@@ -147,26 +143,18 @@ public final class X509CertificateUtils {
|
||||
X500Principal subject = new X500Principal(distinguishedName);
|
||||
BigInteger serialNum = new BigInteger(Long.toString(new SecureRandom().nextLong()));
|
||||
|
||||
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
|
||||
signerCert.getSubjectX500Principal(),
|
||||
serialNum,
|
||||
DEFAULT_START_DATE,
|
||||
DEFAULT_END_DATE,
|
||||
subject,
|
||||
certKey);
|
||||
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(signerCert.getSubjectX500Principal(),
|
||||
serialNum, DEFAULT_START_DATE, DEFAULT_END_DATE, subject, certKey);
|
||||
|
||||
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
|
||||
certBuilder
|
||||
.addExtension(Extension.basicConstraints, true, new BasicConstraints(false))
|
||||
.addExtension(Extension.keyUsage, true,
|
||||
new KeyUsage(KeyUsage.digitalSignature))
|
||||
.addExtension(Extension.authorityKeyIdentifier, false,
|
||||
extensionUtils.createAuthorityKeyIdentifier(signerCert))
|
||||
.addExtension(Extension.subjectKeyIdentifier, false,
|
||||
extensionUtils.createSubjectKeyIdentifier(certKey));
|
||||
certBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false))
|
||||
.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature))
|
||||
.addExtension(Extension.authorityKeyIdentifier, false,
|
||||
extensionUtils.createAuthorityKeyIdentifier(signerCert))
|
||||
.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(certKey));
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder(SHA256_RSA_SIGNATURE_ALGORITHM)
|
||||
.setProvider(BC_PROVIDER).build(signerKey);
|
||||
ContentSigner signer = new JcaContentSignerBuilder(SHA256_RSA_SIGNATURE_ALGORITHM).setProvider(BC_PROVIDER)
|
||||
.build(signerKey);
|
||||
|
||||
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BC_PROVIDER);
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNotAuthorizationServerMetadataRequestThenNotProcessed() throws Exception {
|
||||
AuthorizationServerContextHolder.setContext(
|
||||
new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
AuthorizationServerContextHolder
|
||||
.setContext(new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
|
||||
String requestUri = "/path";
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||
@@ -79,8 +79,8 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterWhenAuthorizationServerMetadataRequestPostThenNotProcessed() throws Exception {
|
||||
AuthorizationServerContextHolder.setContext(
|
||||
new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
AuthorizationServerContextHolder
|
||||
.setContext(new TestAuthorizationServerContext(AuthorizationServerSettings.builder().build(), null));
|
||||
|
||||
String requestUri = DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
|
||||
@@ -126,16 +126,24 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
||||
String authorizationServerMetadataResponse = response.getContentAsString();
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"issuer\":\"https://example.com\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"authorization_endpoint\":\"https://example.com/oauth2/v1/authorize\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"token_endpoint\":\"https://example.com/oauth2/v1/token\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(authorizationServerMetadataResponse)
|
||||
.contains("\"authorization_endpoint\":\"https://example.com/oauth2/v1/authorize\"");
|
||||
assertThat(authorizationServerMetadataResponse)
|
||||
.contains("\"token_endpoint\":\"https://example.com/oauth2/v1/token\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains(
|
||||
"\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"jwks_uri\":\"https://example.com/oauth2/v1/jwks\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"response_types_supported\":[\"code\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\",\"urn:ietf:params:oauth:grant-type:device_code\",\"urn:ietf:params:oauth:grant-type:token-exchange\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"revocation_endpoint\":\"https://example.com/oauth2/v1/revoke\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"introspection_endpoint\":\"https://example.com/oauth2/v1/introspect\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains(
|
||||
"\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\",\"urn:ietf:params:oauth:grant-type:device_code\",\"urn:ietf:params:oauth:grant-type:token-exchange\"]");
|
||||
assertThat(authorizationServerMetadataResponse)
|
||||
.contains("\"revocation_endpoint\":\"https://example.com/oauth2/v1/revoke\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains(
|
||||
"\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(authorizationServerMetadataResponse)
|
||||
.contains("\"introspection_endpoint\":\"https://example.com/oauth2/v1/introspect\"");
|
||||
assertThat(authorizationServerMetadataResponse).contains(
|
||||
"\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"client_secret_jwt\",\"private_key_jwt\",\"tls_client_auth\",\"self_signed_tls_client_auth\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"code_challenge_methods_supported\":[\"S256\"]");
|
||||
assertThat(authorizationServerMetadataResponse).contains("\"tls_client_certificate_bound_access_tokens\":true");
|
||||
}
|
||||
|
||||
@@ -452,17 +452,16 @@ public class OAuth2TokenEndpointFilterTests {
|
||||
@Test
|
||||
public void doFilterWhenTokenExchangeRequestThenAccessTokenResponse() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE).build();
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.build();
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(registeredClient,
|
||||
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
Instant.now(), Instant.now().plus(Duration.ofHours(1)),
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", Instant.now());
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
|
||||
new OAuth2AccessTokenAuthenticationToken(
|
||||
registeredClient, clientPrincipal, accessToken, refreshToken);
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = new OAuth2AccessTokenAuthenticationToken(
|
||||
registeredClient, clientPrincipal, accessToken, refreshToken);
|
||||
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(accessTokenAuthentication);
|
||||
|
||||
@@ -478,24 +477,22 @@ public class OAuth2TokenEndpointFilterTests {
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
ArgumentCaptor<OAuth2TokenExchangeAuthenticationToken> tokenExchangeAuthenticationCaptor =
|
||||
ArgumentCaptor.forClass(OAuth2TokenExchangeAuthenticationToken.class);
|
||||
ArgumentCaptor<OAuth2TokenExchangeAuthenticationToken> tokenExchangeAuthenticationCaptor = ArgumentCaptor
|
||||
.forClass(OAuth2TokenExchangeAuthenticationToken.class);
|
||||
verify(this.authenticationManager).authenticate(tokenExchangeAuthenticationCaptor.capture());
|
||||
|
||||
OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthenticationToken =
|
||||
tokenExchangeAuthenticationCaptor.getValue();
|
||||
OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthenticationToken = tokenExchangeAuthenticationCaptor
|
||||
.getValue();
|
||||
assertThat(tokenExchangeAuthenticationToken.getSubjectToken()).isEqualTo("subject-token");
|
||||
assertThat(tokenExchangeAuthenticationToken.getSubjectTokenType()).isEqualTo(ACCESS_TOKEN_TYPE);
|
||||
assertThat(tokenExchangeAuthenticationToken.getPrincipal()).isEqualTo(clientPrincipal);
|
||||
assertThat(tokenExchangeAuthenticationToken.getScopes()).isEqualTo(registeredClient.getScopes());
|
||||
assertThat(tokenExchangeAuthenticationToken.getAdditionalParameters())
|
||||
.containsExactly(entry("custom-param-1", "custom-value-1"),
|
||||
entry("custom-param-2", new String[] { "custom-value-1", "custom-value-2" }));
|
||||
assertThat(tokenExchangeAuthenticationToken.getDetails())
|
||||
.asInstanceOf(type(WebAuthenticationDetails.class))
|
||||
.extracting(WebAuthenticationDetails::getRemoteAddress)
|
||||
.isEqualTo(REMOTE_ADDRESS);
|
||||
|
||||
assertThat(tokenExchangeAuthenticationToken.getAdditionalParameters()).containsExactly(
|
||||
entry("custom-param-1", "custom-value-1"),
|
||||
entry("custom-param-2", new String[] { "custom-value-1", "custom-value-2" }));
|
||||
assertThat(tokenExchangeAuthenticationToken.getDetails()).asInstanceOf(type(WebAuthenticationDetails.class))
|
||||
.extracting(WebAuthenticationDetails::getRemoteAddress)
|
||||
.isEqualTo(REMOTE_ADDRESS);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
|
||||
OAuth2AccessTokenResponse accessTokenResponse = readAccessTokenResponse(response);
|
||||
@@ -503,10 +500,10 @@ public class OAuth2TokenEndpointFilterTests {
|
||||
OAuth2AccessToken accessTokenResult = accessTokenResponse.getAccessToken();
|
||||
assertThat(accessTokenResult.getTokenType()).isEqualTo(accessToken.getTokenType());
|
||||
assertThat(accessTokenResult.getTokenValue()).isEqualTo(accessToken.getTokenValue());
|
||||
assertThat(accessTokenResult.getIssuedAt()).isBetween(
|
||||
accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResult.getExpiresAt()).isBetween(
|
||||
accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResult.getIssuedAt()).isBetween(accessToken.getIssuedAt().minusSeconds(1),
|
||||
accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResult.getExpiresAt()).isBetween(accessToken.getExpiresAt().minusSeconds(1),
|
||||
accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResult.getScopes()).isEqualTo(accessToken.getScopes());
|
||||
|
||||
OAuth2RefreshToken refreshTokenResult = accessTokenResponse.getRefreshToken();
|
||||
|
||||
@@ -53,13 +53,16 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
* @author Dmitriy Dubson
|
||||
*/
|
||||
public class OAuth2AccessTokenResponseAuthenticationSuccessHandlerTests {
|
||||
|
||||
private final RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
||||
new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
|
||||
private final OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, this.registeredClient.getClientSecret());
|
||||
private final OAuth2AccessTokenResponseAuthenticationSuccessHandler authenticationSuccessHandler =
|
||||
new OAuth2AccessTokenResponseAuthenticationSuccessHandler();
|
||||
this.registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
|
||||
this.registeredClient.getClientSecret());
|
||||
|
||||
private final OAuth2AccessTokenResponseAuthenticationSuccessHandler authenticationSuccessHandler = new OAuth2AccessTokenResponseAuthenticationSuccessHandler();
|
||||
|
||||
@Test
|
||||
public void setAccessTokenResponseCustomizerWhenNullThenThrowIllegalArgumentException() {
|
||||
@@ -79,23 +82,22 @@ public class OAuth2AccessTokenResponseAuthenticationSuccessHandlerTests {
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
|
||||
Map<String, Object> additionalParameters = Collections.singletonMap("param1", "value1");
|
||||
Authentication authentication = new OAuth2AccessTokenAuthenticationToken(
|
||||
this.registeredClient, this.clientPrincipal, accessToken, refreshToken, additionalParameters);
|
||||
Authentication authentication = new OAuth2AccessTokenAuthenticationToken(this.registeredClient,
|
||||
this.clientPrincipal, accessToken, refreshToken, additionalParameters);
|
||||
|
||||
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authentication);
|
||||
|
||||
OAuth2AccessTokenResponse accessTokenResponse = readAccessTokenResponse(response);
|
||||
assertThat(accessTokenResponse.getAccessToken().getTokenValue()).isEqualTo(accessToken.getTokenValue());
|
||||
assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(accessToken.getTokenType());
|
||||
assertThat(accessTokenResponse.getAccessToken().getIssuedAt()).isBetween(
|
||||
accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(
|
||||
accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getAccessToken().getIssuedAt())
|
||||
.isBetween(accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getAccessToken().getExpiresAt())
|
||||
.isBetween(accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getRefreshToken()).isNotNull();
|
||||
assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo(refreshToken.getTokenValue());
|
||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsExactlyInAnyOrderEntriesOf(
|
||||
Map.of("param1", "value1")
|
||||
);
|
||||
assertThat(accessTokenResponse.getAdditionalParameters())
|
||||
.containsExactlyInAnyOrderEntriesOf(Map.of("param1", "value1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,16 +105,17 @@ public class OAuth2AccessTokenResponseAuthenticationSuccessHandlerTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
assertThatThrownBy(() ->
|
||||
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, new TestingAuthenticationToken(this.clientPrincipal, null)))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
|
||||
assertThatThrownBy(() -> this.authenticationSuccessHandler.onAuthenticationSuccess(request, response,
|
||||
new TestingAuthenticationToken(this.clientPrincipal, null)))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAuthenticationSuccessWhenAccessTokenResponseCustomizerSetThenAccessTokenResponseCustomized() throws Exception {
|
||||
public void onAuthenticationSuccessWhenAccessTokenResponseCustomizerSetThenAccessTokenResponseCustomized()
|
||||
throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
@@ -120,8 +123,8 @@ public class OAuth2AccessTokenResponseAuthenticationSuccessHandlerTests {
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
|
||||
Map<String, Object> additionalParameters = Collections.singletonMap("param1", "value1");
|
||||
Authentication authentication = new OAuth2AccessTokenAuthenticationToken(
|
||||
this.registeredClient, this.clientPrincipal, accessToken, refreshToken, additionalParameters);
|
||||
Authentication authentication = new OAuth2AccessTokenAuthenticationToken(this.registeredClient,
|
||||
this.clientPrincipal, accessToken, refreshToken, additionalParameters);
|
||||
|
||||
Consumer<OAuth2AccessTokenAuthenticationContext> accessTokenResponseCustomizer = (authenticationContext) -> {
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = authenticationContext.getAuthentication();
|
||||
@@ -136,20 +139,19 @@ public class OAuth2AccessTokenResponseAuthenticationSuccessHandlerTests {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = readAccessTokenResponse(response);
|
||||
assertThat(accessTokenResponse.getAccessToken().getTokenValue()).isEqualTo(accessToken.getTokenValue());
|
||||
assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(accessToken.getTokenType());
|
||||
assertThat(accessTokenResponse.getAccessToken().getIssuedAt()).isBetween(
|
||||
accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(
|
||||
accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getAccessToken().getIssuedAt())
|
||||
.isBetween(accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getAccessToken().getExpiresAt())
|
||||
.isBetween(accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResponse.getRefreshToken()).isNotNull();
|
||||
assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo(refreshToken.getTokenValue());
|
||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsExactlyInAnyOrderEntriesOf(
|
||||
Map.of("param1", "value1", "authorization_id", "id")
|
||||
);
|
||||
assertThat(accessTokenResponse.getAdditionalParameters())
|
||||
.containsExactlyInAnyOrderEntriesOf(Map.of("param1", "value1", "authorization_id", "id"));
|
||||
}
|
||||
|
||||
private OAuth2AccessTokenResponse readAccessTokenResponse(MockHttpServletResponse response) throws Exception {
|
||||
MockClientHttpResponse httpResponse = new MockClientHttpResponse(
|
||||
response.getContentAsByteArray(), HttpStatus.valueOf(response.getStatus()));
|
||||
MockClientHttpResponse httpResponse = new MockClientHttpResponse(response.getContentAsByteArray(),
|
||||
HttpStatus.valueOf(response.getStatus()));
|
||||
return this.accessTokenHttpResponseConverter.read(OAuth2AccessTokenResponse.class, httpResponse);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,17 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class OAuth2TokenExchangeAuthenticationConverterTests {
|
||||
|
||||
private static final String CLIENT_ID = "client-1";
|
||||
|
||||
private static final String TOKEN_URI = "/oauth2/token";
|
||||
|
||||
private static final String SUBJECT_TOKEN = "EfYu_0jEL";
|
||||
|
||||
private static final String ACTOR_TOKEN = "JlNE_xR1f";
|
||||
|
||||
private static final String ACCESS_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:access_token";
|
||||
|
||||
private static final String JWT_TOKEN_TYPE_VALUE = "urn:ietf:params:oauth:token-type:jwt";
|
||||
|
||||
private OAuth2TokenExchangeAuthenticationConverter converter;
|
||||
@@ -222,7 +228,6 @@ public class OAuth2TokenExchangeAuthenticationConverterTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void convertWhenMultipleActorTokenParametersThenInvalidRequestError() {
|
||||
MockHttpServletRequest request = createRequest();
|
||||
@@ -312,8 +317,8 @@ public class OAuth2TokenExchangeAuthenticationConverterTests {
|
||||
securityContext.setAuthentication(new TestingAuthenticationToken(CLIENT_ID, null));
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
OAuth2TokenExchangeAuthenticationToken authentication =
|
||||
(OAuth2TokenExchangeAuthenticationToken) this.converter.convert(request);
|
||||
OAuth2TokenExchangeAuthenticationToken authentication = (OAuth2TokenExchangeAuthenticationToken) this.converter
|
||||
.convert(request);
|
||||
assertThat(authentication).isNotNull();
|
||||
assertThat(authentication.getResources()).containsExactly("https://mydomain.com/resource1",
|
||||
"https://mydomain.com/resource2");
|
||||
|
||||
@@ -39,6 +39,7 @@ import static org.assertj.core.api.Assertions.entry;
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class X509ClientCertificateAuthenticationConverterTests {
|
||||
|
||||
private final X509ClientCertificateAuthenticationConverter converter = new X509ClientCertificateAuthenticationConverter();
|
||||
|
||||
@Test
|
||||
@@ -51,8 +52,7 @@ public class X509ClientCertificateAuthenticationConverterTests {
|
||||
@Test
|
||||
public void convertWhenEmptyX509CertificateThenReturnNull() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute("jakarta.servlet.request.X509Certificate",
|
||||
new X509Certificate[0]);
|
||||
request.setAttribute("jakarta.servlet.request.X509Certificate", new X509Certificate[0]);
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNull();
|
||||
}
|
||||
@@ -62,11 +62,10 @@ public class X509ClientCertificateAuthenticationConverterTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute("jakarta.servlet.request.X509Certificate",
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
assertThatThrownBy(() -> this.converter.convert(request))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
assertThatThrownBy(() -> this.converter.convert(request)).isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,11 +75,10 @@ public class X509ClientCertificateAuthenticationConverterTests {
|
||||
TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-2");
|
||||
assertThatThrownBy(() -> this.converter.convert(request))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
assertThatThrownBy(() -> this.converter.convert(request)).isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,16 +91,16 @@ public class X509ClientCertificateAuthenticationConverterTests {
|
||||
request.addParameter(OAuth2ParameterNames.CODE, "code");
|
||||
request.addParameter("custom-param-1", "custom-value-1");
|
||||
request.addParameter("custom-param-2", "custom-value-1", "custom-value-2");
|
||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter
|
||||
.convert(request);
|
||||
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
||||
assertThat(authentication.getCredentials()).isEqualTo(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
|
||||
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.TLS_CLIENT_AUTH);
|
||||
assertThat(authentication.getAdditionalParameters())
|
||||
.containsOnly(
|
||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
entry(OAuth2ParameterNames.CODE, "code"),
|
||||
entry("custom-param-1", "custom-value-1"),
|
||||
entry("custom-param-2", new String[] {"custom-value-1", "custom-value-2"}));
|
||||
assertThat(authentication.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.TLS_CLIENT_AUTH);
|
||||
assertThat(authentication.getAdditionalParameters()).containsOnly(
|
||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
entry(OAuth2ParameterNames.CODE, "code"), entry("custom-param-1", "custom-value-1"),
|
||||
entry("custom-param-2", new String[] { "custom-value-1", "custom-value-2" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,16 +113,16 @@ public class X509ClientCertificateAuthenticationConverterTests {
|
||||
request.addParameter(OAuth2ParameterNames.CODE, "code");
|
||||
request.addParameter("custom-param-1", "custom-value-1");
|
||||
request.addParameter("custom-param-2", "custom-value-1", "custom-value-2");
|
||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter
|
||||
.convert(request);
|
||||
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
||||
assertThat(authentication.getCredentials()).isEqualTo(TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE);
|
||||
assertThat(authentication.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH);
|
||||
assertThat(authentication.getAdditionalParameters())
|
||||
.containsOnly(
|
||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
entry(OAuth2ParameterNames.CODE, "code"),
|
||||
entry("custom-param-1", "custom-value-1"),
|
||||
entry("custom-param-2", new String[] {"custom-value-1", "custom-value-2"}));
|
||||
assertThat(authentication.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH);
|
||||
assertThat(authentication.getAdditionalParameters()).containsOnly(
|
||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
entry(OAuth2ParameterNames.CODE, "code"), entry("custom-param-1", "custom-value-1"),
|
||||
entry("custom-param-2", new String[] { "custom-value-1", "custom-value-2" }));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user