This is an automated email from the ASF dual-hosted git repository. alexey pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/kudu.git
The following commit(s) were added to refs/heads/master by this push: new ede75bc16 [client] KUDU-3472 Java client API to import JWT ede75bc16 is described below commit ede75bc162c14cb58b2c5cceef6a7072c0d7428c Author: Zoltan Chovan <zcho...@cloudera.com> AuthorDate: Wed May 3 18:56:47 2023 +0200 [client] KUDU-3472 Java client API to import JWT This patch adds one new method into AsyncKuduClient and KuduClient API to set a JWT (JSON Web Token) to be used for authentication. The newly introduced API matches the one introduced in the C++ Kudu client. Change-Id: Ic43bd1219f4613e9cac11762726a5d6d2cdc764b Reviewed-on: http://gerrit.cloudera.org:8080/19836 Tested-by: Alexey Serbin <ale...@apache.org> Reviewed-by: Alexey Serbin <ale...@apache.org> --- .../org/apache/kudu/client/AsyncKuduClient.java | 19 ++++++++++++ .../java/org/apache/kudu/client/KuduClient.java | 17 +++++++++++ .../org/apache/kudu/client/SecurityContext.java | 14 ++++++--- .../org/apache/kudu/test/TestMiniKuduCluster.java | 35 +++++++--------------- 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java index 2e8a24ed2..68aa1b2fc 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java @@ -80,6 +80,7 @@ import org.apache.kudu.master.Master.GetTableLocationsResponsePB; import org.apache.kudu.master.Master.TSInfoPB; import org.apache.kudu.master.Master.TableIdentifierPB; import org.apache.kudu.master.Master.TabletLocationsPB; +import org.apache.kudu.security.Token; import org.apache.kudu.security.Token.SignedTokenPB; import org.apache.kudu.util.AsyncUtil; import org.apache.kudu.util.NetUtil; @@ -1177,6 +1178,24 @@ public class AsyncKuduClient implements AutoCloseable { securityContext.importAuthenticationCredentials(authnData); } + /** + * Set JWT (JSON Web Token) to authenticate the client to a server. + * <p> + * @note If {@link #importAuthenticationCredentials(byte[] authnData)} and + * this method are called on the same object, the JWT provided with this call + * overrides the corresponding JWT that comes as a part of the imported + * authentication credentials (if present). + * + * @param jwt The JSON web token to set. + */ + @InterfaceStability.Unstable + public void jwt(String jwt) { + Token.JwtRawPB jwtPB = Token.JwtRawPB.newBuilder() + .setJwtData(ByteString.copyFromUtf8(jwt)) + .build(); + securityContext.setJsonWebToken(jwtPB); + } + /** * Get the timeout used for operations on sessions and scanners. * @return a timeout in milliseconds diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/KuduClient.java b/java/kudu-client/src/main/java/org/apache/kudu/client/KuduClient.java index 1536574df..ed2f90e30 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/KuduClient.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/KuduClient.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.concurrent.Executor; import com.google.common.base.Preconditions; +import com.google.protobuf.ByteString; import com.stumbleupon.async.Deferred; import org.apache.yetus.audience.InterfaceAudience; import org.apache.yetus.audience.InterfaceStability; @@ -30,6 +31,7 @@ import org.slf4j.LoggerFactory; import org.apache.kudu.Schema; import org.apache.kudu.master.Master.TableIdentifierPB; +import org.apache.kudu.security.Token; /** * A synchronous and thread-safe client for Kudu. @@ -466,6 +468,21 @@ public class KuduClient implements AutoCloseable { asyncClient.importAuthenticationCredentials(authnData); } + /** + * Set JWT (JSON Web Token) to authenticate the client to a server. + * <p> + * @note If {@link #importAuthenticationCredentials(byte[] authnData)} and + * this method are called on the same object, the JWT provided with this call + * overrides the corresponding JWT that comes as a part of the imported + * authentication credentials (if present). + * + * @param jwt The JSON web token to set. + */ + @InterfaceStability.Unstable + public void jwt(String jwt) { + asyncClient.jwt(jwt); + } + /** * Get the timeout used for operations on sessions and scanners. * @return a timeout in milliseconds diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/SecurityContext.java b/java/kudu-client/src/main/java/org/apache/kudu/client/SecurityContext.java index 8597e0cd9..b02c020a4 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/SecurityContext.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/SecurityContext.java @@ -278,6 +278,9 @@ class SecurityContext { if (authnToken != null) { pb.setAuthnToken(authnToken); } + if (jsonWebToken != null) { + pb.setJwt(jsonWebToken); + } pb.addAllCaCertDers(trustedCertDers); return pb.build().toByteArray(); } @@ -315,10 +318,9 @@ class SecurityContext { } LOG.debug("Importing authentication credentials with {} authn token, " + - "JWT={} , " + - "{} cert(s), and realUser={}", + "with {} JWT, {} cert(s), and realUser={}", pb.hasAuthnToken() ? "one" : "no", - pb.hasJwt() ? pb.getJwt() : "<none>", + pb.hasJwt() ? "one" : "no", pb.getCaCertDersCount(), pb.hasRealUser() ? pb.getRealUser() : "<none>"); if (pb.hasAuthnToken()) { @@ -327,7 +329,11 @@ class SecurityContext { trustCertificates(pb.getCaCertDersList()); if (pb.hasJwt()) { - jsonWebToken = pb.getJwt(); + // Don't overwrite the JWT in the context if it's already set. + if (!jsonWebToken.hasJwtData() || + (jsonWebToken.hasJwtData() && jsonWebToken.getJwtData().isEmpty())) { + jsonWebToken = pb.getJwt(); + } } if (pb.hasRealUser()) { diff --git a/java/kudu-test-utils/src/test/java/org/apache/kudu/test/TestMiniKuduCluster.java b/java/kudu-test-utils/src/test/java/org/apache/kudu/test/TestMiniKuduCluster.java index ddfbe6d9b..c31efb399 100644 --- a/java/kudu-test-utils/src/test/java/org/apache/kudu/test/TestMiniKuduCluster.java +++ b/java/kudu-test-utils/src/test/java/org/apache/kudu/test/TestMiniKuduCluster.java @@ -119,31 +119,18 @@ public class TestMiniKuduCluster { @Test(timeout = 50000) public void testJwt() throws Exception { - try { - MiniKuduClusterBuilder clusterBuilder = new MiniKuduCluster.MiniKuduClusterBuilder() - .numMasterServers(NUM_MASTERS) - .numTabletServers(0) - .enableClientJwt() - .addJwks("account-id", true); - - harness = new KuduTestHarness(clusterBuilder); - harness.before(); - harness.startAllMasterServers(); - - String jwt = harness.createJwtFor("account-id", "subject", true); + try (MiniKuduCluster cluster = new MiniKuduCluster.MiniKuduClusterBuilder() + .numMasterServers(NUM_MASTERS) + .numTabletServers(0) + .enableClientJwt() + .addJwks("account-id", true) + .build(); + KuduClient client = new KuduClientBuilder(cluster.getMasterAddressesAsString()).build()) { + String jwt = cluster.createJwtFor("account-id", "subject", true); assertNotNull(jwt); - AuthenticationCredentialsPB credentials = AuthenticationCredentialsPB.newBuilder() - .setJwt(JwtRawPB.newBuilder() - .setJwtData(ByteString.copyFromUtf8(jwt)) - .build()) - .build(); - - AsyncKuduClient c = harness.getAsyncClient(); - c.importAuthenticationCredentials(credentials.toByteArray()); - c.getTablesList(); - - } catch (Exception e) { - throw new RuntimeException(e); + + client.jwt(jwt); + client.getTablesList(); } }