Search in sources :

Example 1 with SaslHandshakeResponse

use of org.apache.kafka.common.requests.SaslHandshakeResponse in project kafka by apache.

the class SaslAuthenticatorTest method testUnauthenticatedApiVersionsRequest.

/**
     * Tests that Kafka ApiVersionsRequests are handled by the SASL server authenticator
     * prior to SASL handshake flow and that subsequent authentication succeeds
     * when transport layer is PLAINTEXT/SSL. This test uses a non-SASL client that simulates
     * SASL authentication after ApiVersionsRequest.
     * <p>
     * Test sequence (using <tt>securityProtocol=PLAINTEXT</tt> as an example):
     * <ol>
     *   <li>Starts a SASL_PLAINTEXT test server that simply echoes back client requests after authentication.</li>
     *   <li>A (non-SASL) PLAINTEXT test client connects to the SASL server port. Client is now unauthenticated.<./li>
     *   <li>The unauthenticated non-SASL client sends an ApiVersionsRequest and validates the response.
     *       A valid response indicates that {@link SaslServerAuthenticator} of the test server responded to
     *       the ApiVersionsRequest even though the client is not yet authenticated.</li>
     *   <li>The unauthenticated non-SASL client sends a SaslHandshakeRequest and validates the response. A valid response
     *       indicates that {@link SaslServerAuthenticator} of the test server responded to the SaslHandshakeRequest
     *       after processing ApiVersionsRequest.</li>
     *   <li>The unauthenticated non-SASL client sends the SASL/PLAIN packet containing username/password to authenticate
     *       itself. The client is now authenticated by the server. At this point this test client is at the
     *       same state as a regular SASL_PLAINTEXT client that is <tt>ready</tt>.</li>
     *   <li>The authenticated client sends random data to the server and checks that the data is echoed
     *       back by the test server (ie, not Kafka request-response) to ensure that the client now
     *       behaves exactly as a regular SASL_PLAINTEXT client that has completed authentication.</li>
     * </ol>
     */
private void testUnauthenticatedApiVersionsRequest(SecurityProtocol securityProtocol) throws Exception {
    configureMechanisms("PLAIN", Arrays.asList("PLAIN"));
    server = createEchoServer(securityProtocol);
    // Create non-SASL connection to manually authenticate after ApiVersionsRequest
    String node = "1";
    SecurityProtocol clientProtocol;
    switch(securityProtocol) {
        case SASL_PLAINTEXT:
            clientProtocol = SecurityProtocol.PLAINTEXT;
            break;
        case SASL_SSL:
            clientProtocol = SecurityProtocol.SSL;
            break;
        default:
            throw new IllegalArgumentException("Server protocol " + securityProtocol + " is not SASL");
    }
    createClientConnection(clientProtocol, node);
    NetworkTestUtils.waitForChannelReady(selector, node);
    // Send ApiVersionsRequest and check response
    ApiVersionsResponse versionsResponse = sendVersionRequestReceiveResponse(node);
    assertEquals(ApiKeys.SASL_HANDSHAKE.oldestVersion(), versionsResponse.apiVersion(ApiKeys.SASL_HANDSHAKE.id).minVersion);
    assertEquals(ApiKeys.SASL_HANDSHAKE.latestVersion(), versionsResponse.apiVersion(ApiKeys.SASL_HANDSHAKE.id).maxVersion);
    // Send SaslHandshakeRequest and check response
    SaslHandshakeResponse handshakeResponse = sendHandshakeRequestReceiveResponse(node);
    assertEquals(Collections.singletonList("PLAIN"), handshakeResponse.enabledMechanisms());
    // Complete manual authentication and check send/receive succeed
    authenticateUsingSaslPlainAndCheckConnection(node);
}
Also used : ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) SecurityProtocol(org.apache.kafka.common.protocol.SecurityProtocol)

Example 2 with SaslHandshakeResponse

use of org.apache.kafka.common.requests.SaslHandshakeResponse 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;
}
Also used : SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) SaslHandshakeRequest(org.apache.kafka.common.requests.SaslHandshakeRequest)

Example 3 with SaslHandshakeResponse

use of org.apache.kafka.common.requests.SaslHandshakeResponse in project apache-kafka-on-k8s by banzaicloud.

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 {
    short saslHandshakeVersion = 0;
    if (netOutBuffer != null && !flushNetOutBufferAndUpdateInterestOps())
        return;
    switch(saslState) {
        case SEND_APIVERSIONS_REQUEST:
            // Always use version 0 request since brokers treat requests with schema exceptions as GSSAPI tokens
            ApiVersionsRequest apiVersionsRequest = new ApiVersionsRequest((short) 0);
            send(apiVersionsRequest.toSend(node, nextRequestHeader(ApiKeys.API_VERSIONS, apiVersionsRequest.version())));
            setSaslState(SaslState.RECEIVE_APIVERSIONS_RESPONSE);
            break;
        case RECEIVE_APIVERSIONS_RESPONSE:
            ApiVersionsResponse apiVersionsResponse = (ApiVersionsResponse) receiveKafkaResponse();
            if (apiVersionsResponse == null)
                break;
            else {
                saslHandshakeVersion = apiVersionsResponse.apiVersion(ApiKeys.SASL_HANDSHAKE.id).maxVersion;
                ApiVersion authenticateVersion = apiVersionsResponse.apiVersion(ApiKeys.SASL_AUTHENTICATE.id);
                if (authenticateVersion != null)
                    saslAuthenticateVersion((short) Math.min(authenticateVersion.maxVersion, ApiKeys.SASL_AUTHENTICATE.latestVersion()));
                setSaslState(SaslState.SEND_HANDSHAKE_REQUEST);
            // Fall through to send handshake request with the latest supported version
            }
        case SEND_HANDSHAKE_REQUEST:
            SaslHandshakeRequest handshakeRequest = createSaslHandshakeRequest(saslHandshakeVersion);
            send(handshakeRequest.toSend(node, nextRequestHeader(ApiKeys.SASL_HANDSHAKE, handshakeRequest.version())));
            setSaslState(SaslState.RECEIVE_HANDSHAKE_RESPONSE);
            break;
        case RECEIVE_HANDSHAKE_RESPONSE:
            SaslHandshakeResponse handshakeResponse = (SaslHandshakeResponse) receiveKafkaResponse();
            if (handshakeResponse == null)
                break;
            else {
                handleSaslHandshakeResponse(handshakeResponse);
                setSaslState(SaslState.INITIAL);
            // Fall through and start SASL authentication using the configured client mechanism
            }
        case INITIAL:
            sendSaslClientToken(new byte[0], true);
            setSaslState(SaslState.INTERMEDIATE);
            break;
        case INTERMEDIATE:
            byte[] serverToken = receiveToken();
            boolean noResponsesPending = serverToken != null && !sendSaslClientToken(serverToken, false);
            // For versions with SASL_AUTHENTICATE header, server always sends a response to each SASL_AUTHENTICATE request.
            if (saslClient.isComplete()) {
                if (saslAuthenticateVersion == DISABLE_KAFKA_SASL_AUTHENTICATE_HEADER || noResponsesPending)
                    setSaslState(SaslState.COMPLETE);
                else
                    setSaslState(SaslState.CLIENT_COMPLETE);
            }
            break;
        case CLIENT_COMPLETE:
            byte[] serverResponse = receiveToken();
            if (serverResponse != null)
                setSaslState(SaslState.COMPLETE);
            break;
        case COMPLETE:
            break;
        case FAILED:
            // Should never get here since exception would have been propagated earlier
            throw new IllegalStateException("SASL handshake has already failed");
    }
}
Also used : ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) ApiVersion(org.apache.kafka.common.requests.ApiVersionsResponse.ApiVersion) SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) ApiVersionsRequest(org.apache.kafka.common.requests.ApiVersionsRequest) SaslHandshakeRequest(org.apache.kafka.common.requests.SaslHandshakeRequest)

Example 4 with SaslHandshakeResponse

use of org.apache.kafka.common.requests.SaslHandshakeResponse in project kafka by apache.

the class SaslAuthenticatorTest method sendHandshakeRequestReceiveResponse.

private SaslHandshakeResponse sendHandshakeRequestReceiveResponse(String node, short version) throws Exception {
    SaslHandshakeRequest handshakeRequest = buildSaslHandshakeRequest("PLAIN", version);
    SaslHandshakeResponse response = (SaslHandshakeResponse) sendKafkaRequestReceiveResponse(node, ApiKeys.SASL_HANDSHAKE, handshakeRequest);
    assertEquals(Errors.NONE, response.error());
    return response;
}
Also used : SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) SaslHandshakeRequest(org.apache.kafka.common.requests.SaslHandshakeRequest)

Example 5 with SaslHandshakeResponse

use of org.apache.kafka.common.requests.SaslHandshakeResponse in project kafka by apache.

the class SaslServerAuthenticator method handleHandshakeRequest.

private String handleHandshakeRequest(RequestHeader requestHeader, SaslHandshakeRequest handshakeRequest) throws IOException, UnsupportedSaslMechanismException {
    String clientMechanism = handshakeRequest.mechanism();
    if (enabledMechanisms.contains(clientMechanism)) {
        LOG.debug("Using SASL mechanism '{}' provided by client", clientMechanism);
        sendKafkaResponse(requestHeader, new SaslHandshakeResponse(Errors.NONE, enabledMechanisms));
        return clientMechanism;
    } else {
        LOG.debug("SASL mechanism '{}' requested by client is not supported", clientMechanism);
        sendKafkaResponse(requestHeader, new SaslHandshakeResponse(Errors.UNSUPPORTED_SASL_MECHANISM, enabledMechanisms));
        throw new UnsupportedSaslMechanismException("Unsupported SASL mechanism " + clientMechanism);
    }
}
Also used : SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) UnsupportedSaslMechanismException(org.apache.kafka.common.errors.UnsupportedSaslMechanismException)

Aggregations

SaslHandshakeResponse (org.apache.kafka.common.requests.SaslHandshakeResponse)11 ApiVersionsResponse (org.apache.kafka.common.requests.ApiVersionsResponse)5 SaslHandshakeRequest (org.apache.kafka.common.requests.SaslHandshakeRequest)4 UnsupportedSaslMechanismException (org.apache.kafka.common.errors.UnsupportedSaslMechanismException)3 ApiVersionsRequest (org.apache.kafka.common.requests.ApiVersionsRequest)2 SecurityProtocol (org.apache.kafka.common.security.auth.SecurityProtocol)2 SaslHandshakeResponseData (org.apache.kafka.common.message.SaslHandshakeResponseData)1 SecurityProtocol (org.apache.kafka.common.protocol.SecurityProtocol)1 ApiVersion (org.apache.kafka.common.requests.ApiVersionsResponse.ApiVersion)1