You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by ho...@apache.org on 2026/08/31 23:34:53 UTC

(spark) branch branch-4.1 updated: [MINOR] Handle client identity after the handshake is complete

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

asf-gitbox-commits pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 7482cdb6c9c7 [MINOR] Handle client identity after the handshake is complete
7482cdb6c9c7 is described below

commit 7482cdb6c9c7d46b797f20e51818cd1d49914d62
Author: Holden Karau <ho...@snowflake.com>
AuthorDate: Sun Aug 30 05:21:46 2026 +0000

    [MINOR] Handle client identity after the handshake is complete
    
    Co-authored with Kimi & Claude
    
    Co-authored-by: Holden Karau <ho...@pigscanfly.ca>
---
 .../apache/spark/network/sasl/SaslRpcHandler.java  |  8 +++--
 .../apache/spark/network/sasl/SparkSaslSuite.java  | 39 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/common/network-common/src/main/java/org/apache/spark/network/sasl/SaslRpcHandler.java b/common/network-common/src/main/java/org/apache/spark/network/sasl/SaslRpcHandler.java
index b5fffe583ec6..336800dcdbe3 100644
--- a/common/network-common/src/main/java/org/apache/spark/network/sasl/SaslRpcHandler.java
+++ b/common/network-common/src/main/java/org/apache/spark/network/sasl/SaslRpcHandler.java
@@ -56,6 +56,9 @@ public class SaslRpcHandler extends AbstractAuthRpcHandler {
 
   private SparkSaslServer saslServer;
 
+  /** Claimed AppID from initial connection */
+  private String claimedAppId;
+
   public SaslRpcHandler(
       TransportConf conf,
       Channel channel,
@@ -83,8 +86,7 @@ public class SaslRpcHandler extends AbstractAuthRpcHandler {
       }
 
       if (saslServer == null) {
-        // First message in the handshake, setup the necessary state.
-        client.setClientId(saslMessage.appId);
+        claimedAppId = saslMessage.appId;
         saslServer = new SparkSaslServer(saslMessage.appId, secretKeyHolder,
           conf.saslServerAlwaysEncrypt());
       }
@@ -105,6 +107,8 @@ public class SaslRpcHandler extends AbstractAuthRpcHandler {
     // method returns. This assumes that the code ensures, through other means, that no outbound
     // messages are being written to the channel while negotiation is still going on.
     if (saslServer.isComplete()) {
+      // Set app Id once the handshake is completed.
+      client.setClientId(claimedAppId);
       if (!SparkSaslServer.QOP_AUTH_CONF.equals(saslServer.getNegotiatedProperty(Sasl.QOP))) {
         logger.debug("SASL authentication successful for channel {}", client);
         complete(true);
diff --git a/common/network-common/src/test/java/org/apache/spark/network/sasl/SparkSaslSuite.java b/common/network-common/src/test/java/org/apache/spark/network/sasl/SparkSaslSuite.java
index 4feaf5cef3f2..c87c7e517cb2 100644
--- a/common/network-common/src/test/java/org/apache/spark/network/sasl/SparkSaslSuite.java
+++ b/common/network-common/src/test/java/org/apache/spark/network/sasl/SparkSaslSuite.java
@@ -315,6 +315,45 @@ public class SparkSaslSuite {
     }
   }
 
+  @Test
+  public void testClientIdBoundAfter() throws Exception {
+    TransportConf conf = new TransportConf("shuffle", MapConfigProvider.EMPTY);
+    SecretKeyHolder keyHolder = mock(SecretKeyHolder.class);
+    when(keyHolder.getSaslUser(anyString())).thenReturn("user");
+    when(keyHolder.getSecretKey(anyString())).thenReturn("secret");
+    TransportClient client = mock(TransportClient.class);
+    SaslRpcHandler handler = new SaslRpcHandler(conf, null, null, keyHolder);
+    SparkSaslClient saslClient = new SparkSaslClient("app-1", keyHolder, false);
+    try {
+      byte[] clientToken = saslClient.firstToken();
+      boolean authenticated = false;
+      for (int i = 0; i < 10 && !authenticated; i++) {
+        SaslMessage msg = new SaslMessage("app-1", clientToken);
+        ByteBuf buf = Unpooled.buffer(msg.encodedLength() + clientToken.length);
+        msg.encode(buf);
+        buf.writeBytes(msg.body().nioByteBuffer());
+
+        AtomicReference<ByteBuffer> response = new AtomicReference<>();
+        RpcResponseCallback callback = mock(RpcResponseCallback.class);
+        doAnswer(invocation -> {
+          response.set((ByteBuffer) invocation.getArguments()[0]);
+          return null;
+        }).when(callback).onSuccess(any(ByteBuffer.class));
+
+        authenticated = handler.doAuthChallenge(client, buf.nioBuffer(), callback);
+        if (!authenticated) {
+          // No client ID set since we did not finish the challenge.
+          verify(client, never()).setClientId(anyString());
+          clientToken = saslClient.response(JavaUtils.bufferToArray(response.get()));
+        }
+      }
+      assertTrue(authenticated);
+      verify(client).setClientId("app-1");
+    } finally {
+      saslClient.dispose();
+    }
+  }
+
   @Test
   public void testRpcHandlerDelegate() throws Exception {
     // Tests all delegates exception for receive(), which is more complicated and already handled


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org