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/12/16 14:14:47 UTC

[kafka] branch trunk updated: KAFKA-14496: Wrong Base64 encoder used by OIDC OAuthBearerLoginCallbackHandler (#13000)

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 f247aac96a1 KAFKA-14496: Wrong Base64 encoder used by OIDC OAuthBearerLoginCallbackHandler (#13000)
f247aac96a1 is described below

commit f247aac96a1c16ac7255496cb2815223386eae9a
Author: Kirk True <kt...@confluent.io>
AuthorDate: Fri Dec 16 06:14:41 2022 -0800

    KAFKA-14496: Wrong Base64 encoder used by OIDC OAuthBearerLoginCallbackHandler (#13000)
    
    The OAuth code to generate the Authentication header was incorrectly
    using the URL-safe base64 encoder. For client IDs and/or secrets with
    dashes and/or plus signs would not be encoded correctly, leading to the
    OAuth server to reject the credentials.
    
    This change uses the correct base64 encoder, per RFC-7617.
    
    Co-authored-by: Endre Vig <ve...@gmail.com>
---
 .../internals/secured/HttpAccessTokenRetriever.java       |  3 ++-
 .../internals/secured/HttpAccessTokenRetrieverTest.java   | 15 ++++++++++++---
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetriever.java b/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetriever.java
index 78917de6f1e..2e61449304d 100644
--- a/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetriever.java
+++ b/clients/src/main/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetriever.java
@@ -344,7 +344,8 @@ public class HttpAccessTokenRetriever implements AccessTokenRetriever {
         clientSecret = sanitizeString("the token endpoint request client secret parameter", clientSecret);
 
         String s = String.format("%s:%s", clientId, clientSecret);
-        String encoded = Base64.getUrlEncoder().encodeToString(Utils.utf8(s));
+        // Per RFC-7617, we need to use the *non-URL safe* base64 encoder. See KAFKA-14496.
+        String encoded = Base64.getEncoder().encodeToString(Utils.utf8(s));
         return String.format("Basic %s", encoded);
     }
 
diff --git a/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetrieverTest.java b/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetrieverTest.java
index a193545fd38..5086a1dab29 100644
--- a/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetrieverTest.java
+++ b/clients/src/test/java/org/apache/kafka/common/security/oauthbearer/internals/secured/HttpAccessTokenRetrieverTest.java
@@ -173,10 +173,19 @@ public class HttpAccessTokenRetrieverTest extends OAuthBearerTest {
 
     @Test
     public void testFormatAuthorizationHeader() throws IOException {
-        String expected = "Basic " + Base64.getUrlEncoder().encodeToString(Utils.utf8("id:secret"));
+        assertAuthorizationHeader("id", "secret");
+    }
 
-        String actual = HttpAccessTokenRetriever.formatAuthorizationHeader("id", "secret");
-        assertEquals(expected, actual);
+    @Test
+    public void testFormatAuthorizationHeaderEncoding() throws IOException {
+        // See KAFKA-14496
+        assertAuthorizationHeader("SOME_RANDOM_LONG_USER_01234", "9Q|0`8i~ute-n9ksjLWb\\50\"AX@UUED5E");
+    }
+
+    private void assertAuthorizationHeader(String clientId, String clientSecret) throws IOException {
+        String expected = "Basic " + Base64.getEncoder().encodeToString(Utils.utf8(clientId + ":" + clientSecret));
+        String actual = HttpAccessTokenRetriever.formatAuthorizationHeader(clientId, clientSecret);
+        assertEquals(expected, actual, String.format("Expected the HTTP Authorization header generated for client ID \"%s\" and client secret \"%s\" to match", clientId, clientSecret));
     }
 
     @Test