Skip to content

Commit 992b090

Browse files
[MINOR] Handle client identity after the handshake is complete
Co-authored with Kimi & Claude Co-authored-by: Holden Karau <holden@pigscanfly.ca>
1 parent ed95123 commit 992b090

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

‎common/network-common/src/main/java/org/apache/spark/network/sasl/SaslRpcHandler.java‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public class SaslRpcHandler extends AbstractAuthRpcHandler {
5656

5757
private SparkSaslServer saslServer;
5858

59+
/** Claimed AppID from initial connection */
60+
private String claimedAppId;
61+
5962
public SaslRpcHandler(
6063
TransportConf conf,
6164
Channel channel,
@@ -83,8 +86,7 @@ public boolean doAuthChallenge(
8386
}
8487

8588
if (saslServer == null) {
86-
// First message in the handshake, setup the necessary state.
87-
client.setClientId(saslMessage.appId);
89+
claimedAppId = saslMessage.appId;
8890
saslServer = new SparkSaslServer(saslMessage.appId, secretKeyHolder,
8991
conf.saslServerAlwaysEncrypt());
9092
}
@@ -105,6 +107,8 @@ public boolean doAuthChallenge(
105107
// method returns. This assumes that the code ensures, through other means, that no outbound
106108
// messages are being written to the channel while negotiation is still going on.
107109
if (saslServer.isComplete()) {
110+
// Set app Id once the handshake is completed.
111+
client.setClientId(claimedAppId);
108112
if (!SparkSaslServer.QOP_AUTH_CONF.equals(saslServer.getNegotiatedProperty(Sasl.QOP))) {
109113
logger.debug("SASL authentication successful for channel {}", client);
110114
complete(true);

‎common/network-common/src/test/java/org/apache/spark/network/sasl/SparkSaslSuite.java‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,45 @@ public void testDataEncryptionIsActuallyEnabled() throws Exception {
315315
}
316316
}
317317

318+
@Test
319+
public void testClientIdBoundAfter() throws Exception {
320+
TransportConf conf = new TransportConf("shuffle", MapConfigProvider.EMPTY);
321+
SecretKeyHolder keyHolder = mock(SecretKeyHolder.class);
322+
when(keyHolder.getSaslUser(anyString())).thenReturn("user");
323+
when(keyHolder.getSecretKey(anyString())).thenReturn("secret");
324+
TransportClient client = mock(TransportClient.class);
325+
SaslRpcHandler handler = new SaslRpcHandler(conf, null, null, keyHolder);
326+
SparkSaslClient saslClient = new SparkSaslClient("app-1", keyHolder, false);
327+
try {
328+
byte[] clientToken = saslClient.firstToken();
329+
boolean authenticated = false;
330+
for (int i = 0; i < 10 && !authenticated; i++) {
331+
SaslMessage msg = new SaslMessage("app-1", clientToken);
332+
ByteBuf buf = Unpooled.buffer(msg.encodedLength() + clientToken.length);
333+
msg.encode(buf);
334+
buf.writeBytes(msg.body().nioByteBuffer());
335+
336+
AtomicReference<ByteBuffer> response = new AtomicReference<>();
337+
RpcResponseCallback callback = mock(RpcResponseCallback.class);
338+
doAnswer(invocation -> {
339+
response.set((ByteBuffer) invocation.getArguments()[0]);
340+
return null;
341+
}).when(callback).onSuccess(any(ByteBuffer.class));
342+
343+
authenticated = handler.doAuthChallenge(client, buf.nioBuffer(), callback);
344+
if (!authenticated) {
345+
// No client ID set since we did not finish the challenge.
346+
verify(client, never()).setClientId(anyString());
347+
clientToken = saslClient.response(JavaUtils.bufferToArray(response.get()));
348+
}
349+
}
350+
assertTrue(authenticated);
351+
verify(client).setClientId("app-1");
352+
} finally {
353+
saslClient.dispose();
354+
}
355+
}
356+
318357
@Test
319358
public void testRpcHandlerDelegate() throws Exception {
320359
// Tests all delegates exception for receive(), which is more complicated and already handled

0 commit comments

Comments
 (0)