Search in sources :

Example 1 with RequestAndSize

use of org.apache.kafka.common.requests.RequestAndSize 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 header = RequestHeader.parse(requestBuffer);
        ApiKeys apiKey = header.apiKey();
        // following a SaslHandshakeRequest since this is not a GSSAPI client token from a Kafka 0.9.0.x client.
        if (saslState == SaslState.INITIAL_REQUEST)
            setSaslState(SaslState.HANDSHAKE_OR_VERSIONS_REQUEST);
        isKafkaRequest = true;
        // unnecessary exposure to some of the more complex schema types.
        if (apiKey != ApiKeys.API_VERSIONS && apiKey != ApiKeys.SASL_HANDSHAKE)
            throw new IllegalSaslStateException("Unexpected Kafka request of type " + apiKey + " during SASL handshake.");
        LOG.debug("Handling Kafka request {} during {}", apiKey, reauthInfo.authenticationOrReauthenticationText());
        RequestContext requestContext = new RequestContext(header, connectionId, clientAddress(), KafkaPrincipal.ANONYMOUS, listenerName, securityProtocol, ClientInformation.EMPTY, false);
        RequestAndSize requestAndSize = requestContext.parseRequest(requestBuffer);
        if (apiKey == ApiKeys.API_VERSIONS)
            handleApiVersionsRequest(requestContext, (ApiVersionsRequest) requestAndSize.request);
        else
            clientMechanism = handleHandshakeRequest(requestContext, (SaslHandshakeRequest) requestAndSize.request);
    } catch (InvalidRequestException e) {
        if (saslState == SaslState.INITIAL_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 && (!reauthInfo.reauthenticating() || reauthInfo.saslMechanismUnchanged(clientMechanism))) {
        createSaslServer(clientMechanism);
        setSaslState(SaslState.AUTHENTICATE);
    }
    return isKafkaRequest;
}
Also used : ApiKeys(org.apache.kafka.common.protocol.ApiKeys) RequestAndSize(org.apache.kafka.common.requests.RequestAndSize) UnsupportedSaslMechanismException(org.apache.kafka.common.errors.UnsupportedSaslMechanismException) RequestHeader(org.apache.kafka.common.requests.RequestHeader) InvalidRequestException(org.apache.kafka.common.errors.InvalidRequestException) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) RequestContext(org.apache.kafka.common.requests.RequestContext) ByteBuffer(java.nio.ByteBuffer) ApiVersionsRequest(org.apache.kafka.common.requests.ApiVersionsRequest)

Example 2 with RequestAndSize

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

the class SaslServerAuthenticator method handleSaslToken.

private void handleSaslToken(byte[] clientToken) throws IOException {
    if (!enableKafkaSaslAuthenticateHeaders) {
        byte[] response = saslServer.evaluateResponse(clientToken);
        if (response != null) {
            netOutBuffer = new NetworkSend(connectionId, ByteBuffer.wrap(response));
            flushNetOutBufferAndUpdateInterestOps();
        }
    } else {
        ByteBuffer requestBuffer = ByteBuffer.wrap(clientToken);
        RequestHeader header = RequestHeader.parse(requestBuffer);
        ApiKeys apiKey = header.apiKey();
        short version = header.apiVersion();
        RequestContext requestContext = new RequestContext(header, connectionId, clientAddress(), KafkaPrincipal.ANONYMOUS, listenerName, securityProtocol);
        RequestAndSize requestAndSize = requestContext.parseRequest(requestBuffer);
        if (apiKey != ApiKeys.SASL_AUTHENTICATE) {
            IllegalSaslStateException e = new IllegalSaslStateException("Unexpected Kafka request of type " + apiKey + " during SASL authentication.");
            sendKafkaResponse(requestContext, requestAndSize.request.getErrorResponse(e));
            throw e;
        }
        if (!apiKey.isVersionSupported(version)) {
            // This should not normally occur since clients typically check supported versions using ApiVersionsRequest
            throw new UnsupportedVersionException("Version " + version + " is not supported for apiKey " + apiKey);
        }
        SaslAuthenticateRequest saslAuthenticateRequest = (SaslAuthenticateRequest) requestAndSize.request;
        try {
            byte[] responseToken = saslServer.evaluateResponse(Utils.readBytes(saslAuthenticateRequest.saslAuthBytes()));
            // For versions with SASL_AUTHENTICATE header, send a response to SASL_AUTHENTICATE request even if token is empty.
            ByteBuffer responseBuf = responseToken == null ? EMPTY_BUFFER : ByteBuffer.wrap(responseToken);
            sendKafkaResponse(requestContext, new SaslAuthenticateResponse(Errors.NONE, null, responseBuf));
        } catch (SaslAuthenticationException | SaslException e) {
            String errorMessage = e instanceof SaslAuthenticationException ? e.getMessage() : "Authentication failed due to invalid credentials with SASL mechanism " + saslMechanism;
            sendKafkaResponse(requestContext, new SaslAuthenticateResponse(Errors.SASL_AUTHENTICATION_FAILED, errorMessage));
            throw e;
        }
    }
}
Also used : SaslAuthenticateResponse(org.apache.kafka.common.requests.SaslAuthenticateResponse) NetworkSend(org.apache.kafka.common.network.NetworkSend) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) SaslException(javax.security.sasl.SaslException) ByteBuffer(java.nio.ByteBuffer) ApiKeys(org.apache.kafka.common.protocol.ApiKeys) SaslAuthenticateRequest(org.apache.kafka.common.requests.SaslAuthenticateRequest) RequestAndSize(org.apache.kafka.common.requests.RequestAndSize) RequestHeader(org.apache.kafka.common.requests.RequestHeader) RequestContext(org.apache.kafka.common.requests.RequestContext) SaslAuthenticationException(org.apache.kafka.common.errors.SaslAuthenticationException) UnsupportedVersionException(org.apache.kafka.common.errors.UnsupportedVersionException)

Example 3 with RequestAndSize

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

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 header = RequestHeader.parse(requestBuffer);
        ApiKeys apiKey = header.apiKey();
        // following a SaslHandshakeRequest since this is not a GSSAPI client token from a Kafka 0.9.0.x client.
        if (saslState == SaslState.INITIAL_REQUEST)
            setSaslState(SaslState.HANDSHAKE_OR_VERSIONS_REQUEST);
        isKafkaRequest = true;
        // unnecessary exposure to some of the more complex schema types.
        if (apiKey != ApiKeys.API_VERSIONS && apiKey != ApiKeys.SASL_HANDSHAKE)
            throw new IllegalSaslStateException("Unexpected Kafka request of type " + apiKey + " during SASL handshake.");
        LOG.debug("Handling Kafka request {}", apiKey);
        RequestContext requestContext = new RequestContext(header, connectionId, clientAddress(), KafkaPrincipal.ANONYMOUS, listenerName, securityProtocol);
        RequestAndSize requestAndSize = requestContext.parseRequest(requestBuffer);
        if (apiKey == ApiKeys.API_VERSIONS)
            handleApiVersionsRequest(requestContext, (ApiVersionsRequest) requestAndSize.request);
        else
            clientMechanism = handleHandshakeRequest(requestContext, (SaslHandshakeRequest) requestAndSize.request);
    } catch (InvalidRequestException e) {
        if (saslState == SaslState.INITIAL_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;
}
Also used : ApiKeys(org.apache.kafka.common.protocol.ApiKeys) RequestAndSize(org.apache.kafka.common.requests.RequestAndSize) UnsupportedSaslMechanismException(org.apache.kafka.common.errors.UnsupportedSaslMechanismException) RequestHeader(org.apache.kafka.common.requests.RequestHeader) InvalidRequestException(org.apache.kafka.common.errors.InvalidRequestException) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) RequestContext(org.apache.kafka.common.requests.RequestContext) ByteBuffer(java.nio.ByteBuffer) ApiVersionsRequest(org.apache.kafka.common.requests.ApiVersionsRequest)

Example 4 with RequestAndSize

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

the class SaslServerAuthenticator method handleSaslToken.

private void handleSaslToken(byte[] clientToken) throws IOException {
    if (!enableKafkaSaslAuthenticateHeaders) {
        byte[] response = saslServer.evaluateResponse(clientToken);
        if (saslServer.isComplete()) {
            reauthInfo.calcCompletionTimesAndReturnSessionLifetimeMs();
            if (reauthInfo.reauthenticating())
                reauthInfo.ensurePrincipalUnchanged(principal());
        }
        if (response != null) {
            netOutBuffer = ByteBufferSend.sizePrefixed(ByteBuffer.wrap(response));
            flushNetOutBufferAndUpdateInterestOps();
        }
    } else {
        ByteBuffer requestBuffer = ByteBuffer.wrap(clientToken);
        RequestHeader header = RequestHeader.parse(requestBuffer);
        ApiKeys apiKey = header.apiKey();
        short version = header.apiVersion();
        RequestContext requestContext = new RequestContext(header, connectionId, clientAddress(), KafkaPrincipal.ANONYMOUS, listenerName, securityProtocol, ClientInformation.EMPTY, false);
        RequestAndSize requestAndSize = requestContext.parseRequest(requestBuffer);
        if (apiKey != ApiKeys.SASL_AUTHENTICATE) {
            IllegalSaslStateException e = new IllegalSaslStateException("Unexpected Kafka request of type " + apiKey + " during SASL authentication.");
            buildResponseOnAuthenticateFailure(requestContext, requestAndSize.request.getErrorResponse(e));
            throw e;
        }
        if (!apiKey.isVersionSupported(version)) {
            // This should not normally occur since clients typically check supported versions using ApiVersionsRequest
            throw new UnsupportedVersionException("Version " + version + " is not supported for apiKey " + apiKey);
        }
        /*
             * The client sends multiple SASL_AUTHENTICATE requests, and the client is known
             * to support the required version if any one of them indicates it supports that
             * version.
             */
        if (!reauthInfo.connectedClientSupportsReauthentication)
            reauthInfo.connectedClientSupportsReauthentication = version > 0;
        SaslAuthenticateRequest saslAuthenticateRequest = (SaslAuthenticateRequest) requestAndSize.request;
        try {
            byte[] responseToken = saslServer.evaluateResponse(Utils.copyArray(saslAuthenticateRequest.data().authBytes()));
            if (reauthInfo.reauthenticating() && saslServer.isComplete())
                reauthInfo.ensurePrincipalUnchanged(principal());
            // For versions with SASL_AUTHENTICATE header, send a response to SASL_AUTHENTICATE request even if token is empty.
            byte[] responseBytes = responseToken == null ? new byte[0] : responseToken;
            long sessionLifetimeMs = !saslServer.isComplete() ? 0L : reauthInfo.calcCompletionTimesAndReturnSessionLifetimeMs();
            sendKafkaResponse(requestContext, new SaslAuthenticateResponse(new SaslAuthenticateResponseData().setErrorCode(Errors.NONE.code()).setAuthBytes(responseBytes).setSessionLifetimeMs(sessionLifetimeMs)));
        } catch (SaslAuthenticationException e) {
            buildResponseOnAuthenticateFailure(requestContext, new SaslAuthenticateResponse(new SaslAuthenticateResponseData().setErrorCode(Errors.SASL_AUTHENTICATION_FAILED.code()).setErrorMessage(e.getMessage())));
            throw e;
        } catch (SaslException e) {
            KerberosError kerberosError = KerberosError.fromException(e);
            if (kerberosError != null && kerberosError.retriable()) {
                // Handle retriable Kerberos exceptions as I/O exceptions rather than authentication exceptions
                throw e;
            } else {
                // DO NOT include error message from the `SaslException` in the client response since it may
                // contain sensitive data like the existence of the user.
                String errorMessage = "Authentication failed during " + reauthInfo.authenticationOrReauthenticationText() + " due to invalid credentials with SASL mechanism " + saslMechanism;
                buildResponseOnAuthenticateFailure(requestContext, new SaslAuthenticateResponse(new SaslAuthenticateResponseData().setErrorCode(Errors.SASL_AUTHENTICATION_FAILED.code()).setErrorMessage(errorMessage)));
                throw new SaslAuthenticationException(errorMessage, e);
            }
        }
    }
}
Also used : SaslAuthenticateResponse(org.apache.kafka.common.requests.SaslAuthenticateResponse) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) KerberosError(org.apache.kafka.common.security.kerberos.KerberosError) SaslException(javax.security.sasl.SaslException) ByteBuffer(java.nio.ByteBuffer) SaslAuthenticateResponseData(org.apache.kafka.common.message.SaslAuthenticateResponseData) ApiKeys(org.apache.kafka.common.protocol.ApiKeys) SaslAuthenticateRequest(org.apache.kafka.common.requests.SaslAuthenticateRequest) RequestAndSize(org.apache.kafka.common.requests.RequestAndSize) RequestHeader(org.apache.kafka.common.requests.RequestHeader) RequestContext(org.apache.kafka.common.requests.RequestContext) SaslAuthenticationException(org.apache.kafka.common.errors.SaslAuthenticationException) UnsupportedVersionException(org.apache.kafka.common.errors.UnsupportedVersionException)

Aggregations

ByteBuffer (java.nio.ByteBuffer)4 IllegalSaslStateException (org.apache.kafka.common.errors.IllegalSaslStateException)4 ApiKeys (org.apache.kafka.common.protocol.ApiKeys)4 RequestAndSize (org.apache.kafka.common.requests.RequestAndSize)4 RequestContext (org.apache.kafka.common.requests.RequestContext)4 RequestHeader (org.apache.kafka.common.requests.RequestHeader)4 SaslException (javax.security.sasl.SaslException)2 InvalidRequestException (org.apache.kafka.common.errors.InvalidRequestException)2 SaslAuthenticationException (org.apache.kafka.common.errors.SaslAuthenticationException)2 UnsupportedSaslMechanismException (org.apache.kafka.common.errors.UnsupportedSaslMechanismException)2 UnsupportedVersionException (org.apache.kafka.common.errors.UnsupportedVersionException)2 ApiVersionsRequest (org.apache.kafka.common.requests.ApiVersionsRequest)2 SaslAuthenticateRequest (org.apache.kafka.common.requests.SaslAuthenticateRequest)2 SaslAuthenticateResponse (org.apache.kafka.common.requests.SaslAuthenticateResponse)2 SaslAuthenticateResponseData (org.apache.kafka.common.message.SaslAuthenticateResponseData)1 NetworkSend (org.apache.kafka.common.network.NetworkSend)1 KerberosError (org.apache.kafka.common.security.kerberos.KerberosError)1