Description
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 + "\"");