Search in sources :

Example 1 with IllegalSaslStateException

use of org.apache.kafka.common.errors.IllegalSaslStateException in project apache-kafka-on-k8s by banzaicloud.

the class SaslClientAuthenticator method receiveKafkaResponse.

private AbstractResponse receiveKafkaResponse() throws IOException {
    try {
        byte[] responseBytes = receiveResponseOrToken();
        if (responseBytes == null)
            return null;
        else {
            AbstractResponse response = NetworkClient.parseResponse(ByteBuffer.wrap(responseBytes), currentRequestHeader);
            currentRequestHeader = null;
            return response;
        }
    } catch (SchemaException | IllegalArgumentException e) {
        LOG.debug("Invalid SASL mechanism response, server may be expecting only GSSAPI tokens");
        setSaslState(SaslState.FAILED);
        throw new IllegalSaslStateException("Invalid SASL mechanism response, server may be expecting a different protocol", e);
    }
}
Also used : SchemaException(org.apache.kafka.common.protocol.types.SchemaException) AbstractResponse(org.apache.kafka.common.requests.AbstractResponse) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException)

Example 2 with IllegalSaslStateException

use of org.apache.kafka.common.errors.IllegalSaslStateException in project apache-kafka-on-k8s by banzaicloud.

the class ScramSaslServer method evaluateResponse.

/**
 * @throws SaslAuthenticationException if the requested authorization id is not the same as username.
 * <p>
 * <b>Note:</b> This method may throw {@link SaslAuthenticationException} to provide custom error messages
 * to clients. But care should be taken to avoid including any information in the exception message that
 * should not be leaked to unauthenticated clients. It may be safer to throw {@link SaslException} in
 * most cases so that a standard error message is returned to clients.
 * </p>
 */
@Override
public byte[] evaluateResponse(byte[] response) throws SaslException, SaslAuthenticationException {
    try {
        switch(state) {
            case RECEIVE_CLIENT_FIRST_MESSAGE:
                this.clientFirstMessage = new ClientFirstMessage(response);
                this.scramExtensions = clientFirstMessage.extensions();
                if (!SUPPORTED_EXTENSIONS.containsAll(scramExtensions.extensionNames())) {
                    log.debug("Unsupported extensions will be ignored, supported {}, provided {}", SUPPORTED_EXTENSIONS, scramExtensions.extensionNames());
                }
                String serverNonce = formatter.secureRandomString();
                try {
                    String saslName = clientFirstMessage.saslName();
                    this.username = formatter.username(saslName);
                    NameCallback nameCallback = new NameCallback("username", username);
                    ScramCredentialCallback credentialCallback;
                    if (scramExtensions.tokenAuthenticated()) {
                        DelegationTokenCredentialCallback tokenCallback = new DelegationTokenCredentialCallback();
                        credentialCallback = tokenCallback;
                        callbackHandler.handle(new Callback[] { nameCallback, tokenCallback });
                        if (tokenCallback.tokenOwner() == null)
                            throw new SaslException("Token Authentication failed: Invalid tokenId : " + username);
                        this.authorizationId = tokenCallback.tokenOwner();
                    } else {
                        credentialCallback = new ScramCredentialCallback();
                        callbackHandler.handle(new Callback[] { nameCallback, credentialCallback });
                        this.authorizationId = username;
                    }
                    this.scramCredential = credentialCallback.scramCredential();
                    if (scramCredential == null)
                        throw new SaslException("Authentication failed: Invalid user credentials");
                    String authorizationIdFromClient = clientFirstMessage.authorizationId();
                    if (!authorizationIdFromClient.isEmpty() && !authorizationIdFromClient.equals(username))
                        throw new SaslAuthenticationException("Authentication failed: Client requested an authorization id that is different from username");
                    if (scramCredential.iterations() < mechanism.minIterations())
                        throw new SaslException("Iterations " + scramCredential.iterations() + " is less than the minimum " + mechanism.minIterations() + " for " + mechanism);
                    this.serverFirstMessage = new ServerFirstMessage(clientFirstMessage.nonce(), serverNonce, scramCredential.salt(), scramCredential.iterations());
                    setState(State.RECEIVE_CLIENT_FINAL_MESSAGE);
                    return serverFirstMessage.toBytes();
                } catch (IOException | NumberFormatException | UnsupportedCallbackException e) {
                    throw new SaslException("Authentication failed: Credentials could not be obtained", e);
                }
            case RECEIVE_CLIENT_FINAL_MESSAGE:
                try {
                    ClientFinalMessage clientFinalMessage = new ClientFinalMessage(response);
                    verifyClientProof(clientFinalMessage);
                    byte[] serverKey = scramCredential.serverKey();
                    byte[] serverSignature = formatter.serverSignature(serverKey, clientFirstMessage, serverFirstMessage, clientFinalMessage);
                    ServerFinalMessage serverFinalMessage = new ServerFinalMessage(null, serverSignature);
                    clearCredentials();
                    setState(State.COMPLETE);
                    return serverFinalMessage.toBytes();
                } catch (InvalidKeyException e) {
                    throw new SaslException("Authentication failed: Invalid client final message", e);
                }
            default:
                throw new IllegalSaslStateException("Unexpected challenge in Sasl server state " + state);
        }
    } catch (SaslException e) {
        clearCredentials();
        setState(State.FAILED);
        throw e;
    }
}
Also used : ClientFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ClientFirstMessage) IOException(java.io.IOException) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) SaslException(javax.security.sasl.SaslException) InvalidKeyException(java.security.InvalidKeyException) NameCallback(javax.security.auth.callback.NameCallback) ClientFinalMessage(org.apache.kafka.common.security.scram.ScramMessages.ClientFinalMessage) ServerFinalMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFinalMessage) DelegationTokenCredentialCallback(org.apache.kafka.common.security.token.delegation.DelegationTokenCredentialCallback) ServerFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage) UnsupportedCallbackException(javax.security.auth.callback.UnsupportedCallbackException) SaslAuthenticationException(org.apache.kafka.common.errors.SaslAuthenticationException)

Example 3 with IllegalSaslStateException

use of org.apache.kafka.common.errors.IllegalSaslStateException in project kafka by apache.

the class ScramSaslClient method evaluateChallenge.

@Override
public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
    try {
        switch(state) {
            case SEND_CLIENT_FIRST_MESSAGE:
                if (challenge != null && challenge.length != 0)
                    throw new SaslException("Expected empty challenge");
                clientNonce = formatter.secureRandomString();
                NameCallback nameCallback = new NameCallback("Name:");
                ScramExtensionsCallback extensionsCallback = new ScramExtensionsCallback();
                try {
                    callbackHandler.handle(new Callback[] { nameCallback });
                    try {
                        callbackHandler.handle(new Callback[] { extensionsCallback });
                    } catch (UnsupportedCallbackException e) {
                        log.debug("Extensions callback is not supported by client callback handler {}, no extensions will be added", callbackHandler);
                    }
                } catch (Throwable e) {
                    throw new SaslException("User name or extensions could not be obtained", e);
                }
                String username = nameCallback.getName();
                String saslName = ScramFormatter.saslName(username);
                Map<String, String> extensions = extensionsCallback.extensions();
                this.clientFirstMessage = new ScramMessages.ClientFirstMessage(saslName, clientNonce, extensions);
                setState(State.RECEIVE_SERVER_FIRST_MESSAGE);
                return clientFirstMessage.toBytes();
            case RECEIVE_SERVER_FIRST_MESSAGE:
                this.serverFirstMessage = new ServerFirstMessage(challenge);
                if (!serverFirstMessage.nonce().startsWith(clientNonce))
                    throw new SaslException("Invalid server nonce: does not start with client nonce");
                if (serverFirstMessage.iterations() < mechanism.minIterations())
                    throw new SaslException("Requested iterations " + serverFirstMessage.iterations() + " is less than the minimum " + mechanism.minIterations() + " for " + mechanism);
                PasswordCallback passwordCallback = new PasswordCallback("Password:", false);
                try {
                    callbackHandler.handle(new Callback[] { passwordCallback });
                } catch (Throwable e) {
                    throw new SaslException("User name could not be obtained", e);
                }
                this.clientFinalMessage = handleServerFirstMessage(passwordCallback.getPassword());
                setState(State.RECEIVE_SERVER_FINAL_MESSAGE);
                return clientFinalMessage.toBytes();
            case RECEIVE_SERVER_FINAL_MESSAGE:
                ServerFinalMessage serverFinalMessage = new ServerFinalMessage(challenge);
                if (serverFinalMessage.error() != null)
                    throw new SaslException("Sasl authentication using " + mechanism + " failed with error: " + serverFinalMessage.error());
                handleServerFinalMessage(serverFinalMessage.serverSignature());
                setState(State.COMPLETE);
                return null;
            default:
                throw new IllegalSaslStateException("Unexpected challenge in Sasl client state " + state);
        }
    } catch (SaslException e) {
        setState(State.FAILED);
        throw e;
    }
}
Also used : IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) SaslException(javax.security.sasl.SaslException) NameCallback(javax.security.auth.callback.NameCallback) ScramExtensionsCallback(org.apache.kafka.common.security.scram.ScramExtensionsCallback) ServerFinalMessage(org.apache.kafka.common.security.scram.internals.ScramMessages.ServerFinalMessage) PasswordCallback(javax.security.auth.callback.PasswordCallback) ServerFirstMessage(org.apache.kafka.common.security.scram.internals.ScramMessages.ServerFirstMessage) UnsupportedCallbackException(javax.security.auth.callback.UnsupportedCallbackException)

Example 4 with IllegalSaslStateException

use of org.apache.kafka.common.errors.IllegalSaslStateException 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 5 with IllegalSaslStateException

use of org.apache.kafka.common.errors.IllegalSaslStateException in project kafka by apache.

the class SaslClientAuthenticator method receiveKafkaResponse.

private AbstractResponse receiveKafkaResponse() throws IOException {
    if (netInBuffer == null)
        netInBuffer = new NetworkReceive(node);
    NetworkReceive receive = netInBuffer;
    try {
        byte[] responseBytes = receiveResponseOrToken();
        if (responseBytes == null)
            return null;
        else {
            AbstractResponse response = NetworkClient.parseResponse(ByteBuffer.wrap(responseBytes), currentRequestHeader);
            currentRequestHeader = null;
            return response;
        }
    } catch (BufferUnderflowException | SchemaException | IllegalArgumentException e) {
        /*
             * Account for the fact that during re-authentication there may be responses
             * arriving for requests that were sent in the past.
             */
        if (reauthInfo.reauthenticating()) {
            /*
                 * It didn't match the current request header, so it must be unrelated to
                 * re-authentication. Save it so it can be processed later.
                 */
            receive.payload().rewind();
            reauthInfo.pendingAuthenticatedReceives.add(receive);
            return null;
        }
        log.debug("Invalid SASL mechanism response, server may be expecting only GSSAPI tokens");
        setSaslState(SaslState.FAILED);
        throw new IllegalSaslStateException("Invalid SASL mechanism response, server may be expecting a different protocol", e);
    }
}
Also used : SchemaException(org.apache.kafka.common.protocol.types.SchemaException) AbstractResponse(org.apache.kafka.common.requests.AbstractResponse) NetworkReceive(org.apache.kafka.common.network.NetworkReceive) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) BufferUnderflowException(java.nio.BufferUnderflowException)

Aggregations

IllegalSaslStateException (org.apache.kafka.common.errors.IllegalSaslStateException)15 SaslException (javax.security.sasl.SaslException)9 IOException (java.io.IOException)6 ByteBuffer (java.nio.ByteBuffer)6 NameCallback (javax.security.auth.callback.NameCallback)6 UnsupportedCallbackException (javax.security.auth.callback.UnsupportedCallbackException)6 RequestHeader (org.apache.kafka.common.requests.RequestHeader)6 ApiKeys (org.apache.kafka.common.protocol.ApiKeys)5 SaslAuthenticationException (org.apache.kafka.common.errors.SaslAuthenticationException)4 RequestAndSize (org.apache.kafka.common.requests.RequestAndSize)4 RequestContext (org.apache.kafka.common.requests.RequestContext)4 ServerFinalMessage (org.apache.kafka.common.security.scram.ScramMessages.ServerFinalMessage)4 ServerFirstMessage (org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage)4 InvalidKeyException (java.security.InvalidKeyException)3 PasswordCallback (javax.security.auth.callback.PasswordCallback)3 ApiVersionsRequest (org.apache.kafka.common.requests.ApiVersionsRequest)3 InvalidRequestException (org.apache.kafka.common.errors.InvalidRequestException)2 UnsupportedSaslMechanismException (org.apache.kafka.common.errors.UnsupportedSaslMechanismException)2 UnsupportedVersionException (org.apache.kafka.common.errors.UnsupportedVersionException)2 TransportLayer (org.apache.kafka.common.network.TransportLayer)2