Search in sources :

Example 21 with ApiVersionsResponse

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

the class NetworkClient method handleCompletedReceives.

/**
 * Handle any completed receives and update the response list with the responses received.
 *
 * @param responses The list of responses to update
 * @param now The current time
 */
private void handleCompletedReceives(List<ClientResponse> responses, long now) {
    for (NetworkReceive receive : this.selector.completedReceives()) {
        String source = receive.source();
        InFlightRequest req = inFlightRequests.completeNext(source);
        Struct responseStruct = parseStructMaybeUpdateThrottleTimeMetrics(receive.payload(), req.header, throttleTimeSensor, now);
        if (log.isTraceEnabled()) {
            log.trace("Completed receive from node {} for {} with correlation id {}, received {}", req.destination, req.header.apiKey(), req.header.correlationId(), responseStruct);
        }
        AbstractResponse body = AbstractResponse.parseResponse(req.header.apiKey(), responseStruct);
        if (req.isInternalRequest && body instanceof MetadataResponse)
            metadataUpdater.handleCompletedMetadataResponse(req.header, now, (MetadataResponse) body);
        else if (req.isInternalRequest && body instanceof ApiVersionsResponse)
            handleApiVersionsResponse(responses, req, now, (ApiVersionsResponse) body);
        else
            responses.add(req.completed(body, now));
    }
}
Also used : ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) AbstractResponse(org.apache.kafka.common.requests.AbstractResponse) NetworkReceive(org.apache.kafka.common.network.NetworkReceive) MetadataResponse(org.apache.kafka.common.requests.MetadataResponse) Struct(org.apache.kafka.common.protocol.types.Struct)

Example 22 with ApiVersionsResponse

use of org.apache.kafka.common.requests.ApiVersionsResponse 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)

Example 23 with ApiVersionsResponse

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

the class NodeApiVersionsTest method testConstructionFromApiVersionsResponse.

@ParameterizedTest
@EnumSource(ApiMessageType.ListenerType.class)
public void testConstructionFromApiVersionsResponse(ApiMessageType.ListenerType scope) {
    ApiVersionsResponse apiVersionsResponse = ApiVersionsResponse.defaultApiVersionsResponse(scope);
    NodeApiVersions versions = new NodeApiVersions(apiVersionsResponse.data().apiKeys());
    for (ApiVersion apiVersionKey : apiVersionsResponse.data().apiKeys()) {
        ApiVersion apiVersion = versions.apiVersion(ApiKeys.forId(apiVersionKey.apiKey()));
        assertEquals(apiVersionKey.apiKey(), apiVersion.apiKey());
        assertEquals(apiVersionKey.minVersion(), apiVersion.minVersion());
        assertEquals(apiVersionKey.maxVersion(), apiVersion.maxVersion());
    }
}
Also used : ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) ApiVersion(org.apache.kafka.common.message.ApiVersionsResponseData.ApiVersion) EnumSource(org.junit.jupiter.params.provider.EnumSource) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 24 with ApiVersionsResponse

use of org.apache.kafka.common.requests.ApiVersionsResponse 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, 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 25 with ApiVersionsResponse

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

the class SaslAuthenticatorTest method startServerApiVersionsUnsupportedByClient.

private NioEchoServer startServerApiVersionsUnsupportedByClient(final SecurityProtocol securityProtocol, String saslMechanism) throws Exception {
    final ListenerName listenerName = ListenerName.forSecurityProtocol(securityProtocol);
    final Map<String, ?> configs = Collections.emptyMap();
    final JaasContext jaasContext = JaasContext.loadServerContext(listenerName, saslMechanism, configs);
    final Map<String, JaasContext> jaasContexts = Collections.singletonMap(saslMechanism, jaasContext);
    boolean isScram = ScramMechanism.isScram(saslMechanism);
    if (isScram)
        ScramCredentialUtils.createCache(credentialCache, Arrays.asList(saslMechanism));
    Supplier<ApiVersionsResponse> apiVersionSupplier = () -> {
        ApiVersionCollection versionCollection = new ApiVersionCollection(2);
        versionCollection.add(new ApiVersion().setApiKey(ApiKeys.SASL_HANDSHAKE.id).setMinVersion((short) 0).setMaxVersion((short) 100));
        versionCollection.add(new ApiVersion().setApiKey(ApiKeys.SASL_AUTHENTICATE.id).setMinVersion((short) 0).setMaxVersion((short) 100));
        return new ApiVersionsResponse(new ApiVersionsResponseData().setApiKeys(versionCollection));
    };
    SaslChannelBuilder serverChannelBuilder = new SaslChannelBuilder(Mode.SERVER, jaasContexts, securityProtocol, listenerName, false, saslMechanism, true, credentialCache, null, null, time, new LogContext(), apiVersionSupplier);
    serverChannelBuilder.configure(saslServerConfigs);
    server = new NioEchoServer(listenerName, securityProtocol, new TestSecurityConfig(saslServerConfigs), "localhost", serverChannelBuilder, credentialCache, time);
    server.start();
    return server;
}
Also used : ApiVersionCollection(org.apache.kafka.common.message.ApiVersionsResponseData.ApiVersionCollection) ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) ApiVersion(org.apache.kafka.common.message.ApiVersionsResponseData.ApiVersion) LogContext(org.apache.kafka.common.utils.LogContext) ListenerName(org.apache.kafka.common.network.ListenerName) JaasContext(org.apache.kafka.common.security.JaasContext) NioEchoServer(org.apache.kafka.common.network.NioEchoServer) TestSecurityConfig(org.apache.kafka.common.security.TestSecurityConfig) SaslChannelBuilder(org.apache.kafka.common.network.SaslChannelBuilder) ApiVersionsResponseData(org.apache.kafka.common.message.ApiVersionsResponseData)

Aggregations

ApiVersionsResponse (org.apache.kafka.common.requests.ApiVersionsResponse)30 ApiVersionsRequest (org.apache.kafka.common.requests.ApiVersionsRequest)11 ByteBuffer (java.nio.ByteBuffer)10 Test (org.junit.jupiter.api.Test)8 RequestHeader (org.apache.kafka.common.requests.RequestHeader)7 ApiVersion (org.apache.kafka.common.message.ApiVersionsResponseData.ApiVersion)6 NetworkReceive (org.apache.kafka.common.network.NetworkReceive)6 SecurityProtocol (org.apache.kafka.common.security.auth.SecurityProtocol)6 ApiVersionsResponseData (org.apache.kafka.common.message.ApiVersionsResponseData)5 ListenerName (org.apache.kafka.common.network.ListenerName)5 SaslHandshakeResponse (org.apache.kafka.common.requests.SaslHandshakeResponse)5 HashMap (java.util.HashMap)4 SaslChannelBuilder (org.apache.kafka.common.network.SaslChannelBuilder)4 JaasContext (org.apache.kafka.common.security.JaasContext)4 Map (java.util.Map)3 ClientRequest (org.apache.kafka.clients.ClientRequest)3 ApiVersionCollection (org.apache.kafka.common.message.ApiVersionsResponseData.ApiVersionCollection)3 NetworkSend (org.apache.kafka.common.network.NetworkSend)3 NioEchoServer (org.apache.kafka.common.network.NioEchoServer)3 TransportLayer (org.apache.kafka.common.network.TransportLayer)3