ClientRegistration contains Provider Configuration Metadata
Fixes gh-5540
This commit is contained in:
parent
c60fcf263e
commit
057587ef29
|
@ -24,7 +24,9 @@ import org.springframework.util.StringUtils;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -153,6 +155,7 @@ public final class ClientRegistration {
|
|||
private String tokenUri;
|
||||
private UserInfoEndpoint userInfoEndpoint = new UserInfoEndpoint();
|
||||
private String jwkSetUri;
|
||||
private Map<String, Object> configurationMetadata = Collections.emptyMap();
|
||||
|
||||
private ProviderDetails() {
|
||||
}
|
||||
|
@ -193,6 +196,16 @@ public final class ClientRegistration {
|
|||
return this.jwkSetUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Map} of the metadata describing the provider's configuration.
|
||||
*
|
||||
* @since 5.1
|
||||
* @return a {@code Map} of the metadata describing the provider's configuration
|
||||
*/
|
||||
public Map<String, Object> getConfigurationMetadata() {
|
||||
return this.configurationMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Details of the UserInfo Endpoint.
|
||||
*/
|
||||
|
@ -262,6 +275,7 @@ public final class ClientRegistration {
|
|||
private AuthenticationMethod userInfoAuthenticationMethod = AuthenticationMethod.HEADER;
|
||||
private String userNameAttributeName;
|
||||
private String jwkSetUri;
|
||||
private Map<String, Object> configurationMetadata = Collections.emptyMap();
|
||||
private String clientName;
|
||||
|
||||
private Builder(String registrationId) {
|
||||
|
@ -430,6 +444,20 @@ public final class ClientRegistration {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the metadata describing the provider's configuration.
|
||||
*
|
||||
* @since 5.1
|
||||
* @param configurationMetadata the metadata describing the provider's configuration
|
||||
* @return the {@link Builder}
|
||||
*/
|
||||
public Builder providerConfigurationMetadata(Map<String, Object> configurationMetadata) {
|
||||
if (configurationMetadata != null) {
|
||||
this.configurationMetadata = new LinkedHashMap<>(configurationMetadata);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logical name of the client or registration.
|
||||
*
|
||||
|
@ -476,6 +504,7 @@ public final class ClientRegistration {
|
|||
providerDetails.userInfoEndpoint.authenticationMethod = this.userInfoAuthenticationMethod;
|
||||
providerDetails.userInfoEndpoint.userNameAttributeName = this.userNameAttributeName;
|
||||
providerDetails.jwkSetUri = this.jwkSetUri;
|
||||
providerDetails.configurationMetadata = Collections.unmodifiableMap(this.configurationMetadata);
|
||||
clientRegistration.providerDetails = providerDetails;
|
||||
|
||||
clientRegistration.clientName = StringUtils.hasText(this.clientName) ?
|
||||
|
|
|
@ -16,21 +16,22 @@
|
|||
|
||||
package org.springframework.security.oauth2.client.registration;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.GrantType;
|
||||
import com.nimbusds.oauth2.sdk.ParseException;
|
||||
import com.nimbusds.oauth2.sdk.Scope;
|
||||
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
|
||||
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Allows creating a {@link ClientRegistration.Builder} from an
|
||||
* <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig">OpenID Provider Configuration</a>.
|
||||
|
@ -83,6 +84,8 @@ public final class ClientRegistrations {
|
|||
throw new IllegalArgumentException("Only AuthorizationGrantType.AUTHORIZATION_CODE is supported. The issuer \"" + issuer + "\" returned a configuration of " + grantTypes);
|
||||
}
|
||||
List<String> scopes = getScopes(metadata);
|
||||
Map<String, Object> configurationMetadata = new LinkedHashMap<>(metadata.toJSONObject());
|
||||
|
||||
return ClientRegistration.withRegistrationId(name)
|
||||
.userNameAttributeName(IdTokenClaimNames.SUB)
|
||||
.scope(scopes)
|
||||
|
@ -91,6 +94,7 @@ public final class ClientRegistrations {
|
|||
.redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}")
|
||||
.authorizationUri(metadata.getAuthorizationEndpointURI().toASCIIString())
|
||||
.jwkSetUri(metadata.getJWKSetURI().toASCIIString())
|
||||
.providerConfigurationMetadata(configurationMetadata)
|
||||
.userInfoUri(metadata.getUserInfoEndpointURI().toASCIIString())
|
||||
.tokenUri(metadata.getTokenEndpointURI().toASCIIString())
|
||||
.clientName(issuer);
|
||||
|
|
|
@ -20,9 +20,12 @@ import org.springframework.security.oauth2.core.AuthenticationMethod;
|
|||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
@ -37,11 +40,21 @@ public class ClientRegistrationTests {
|
|||
private static final String CLIENT_ID = "client-1";
|
||||
private static final String CLIENT_SECRET = "secret";
|
||||
private static final String REDIRECT_URI = "https://example.com";
|
||||
private static final Set<String> SCOPES = new LinkedHashSet<>(Arrays.asList("openid", "profile", "email"));
|
||||
private static final Set<String> SCOPES = Collections.unmodifiableSet(
|
||||
Stream.of("openid", "profile", "email").collect(Collectors.toSet()));
|
||||
private static final String AUTHORIZATION_URI = "https://provider.com/oauth2/authorization";
|
||||
private static final String TOKEN_URI = "https://provider.com/oauth2/token";
|
||||
private static final String JWK_SET_URI = "https://provider.com/oauth2/keys";
|
||||
private static final String CLIENT_NAME = "Client 1";
|
||||
private static final Map<String, Object> PROVIDER_CONFIGURATION_METADATA =
|
||||
Collections.unmodifiableMap(createProviderConfigurationMetadata());
|
||||
|
||||
private static Map<String, Object> createProviderConfigurationMetadata() {
|
||||
Map<String, Object> configurationMetadata = new LinkedHashMap<>();
|
||||
configurationMetadata.put("config-1", "value-1");
|
||||
configurationMetadata.put("config-2", "value-2");
|
||||
return configurationMetadata;
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationGrantTypeIsNullThenThrowIllegalArgumentException() {
|
||||
|
@ -73,6 +86,7 @@ public class ClientRegistrationTests {
|
|||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.providerConfigurationMetadata(PROVIDER_CONFIGURATION_METADATA)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
|
||||
|
@ -87,6 +101,7 @@ public class ClientRegistrationTests {
|
|||
assertThat(registration.getProviderDetails().getTokenUri()).isEqualTo(TOKEN_URI);
|
||||
assertThat(registration.getProviderDetails().getUserInfoEndpoint().getAuthenticationMethod()).isEqualTo(AuthenticationMethod.FORM);
|
||||
assertThat(registration.getProviderDetails().getJwkSetUri()).isEqualTo(JWK_SET_URI);
|
||||
assertThat(registration.getProviderDetails().getConfigurationMetadata()).isEqualTo(PROVIDER_CONFIGURATION_METADATA);
|
||||
assertThat(registration.getClientName()).isEqualTo(CLIENT_NAME);
|
||||
}
|
||||
|
||||
|
@ -276,6 +291,46 @@ public class ClientRegistrationTests {
|
|||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantProviderConfigurationMetadataIsNullThenDefaultToEmpty() {
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUriTemplate(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.HEADER)
|
||||
.providerConfigurationMetadata(null)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isNotNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantProviderConfigurationMetadataEmptyThenIsEmpty() {
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUriTemplate(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.HEADER)
|
||||
.providerConfigurationMetadata(Collections.emptyMap())
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isNotNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenImplicitGrantAllAttributesProvidedThenAllAttributesAreSet() {
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
|
||||
package org.springframework.security.oauth2.client.registration;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
|
@ -26,12 +23,14 @@ import okhttp3.mockwebserver.MockWebServer;
|
|||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
@ -131,6 +130,10 @@ public class ClientRegistrationsTest {
|
|||
assertThat(provider.getAuthorizationUri()).isEqualTo("https://example.com/o/oauth2/v2/auth");
|
||||
assertThat(provider.getTokenUri()).isEqualTo("https://example.com/oauth2/v4/token");
|
||||
assertThat(provider.getJwkSetUri()).isEqualTo("https://example.com/oauth2/v3/certs");
|
||||
assertThat(provider.getConfigurationMetadata()).containsKeys("authorization_endpoint", "claims_supported",
|
||||
"code_challenge_methods_supported", "id_token_signing_alg_values_supported", "issuer", "jwks_uri",
|
||||
"response_types_supported", "revocation_endpoint", "scopes_supported", "subject_types_supported",
|
||||
"grant_types_supported", "token_endpoint", "token_endpoint_auth_methods_supported", "userinfo_endpoint");
|
||||
assertThat(provider.getUserInfoEndpoint().getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue