use of org.apache.kafka.common.requests.SaslHandshakeRequest in project kafka by apache.
the class SaslServerAuthenticator method handleKafkaRequest.
private boolean handleKafkaRequest(byte[] requestBytes) throws IOException, AuthenticationException {
boolean isKafkaRequest = false;
String clientMechanism = null;
try {
ByteBuffer requestBuffer = ByteBuffer.wrap(requestBytes);
RequestHeader requestHeader = RequestHeader.parse(requestBuffer);
ApiKeys apiKey = ApiKeys.forId(requestHeader.apiKey());
// A valid Kafka request header was received. SASL authentication tokens are now expected only
// following a SaslHandshakeRequest since this is not a GSSAPI client token from a Kafka 0.9.0.x client.
setSaslState(SaslState.HANDSHAKE_REQUEST);
isKafkaRequest = true;
if (!Protocol.apiVersionSupported(requestHeader.apiKey(), requestHeader.apiVersion())) {
if (apiKey == ApiKeys.API_VERSIONS)
sendKafkaResponse(ApiVersionsResponse.unsupportedVersionSend(node, requestHeader));
else
throw new UnsupportedVersionException("Version " + requestHeader.apiVersion() + " is not supported for apiKey " + apiKey);
} else {
AbstractRequest request = AbstractRequest.getRequest(requestHeader.apiKey(), requestHeader.apiVersion(), requestBuffer).request;
LOG.debug("Handle Kafka request {}", apiKey);
switch(apiKey) {
case API_VERSIONS:
handleApiVersionsRequest(requestHeader);
break;
case SASL_HANDSHAKE:
clientMechanism = handleHandshakeRequest(requestHeader, (SaslHandshakeRequest) request);
break;
default:
throw new IllegalSaslStateException("Unexpected Kafka request of type " + apiKey + " during SASL handshake.");
}
}
} catch (SchemaException | IllegalArgumentException e) {
if (saslState == SaslState.GSSAPI_OR_HANDSHAKE_REQUEST) {
// starting with 0x60, revert to GSSAPI for both these exceptions.
if (LOG.isDebugEnabled()) {
StringBuilder tokenBuilder = new StringBuilder();
for (byte b : requestBytes) {
tokenBuilder.append(String.format("%02x", b));
if (tokenBuilder.length() >= 20)
break;
}
LOG.debug("Received client packet of length {} starting with bytes 0x{}, process as GSSAPI packet", requestBytes.length, tokenBuilder);
}
if (enabledMechanisms.contains(SaslConfigs.GSSAPI_MECHANISM)) {
LOG.debug("First client packet is not a SASL mechanism request, using default mechanism GSSAPI");
clientMechanism = SaslConfigs.GSSAPI_MECHANISM;
} else
throw new UnsupportedSaslMechanismException("Exception handling first SASL packet from client, GSSAPI is not supported by server", e);
} else
throw e;
}
if (clientMechanism != null) {
createSaslServer(clientMechanism);
setSaslState(SaslState.AUTHENTICATE);
}
return isKafkaRequest;
}
use of org.apache.kafka.common.requests.SaslHandshakeRequest in project kafka by apache.
the class SaslAuthenticatorTest method sendHandshakeRequestReceiveResponse.
private SaslHandshakeResponse sendHandshakeRequestReceiveResponse(String node) throws Exception {
SaslHandshakeRequest handshakeRequest = new SaslHandshakeRequest("PLAIN");
SaslHandshakeResponse response = (SaslHandshakeResponse) sendKafkaRequestReceiveResponse(node, ApiKeys.SASL_HANDSHAKE, handshakeRequest);
assertEquals(Errors.NONE, response.error());
return response;
}
use of org.apache.kafka.common.requests.SaslHandshakeRequest in project kafka by apache.
the class SaslClientAuthenticator method authenticate.
/**
* Sends an empty message to the server to initiate the authentication process. It then evaluates server challenges
* via `SaslClient.evaluateChallenge` and returns client responses until authentication succeeds or fails.
*
* The messages are sent and received as size delimited bytes that consists of a 4 byte network-ordered size N
* followed by N bytes representing the opaque payload.
*/
public void authenticate() throws IOException {
if (netOutBuffer != null && !flushNetOutBufferAndUpdateInterestOps())
return;
switch(saslState) {
case SEND_HANDSHAKE_REQUEST:
// When multiple versions of SASL_HANDSHAKE_REQUEST are to be supported,
// API_VERSIONS_REQUEST must be sent prior to sending SASL_HANDSHAKE_REQUEST to
// fetch supported versions.
String clientId = (String) configs.get(CommonClientConfigs.CLIENT_ID_CONFIG);
SaslHandshakeRequest handshakeRequest = new SaslHandshakeRequest(mechanism);
currentRequestHeader = new RequestHeader(ApiKeys.SASL_HANDSHAKE.id, handshakeRequest.version(), clientId, correlationId++);
send(handshakeRequest.toSend(node, currentRequestHeader));
setSaslState(SaslState.RECEIVE_HANDSHAKE_RESPONSE);
break;
case RECEIVE_HANDSHAKE_RESPONSE:
byte[] responseBytes = receiveResponseOrToken();
if (responseBytes == null)
break;
else {
try {
handleKafkaResponse(currentRequestHeader, responseBytes);
currentRequestHeader = null;
} catch (Exception e) {
setSaslState(SaslState.FAILED);
throw e;
}
setSaslState(SaslState.INITIAL);
// Fall through and start SASL authentication using the configured client mechanism
}
case INITIAL:
sendSaslToken(new byte[0], true);
setSaslState(SaslState.INTERMEDIATE);
break;
case INTERMEDIATE:
byte[] serverToken = receiveResponseOrToken();
if (serverToken != null) {
sendSaslToken(serverToken, false);
}
if (saslClient.isComplete()) {
setSaslState(SaslState.COMPLETE);
transportLayer.removeInterestOps(SelectionKey.OP_WRITE);
}
break;
case COMPLETE:
break;
case FAILED:
throw new IOException("SASL handshake failed");
}
}
use of org.apache.kafka.common.requests.SaslHandshakeRequest in project kafka by apache.
the class SaslAuthenticatorTest method testSaslHandshakeRequestWithUnsupportedVersion.
/**
* Tests that unsupported version of SASL handshake request returns error
* response and fails authentication. This test is similar to
* {@link #testUnauthenticatedApiVersionsRequest(SecurityProtocol)}
* where a non-SASL client is used to send requests that are processed by
* {@link SaslServerAuthenticator} of the server prior to client authentication.
*/
@Test
public void testSaslHandshakeRequestWithUnsupportedVersion() throws Exception {
SecurityProtocol securityProtocol = SecurityProtocol.SASL_PLAINTEXT;
configureMechanisms("PLAIN", Arrays.asList("PLAIN"));
server = createEchoServer(securityProtocol);
// Send ApiVersionsRequest and validate error response.
String node1 = "invalid1";
createClientConnection(SecurityProtocol.PLAINTEXT, node1);
SaslHandshakeRequest request = new SaslHandshakeRequest("PLAIN");
RequestHeader header = new RequestHeader(ApiKeys.SASL_HANDSHAKE.id, Short.MAX_VALUE, "someclient", 2);
selector.send(request.toSend(node1, header));
NetworkTestUtils.waitForChannelClose(selector, node1);
selector.close();
// Test good connection still works
createAndCheckClientConnection(securityProtocol, "good1");
}
Aggregations