diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimAccessor.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimAccessor.java
index a6630476..d32a9180 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimAccessor.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimAccessor.java
@@ -146,12 +146,12 @@ public interface OidcClientMetadataClaimAccessor extends ClaimAccessor {
}
/**
- * Returns the {@code URL} of the OAuth 2.0 Client Configuration Endpoint.
+ * Returns the {@code URL} of the Client Configuration Endpoint where the Registration Access Token can be used.
*
- * @return the {@code URL} of the OAuth 2.0 Client Configuration Endpoint
+ * @return the {@code URL} of the Client Configuration Endpoint where the Registration Access Token can be used
* @since 0.2.1
*/
- default URL getRegistrationClientUri() {
+ default URL getRegistrationClientUrl() {
return getClaimAsURL(OidcClientMetadataClaimNames.REGISTRATION_CLIENT_URI);
}
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimNames.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimNames.java
index 786f4db9..0fc03c2a 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimNames.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimNames.java
@@ -84,13 +84,13 @@ public interface OidcClientMetadataClaimNames {
String ID_TOKEN_SIGNED_RESPONSE_ALG = "id_token_signed_response_alg";
/**
- * {@code registration_access_token} - Registration Access Token that can be used at the Client Configuration Endpoint to perform subsequent operations upon the Client registration
+ * {@code registration_access_token} - the Registration Access Token that can be used at the Client Configuration Endpoint
* @since 0.2.1
*/
String REGISTRATION_ACCESS_TOKEN = "registration_access_token";
/**
- * {@code registration_client_uri} - the {@code URL} of the OAuth 2.0 Client Configuration Endpoint
+ * {@code registration_client_uri} - the {@code URL} of the Client Configuration Endpoint where the Registration Access Token can be used
* @since 0.2.1
*/
String REGISTRATION_CLIENT_URI = "registration_client_uri";
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistration.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistration.java
index 2361a775..8ed3f95f 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistration.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistration.java
@@ -252,23 +252,25 @@ public final class OidcClientRegistration implements OidcClientMetadataClaimAcce
}
/**
- * Sets the Registration Access Token that can be used at the Client Configuration Endpoint to perform subsequent operations upon the Client registration, OPTIONAL.
+ * Sets the Registration Access Token that can be used at the Client Configuration Endpoint, OPTIONAL.
*
- * @param registrationAccessToken the Registration Access Token that can be used at the Client Configuration Endpoint to perform subsequent operations upon the Client registration
+ * @param registrationAccessToken the Registration Access Token that can be used at the Client Configuration Endpoint
* @return the {@link Builder} for further configuration
+ * @since 0.2.1
*/
public Builder registrationAccessToken(String registrationAccessToken) {
return claim(OidcClientMetadataClaimNames.REGISTRATION_ACCESS_TOKEN, registrationAccessToken);
}
/**
- * Sets the {@code URL} of the OAuth 2.0 Client Configuration Endpoint, OPTIONAL.
+ * Sets the {@code URL} of the Client Configuration Endpoint where the Registration Access Token can be used, OPTIONAL.
*
- * @param registrationClientUri the {@code URL} of the OAuth 2.0 Client Configuration Endpoint
+ * @param registrationClientUrl the {@code URL} of the Client Configuration Endpoint where the Registration Access Token can be used
* @return the {@link Builder} for further configuration
+ * @since 0.2.1
*/
- public Builder registrationClientUri(String registrationClientUri) {
- return claim(OidcClientMetadataClaimNames.REGISTRATION_CLIENT_URI, registrationClientUri);
+ public Builder registrationClientUrl(String registrationClientUrl) {
+ return claim(OidcClientMetadataClaimNames.REGISTRATION_CLIENT_URI, registrationClientUrl);
}
/**
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/JwtUtils.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/JwtUtils.java
index a477d689..ef9d88db 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/JwtUtils.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/JwtUtils.java
@@ -19,6 +19,7 @@ import java.time.Instant;
import java.util.Collections;
import java.util.Set;
+import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.JoseHeader;
@@ -29,14 +30,17 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
+ * TODO
+ * This class is mostly a straight copy from {@code org.springframework.security.oauth2.server.authorization.authentication.JwtUtils}.
+ * It should be consolidated when we introduce a token generator abstraction.
+ *
+ * Utility methods used by the {@link AuthenticationProvider}'s when issuing {@link Jwt}'s.
*
- * Utility methods used by the {@link OidcClientRegistrationAuthenticationProvider} when issuing {@link Jwt}'s.
* @author Ovidiu Popa
* @since 0.2.1
*/
final class JwtUtils {
- //TODO Duplicate of {@code org.springframework.security.oauth2.server.authorization.authentication.JwtUtils}. To be refactored
private JwtUtils() {
}
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProvider.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProvider.java
index d4b83a2f..e07cf893 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProvider.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProvider.java
@@ -20,13 +20,12 @@ import java.net.URISyntaxException;
import java.time.Instant;
import java.util.Base64;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -56,18 +55,17 @@ import org.springframework.security.oauth2.server.authorization.config.TokenSett
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
/**
- * An {@link AuthenticationProvider} implementation for OpenID Connect Dynamic Client Registration 1.0 and
- * OpenID Connect Client Configuration 1.0.
+ * An {@link AuthenticationProvider} implementation for OpenID Connect 1.0 Dynamic Client Registration (and Configuration) Endpoint.
*
* @author Ovidiu Popa
* @author Joe Grandja
* @since 0.1.1
* @see RegisteredClientRepository
* @see OAuth2AuthorizationService
+ * @see JwtEncoder
* @see 3. Client Registration Endpoint
* @see 4. Client Configuration Endpoint
*/
@@ -80,9 +78,25 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
private static final String DEFAULT_CLIENT_CONFIGURATION_AUTHORIZED_SCOPE = "client.read";
private final RegisteredClientRepository registeredClientRepository;
private final OAuth2AuthorizationService authorizationService;
- private final JwtEncoder jwtEncoder;
+ private JwtEncoder jwtEncoder;
private ProviderSettings providerSettings;
+ /**
+ * Constructs an {@code OidcClientRegistrationAuthenticationProvider} using the provided parameters.
+ *
+ * @param registeredClientRepository the repository of registered clients
+ * @param authorizationService the authorization service
+ * @deprecated Use {@link #OidcClientRegistrationAuthenticationProvider(RegisteredClientRepository, OAuth2AuthorizationService, JwtEncoder)} instead
+ */
+ @Deprecated
+ public OidcClientRegistrationAuthenticationProvider(RegisteredClientRepository registeredClientRepository,
+ OAuth2AuthorizationService authorizationService) {
+ Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
+ Assert.notNull(authorizationService, "authorizationService cannot be null");
+ this.registeredClientRepository = registeredClientRepository;
+ this.authorizationService = authorizationService;
+ }
+
/**
* Constructs an {@code OidcClientRegistrationAuthenticationProvider} using the provided parameters.
*
@@ -100,6 +114,12 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
this.jwtEncoder = jwtEncoder;
}
+ @Deprecated
+ @Autowired(required = false)
+ protected void setJwtEncoder(JwtEncoder jwtEncoder) {
+ this.jwtEncoder = jwtEncoder;
+ }
+
@Autowired(required = false)
protected void setProviderSettings(ProviderSettings providerSettings) {
this.providerSettings = providerSettings;
@@ -110,7 +130,7 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
OidcClientRegistrationAuthenticationToken clientRegistrationAuthentication =
(OidcClientRegistrationAuthenticationToken) authentication;
- // Validate the "initial" and the registration access token
+ // Validate the "initial" or "registration" access token
AbstractOAuth2TokenAuthenticationToken> accessTokenAuthentication = null;
if (AbstractOAuth2TokenAuthenticationToken.class.isAssignableFrom(clientRegistrationAuthentication.getPrincipal().getClass())) {
accessTokenAuthentication = (AbstractOAuth2TokenAuthenticationToken>) clientRegistrationAuthentication.getPrincipal();
@@ -132,78 +152,77 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
- if (clientRegistrationAuthentication.getClientRegistration() != null) {
+ return clientRegistrationAuthentication.getClientRegistration() != null ?
+ registerClient(clientRegistrationAuthentication, authorization) :
+ findRegistration(clientRegistrationAuthentication, authorization);
+ }
- return registerClient(clientRegistrationAuthentication, authorization);
- }
+ @Override
+ public boolean supports(Class> authentication) {
+ return OidcClientRegistrationAuthenticationToken.class.isAssignableFrom(authentication);
+ }
- if (isNotAuthorized(authorizedAccessToken, DEFAULT_CLIENT_CONFIGURATION_AUTHORIZED_SCOPE)) {
- throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);
- }
+ private OidcClientRegistrationAuthenticationToken findRegistration(OidcClientRegistrationAuthenticationToken clientRegistrationAuthentication,
+ OAuth2Authorization authorization) {
- RegisteredClient registeredClient = this.registeredClientRepository
- .findByClientId(clientRegistrationAuthentication.getClientId());
+ OAuth2Authorization.Token authorizedAccessToken = authorization.getAccessToken();
+ checkScopeForConfiguration(authorizedAccessToken);
+ RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(
+ clientRegistrationAuthentication.getClientId());
if (registeredClient == null) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
+
if (!registeredClient.getId().equals(authorization.getRegisteredClientId())) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
- String registrationClientUri = registrationClientUri(getIssuer(), this.providerSettings.getOidcClientRegistrationEndpoint(), registeredClient.getClientId());
- return new OidcClientRegistrationAuthenticationToken(accessTokenAuthentication,
- convert(registeredClient, registrationClientUri, null));
+ OidcClientRegistration clientRegistration = buildRegistration(registeredClient).build();
+ return new OidcClientRegistrationAuthenticationToken(
+ (Authentication) clientRegistrationAuthentication.getPrincipal(), clientRegistration);
}
private OidcClientRegistrationAuthenticationToken registerClient(OidcClientRegistrationAuthenticationToken clientRegistrationAuthentication,
OAuth2Authorization authorization) {
OAuth2Authorization.Token authorizedAccessToken = authorization.getAccessToken();
- if (isNotAuthorized(authorizedAccessToken, DEFAULT_CLIENT_REGISTRATION_AUTHORIZED_SCOPE)) {
- throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);
- }
+ checkScopeForRegistration(authorizedAccessToken);
if (!isValidRedirectUris(clientRegistrationAuthentication.getClientRegistration().getRedirectUris())) {
// TODO Add OAuth2ErrorCodes.INVALID_REDIRECT_URI
throw new OAuth2AuthenticationException("invalid_redirect_uri");
}
- RegisteredClient registeredClient = create(clientRegistrationAuthentication.getClientRegistration());
+ RegisteredClient registeredClient = createClient(clientRegistrationAuthentication.getClientRegistration());
this.registeredClientRepository.save(registeredClient);
+ OAuth2Authorization registeredClientAuthorization = registerAccessToken(registeredClient);
+
// Invalidate the "initial" access token as it can only be used once
authorization = OidcAuthenticationProviderUtils.invalidate(authorization, authorizedAccessToken.getToken());
if (authorization.getRefreshToken() != null) {
authorization = OidcAuthenticationProviderUtils.invalidate(authorization, authorization.getRefreshToken().getToken());
}
this.authorizationService.save(authorization);
- String registrationClientUri = registrationClientUri(getIssuer(), this.providerSettings.getOidcClientRegistrationEndpoint(), registeredClient.getClientId());
- String registrationAccessToken = registerAccessToken(registeredClient)
- .getAccessToken().getToken().getTokenValue();
-
- return new OidcClientRegistrationAuthenticationToken((AbstractOAuth2TokenAuthenticationToken>) clientRegistrationAuthentication.getPrincipal(),
- convert(registeredClient, registrationClientUri, registrationAccessToken));
- }
- @Override
- public boolean supports(Class> authentication) {
- return OidcClientRegistrationAuthenticationToken.class.isAssignableFrom(authentication);
- }
+ OidcClientRegistration clientRegistration = buildRegistration(registeredClient)
+ .registrationAccessToken(registeredClientAuthorization.getAccessToken().getToken().getTokenValue())
+ .build();
- private String getIssuer() {
- return this.providerSettings != null ? this.providerSettings.getIssuer() : null;
+ return new OidcClientRegistrationAuthenticationToken(
+ (Authentication) clientRegistrationAuthentication.getPrincipal(), clientRegistration);
}
private OAuth2Authorization registerAccessToken(RegisteredClient registeredClient) {
-
- String issuer = getIssuer();
- Set authorizedScopes = new HashSet<>();
- authorizedScopes.add(DEFAULT_CLIENT_CONFIGURATION_AUTHORIZED_SCOPE);
JoseHeader headers = JwtUtils.headers().build();
+
+ Set authorizedScopes = Collections.singleton(DEFAULT_CLIENT_CONFIGURATION_AUTHORIZED_SCOPE);
+
JwtClaimsSet claims = JwtUtils.accessTokenClaims(
- registeredClient, issuer, registeredClient.getClientId(), authorizedScopes).build();
+ registeredClient, this.providerSettings.getIssuer(), registeredClient.getClientId(), authorizedScopes)
+ .build();
Jwt registrationAccessToken = this.jwtEncoder.encode(headers, claims);
@@ -212,7 +231,7 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
registrationAccessToken.getExpiresAt(), authorizedScopes);
// @formatter:off
- OAuth2Authorization accessTokenAuthorization = OAuth2Authorization.withRegisteredClient(registeredClient)
+ OAuth2Authorization registeredClientAuthorization = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(registeredClient.getClientId())
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.token(accessToken,
@@ -222,14 +241,69 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
.build();
// @formatter:on
- this.authorizationService.save(accessTokenAuthorization);
- return accessTokenAuthorization;
+ this.authorizationService.save(registeredClientAuthorization);
+
+ return registeredClientAuthorization;
+ }
+
+ private OidcClientRegistration.Builder buildRegistration(RegisteredClient registeredClient) {
+ // @formatter:off
+ OidcClientRegistration.Builder builder = OidcClientRegistration.builder()
+ .clientId(registeredClient.getClientId())
+ .clientIdIssuedAt(registeredClient.getClientIdIssuedAt())
+ .clientSecret(registeredClient.getClientSecret())
+ .clientName(registeredClient.getClientName());
+
+ builder.redirectUris(redirectUris ->
+ redirectUris.addAll(registeredClient.getRedirectUris()));
+
+ builder.grantTypes(grantTypes ->
+ registeredClient.getAuthorizationGrantTypes().forEach(authorizationGrantType ->
+ grantTypes.add(authorizationGrantType.getValue())));
+
+ if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
+ builder.responseType(OAuth2AuthorizationResponseType.CODE.getValue());
+ }
+
+ if (!CollectionUtils.isEmpty(registeredClient.getScopes())) {
+ builder.scopes(scopes ->
+ scopes.addAll(registeredClient.getScopes()));
+ }
+
+ String registrationClientUri = UriComponentsBuilder.fromUriString(this.providerSettings.getIssuer())
+ .path(this.providerSettings.getOidcClientRegistrationEndpoint())
+ .queryParam(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
+ .toUriString();
+
+ builder
+ .tokenEndpointAuthenticationMethod(registeredClient.getClientAuthenticationMethods().iterator().next().getValue())
+ .idTokenSignedResponseAlgorithm(registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm().getName())
+ .registrationClientUrl(registrationClientUri);
+
+ return builder;
+ // @formatter:on
+ }
+
+ private static void checkScopeForRegistration(OAuth2Authorization.Token authorizedAccessToken) {
+ checkScope(authorizedAccessToken, Collections.singleton(DEFAULT_CLIENT_REGISTRATION_AUTHORIZED_SCOPE));
+ }
+
+ private static void checkScopeForConfiguration(OAuth2Authorization.Token authorizedAccessToken) {
+ checkScope(authorizedAccessToken, Collections.singleton(DEFAULT_CLIENT_CONFIGURATION_AUTHORIZED_SCOPE));
}
@SuppressWarnings("unchecked")
- private static boolean isNotAuthorized(OAuth2Authorization.Token authorizedAccessToken, String requiredScope) {
- Object scope = authorizedAccessToken.getClaims().get(OAuth2ParameterNames.SCOPE);
- return scope == null || !((Collection) scope).contains(requiredScope);
+ private static void checkScope(OAuth2Authorization.Token authorizedAccessToken, Set requiredScope) {
+ Collection authorizedScope = Collections.emptySet();
+ if (authorizedAccessToken.getClaims().containsKey(OAuth2ParameterNames.SCOPE)) {
+ authorizedScope = (Collection) authorizedAccessToken.getClaims().get(OAuth2ParameterNames.SCOPE);
+ }
+ if (!authorizedScope.containsAll(requiredScope)) {
+ throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);
+ } else if (authorizedScope.size() != requiredScope.size()) {
+ // Restrict the access token to only contain the required scope
+ throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
+ }
}
private static boolean isValidRedirectUris(List redirectUris) {
@@ -251,7 +325,7 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
return true;
}
- private static RegisteredClient create(OidcClientRegistration clientRegistration) {
+ private static RegisteredClient createClient(OidcClientRegistration clientRegistration) {
// @formatter:off
RegisteredClient.Builder builder = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId(CLIENT_ID_GENERATOR.generateKey())
@@ -298,47 +372,4 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
// @formatter:on
}
-
- private static String registrationClientUri(String issuer, String oidcClientRegistrationEndpoint, String clientId){
- return UriComponentsBuilder.fromUriString(issuer)
- .path(oidcClientRegistrationEndpoint)
- .queryParam(OAuth2ParameterNames.CLIENT_ID, clientId).toUriString();
- }
-
- private static OidcClientRegistration convert(RegisteredClient registeredClient, String registrationClientUri,
- @Nullable String registrationAccessToken) {
- // @formatter:off
- OidcClientRegistration.Builder builder = OidcClientRegistration.builder()
- .clientId(registeredClient.getClientId())
- .clientIdIssuedAt(registeredClient.getClientIdIssuedAt())
- .clientSecret(registeredClient.getClientSecret())
- .clientName(registeredClient.getClientName());
-
- builder.redirectUris(redirectUris ->
- redirectUris.addAll(registeredClient.getRedirectUris()));
-
- builder.grantTypes(grantTypes ->
- registeredClient.getAuthorizationGrantTypes().forEach(authorizationGrantType ->
- grantTypes.add(authorizationGrantType.getValue())));
-
- if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
- builder.responseType(OAuth2AuthorizationResponseType.CODE.getValue());
- }
-
- if (!CollectionUtils.isEmpty(registeredClient.getScopes())) {
- builder.scopes(scopes ->
- scopes.addAll(registeredClient.getScopes()));
- }
-
- builder
- .tokenEndpointAuthenticationMethod(registeredClient.getClientAuthenticationMethods().iterator().next().getValue())
- .idTokenSignedResponseAlgorithm(registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm().getName())
- .registrationClientUri(registrationClientUri);
- if (StringUtils.hasText(registrationAccessToken)) {
- builder.registrationAccessToken(registrationAccessToken);
- }
- return builder.build();
- // @formatter:on
- }
-
}
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationToken.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationToken.java
index 19e4753f..a227c21e 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationToken.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationToken.java
@@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.authorization.oidc.authentica
import java.util.Collections;
+import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.Version;
@@ -24,7 +25,7 @@ import org.springframework.security.oauth2.core.oidc.OidcClientRegistration;
import org.springframework.util.Assert;
/**
- * An {@link Authentication} implementation used for OpenID Connect Dynamic Client Registration 1.0.
+ * An {@link Authentication} implementation used for OpenID Connect 1.0 Dynamic Client Registration (and Configuration) Endpoint.
*
* @author Joe Grandja
* @author Ovidiu Popa
@@ -36,8 +37,9 @@ import org.springframework.util.Assert;
public class OidcClientRegistrationAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
private final Authentication principal;
- private OidcClientRegistration clientRegistration;
- private String clientId;
+ private final OidcClientRegistration clientRegistration;
+ private final String clientId;
+
/**
* Constructs an {@code OidcClientRegistrationAuthenticationToken} using the provided parameters.
*
@@ -50,6 +52,7 @@ public class OidcClientRegistrationAuthenticationToken extends AbstractAuthentic
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
this.principal = principal;
this.clientRegistration = clientRegistration;
+ this.clientId = null;
setAuthenticated(principal.isAuthenticated());
}
@@ -57,13 +60,14 @@ public class OidcClientRegistrationAuthenticationToken extends AbstractAuthentic
* Constructs an {@code OidcClientRegistrationAuthenticationToken} using the provided parameters.
*
* @param principal the authenticated principal
- * @param clientId the registered client_id
+ * @param clientId the client identifier
*/
public OidcClientRegistrationAuthenticationToken(Authentication principal, String clientId) {
super(Collections.emptyList());
Assert.notNull(principal, "principal cannot be null");
- Assert.hasText(clientId, "clientId cannot be null or empty");
+ Assert.hasText(clientId, "clientId cannot be empty");
this.principal = principal;
+ this.clientRegistration = null;
this.clientId = clientId;
setAuthenticated(principal.isAuthenticated());
}
@@ -88,11 +92,12 @@ public class OidcClientRegistrationAuthenticationToken extends AbstractAuthentic
}
/**
- * Returns the registered client_id.
+ * Returns the client identifier.
*
- * @return the registered client_id
+ * @return the client identifier
* @since 0.2.1
*/
+ @Nullable
public String getClientId() {
return this.clientId;
}
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilter.java
index 3eeb2217..7c4911f8 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilter.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilter.java
@@ -47,7 +47,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
/**
- * A {@code Filter} that processes OpenID Connect Dynamic Client Registration 1.0 Requests and OpenID Connect Client Configuration 1.0 Requests.
+ * A {@code Filter} that processes OpenID Connect Dynamic Client Registration (and Configuration) 1.0 Requests.
*
* @author Ovidiu Popa
* @author Joe Grandja
@@ -64,8 +64,6 @@ public final class OidcClientRegistrationEndpointFilter extends OncePerRequestFi
private final AuthenticationManager authenticationManager;
private final RequestMatcher clientRegistrationEndpointMatcher;
- private final RequestMatcher registerClientEndpointMatcher;
- private final RequestMatcher clientConfigurationEndpointMatcher;
private final HttpMessageConverter clientRegistrationHttpMessageConverter =
new OidcClientRegistrationHttpMessageConverter();
private final HttpMessageConverter errorHttpResponseConverter =
@@ -91,15 +89,14 @@ public final class OidcClientRegistrationEndpointFilter extends OncePerRequestFi
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
Assert.hasText(clientRegistrationEndpointUri, "clientRegistrationEndpointUri cannot be empty");
this.authenticationManager = authenticationManager;
- this.registerClientEndpointMatcher = new AntPathRequestMatcher(
- clientRegistrationEndpointUri, HttpMethod.POST.name());
- this.clientConfigurationEndpointMatcher = createClientConfigurationEndpointMatcher(clientRegistrationEndpointUri);
- this.clientRegistrationEndpointMatcher = new OrRequestMatcher(this.registerClientEndpointMatcher, this.clientConfigurationEndpointMatcher);
+ this.clientRegistrationEndpointMatcher = new OrRequestMatcher(
+ new AntPathRequestMatcher(
+ clientRegistrationEndpointUri, HttpMethod.POST.name()),
+ createConfigureClientMatcher(clientRegistrationEndpointUri));
}
- private static RequestMatcher createClientConfigurationEndpointMatcher(String clientRegistrationEndpointUri) {
-
- RequestMatcher clientConfigurationRequestGetMatcher = new AntPathRequestMatcher(
+ private static RequestMatcher createConfigureClientMatcher(String clientRegistrationEndpointUri) {
+ RequestMatcher configureClientGetMatcher = new AntPathRequestMatcher(
clientRegistrationEndpointUri, HttpMethod.GET.name());
RequestMatcher clientIdMatcher = request -> {
@@ -107,7 +104,7 @@ public final class OidcClientRegistrationEndpointFilter extends OncePerRequestFi
return StringUtils.hasText(clientId);
};
- return new AndRequestMatcher(clientConfigurationRequestGetMatcher, clientIdMatcher);
+ return new AndRequestMatcher(configureClientGetMatcher, clientIdMatcher);
}
@Override
@@ -120,17 +117,17 @@ public final class OidcClientRegistrationEndpointFilter extends OncePerRequestFi
}
try {
- OidcClientRegistrationAuthenticationToken clientRegistrationAuthenticationToken = convert(request);
+ OidcClientRegistrationAuthenticationToken clientRegistrationAuthentication = convert(request);
OidcClientRegistrationAuthenticationToken clientRegistrationAuthenticationResult =
- (OidcClientRegistrationAuthenticationToken) this.authenticationManager.authenticate(clientRegistrationAuthenticationToken);
+ (OidcClientRegistrationAuthenticationToken) this.authenticationManager.authenticate(clientRegistrationAuthentication);
- if (clientRegistrationAuthenticationToken.getClientRegistration() != null) {
- sendClientRegistrationResponse(response, HttpStatus.CREATED, clientRegistrationAuthenticationResult.getClientRegistration());
- return;
+ HttpStatus httpStatus = HttpStatus.OK;
+ if (clientRegistrationAuthentication.getClientRegistration() != null) {
+ httpStatus = HttpStatus.CREATED;
}
- sendClientRegistrationResponse(response, HttpStatus.OK, clientRegistrationAuthenticationResult.getClientRegistration());
+ sendClientRegistrationResponse(response, httpStatus, clientRegistrationAuthenticationResult.getClientRegistration());
} catch (OAuth2AuthenticationException ex) {
sendErrorResponse(response, ex.getError());
@@ -145,41 +142,23 @@ public final class OidcClientRegistrationEndpointFilter extends OncePerRequestFi
}
}
- private OidcClientRegistrationAuthenticationToken convert(HttpServletRequest request) {
- if (this.registerClientEndpointMatcher.matches(request)) {
- return convertOidcClientRegistrationRequest(request);
- }
+ private OidcClientRegistrationAuthenticationToken convert(HttpServletRequest request) throws Exception {
+ Authentication principal = SecurityContextHolder.getContext().getAuthentication();
- if (this.clientConfigurationEndpointMatcher.matches(request)) {
- return convertOidcClientConfigurationRequest(request);
+ if ("POST".equals(request.getMethod())) {
+ OidcClientRegistration clientRegistration = this.clientRegistrationHttpMessageConverter.read(
+ OidcClientRegistration.class, new ServletServerHttpRequest(request));
+ return new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
}
- throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
- }
-
- private OidcClientRegistrationAuthenticationToken convertOidcClientConfigurationRequest(HttpServletRequest request) {
- Authentication principal = SecurityContextHolder.getContext().getAuthentication();
+ // client_id (REQUIRED)
String clientId = request.getParameter(OAuth2ParameterNames.CLIENT_ID);
String[] clientIdParameters = request.getParameterValues(OAuth2ParameterNames.CLIENT_ID);
if (!StringUtils.hasText(clientId) || clientIdParameters.length != 1) {
- throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
+ throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
}
- return new OidcClientRegistrationAuthenticationToken(principal, clientId);
- }
- private OidcClientRegistrationAuthenticationToken convertOidcClientRegistrationRequest(HttpServletRequest request) {
- try {
- Authentication principal = SecurityContextHolder.getContext().getAuthentication();
- OidcClientRegistration clientRegistration = this.clientRegistrationHttpMessageConverter.read(
- OidcClientRegistration.class, new ServletServerHttpRequest(request));
- return new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
- } catch (IOException ex) {
- OAuth2Error error = new OAuth2Error(
- OAuth2ErrorCodes.INVALID_REQUEST,
- "OpenID Client Registration Error: " + ex.getMessage(),
- "https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError");
- throw new OAuth2AuthenticationException(error);
- }
+ return new OidcClientRegistrationAuthenticationToken(principal, clientId);
}
private void sendClientRegistrationResponse(HttpServletResponse response, HttpStatus httpStatus, OidcClientRegistration clientRegistration) throws IOException {
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java
index 447cd534..92d1ade0 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java
@@ -18,17 +18,16 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
-import java.util.stream.Collectors;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
-
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
@@ -138,28 +137,6 @@ public class OidcClientRegistrationTests {
public void requestWhenClientRegistrationRequestAuthorizedThenClientRegistrationResponse() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
- // ***** (1) Obtain the "initial" access token used for registering the client
-
- String clientRegistrationScope = "client.create";
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient2()
- .scope(clientRegistrationScope)
- .build();
- this.registeredClientRepository.save(registeredClient);
-
- MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
- .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
- .param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
- .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
- registeredClient.getClientId(), registeredClient.getClientSecret())))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.access_token").isNotEmpty())
- .andExpect(jsonPath("$.scope").value(clientRegistrationScope))
- .andReturn();
-
- OAuth2AccessToken accessToken = readAccessTokenResponse(mvcResult.getResponse()).getAccessToken();
-
- // ***** (2) Register the client
-
// @formatter:off
OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
.clientName("client-name")
@@ -171,20 +148,8 @@ public class OidcClientRegistrationTests {
.build();
// @formatter:on
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.setBearerAuth(accessToken.getTokenValue());
-
- // Register the client
- mvcResult = this.mvc.perform(post(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
- .headers(httpHeaders)
- .contentType(MediaType.APPLICATION_JSON)
- .content(getClientRegistrationRequestContent(clientRegistration)))
- .andExpect(status().isCreated())
- .andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
- .andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
- .andReturn();
+ OidcClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
- OidcClientRegistration clientRegistrationResponse = readClientRegistrationResponse(mvcResult.getResponse());
assertThat(clientRegistrationResponse.getClientId()).isNotNull();
assertThat(clientRegistrationResponse.getClientIdIssuedAt()).isNotNull();
assertThat(clientRegistrationResponse.getClientSecret()).isNotNull();
@@ -202,181 +167,75 @@ public class OidcClientRegistrationTests {
.isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue());
assertThat(clientRegistrationResponse.getIdTokenSignedResponseAlgorithm())
.isEqualTo(SignatureAlgorithm.RS256.getName());
- assertThat(clientRegistrationResponse.getRegistrationClientUri())
- .isNotNull();
+ assertThat(clientRegistrationResponse.getRegistrationClientUrl()).isNotNull();
assertThat(clientRegistrationResponse.getRegistrationAccessToken()).isNotEmpty();
}
- @Test
- public void requestWhenClientConfigurationRequestAndRegisteredClientNotEqualToAuthorizationRegisteredClientThenUnauthorized() throws Exception {
- this.spring.register(AuthorizationServerConfiguration.class).autowire();
-
- // ***** (1) Obtain the registration access token used for fetching the registered client configuration
-
- String clientConfigurationRequestScope = "client.read";
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
- .scope(clientConfigurationRequestScope)
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
- .build();
- this.registeredClientRepository.save(registeredClient);
-
- RegisteredClient unauthorizedRegisteredClient = TestRegisteredClients.registeredClient()
- .id("registration-2")
- .clientId("client-2")
- .scope(clientConfigurationRequestScope)
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
- .build();
- this.registeredClientRepository.save(unauthorizedRegisteredClient);
-
- MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
- .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
- .param(OAuth2ParameterNames.SCOPE, clientConfigurationRequestScope)
- .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
- registeredClient.getClientId(), registeredClient.getClientSecret())))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.access_token").isNotEmpty())
- .andExpect(jsonPath("$.scope").value(clientConfigurationRequestScope))
- .andReturn();
-
- OAuth2AccessToken accessToken = readAccessTokenResponse(mvcResult.getResponse()).getAccessToken();
-
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.setBearerAuth(accessToken.getTokenValue());
-
- // ***** (2) Get RegisteredClient Configuration
- this.mvc.perform(get(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
- .headers(httpHeaders)
- .queryParam(OAuth2ParameterNames.CLIENT_ID, unauthorizedRegisteredClient.getClientId()))
- .andExpect(status().isUnauthorized());
- }
-
@Test
public void requestWhenClientConfigurationRequestAuthorizedThenClientRegistrationResponse() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
- // ***** (1) Obtain the registration access token used for fetching the registered client configuration
-
- String clientConfigurationRequestScope = "client.read";
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
- .scope(clientConfigurationRequestScope)
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
+ // @formatter:off
+ OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
+ .clientName("client-name")
+ .redirectUri("https://client.example.com")
+ .grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
+ .grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
+ .scope("scope1")
+ .scope("scope2")
.build();
- this.registeredClientRepository.save(registeredClient);
-
- MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
- .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
- .param(OAuth2ParameterNames.SCOPE, clientConfigurationRequestScope)
- .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
- registeredClient.getClientId(), registeredClient.getClientSecret())))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.access_token").isNotEmpty())
- .andExpect(jsonPath("$.scope").value(clientConfigurationRequestScope))
- .andReturn();
+ // @formatter:on
- OAuth2AccessToken accessToken = readAccessTokenResponse(mvcResult.getResponse()).getAccessToken();
+ OidcClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.setBearerAuth(accessToken.getTokenValue());
+ httpHeaders.setBearerAuth(clientRegistrationResponse.getRegistrationAccessToken());
- // ***** (2) Get RegisteredClient Configuration
- mvcResult = this.mvc.perform(get(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
- .headers(httpHeaders)
- .queryParam(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()))
+ MvcResult mvcResult = this.mvc.perform(get(clientRegistrationResponse.getRegistrationClientUrl().toURI())
+ .headers(httpHeaders))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andReturn();
OidcClientRegistration clientConfigurationResponse = readClientRegistrationResponse(mvcResult.getResponse());
- assertThat(clientConfigurationResponse.getClientId()).isNotNull().isEqualTo(registeredClient.getClientId());
- assertThat(clientConfigurationResponse.getClientIdIssuedAt()).isNotNull();
- assertThat(clientConfigurationResponse.getClientSecret()).isNotNull().isEqualTo(registeredClient.getClientSecret());
- assertThat(clientConfigurationResponse.getClientSecretExpiresAt()).isNull();
- assertThat(clientConfigurationResponse.getClientName()).isEqualTo(registeredClient.getClientName());
+
+ assertThat(clientConfigurationResponse.getClientId()).isEqualTo(clientRegistrationResponse.getClientId());
+ assertThat(clientConfigurationResponse.getClientIdIssuedAt()).isEqualTo(clientRegistrationResponse.getClientIdIssuedAt());
+ assertThat(clientConfigurationResponse.getClientSecret()).isEqualTo(clientRegistrationResponse.getClientSecret());
+ assertThat(clientConfigurationResponse.getClientSecretExpiresAt()).isEqualTo(clientRegistrationResponse.getClientSecretExpiresAt());
+ assertThat(clientConfigurationResponse.getClientName()).isEqualTo(clientRegistrationResponse.getClientName());
assertThat(clientConfigurationResponse.getRedirectUris())
- .containsExactlyInAnyOrderElementsOf(registeredClient.getRedirectUris());
+ .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getRedirectUris());
assertThat(clientConfigurationResponse.getGrantTypes())
- .containsExactlyInAnyOrderElementsOf(registeredClient.getAuthorizationGrantTypes().stream().map(AuthorizationGrantType::getValue).collect(Collectors.toList()));
+ .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getGrantTypes());
assertThat(clientConfigurationResponse.getResponseTypes())
- .containsExactly(OAuth2AuthorizationResponseType.CODE.getValue());
+ .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getResponseTypes());
assertThat(clientConfigurationResponse.getScopes())
- .containsExactlyInAnyOrderElementsOf(registeredClient.getScopes());
+ .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getScopes());
assertThat(clientConfigurationResponse.getTokenEndpointAuthenticationMethod())
- .isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue());
+ .isEqualTo(clientRegistrationResponse.getTokenEndpointAuthenticationMethod());
assertThat(clientConfigurationResponse.getIdTokenSignedResponseAlgorithm())
- .isEqualTo(SignatureAlgorithm.RS256.getName());
- assertThat(clientConfigurationResponse.getRegistrationClientUri())
- .isNotNull();
+ .isEqualTo(clientRegistrationResponse.getIdTokenSignedResponseAlgorithm());
+ assertThat(clientConfigurationResponse.getRegistrationClientUrl())
+ .isEqualTo(clientRegistrationResponse.getRegistrationClientUrl());
assertThat(clientConfigurationResponse.getRegistrationAccessToken()).isNull();
}
- @Test
- public void requestWhenClientConfigurationRequestTwiceSameAccessTokenAuthorizedThenClientRegistrationResponse() throws Exception {
- this.spring.register(AuthorizationServerConfiguration.class).autowire();
-
- // ***** (1) Obtain the registration access token used for fetching the registered client configuration
-
- String clientConfigurationRequestScope = "client.read";
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
- .scope(clientConfigurationRequestScope)
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
- .build();
- this.registeredClientRepository.save(registeredClient);
-
- MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
- .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
- .param(OAuth2ParameterNames.SCOPE, clientConfigurationRequestScope)
- .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
- registeredClient.getClientId(), registeredClient.getClientSecret())))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.access_token").isNotEmpty())
- .andExpect(jsonPath("$.scope").value(clientConfigurationRequestScope))
- .andReturn();
-
- OAuth2AccessToken accessToken = readAccessTokenResponse(mvcResult.getResponse()).getAccessToken();
-
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.setBearerAuth(accessToken.getTokenValue());
-
- // ***** (2) Get RegisteredClient Configuration
- mvcResult = this.mvc.perform(get(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
- .headers(httpHeaders)
- .queryParam(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()))
- .andExpect(status().isOk())
- .andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
- .andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
- .andReturn();
-
- assertClientConfigurationResponse(registeredClient, mvcResult);
-
- // ***** (3) Get RegisteredClient Configuration with the same access token
- mvcResult = this.mvc.perform(get(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
- .headers(httpHeaders)
- .queryParam(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()))
- .andExpect(status().isOk())
- .andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
- .andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
- .andReturn();
- assertClientConfigurationResponse(registeredClient, mvcResult);
- }
-
- @Test
- public void requestWhenClientRegistrationRequestAndClientConfigurationRequestAuthorizedThenClientRegistrationResponse() throws Exception {
- this.spring.register(AuthorizationServerConfiguration.class).autowire();
-
+ private OidcClientRegistration registerClient(OidcClientRegistration clientRegistration) throws Exception {
// ***** (1) Obtain the "initial" access token used for registering the client
String clientRegistrationScope = "client.create";
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient2()
+ RegisteredClient clientRegistrar = TestRegisteredClients.registeredClient2()
.scope(clientRegistrationScope)
.build();
- this.registeredClientRepository.save(registeredClient);
+ this.registeredClientRepository.save(clientRegistrar);
MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
- .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
- .param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
- .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
- registeredClient.getClientId(), registeredClient.getClientSecret())))
+ .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
+ .param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
+ .header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
+ clientRegistrar.getClientId(), clientRegistrar.getClientSecret())))
.andExpect(status().isOk())
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.scope").value(clientRegistrationScope))
@@ -386,93 +245,22 @@ public class OidcClientRegistrationTests {
// ***** (2) Register the client
- // @formatter:off
- OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
- .clientName("client-name")
- .redirectUri("https://client.example.com")
- .grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
- .grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
- .scope("scope1")
- .scope("scope2")
- .build();
- // @formatter:on
-
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setBearerAuth(accessToken.getTokenValue());
// Register the client
mvcResult = this.mvc.perform(post(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
- .headers(httpHeaders)
- .contentType(MediaType.APPLICATION_JSON)
- .content(getClientRegistrationRequestContent(clientRegistration)))
+ .headers(httpHeaders)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(getClientRegistrationRequestContent(clientRegistration)))
.andExpect(status().isCreated())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
.andReturn();
- OidcClientRegistration clientRegistrationResponse = readClientRegistrationResponse(mvcResult.getResponse());
-
-
- httpHeaders = new HttpHeaders();
- httpHeaders.setBearerAuth(clientRegistrationResponse.getRegistrationAccessToken());
-
- // ***** (3) Get RegisteredClient Configuration
- mvcResult = this.mvc.perform(get(clientRegistrationResponse.getRegistrationClientUri().toString())
- .headers(httpHeaders))
- .andExpect(status().isOk())
- .andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
- .andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
- .andReturn();
-
- OidcClientRegistration clientConfigurationResponse = readClientRegistrationResponse(mvcResult.getResponse());
- assertThat(clientConfigurationResponse.getClientId()).isNotNull().isEqualTo(clientRegistrationResponse.getClientId());
- assertThat(clientConfigurationResponse.getClientIdIssuedAt()).isNotNull();
- assertThat(clientConfigurationResponse.getClientSecret()).isNotNull().isEqualTo(clientRegistrationResponse.getClientSecret());
- assertThat(clientConfigurationResponse.getClientSecretExpiresAt()).isNull();
- assertThat(clientConfigurationResponse.getClientName()).isEqualTo(clientRegistrationResponse.getClientName());
- assertThat(clientConfigurationResponse.getRedirectUris())
- .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getRedirectUris());
- assertThat(clientConfigurationResponse.getGrantTypes())
- .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getGrantTypes());
- assertThat(clientConfigurationResponse.getResponseTypes())
- .containsExactly(OAuth2AuthorizationResponseType.CODE.getValue());
- assertThat(clientConfigurationResponse.getScopes())
- .containsExactlyInAnyOrderElementsOf(clientRegistrationResponse.getScopes());
- assertThat(clientConfigurationResponse.getTokenEndpointAuthenticationMethod())
- .isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue());
- assertThat(clientConfigurationResponse.getIdTokenSignedResponseAlgorithm())
- .isEqualTo(SignatureAlgorithm.RS256.getName());
- assertThat(clientConfigurationResponse.getRegistrationClientUri())
- .isNotNull();
- assertThat(clientConfigurationResponse.getRegistrationAccessToken()).isNull();
- }
-
- private static void assertClientConfigurationResponse(RegisteredClient registeredClient, MvcResult mvcResult) throws Exception {
- OidcClientRegistration clientConfigurationResponse;
- clientConfigurationResponse = readClientRegistrationResponse(mvcResult.getResponse());
- assertThat(clientConfigurationResponse.getClientId()).isNotNull().isEqualTo(registeredClient.getClientId());
- assertThat(clientConfigurationResponse.getClientIdIssuedAt()).isNotNull();
- assertThat(clientConfigurationResponse.getClientSecret()).isNotNull().isEqualTo(registeredClient.getClientSecret());
- assertThat(clientConfigurationResponse.getClientSecretExpiresAt()).isNull();
- assertThat(clientConfigurationResponse.getClientName()).isEqualTo(registeredClient.getClientName());
- assertThat(clientConfigurationResponse.getRedirectUris())
- .containsExactlyInAnyOrderElementsOf(registeredClient.getRedirectUris());
- assertThat(clientConfigurationResponse.getGrantTypes())
- .containsExactlyInAnyOrderElementsOf(registeredClient.getAuthorizationGrantTypes().stream().map(AuthorizationGrantType::getValue).collect(Collectors.toList()));
- assertThat(clientConfigurationResponse.getResponseTypes())
- .containsExactly(OAuth2AuthorizationResponseType.CODE.getValue());
- assertThat(clientConfigurationResponse.getScopes())
- .containsExactlyInAnyOrderElementsOf(registeredClient.getScopes());
- assertThat(clientConfigurationResponse.getTokenEndpointAuthenticationMethod())
- .isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue());
- assertThat(clientConfigurationResponse.getIdTokenSignedResponseAlgorithm())
- .isEqualTo(SignatureAlgorithm.RS256.getName());
- assertThat(clientConfigurationResponse.getRegistrationClientUri())
- .isNotNull();
- assertThat(clientConfigurationResponse.getRegistrationAccessToken()).isNull();
+ return readClientRegistrationResponse(mvcResult.getResponse());
}
-
private static String encodeBasicAuth(String clientId, String secret) throws Exception {
clientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8.name());
secret = URLEncoder.encode(secret, StandardCharsets.UTF_8.name());
@@ -552,8 +340,9 @@ public class OidcClientRegistrationTests {
@Bean
ProviderSettings providerSettings() {
- return ProviderSettings.builder().issuer("http://auth-server:9000")
- .oidcClientRegistrationEndpoint("/connect/register").build();
+ return ProviderSettings.builder()
+ .issuer("https://auth-server:9000")
+ .build();
}
@Bean
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistrationTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistrationTests.java
index 9f956229..02e04579 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistrationTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/OidcClientRegistrationTests.java
@@ -63,9 +63,9 @@ public class OidcClientRegistrationTests {
.scope("scope1")
.scope("scope2")
.idTokenSignedResponseAlgorithm(SignatureAlgorithm.RS256.getName())
- .claim("a-claim", "a-value")
.registrationAccessToken("registration-access-token")
- .registrationClientUri("https://auth-server.com/connect/register?client_id=1")
+ .registrationClientUrl("https://auth-server.com/connect/register?client_id=1")
+ .claim("a-claim", "a-value")
.build();
// @formatter:on
@@ -80,9 +80,9 @@ public class OidcClientRegistrationTests {
assertThat(clientRegistration.getResponseTypes()).containsOnly("code");
assertThat(clientRegistration.getScopes()).containsExactlyInAnyOrder("scope1", "scope2");
assertThat(clientRegistration.getIdTokenSignedResponseAlgorithm()).isEqualTo("RS256");
- assertThat(clientRegistration.getClaimAsString("a-claim")).isEqualTo("a-value");
assertThat(clientRegistration.getRegistrationAccessToken()).isEqualTo("registration-access-token");
- assertThat(clientRegistration.getRegistrationClientUri().toString()).isEqualTo("https://auth-server.com/connect/register?client_id=1");
+ assertThat(clientRegistration.getRegistrationClientUrl().toString()).isEqualTo("https://auth-server.com/connect/register?client_id=1");
+ assertThat(clientRegistration.getClaimAsString("a-claim")).isEqualTo("a-value");
}
@Test
@@ -108,9 +108,9 @@ public class OidcClientRegistrationTests {
claims.put(OidcClientMetadataClaimNames.RESPONSE_TYPES, Collections.singletonList("code"));
claims.put(OidcClientMetadataClaimNames.SCOPE, Arrays.asList("scope1", "scope2"));
claims.put(OidcClientMetadataClaimNames.ID_TOKEN_SIGNED_RESPONSE_ALG, SignatureAlgorithm.RS256.getName());
- claims.put("a-claim", "a-value");
claims.put(OidcClientMetadataClaimNames.REGISTRATION_ACCESS_TOKEN, "registration-access-token");
claims.put(OidcClientMetadataClaimNames.REGISTRATION_CLIENT_URI, "https://auth-server.com/connect/register?client_id=1");
+ claims.put("a-claim", "a-value");
OidcClientRegistration clientRegistration = OidcClientRegistration.withClaims(claims).build();
@@ -125,9 +125,9 @@ public class OidcClientRegistrationTests {
assertThat(clientRegistration.getResponseTypes()).containsOnly("code");
assertThat(clientRegistration.getScopes()).containsExactlyInAnyOrder("scope1", "scope2");
assertThat(clientRegistration.getIdTokenSignedResponseAlgorithm()).isEqualTo("RS256");
- assertThat(clientRegistration.getClaimAsString("a-claim")).isEqualTo("a-value");
assertThat(clientRegistration.getRegistrationAccessToken()).isEqualTo("registration-access-token");
- assertThat(clientRegistration.getRegistrationClientUri().toString()).isEqualTo("https://auth-server.com/connect/register?client_id=1");
+ assertThat(clientRegistration.getRegistrationClientUrl().toString()).isEqualTo("https://auth-server.com/connect/register?client_id=1");
+ assertThat(clientRegistration.getClaimAsString("a-claim")).isEqualTo("a-value");
}
@Test
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/http/converter/OidcClientRegistrationHttpMessageConverterTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/http/converter/OidcClientRegistrationHttpMessageConverterTests.java
index dc547e42..f63246b6 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/http/converter/OidcClientRegistrationHttpMessageConverterTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/core/oidc/http/converter/OidcClientRegistrationHttpMessageConverterTests.java
@@ -184,9 +184,9 @@ public class OidcClientRegistrationHttpMessageConverterTests {
.scope("scope1")
.scope("scope2")
.idTokenSignedResponseAlgorithm(SignatureAlgorithm.RS256.getName())
- .claim("a-claim", "a-value")
- .registrationClientUri("https://auth-server.com/connect/register?client_id=1")
.registrationAccessToken("registration-access-token")
+ .registrationClientUrl("https://auth-server.com/connect/register?client_id=1")
+ .claim("a-claim", "a-value")
.build();
// @formatter:on
@@ -205,9 +205,9 @@ public class OidcClientRegistrationHttpMessageConverterTests {
assertThat(clientRegistrationResponse).contains("\"response_types\":[\"code\"]");
assertThat(clientRegistrationResponse).contains("\"scope\":\"scope1 scope2\"");
assertThat(clientRegistrationResponse).contains("\"id_token_signed_response_alg\":\"RS256\"");
- assertThat(clientRegistrationResponse).contains("\"a-claim\":\"a-value\"");
assertThat(clientRegistrationResponse).contains("\"registration_access_token\":\"registration-access-token\"");
assertThat(clientRegistrationResponse).contains("\"registration_client_uri\":\"https://auth-server.com/connect/register?client_id=1\"");
+ assertThat(clientRegistrationResponse).contains("\"a-claim\":\"a-value\"");
}
@Test
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java
index 7c40d8ea..db9368dd 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java
@@ -16,13 +16,16 @@
package org.springframework.security.oauth2.server.authorization.oidc.authentication;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
@@ -57,6 +60,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -70,34 +74,32 @@ import static org.mockito.Mockito.when;
public class OidcClientRegistrationAuthenticationProviderTests {
private RegisteredClientRepository registeredClientRepository;
private OAuth2AuthorizationService authorizationService;
- private OidcClientRegistrationAuthenticationProvider authenticationProvider;
private JwtEncoder jwtEncoder;
private ProviderSettings providerSettings;
+ private OidcClientRegistrationAuthenticationProvider authenticationProvider;
@Before
public void setUp() {
-
this.registeredClientRepository = mock(RegisteredClientRepository.class);
this.authorizationService = mock(OAuth2AuthorizationService.class);
this.jwtEncoder = mock(JwtEncoder.class);
- this.providerSettings = ProviderSettings.builder().issuer("http://auth-server:9000").build();
+ this.providerSettings = ProviderSettings.builder().issuer("https://auth-server:9000").build();
this.authenticationProvider = new OidcClientRegistrationAuthenticationProvider(
- this.registeredClientRepository, this.authorizationService,
- this.jwtEncoder);
- this.authenticationProvider.setProviderSettings(providerSettings);
+ this.registeredClientRepository, this.authorizationService, this.jwtEncoder);
+ this.authenticationProvider.setProviderSettings(this.providerSettings);
}
@Test
public void constructorWhenRegisteredClientRepositoryNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> new OidcClientRegistrationAuthenticationProvider(null, this.authorizationService, jwtEncoder))
+ .isThrownBy(() -> new OidcClientRegistrationAuthenticationProvider(null, this.authorizationService, this.jwtEncoder))
.withMessage("registeredClientRepository cannot be null");
}
@Test
public void constructorWhenAuthorizationServiceNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> new OidcClientRegistrationAuthenticationProvider(this.registeredClientRepository, null, jwtEncoder))
+ .isThrownBy(() -> new OidcClientRegistrationAuthenticationProvider(this.registeredClientRepository, null, this.jwtEncoder))
.withMessage("authorizationService cannot be null");
}
@@ -114,13 +116,14 @@ public class OidcClientRegistrationAuthenticationProviderTests {
}
@Test
- public void authenticateWhenClientRegistrationRequestAndPrincipalNotOAuth2TokenAuthenticationTokenThenThrowOAuth2AuthenticationException() {
+ public void authenticateWhenPrincipalNotOAuth2TokenAuthenticationTokenThenThrowOAuth2AuthenticationException() {
TestingAuthenticationToken principal = new TestingAuthenticationToken("principal", "credentials");
OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
.redirectUri("https://client.example.com")
.build();
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -129,13 +132,14 @@ public class OidcClientRegistrationAuthenticationProviderTests {
}
@Test
- public void authenticateWhenClientRegistrationRequestAndPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
+ public void authenticateWhenPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
JwtAuthenticationToken principal = new JwtAuthenticationToken(createJwtClientRegistration());
OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
.redirectUri("https://client.example.com")
.build();
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -144,7 +148,7 @@ public class OidcClientRegistrationAuthenticationProviderTests {
}
@Test
- public void authenticateWhenClientRegistrationRequestAndAccessTokenNotFoundThenThrowOAuth2AuthenticationException() {
+ public void authenticateWhenAccessTokenNotFoundThenThrowOAuth2AuthenticationException() {
Jwt jwt = createJwtClientRegistration();
JwtAuthenticationToken principal = new JwtAuthenticationToken(
jwt, AuthorityUtils.createAuthorityList("SCOPE_client.create"));
@@ -152,7 +156,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.redirectUri("https://client.example.com")
.build();
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -163,7 +168,7 @@ public class OidcClientRegistrationAuthenticationProviderTests {
}
@Test
- public void authenticateWhenClientRegistrationRequestAndAccessTokenNotActiveThenThrowOAuth2AuthenticationException() {
+ public void authenticateWhenAccessTokenNotActiveThenThrowOAuth2AuthenticationException() {
Jwt jwt = createJwtClientRegistration();
OAuth2AccessToken jwtAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
jwt.getTokenValue(), jwt.getIssuedAt(),
@@ -182,7 +187,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.redirectUri("https://client.example.com")
.build();
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -211,7 +217,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.redirectUri("https://client.example.com")
.build();
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -221,6 +228,36 @@ public class OidcClientRegistrationAuthenticationProviderTests {
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN));
}
+ @Test
+ public void authenticateWhenClientRegistrationRequestAndAccessTokenContainsRequiredScopeAndAdditionalScopeThenThrowOAuth2AuthenticationException() {
+ Jwt jwt = createJwt(new HashSet<>(Arrays.asList("client.create", "scope1")));
+ OAuth2AccessToken jwtAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
+ jwt.getTokenValue(), jwt.getIssuedAt(),
+ jwt.getExpiresAt(), jwt.getClaim(OAuth2ParameterNames.SCOPE));
+ RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
+ OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
+ registeredClient, jwtAccessToken, jwt.getClaims()).build();
+ when(this.authorizationService.findByToken(
+ eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)))
+ .thenReturn(authorization);
+
+ JwtAuthenticationToken principal = new JwtAuthenticationToken(
+ jwt, AuthorityUtils.createAuthorityList("SCOPE_client.create", "SCOPE_scope1"));
+ OidcClientRegistration clientRegistration = OidcClientRegistration.builder()
+ .redirectUri("https://client.example.com")
+ .build();
+
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
+
+ assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
+ .isInstanceOf(OAuth2AuthenticationException.class)
+ .extracting(ex -> ((OAuth2AuthenticationException) ex).getError()).extracting("errorCode")
+ .isEqualTo(OAuth2ErrorCodes.INVALID_TOKEN);
+ verify(this.authorizationService).findByToken(
+ eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN));
+ }
+
@Test
public void authenticateWhenClientRegistrationRequestAndInvalidRedirectUriThenThrowOAuth2AuthenticationException() {
Jwt jwt = createJwtClientRegistration();
@@ -242,7 +279,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.build();
// @formatter:on
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -273,7 +311,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.build();
// @formatter:on
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -295,7 +334,7 @@ public class OidcClientRegistrationAuthenticationProviderTests {
when(this.authorizationService.findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)))
.thenReturn(authorization);
- when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt(Collections.singleton("client.read")));
+ when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwtClientConfiguration());
JwtAuthenticationToken principal = new JwtAuthenticationToken(
jwt, AuthorityUtils.createAuthorityList("SCOPE_client.create"));
@@ -310,7 +349,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.build();
// @formatter:on
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, clientRegistration);
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, clientRegistration);
OidcClientRegistrationAuthenticationToken authenticationResult =
(OidcClientRegistrationAuthenticationToken) this.authenticationProvider.authenticate(authentication);
@@ -323,20 +363,20 @@ public class OidcClientRegistrationAuthenticationProviderTests {
verify(this.authorizationService, times(2)).save(authorizationCaptor.capture());
verify(this.jwtEncoder).encode(any(), any());
- // assert access token
+ // assert "registration" access token, which should be used for subsequent calls to client configuration endpoint
OAuth2Authorization authorizationResult = authorizationCaptor.getAllValues().get(0);
+ assertThat(authorizationResult.getAccessToken().getToken().getScopes())
+ .containsExactly("client.read");
+ assertThat(authorizationResult.getAccessToken().isActive()).isTrue();
+ assertThat(authorizationResult.getRefreshToken()).isNull();
+
+ // assert "initial" access token is invalidated
+ authorizationResult = authorizationCaptor.getAllValues().get(1);
assertThat(authorizationResult.getAccessToken().isInvalidated()).isTrue();
if (authorizationResult.getRefreshToken() != null) {
assertThat(authorizationResult.getRefreshToken().isInvalidated()).isTrue();
}
- // assert registration access token which should be used for subsequent calls to client configuration endpoint
- authorizationResult = authorizationCaptor.getAllValues().get(1);
- assertThat(authorizationResult.getAccessToken().isInvalidated()).isFalse();
- assertThat(authorizationResult.getRefreshToken()).isNull();
- assertThat(authorizationResult.getAccessToken().getToken().getScopes())
- .containsExactly("client.read");
-
RegisteredClient registeredClientResult = registeredClientCaptor.getValue();
assertThat(registeredClientResult.getId()).isNotNull();
assertThat(registeredClientResult.getClientId()).isNotNull();
@@ -375,84 +415,44 @@ public class OidcClientRegistrationAuthenticationProviderTests {
assertThat(clientRegistrationResult.getIdTokenSignedResponseAlgorithm())
.isEqualTo(registeredClientResult.getTokenSettings().getIdTokenSignatureAlgorithm().getName());
- String expectedRegistrationClientUri = UriComponentsBuilder.fromUriString(this.providerSettings.getIssuer())
+ String expectedRegistrationClientUrl = UriComponentsBuilder.fromUriString(this.providerSettings.getIssuer())
.path(this.providerSettings.getOidcClientRegistrationEndpoint())
- .queryParam("client_id", registeredClientResult.getClientId()).toUriString();
-
- assertThat(clientRegistrationResult.getRegistrationClientUri().toString()).isEqualTo(expectedRegistrationClientUri);
- assertThat(clientRegistrationResult.getRegistrationAccessToken()).isNotEmpty().isEqualTo(jwt.getTokenValue());
- }
-
- @Test
- public void authenticateWhenClientConfigurationRequestAndPrincipalNotOAuth2TokenAuthenticationTokenThenThrowOAuth2AuthenticationException() {
- TestingAuthenticationToken principal = new TestingAuthenticationToken("principal", "credentials");
-
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, "client-1");
-
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
- .isInstanceOf(OAuth2AuthenticationException.class)
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError()).extracting("errorCode")
- .isEqualTo(OAuth2ErrorCodes.INVALID_TOKEN);
- }
+ .queryParam(OAuth2ParameterNames.CLIENT_ID, registeredClientResult.getClientId()).toUriString();
- @Test
- public void authenticateWhenClientConfigurationRequestAndPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
- JwtAuthenticationToken principal = new JwtAuthenticationToken(createJwtClientConfiguration());
-
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, "client-1");
-
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
- .isInstanceOf(OAuth2AuthenticationException.class)
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError()).extracting("errorCode")
- .isEqualTo(OAuth2ErrorCodes.INVALID_TOKEN);
- }
-
- @Test
- public void authenticateWhenClientConfigurationRequestAndAccessTokenNotFoundThenThrowOAuth2AuthenticationException() {
- Jwt jwt = createJwtClientConfiguration();
- JwtAuthenticationToken principal = new JwtAuthenticationToken(
- jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
-
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, "client-1");
-
- assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
- .isInstanceOf(OAuth2AuthenticationException.class)
- .extracting(ex -> ((OAuth2AuthenticationException) ex).getError()).extracting("errorCode")
- .isEqualTo(OAuth2ErrorCodes.INVALID_TOKEN);
- verify(this.authorizationService).findByToken(
- eq(jwt.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN));
+ assertThat(clientRegistrationResult.getRegistrationClientUrl().toString()).isEqualTo(expectedRegistrationClientUrl);
+ assertThat(clientRegistrationResult.getRegistrationAccessToken()).isEqualTo(jwt.getTokenValue());
}
@Test
- public void authenticateWhenClientConfigurationRequestAndAccessTokenNotActiveThenThrowOAuth2AuthenticationException() {
- Jwt jwt = createJwtClientConfiguration();
+ public void authenticateWhenClientConfigurationRequestAndAccessTokenNotAuthorizedThenThrowOAuth2AuthenticationException() {
+ Jwt jwt = createJwt(Collections.singleton("unauthorized.scope"));
OAuth2AccessToken jwtAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
jwt.getTokenValue(), jwt.getIssuedAt(),
jwt.getExpiresAt(), jwt.getClaim(OAuth2ParameterNames.SCOPE));
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
registeredClient, jwtAccessToken, jwt.getClaims()).build();
- authorization = OidcAuthenticationProviderUtils.invalidate(authorization, jwtAccessToken);
when(this.authorizationService.findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)))
.thenReturn(authorization);
JwtAuthenticationToken principal = new JwtAuthenticationToken(
- jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
+ jwt, AuthorityUtils.createAuthorityList("SCOPE_unauthorized.scope"));
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, "client-1");
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, registeredClient.getClientId());
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError()).extracting("errorCode")
- .isEqualTo(OAuth2ErrorCodes.INVALID_TOKEN);
+ .isEqualTo(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);
verify(this.authorizationService).findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN));
}
@Test
- public void authenticateWhenClientConfigurationRequestAndAccessTokenNotAuthorizedThenThrowOAuth2AuthenticationException() {
- Jwt jwt = createJwt(Collections.singleton("unauthorized.scope"));
+ public void authenticateWhenClientConfigurationRequestAndAccessTokenContainsRequiredScopeAndAdditionalScopeThenThrowOAuth2AuthenticationException() {
+ Jwt jwt = createJwt(new HashSet<>(Arrays.asList("client.read", "scope1")));
OAuth2AccessToken jwtAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
jwt.getTokenValue(), jwt.getIssuedAt(),
jwt.getExpiresAt(), jwt.getClaim(OAuth2ParameterNames.SCOPE));
@@ -464,14 +464,15 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.thenReturn(authorization);
JwtAuthenticationToken principal = new JwtAuthenticationToken(
- jwt, AuthorityUtils.createAuthorityList("SCOPE_unauthorized.scope"));
+ jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read", "SCOPE_scope1"));
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, registeredClient.getClientId());
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, registeredClient.getClientId());
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError()).extracting("errorCode")
- .isEqualTo(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);
+ .isEqualTo(OAuth2ErrorCodes.INVALID_TOKEN);
verify(this.authorizationService).findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN));
}
@@ -482,21 +483,18 @@ public class OidcClientRegistrationAuthenticationProviderTests {
OAuth2AccessToken jwtAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
jwt.getTokenValue(), jwt.getIssuedAt(),
jwt.getExpiresAt(), jwt.getClaim(OAuth2ParameterNames.SCOPE));
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
- .build();
+ RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
registeredClient, jwtAccessToken, jwt.getClaims()).build();
when(this.authorizationService.findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)))
.thenReturn(authorization);
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
- .thenReturn(null);
-
JwtAuthenticationToken principal = new JwtAuthenticationToken(
jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, registeredClient.getClientId());
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, registeredClient.getClientId());
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -509,30 +507,27 @@ public class OidcClientRegistrationAuthenticationProviderTests {
}
@Test
- public void authenticateWhenClientConfigurationRequestRegisteredClientNotEqualToAuthorizationRegisteredClientThenThrowOAuth2AuthenticationException() {
+ public void authenticateWhenClientConfigurationRequestClientIdNotEqualToAuthorizedClientThenThrowOAuth2AuthenticationException() {
Jwt jwt = createJwtClientConfiguration();
OAuth2AccessToken jwtAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
jwt.getTokenValue(), jwt.getIssuedAt(),
jwt.getExpiresAt(), jwt.getClaim(OAuth2ParameterNames.SCOPE));
-
- RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
- .id("registration-1").clientId("client-1").build();
- RegisteredClient authorizationRegisteredClient = TestRegisteredClients.registeredClient()
+ RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
+ RegisteredClient authorizedRegisteredClient = TestRegisteredClients.registeredClient()
.id("registration-2").clientId("client-2").build();
-
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(
- authorizationRegisteredClient, jwtAccessToken, jwt.getClaims()).build();
+ authorizedRegisteredClient, jwtAccessToken, jwt.getClaims()).build();
when(this.authorizationService.findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)))
.thenReturn(authorization);
-
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
.thenReturn(registeredClient);
JwtAuthenticationToken principal = new JwtAuthenticationToken(
jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
- OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(principal, registeredClient.getClientId());
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, registeredClient.getClientId());
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -558,15 +553,14 @@ public class OidcClientRegistrationAuthenticationProviderTests {
when(this.authorizationService.findByToken(
eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)))
.thenReturn(authorization);
+ when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
+ .thenReturn(registeredClient);
JwtAuthenticationToken principal = new JwtAuthenticationToken(
jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
- when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
- .thenReturn(registeredClient);
-
- OidcClientRegistrationAuthenticationToken authentication =
- new OidcClientRegistrationAuthenticationToken(principal, registeredClient.getClientId());
+ OidcClientRegistrationAuthenticationToken authentication = new OidcClientRegistrationAuthenticationToken(
+ principal, registeredClient.getClientId());
OidcClientRegistrationAuthenticationToken authenticationResult =
(OidcClientRegistrationAuthenticationToken) this.authenticationProvider.authenticate(authentication);
@@ -576,8 +570,8 @@ public class OidcClientRegistrationAuthenticationProviderTests {
verify(this.registeredClientRepository).findByClientId(
eq(registeredClient.getClientId()));
- // verify that the registration access token is not invalidated after its used
- verify(this.authorizationService, times(0)).save(eq(authorization));
+ // verify that the "registration" access token is not invalidated after it is used
+ verify(this.authorizationService, never()).save(eq(authorization));
assertThat(authorization.getAccessToken().isInvalidated()).isFalse();
OidcClientRegistration clientRegistrationResult = authenticationResult.getClientRegistration();
@@ -602,10 +596,12 @@ public class OidcClientRegistrationAuthenticationProviderTests {
.isEqualTo(registeredClient.getClientAuthenticationMethods().iterator().next().getValue());
assertThat(clientRegistrationResult.getIdTokenSignedResponseAlgorithm())
.isEqualTo(registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm().getName());
- String expectedRegistrationClientUri = UriComponentsBuilder.fromUriString(this.providerSettings.getIssuer())
+
+ String expectedRegistrationClientUrl = UriComponentsBuilder.fromUriString(this.providerSettings.getIssuer())
.path(this.providerSettings.getOidcClientRegistrationEndpoint())
- .queryParam("client_id", registeredClient.getClientId()).toUriString();
- assertThat(clientRegistrationResult.getRegistrationClientUri().toString()).isEqualTo(expectedRegistrationClientUri);
+ .queryParam(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId()).toUriString();
+
+ assertThat(clientRegistrationResult.getRegistrationClientUrl().toString()).isEqualTo(expectedRegistrationClientUrl);
assertThat(clientRegistrationResult.getRegistrationAccessToken()).isNull();
}
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationTokenTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationTokenTests.java
index 948baaa2..7d1f83f6 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationTokenTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationTokenTests.java
@@ -51,14 +51,14 @@ public class OidcClientRegistrationAuthenticationTokenTests {
public void constructorWhenClientIdNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new OidcClientRegistrationAuthenticationToken(this.principal, (String) null))
- .withMessage("clientId cannot be null or empty");
+ .withMessage("clientId cannot be empty");
}
@Test
public void constructorWhenClientIdEmptyThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new OidcClientRegistrationAuthenticationToken(this.principal, ""))
- .withMessage("clientId cannot be null or empty");
+ .withMessage("clientId cannot be empty");
}
@Test
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java
index 3e2ed014..9bb78136 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java
@@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.mock.http.client.MockClientHttpRequest;
@@ -219,8 +220,8 @@ public class OidcClientRegistrationEndpointFilterTests {
.tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
.responseType(OAuth2AuthorizationResponseType.CODE.getValue())
.idTokenSignedResponseAlgorithm(SignatureAlgorithm.RS256.getName())
- .registrationClientUri("http://auth-server:9000/connect/register?client_id=client-id")
.registrationAccessToken("registration-access-token")
+ .registrationClientUrl("https://auth-server:9000/connect/register?client_id=client-id")
.build();
// @formatter:on
@@ -270,23 +271,10 @@ public class OidcClientRegistrationEndpointFilterTests {
.isEqualTo(expectedClientRegistrationResponse.getTokenEndpointAuthenticationMethod());
assertThat(clientRegistrationResponse.getIdTokenSignedResponseAlgorithm())
.isEqualTo(expectedClientRegistrationResponse.getIdTokenSignedResponseAlgorithm());
- assertThat(clientRegistrationResponse.getRegistrationClientUri())
- .isEqualTo(expectedClientRegistrationResponse.getRegistrationClientUri());
assertThat(clientRegistrationResponse.getRegistrationAccessToken())
.isEqualTo(expectedClientRegistrationResponse.getRegistrationAccessToken());
- }
-
- @Test
- public void doFilterWhenNotClientConfigurationRequestThenNotProcessed() throws Exception {
- String requestUri = "/path";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- MockHttpServletResponse response = new MockHttpServletResponse();
- FilterChain filterChain = mock(FilterChain.class);
-
- this.filter.doFilter(request, response, filterChain);
-
- verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
+ assertThat(clientRegistrationResponse.getRegistrationClientUrl())
+ .isEqualTo(expectedClientRegistrationResponse.getRegistrationClientUrl());
}
@Test
@@ -330,7 +318,7 @@ public class OidcClientRegistrationEndpointFilterTests {
}
@Test
- public void doFilterWhenClientConfigurationRequestMultipleClientIdParametersThenInvalidClientError() throws Exception {
+ public void doFilterWhenClientConfigurationRequestMultipleClientIdThenInvalidRequestError() throws Exception {
String requestUri = DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
@@ -340,10 +328,11 @@ public class OidcClientRegistrationEndpointFilterTests {
FilterChain filterChain = mock(FilterChain.class);
this.filter.doFilter(request, response, filterChain);
+
verifyNoInteractions(filterChain);
- assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
OAuth2Error error = readError(response);
- assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
+ assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
}
@Test
@@ -353,7 +342,7 @@ public class OidcClientRegistrationEndpointFilterTests {
}
@Test
- public void doFilterWhenClientConfigurationRequestInsufficientTokenScopeThenForbiddenError() throws Exception {
+ public void doFilterWhenClientConfigurationRequestInsufficientScopeThenForbiddenError() throws Exception {
doFilterWhenClientConfigurationRequestInvalidThenError(
OAuth2ErrorCodes.INSUFFICIENT_SCOPE, HttpStatus.FORBIDDEN);
}
@@ -364,6 +353,35 @@ public class OidcClientRegistrationEndpointFilterTests {
OAuth2ErrorCodes.INVALID_CLIENT, HttpStatus.UNAUTHORIZED);
}
+ private void doFilterWhenClientConfigurationRequestInvalidThenError(
+ String errorCode, HttpStatus status) throws Exception {
+ Jwt jwt = createJwt("client.read");
+ JwtAuthenticationToken principal = new JwtAuthenticationToken(
+ jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
+
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ securityContext.setAuthentication(principal);
+ SecurityContextHolder.setContext(securityContext);
+
+ when(this.authenticationManager.authenticate(any()))
+ .thenThrow(new OAuth2AuthenticationException(errorCode));
+
+ String requestUri = DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI;
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
+ request.setServletPath(requestUri);
+ request.setParameter(OAuth2ParameterNames.CLIENT_ID, "client1");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ FilterChain filterChain = mock(FilterChain.class);
+
+ this.filter.doFilter(request, response, filterChain);
+
+ verifyNoInteractions(filterChain);
+
+ assertThat(response.getStatus()).isEqualTo(status.value());
+ OAuth2Error error = readError(response);
+ assertThat(error.getErrorCode()).isEqualTo(errorCode);
+ }
+
@Test
public void doFilterWhenClientConfigurationRequestValidThenSuccessResponse() throws Exception {
// @formatter:off
@@ -380,7 +398,7 @@ public class OidcClientRegistrationEndpointFilterTests {
.idTokenSignedResponseAlgorithm(SignatureAlgorithm.RS256.getName())
.scope("scope1")
.scope("scope2")
- .registrationClientUri("http://auth-server:9000/connect/register?client_id=client-id")
+ .registrationClientUrl("https://auth-server:9000/connect/register?client_id=client-id")
.build();
// @formatter:on
@@ -400,7 +418,7 @@ public class OidcClientRegistrationEndpointFilterTests {
String requestUri = DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
- request.setParameter(OAuth2ParameterNames.CLIENT_ID, "client-id");
+ request.setParameter(OAuth2ParameterNames.CLIENT_ID, expectedClientRegistrationResponse.getClientId());
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
@@ -430,38 +448,8 @@ public class OidcClientRegistrationEndpointFilterTests {
.isEqualTo(expectedClientRegistrationResponse.getTokenEndpointAuthenticationMethod());
assertThat(clientRegistrationResponse.getIdTokenSignedResponseAlgorithm())
.isEqualTo(expectedClientRegistrationResponse.getIdTokenSignedResponseAlgorithm());
- assertThat(clientRegistrationResponse.getRegistrationClientUri())
- .isEqualTo(expectedClientRegistrationResponse.getRegistrationClientUri());
- }
-
-
- private void doFilterWhenClientConfigurationRequestInvalidThenError(
- String errorCode, HttpStatus status) throws Exception {
- Jwt jwt = createJwt("client.read");
- JwtAuthenticationToken principal = new JwtAuthenticationToken(
- jwt, AuthorityUtils.createAuthorityList("SCOPE_client.read"));
-
- SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
- securityContext.setAuthentication(principal);
- SecurityContextHolder.setContext(securityContext);
-
- when(this.authenticationManager.authenticate(any()))
- .thenThrow(new OAuth2AuthenticationException(errorCode));
-
- String requestUri = DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI;
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.setParameter(OAuth2ParameterNames.CLIENT_ID, "client1");
- MockHttpServletResponse response = new MockHttpServletResponse();
- FilterChain filterChain = mock(FilterChain.class);
-
- this.filter.doFilter(request, response, filterChain);
-
- verifyNoInteractions(filterChain);
-
- assertThat(response.getStatus()).isEqualTo(status.value());
- OAuth2Error error = readError(response);
- assertThat(error.getErrorCode()).isEqualTo(errorCode);
+ assertThat(clientRegistrationResponse.getRegistrationClientUrl())
+ .isEqualTo(expectedClientRegistrationResponse.getRegistrationClientUrl());
}
private OAuth2Error readError(MockHttpServletResponse response) throws Exception {