Browse Source

Relax client_id validation in AtJwtBuilder

RFC 9068 requires that access token JWTs include the `client_id`
claim, but it does not require resource servers to validate it against
a specific value.

Relates to gh-18381

Signed-off-by: Giacomo Baso <gbaso@users.noreply.github.com>
pull/18890/head
Giacomo Baso 6 days ago
parent
commit
c583f75ca9
No known key found for this signature in database
GPG Key ID: 4580D77DF32AA0BA
  1. 4
      oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java
  2. 19
      oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtValidatorsTests.java

4
oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java

@ -147,13 +147,14 @@ public final class JwtValidators { @@ -147,13 +147,14 @@ public final class JwtValidators {
*
* <p>
* To comply with this spec, this builder needs you to specify at least the
* {@link #audience}, {@link #issuer}, and {@link #clientId}.
* {@link #audience} and {@link #issuer}.
*
* <p>
* While building, the claims are keyed by claim name to allow for simplified lookup
* and replacement in {@link #validators}.
*
* @author Josh Cummings
* @author Giacomo Baso
* @since 6.5
*/
public static final class AtJwtBuilder {
@ -167,6 +168,7 @@ public final class JwtValidators { @@ -167,6 +168,7 @@ public final class JwtValidators {
this.validators.put(JwtClaimNames.SUB, require(JwtClaimNames.SUB));
this.validators.put(JwtClaimNames.IAT, require(JwtClaimNames.IAT).and(timestamps));
this.validators.put(JwtClaimNames.JTI, require(JwtClaimNames.JTI));
this.validators.put("client_id", require("client_id"));
}
/**

19
oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtValidatorsTests.java

@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThatException; @@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThatException;
* Tests for {@link JwtValidators}.
*
* @author Max Batischev
* @author Giacomo Baso
*/
public class JwtValidatorsTests {
@ -105,6 +106,24 @@ public class JwtValidatorsTests { @@ -105,6 +106,24 @@ public class JwtValidatorsTests {
assertThat(result.getErrors().toString()).doesNotContain("iss");
}
@Test
void createAtJwtWhenClientIdIsNotPresentThenRequireClientIdWithAnyValue() {
Jwt.Builder builder = TestJwts.jwt();
OAuth2TokenValidator<Jwt> validator = JwtValidators.createAtJwtValidator()
.audience("audience")
.issuer("issuer")
.build();
OAuth2TokenValidatorResult result = validator.validate(builder.build());
assertThat(result.getErrors().toString()).contains("at+jwt")
.contains("aud")
.contains("client_id")
.contains("iss");
result = validator.validate(builder.claim("client_id", "clientId").build());
assertThat(result.getErrors().toString()).doesNotContain("client_id");
}
@SuppressWarnings("unchecked")
private boolean containsByType(OAuth2TokenValidator<Jwt> validator, Class<? extends OAuth2TokenValidator<?>> type) {
DelegatingOAuth2TokenValidator<Jwt> delegatingOAuth2TokenValidator = (DelegatingOAuth2TokenValidator<Jwt>) validator;

Loading…
Cancel
Save