Validate ID Token Issuer

When the issuer is set in the provider metadata, we validate the iss
field of the ID Token against it.

The OpenID Connect Specification says this must always be validated.
But this would be a breaking change for applications configured other
than with ClientRegistrations.fromOidcIssuerLocation(issuer). This will
be done later with #8326

Fixes gh-8321
This commit is contained in:
Daniel Furtlehner 2020-04-08 16:16:22 +02:00 committed by Joe Grandja
parent 70792a9072
commit 32ce94d2dd
2 changed files with 36 additions and 1 deletions

View File

@ -33,6 +33,7 @@ import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* An {@link OAuth2TokenValidator} responsible for
@ -68,7 +69,12 @@ 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.
// TODO Depends on gh-4413
String metadataIssuer = (String) this.clientRegistration.getProviderDetails().getConfigurationMetadata()
.get("issuer");
if (metadataIssuer != null && !Objects.equals(metadataIssuer, idToken.getIssuer().toExternalForm())) {
invalidClaims.put(IdTokenClaimNames.ISS, idToken.getIssuer());
}
// 3. The Client MUST validate that the aud (audience) Claim contains its client_id value
// registered at the Issuer identified by the iss (issuer) Claim as an audience.

View File

@ -92,6 +92,35 @@ public class OidcIdTokenValidatorTests {
.allMatch(msg -> msg.contains(IdTokenClaimNames.ISS));
}
@Test
public void validateWhenMetadataIssuerMismatchThenHasErrors() {
/*
* 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);
assertThat(this.validateIdToken())
.hasSize(1)
.extracting(OAuth2Error::getDescription)
.allMatch(msg -> msg.contains(IdTokenClaimNames.ISS));
}
@Test
public void validateWhenMetadataIssuerMatchThenNoErrors() {
/*
* 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);
assertThat(this.validateIdToken()).isEmpty();
}
@Test
public void validateWhenSubNullThenHasErrors() {
this.claims.remove(IdTokenClaimNames.SUB);