Add issuerUri to ClientRegistration.providerDetails
- Add "issuerUri" attribute to ClientRegistration.providerDetails for OpenID Connect Discovery 1.0 or OAuth 2.0 Authorization Server Metadata. - Validate OidcIdToken "iss" claim against the OpenID Provider "issuerUri" value. - Update documentation for client registration: it includes issuer-uri property now. Fixes gh-8326
This commit is contained in:
parent
db4ca1f756
commit
78fa859798
|
@ -42,6 +42,7 @@ public enum CommonOAuth2Provider {
|
|||
builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
|
||||
builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
|
||||
builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
|
||||
builder.issuerUri("https://accounts.google.com");
|
||||
builder.userNameAttributeName(IdTokenClaimNames.SUB);
|
||||
builder.clientName("Google");
|
||||
return builder;
|
||||
|
|
|
@ -165,6 +165,7 @@ public class ClientRegistrationsBeanDefinitionParserTests {
|
|||
.isEqualTo(AuthenticationMethod.HEADER);
|
||||
assertThat(googleProviderDetails.getUserInfoEndpoint().getUserNameAttributeName()).isEqualTo("sub");
|
||||
assertThat(googleProviderDetails.getJwkSetUri()).isEqualTo("https://example.com/oauth2/v3/certs");
|
||||
assertThat(googleProviderDetails.getIssuerUri()).isEqualTo(serverUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -195,6 +196,7 @@ public class ClientRegistrationsBeanDefinitionParserTests {
|
|||
.isEqualTo(AuthenticationMethod.HEADER);
|
||||
assertThat(googleProviderDetails.getUserInfoEndpoint().getUserNameAttributeName()).isEqualTo("sub");
|
||||
assertThat(googleProviderDetails.getJwkSetUri()).isEqualTo("https://www.googleapis.com/oauth2/v3/certs");
|
||||
assertThat(googleProviderDetails.getIssuerUri()).isEqualTo("https://accounts.google.com");
|
||||
|
||||
ClientRegistration githubRegistration = clientRegistrationRepository.findByRegistrationId("github-login");
|
||||
assertThat(githubRegistration).isNotNull();
|
||||
|
|
|
@ -137,9 +137,11 @@ The following table outlines the mapping of the Spring Boot 2.x OAuth Client pro
|
|||
|`spring.security.oauth2.client.provider._[providerId]_.user-info-authentication-method`
|
||||
|`providerDetails.userInfoEndpoint.authenticationMethod`
|
||||
|
||||
|
||||
|`spring.security.oauth2.client.provider._[providerId]_.user-name-attribute`
|
||||
|`providerDetails.userInfoEndpoint.userNameAttributeName`
|
||||
|
||||
|`spring.security.oauth2.client.provider._[providerId]_.issuer-uri`
|
||||
|`providerDetails.issuerUri`
|
||||
|===
|
||||
|
||||
[TIP]
|
||||
|
|
|
@ -69,8 +69,7 @@ public final class OidcIdTokenValidator implements OAuth2TokenValidator<Jwt> {
|
|||
|
||||
// 2. The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)
|
||||
// MUST exactly match the value of the iss (issuer) Claim.
|
||||
String metadataIssuer = (String) this.clientRegistration.getProviderDetails().getConfigurationMetadata()
|
||||
.get("issuer");
|
||||
String metadataIssuer = this.clientRegistration.getProviderDetails().getIssuerUri();
|
||||
|
||||
if (metadataIssuer != null && !Objects.equals(metadataIssuer, idToken.getIssuer().toExternalForm())) {
|
||||
invalidClaims.put(IdTokenClaimNames.ISS, idToken.getIssuer());
|
||||
|
|
|
@ -163,6 +163,7 @@ public final class ClientRegistration implements Serializable {
|
|||
private String tokenUri;
|
||||
private UserInfoEndpoint userInfoEndpoint = new UserInfoEndpoint();
|
||||
private String jwkSetUri;
|
||||
private String issuerUri;
|
||||
private Map<String, Object> configurationMetadata = Collections.emptyMap();
|
||||
|
||||
private ProviderDetails() {
|
||||
|
@ -204,6 +205,16 @@ public final class ClientRegistration implements Serializable {
|
|||
return this.jwkSetUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uri for the OpenID Provider Issuer.
|
||||
*
|
||||
* @since 5.4
|
||||
* @return the uri for the OpenID Provider Issuer
|
||||
*/
|
||||
public String getIssuerUri() {
|
||||
return this.issuerUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Map} of the metadata describing the provider's configuration.
|
||||
*
|
||||
|
@ -296,6 +307,7 @@ public final class ClientRegistration implements Serializable {
|
|||
private AuthenticationMethod userInfoAuthenticationMethod = AuthenticationMethod.HEADER;
|
||||
private String userNameAttributeName;
|
||||
private String jwkSetUri;
|
||||
private String issuerUri;
|
||||
private Map<String, Object> configurationMetadata = Collections.emptyMap();
|
||||
private String clientName;
|
||||
|
||||
|
@ -317,6 +329,7 @@ public final class ClientRegistration implements Serializable {
|
|||
this.userInfoAuthenticationMethod = clientRegistration.providerDetails.userInfoEndpoint.authenticationMethod;
|
||||
this.userNameAttributeName = clientRegistration.providerDetails.userInfoEndpoint.userNameAttributeName;
|
||||
this.jwkSetUri = clientRegistration.providerDetails.jwkSetUri;
|
||||
this.issuerUri = clientRegistration.providerDetails.issuerUri;
|
||||
Map<String, Object> configurationMetadata = clientRegistration.providerDetails.configurationMetadata;
|
||||
if (configurationMetadata != EMPTY_MAP) {
|
||||
this.configurationMetadata = new HashMap<>(configurationMetadata);
|
||||
|
@ -486,6 +499,17 @@ public final class ClientRegistration implements Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uri for the OpenID Provider Issuer.
|
||||
*
|
||||
* @param issuerUri the uri for the OpenID Provider Issuer
|
||||
* @return the {@link Builder}
|
||||
*/
|
||||
public Builder issuerUri(String issuerUri) {
|
||||
this.issuerUri = issuerUri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the metadata describing the provider's configuration.
|
||||
*
|
||||
|
@ -554,6 +578,7 @@ public final class ClientRegistration implements Serializable {
|
|||
providerDetails.userInfoEndpoint.authenticationMethod = this.userInfoAuthenticationMethod;
|
||||
providerDetails.userInfoEndpoint.userNameAttributeName = this.userNameAttributeName;
|
||||
providerDetails.jwkSetUri = this.jwkSetUri;
|
||||
providerDetails.issuerUri = this.issuerUri;
|
||||
providerDetails.configurationMetadata = Collections.unmodifiableMap(this.configurationMetadata);
|
||||
clientRegistration.providerDetails = providerDetails;
|
||||
|
||||
|
|
|
@ -248,6 +248,7 @@ public final class ClientRegistrations {
|
|||
.authorizationUri(metadata.getAuthorizationEndpointURI().toASCIIString())
|
||||
.providerConfigurationMetadata(configurationMetadata)
|
||||
.tokenUri(metadata.getTokenEndpointURI().toASCIIString())
|
||||
.issuerUri(issuer)
|
||||
.clientName(issuer);
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,8 @@ public class OAuth2AuthorizedClientMixinTests {
|
|||
.isEqualTo(expectedClientRegistration.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName());
|
||||
assertThat(clientRegistration.getProviderDetails().getJwkSetUri())
|
||||
.isEqualTo(expectedClientRegistration.getProviderDetails().getJwkSetUri());
|
||||
assertThat(clientRegistration.getProviderDetails().getIssuerUri())
|
||||
.isEqualTo(expectedClientRegistration.getProviderDetails().getIssuerUri());
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata())
|
||||
.containsExactlyEntriesOf(clientRegistration.getProviderDetails().getConfigurationMetadata());
|
||||
assertThat(clientRegistration.getClientName())
|
||||
|
@ -203,6 +205,7 @@ public class OAuth2AuthorizedClientMixinTests {
|
|||
.isEqualTo(expectedClientRegistration.getProviderDetails().getUserInfoEndpoint().getAuthenticationMethod());
|
||||
assertThat(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName()).isNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getJwkSetUri()).isNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getIssuerUri()).isNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isEmpty();
|
||||
assertThat(clientRegistration.getClientName())
|
||||
.isEqualTo(clientRegistration.getRegistrationId());
|
||||
|
@ -276,6 +279,7 @@ public class OAuth2AuthorizedClientMixinTests {
|
|||
" \"userNameAttributeName\": " + (userInfoEndpoint.getUserNameAttributeName() != null ? "\"" + userInfoEndpoint.getUserNameAttributeName() + "\"" : null) + "\n" +
|
||||
" },\n" +
|
||||
" \"jwkSetUri\": " + (providerDetails.getJwkSetUri() != null ? "\"" + providerDetails.getJwkSetUri() + "\"" : null) + ",\n" +
|
||||
" \"issuerUri\": " + (providerDetails.getIssuerUri() != null ? "\"" + providerDetails.getIssuerUri() + "\"" : null) + ",\n" +
|
||||
" \"configurationMetadata\": {\n" +
|
||||
" " + configurationMetadata + "\n" +
|
||||
" }\n" +
|
||||
|
|
|
@ -98,9 +98,7 @@ public class OidcIdTokenValidatorTests {
|
|||
* When the issuer is set in the provider metadata, and it does not match the issuer in the ID Token,
|
||||
* the validation must fail
|
||||
*/
|
||||
Map<String, Object> configurationMetadata = new HashMap<>();
|
||||
configurationMetadata.put("issuer", "https://issuer.somethingelse.com");
|
||||
this.registration = this.registration.providerConfigurationMetadata(configurationMetadata);
|
||||
this.registration = this.registration.issuerUri("https://issuer.somethingelse.com");
|
||||
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
|
@ -114,9 +112,7 @@ public class OidcIdTokenValidatorTests {
|
|||
* When the issuer is set in the provider metadata, and it does match the issuer in the ID Token,
|
||||
* the validation must succeed
|
||||
*/
|
||||
Map<String, Object> configurationMetadata = new HashMap<>();
|
||||
configurationMetadata.put("issuer", "https://issuer.example.com");
|
||||
this.registration = this.registration.providerConfigurationMetadata(configurationMetadata);
|
||||
this.registration = this.registration.issuerUri("https://issuer.example.com");
|
||||
|
||||
assertThat(this.validateIdToken()).isEmpty();
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ 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.getIssuerUri()).isEqualTo(this.issuer);
|
||||
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",
|
||||
|
|
Loading…
Reference in New Issue