You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kafka.apache.org by ma...@apache.org on 2022/07/27 11:15:18 UTC

[kafka] branch trunk updated: KAFKA-13730: OAuth access token validation fails if it does not contain the "sub" claim (#11886)

This is an automated email from the ASF dual-hosted git repository.

manikumar pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 160a6ab4cb KAFKA-13730: OAuth access token validation fails if it does not contain the "sub" claim (#11886)
160a6ab4cb is described below

commit 160a6ab4cb0bd4c3e303329b5bb30a13c196b030
Author: Daniel Fonai <75...@users.noreply.github.com>
AuthorDate: Wed Jul 27 13:14:54 2022 +0200

    KAFKA-13730: OAuth access token validation fails if it does not contain the "sub" claim (#11886)
    
    Removes the requirement of presence of sub claim in JWT access tokens, when clients authenticate via OAuth.
    This does not interfere with OAuth specifications and is to ensure wider compatibility with OAuth providers.
    Unit test added.
    
    Reviewers:  Kirk True <kt...@confluent.io>, Viktor Somogyi-Vass <vi...@gmail.com>,  Manikumar Reddy <ma...@gmail.com>
---
 .../secured/ValidatorAccessTokenValidator.java     |  1 -
 .../oauthbearer/secured/AccessTokenBuilder.java    | 24 +++++++++++++++++++++-
 .../secured/ValidatorAccessTokenValidatorTest.java | 19 +++++++++++++++++
 3 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidator.java b/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidator.java
index 7668438614..71d549153b 100644
--- a/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidator.java
+++ b/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidator.java
@@ -131,7 +131,6 @@ public class ValidatorAccessTokenValidator implements AccessTokenValidator {
             .setJwsAlgorithmConstraints(DISALLOW_NONE)
             .setRequireExpirationTime()
             .setRequireIssuedAt()
-            .setRequireSubject()
             .setVerificationKeyResolver(verificationKeyResolver)
             .build();
         this.scopeClaimName = scopeClaimName;
diff --git a/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/AccessTokenBuilder.java b/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/AccessTokenBuilder.java
index 24a40aa5b6..5387d40abf 100644
--- a/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/AccessTokenBuilder.java
+++ b/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/AccessTokenBuilder.java
@@ -22,6 +22,9 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.io.IOException;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.kafka.common.utils.MockTime;
 import org.apache.kafka.common.utils.Time;
 import org.jose4j.jwk.PublicJsonWebKey;
@@ -39,7 +42,7 @@ public class AccessTokenBuilder {
 
     private String subject = "jdoe";
 
-    private final String subjectClaimName = ReservedClaimNames.SUBJECT;
+    private String subjectClaimName = ReservedClaimNames.SUBJECT;
 
     private Object scope = "engineering";
 
@@ -51,6 +54,8 @@ public class AccessTokenBuilder {
 
     private PublicJsonWebKey jwk;
 
+    private final Map<String, String> customClaims = new HashMap<>();
+
     public AccessTokenBuilder() {
         this(new MockTime());
     }
@@ -87,6 +92,11 @@ public class AccessTokenBuilder {
         return subjectClaimName;
     }
 
+    public AccessTokenBuilder subjectClaimName(String subjectClaimName) {
+        this.subjectClaimName = subjectClaimName;
+        return this;
+    }
+
     public Object scope() {
         return scope;
     }
@@ -133,6 +143,14 @@ public class AccessTokenBuilder {
         return this;
     }
 
+    public AccessTokenBuilder addCustomClaim(String name, String value) {
+        String validatedName = ClaimValidationUtils.validateClaimNameOverride("claim name", name);
+        String validatedValue = ClaimValidationUtils.validateClaimNameOverride(validatedName, value);
+
+        customClaims.put(validatedName, validatedValue);
+        return this;
+    }
+
     @SuppressWarnings("unchecked")
     public String build() throws JoseException, IOException {
         ObjectNode node = objectMapper.createObjectNode();
@@ -162,6 +180,10 @@ public class AccessTokenBuilder {
         if (expirationSeconds != null)
             node.put(ReservedClaimNames.EXPIRATION_TIME, expirationSeconds);
 
+        for (Map.Entry<String, String> claim : customClaims.entrySet()) {
+            node.put(claim.getKey(), claim.getValue());
+        }
+
         String json = objectMapper.writeValueAsString(node);
 
         JsonWebSignature jws = new JsonWebSignature();
diff --git a/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidatorTest.java b/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidatorTest.java
index a48198879e..f24bd590ac 100644
--- a/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidatorTest.java
+++ b/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/secured/ValidatorAccessTokenValidatorTest.java
@@ -59,6 +59,25 @@ public class ValidatorAccessTokenValidatorTest extends AccessTokenValidatorTest
             "fake is an unknown, unsupported or unavailable alg algorithm");
     }
 
+    @Test
+    public void testMissingSubShouldBeValid() throws Exception {
+        String subClaimName = "client_id";
+        String subject = "otherSub";
+        PublicJsonWebKey jwk = createRsaJwk();
+        AccessTokenBuilder tokenBuilder = new AccessTokenBuilder()
+            .jwk(jwk)
+            .alg(AlgorithmIdentifiers.RSA_USING_SHA256)
+            .addCustomClaim(subClaimName, subject)
+            .subjectClaimName(subClaimName)
+            .subject(null);
+        AccessTokenValidator validator = createAccessTokenValidator(tokenBuilder);
+
+        // Validation should succeed (e.g. signature verification) even if sub claim is missing
+        OAuthBearerToken token = validator.validate(tokenBuilder.build());
+
+        assertEquals(subject, token.principalName());
+    }
+
     private void testEncryptionAlgorithm(PublicJsonWebKey jwk, String alg) throws Exception {
         AccessTokenBuilder builder = new AccessTokenBuilder().jwk(jwk).alg(alg);
         AccessTokenValidator validator = createAccessTokenValidator(builder);