Skip to content

ClientRegistrations class's OpenID Provider Configuration Validation does not conform to specification #16460

Closed as not planned
@abchau

Description

@abchau

Describe the bug

The section 4.3 in the OpenID Connect Discovery specification says "the Issuer URL that was used as the prefix to /.well-known/openid-configuration". However, the validation in ClientRegistrations.class does an equal() comparison of the entire issuer URL which is comparing too much because a provider's Issuer URL might contain additional parameters.

For example, in Azure AD B2C multiple OIDC configurations could be using the same Issuer and configuration URL in Azure AD B2C is not an straightforward URL. An additional parameter p is added at the end to identify which configurations you want to retrieve.

Usual Provider:

https://someprovider.com/someprefix/v2.0/

Azure AD B2C:

https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/?p=b2c_1_policy_name_a
{
  "issuer": "https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/",
  "authorization_endpoint": "https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/oauth2/v2.0/authorize?p=b2c_1_policy_name_a",
...
}

https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/?p=b2c_1_policy_name_b
{
  "issuer": "https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/",
  "authorization_endpoint": "https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/oauth2/v2.0/authorize?p=b2c_1_policy_name_b",
...
}

To Reproduce

Follow the procedure at https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory-b2c-oidc

Because the well known uri is https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/.well-known/openid-configuration?p=b2c_1_policy_name_a, this Issuer URL must be configurated with additional ?p=b2c_1_policy_name_a at the end.

# application.properties
spring.security.oauth2.client.provider.b2c.issuer-uri=https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/?p=b2c_1_policy_name_a

The following exception will be thrown during start up.

Caused by: java.lang.IllegalStateException: The Issuer "https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/" provided in the configuration metadata did not match the requested issuer "https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/?p=b2c_1_policy_name_a"
	at org.springframework.util.Assert.state(Assert.java:101) ~[spring-core-6.2.1.jar:6.2.1]
	at org.springframework.security.oauth2.client.registration.ClientRegistrations.withProviderConfiguration(ClientRegistrations.java:286) ~[main/:na]
	at org.springframework.security.oauth2.client.registration.ClientRegistrations.lambda$oidc$0(ClientRegistrations.java:205) ~[main/:na]
	at org.springframework.security.oauth2.client.registration.ClientRegistrations.getBuilder(ClientRegistrations.java:256) ~[main/:na]
	at org.springframework.security.oauth2.client.registration.ClientRegistrations.fromIssuerLocation(ClientRegistrations.java:192) ~[main/:na]

The exception was due to this method is comparing https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/ (metadata.getIssuer().getValue()) and https://eaxmple.b2clogin.com/00000000-0000-0000-00000000-000000000000/v2.0/?p=b2c_1_policy_name_a (issuer).

	private static ClientRegistration.Builder withProviderConfiguration(AuthorizationServerMetadata metadata, String issuer) {
		String metadataIssuer = metadata.getIssuer().getValue();
		Assert.state(issuer.equals(metadataIssuer),
				() -> "The Issuer \"" + metadataIssuer + "\" provided in the configuration metadata did "
						+ "not match the requested issuer \"" + issuer + "\"");

Expected behavior
The validation should be validating whether the issuer value from well known configuration is the prefix of Issuer URL.
defined in spring.security.oauth2.client.provider.b2c.issuer-uri= without taking into account of additional query string parameters .

Possible Solution

I've tested in my local that using issuer.startsWith(metadataIssuer) instead of issuer.equals(metadataIssuer) could avoid the issue and it seems more conform to the specification as in "the Issuer URL that was used as the prefix to /.well-known/openid-configuration".

e.g.

		Assert.state(issuer.startsWith(metadataIssuer),
				() -> "The Issuer \"" + metadataIssuer + "\" provided in the configuration metadata did "
						+ "not match the requested issuer \"" + issuer + "\"");

Metadata

Metadata

Assignees

Labels

in: oauth2An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose)status: invalidAn issue that we don't feel is validtype: bugA general bug

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions