Search in sources :

Example 6 with SaslHandshakeResponse

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

the class SaslServerAuthenticator method handleHandshakeRequest.

private String handleHandshakeRequest(RequestContext context, SaslHandshakeRequest handshakeRequest) throws IOException, UnsupportedSaslMechanismException {
    String clientMechanism = handshakeRequest.mechanism();
    short version = context.header.apiVersion();
    if (version >= 1)
        this.enableKafkaSaslAuthenticateHeaders(true);
    if (enabledMechanisms.contains(clientMechanism)) {
        LOG.debug("Using SASL mechanism '{}' provided by client", clientMechanism);
        sendKafkaResponse(context, new SaslHandshakeResponse(Errors.NONE, enabledMechanisms));
        return clientMechanism;
    } else {
        LOG.debug("SASL mechanism '{}' requested by client is not supported", clientMechanism);
        sendKafkaResponse(context, 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)

Example 7 with SaslHandshakeResponse

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

the class SaslAuthenticatorTest method sendHandshakeRequestReceiveResponse.

private SaslHandshakeResponse sendHandshakeRequestReceiveResponse(String node, short version) throws Exception {
    SaslHandshakeRequest handshakeRequest = new SaslHandshakeRequest.Builder("PLAIN").build(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 8 with SaslHandshakeResponse

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

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, short saslHandshakeVersion) 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);
    assertEquals(ApiKeys.SASL_AUTHENTICATE.oldestVersion(), versionsResponse.apiVersion(ApiKeys.SASL_AUTHENTICATE.id).minVersion);
    assertEquals(ApiKeys.SASL_AUTHENTICATE.latestVersion(), versionsResponse.apiVersion(ApiKeys.SASL_AUTHENTICATE.id).maxVersion);
    // Send SaslHandshakeRequest and check response
    SaslHandshakeResponse handshakeResponse = sendHandshakeRequestReceiveResponse(node, saslHandshakeVersion);
    assertEquals(Collections.singletonList("PLAIN"), handshakeResponse.enabledMechanisms());
    // Complete manual authentication and check send/receive succeed
    authenticateUsingSaslPlainAndCheckConnection(node, saslHandshakeVersion > 0);
}
Also used : ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) SecurityProtocol(org.apache.kafka.common.security.auth.SecurityProtocol)

Example 9 with SaslHandshakeResponse

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

the class SaslServerAuthenticator method handleHandshakeRequest.

private String handleHandshakeRequest(RequestContext context, SaslHandshakeRequest handshakeRequest) throws IOException, UnsupportedSaslMechanismException {
    String clientMechanism = handshakeRequest.data().mechanism();
    short version = context.header.apiVersion();
    if (version >= 1)
        this.enableKafkaSaslAuthenticateHeaders(true);
    if (enabledMechanisms.contains(clientMechanism)) {
        LOG.debug("Using SASL mechanism '{}' provided by client", clientMechanism);
        sendKafkaResponse(context, new SaslHandshakeResponse(new SaslHandshakeResponseData().setErrorCode(Errors.NONE.code()).setMechanisms(enabledMechanisms)));
        return clientMechanism;
    } else {
        LOG.debug("SASL mechanism '{}' requested by client is not supported", clientMechanism);
        buildResponseOnAuthenticateFailure(context, new SaslHandshakeResponse(new SaslHandshakeResponseData().setErrorCode(Errors.UNSUPPORTED_SASL_MECHANISM.code()).setMechanisms(enabledMechanisms)));
        throw new UnsupportedSaslMechanismException("Unsupported SASL mechanism " + clientMechanism);
    }
}
Also used : SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) UnsupportedSaslMechanismException(org.apache.kafka.common.errors.UnsupportedSaslMechanismException) SaslHandshakeResponseData(org.apache.kafka.common.message.SaslHandshakeResponseData)

Example 10 with SaslHandshakeResponse

use of org.apache.kafka.common.requests.SaslHandshakeResponse 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.
 */
@SuppressWarnings("fallthrough")
public void authenticate() throws IOException {
    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.Builder().build((short) 0);
            send(apiVersionsRequest.toSend(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 {
                setSaslAuthenticateAndHandshakeVersions(apiVersionsResponse);
                reauthInfo.apiVersionsResponseReceivedFromBroker = apiVersionsResponse;
                setSaslState(SaslState.SEND_HANDSHAKE_REQUEST);
            // Fall through to send handshake request with the latest supported version
            }
        case SEND_HANDSHAKE_REQUEST:
            sendHandshakeRequest(saslHandshakeVersion);
            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:
            sendInitialToken();
            setSaslState(SaslState.INTERMEDIATE);
            break;
        case REAUTH_PROCESS_ORIG_APIVERSIONS_RESPONSE:
            setSaslAuthenticateAndHandshakeVersions(reauthInfo.apiVersionsResponseFromOriginalAuthentication);
            // Will set immediately
            setSaslState(SaslState.REAUTH_SEND_HANDSHAKE_REQUEST);
        // Fall through to send handshake request with the latest supported version
        case REAUTH_SEND_HANDSHAKE_REQUEST:
            sendHandshakeRequest(saslHandshakeVersion);
            setSaslState(SaslState.REAUTH_RECEIVE_HANDSHAKE_OR_OTHER_RESPONSE);
            break;
        case REAUTH_RECEIVE_HANDSHAKE_OR_OTHER_RESPONSE:
            handshakeResponse = (SaslHandshakeResponse) receiveKafkaResponse();
            if (handshakeResponse == null)
                break;
            handleSaslHandshakeResponse(handshakeResponse);
            // Will set immediately
            setSaslState(SaslState.REAUTH_INITIAL);
        /*
                 * Fall through and start SASL authentication using the configured client
                 * mechanism. Note that we have to either fall through or add a loop to enter
                 * the switch statement again. We will fall through to avoid adding the loop and
                 * therefore minimize the changes to authentication-related code due to the
                 * changes related to re-authentication.
                 */
        case REAUTH_INITIAL:
            sendInitialToken();
            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) SaslHandshakeResponse(org.apache.kafka.common.requests.SaslHandshakeResponse) ApiVersionsRequest(org.apache.kafka.common.requests.ApiVersionsRequest)

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