Search in sources :

Example 11 with IllegalSaslStateException

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

the class SaslServerAuthenticatorTest method testUnexpectedRequestType.

@Test
public void testUnexpectedRequestType() throws IOException {
    TransportLayer transportLayer = EasyMock.mock(TransportLayer.class);
    Map<String, ?> configs = Collections.singletonMap(BrokerSecurityConfigs.SASL_ENABLED_MECHANISMS_CONFIG, Collections.singletonList(SCRAM_SHA_256.mechanismName()));
    SaslServerAuthenticator authenticator = setupAuthenticator(configs, transportLayer, SCRAM_SHA_256.mechanismName());
    final RequestHeader header = new RequestHeader(ApiKeys.METADATA, (short) 0, "clientId", 13243);
    final Struct headerStruct = header.toStruct();
    final Capture<ByteBuffer> size = EasyMock.newCapture();
    EasyMock.expect(transportLayer.read(EasyMock.capture(size))).andAnswer(new IAnswer<Integer>() {

        @Override
        public Integer answer() throws Throwable {
            size.getValue().putInt(headerStruct.sizeOf());
            return 4;
        }
    });
    final Capture<ByteBuffer> payload = EasyMock.newCapture();
    EasyMock.expect(transportLayer.read(EasyMock.capture(payload))).andAnswer(new IAnswer<Integer>() {

        @Override
        public Integer answer() throws Throwable {
            // serialize only the request header. the authenticator should not parse beyond this
            headerStruct.writeTo(payload.getValue());
            return headerStruct.sizeOf();
        }
    });
    EasyMock.replay(transportLayer);
    try {
        authenticator.authenticate();
        fail("Expected authenticate() to raise an exception");
    } catch (IllegalSaslStateException e) {
    // expected exception
    }
}
Also used : IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) ByteBuffer(java.nio.ByteBuffer) Struct(org.apache.kafka.common.protocol.types.Struct) TransportLayer(org.apache.kafka.common.network.TransportLayer) RequestHeader(org.apache.kafka.common.requests.RequestHeader) Test(org.junit.Test)

Example 12 with IllegalSaslStateException

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

Example 13 with IllegalSaslStateException

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

the class OAuthBearerSaslClient method evaluateChallenge.

@Override
public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
    try {
        OAuthBearerTokenCallback callback = new OAuthBearerTokenCallback();
        switch(state) {
            case SEND_CLIENT_FIRST_MESSAGE:
                if (challenge != null && challenge.length != 0)
                    throw new SaslException("Expected empty challenge");
                callbackHandler().handle(new Callback[] { callback });
                SaslExtensions extensions = retrieveCustomExtensions();
                setState(State.RECEIVE_SERVER_FIRST_MESSAGE);
                return new OAuthBearerClientInitialResponse(callback.token().value(), extensions).toBytes();
            case RECEIVE_SERVER_FIRST_MESSAGE:
                if (challenge != null && challenge.length != 0) {
                    String jsonErrorResponse = new String(challenge, StandardCharsets.UTF_8);
                    if (log.isDebugEnabled())
                        log.debug("Sending %%x01 response to server after receiving an error: {}", jsonErrorResponse);
                    setState(State.RECEIVE_SERVER_MESSAGE_AFTER_FAILURE);
                    return new byte[] { BYTE_CONTROL_A };
                }
                callbackHandler().handle(new Callback[] { callback });
                if (log.isDebugEnabled())
                    log.debug("Successfully authenticated as {}", callback.token().principalName());
                setState(State.COMPLETE);
                return null;
            default:
                throw new IllegalSaslStateException("Unexpected challenge in Sasl client state " + state);
        }
    } catch (SaslException e) {
        setState(State.FAILED);
        throw e;
    } catch (IOException | UnsupportedCallbackException e) {
        setState(State.FAILED);
        throw new SaslException(e.getMessage(), e);
    }
}
Also used : OAuthBearerTokenCallback(org.apache.kafka.common.security.oauthbearer.OAuthBearerTokenCallback) SaslExtensions(org.apache.kafka.common.security.auth.SaslExtensions) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) IOException(java.io.IOException) UnsupportedCallbackException(javax.security.auth.callback.UnsupportedCallbackException) SaslException(javax.security.sasl.SaslException)

Example 14 with IllegalSaslStateException

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

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.map().keySet())) {
                    log.debug("Unsupported extensions will be ignored, supported {}, provided {}", SUPPORTED_EXTENSIONS, scramExtensions.map().keySet());
                }
                String serverNonce = formatter.secureRandomString();
                try {
                    String saslName = clientFirstMessage.saslName();
                    this.username = ScramFormatter.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();
                        this.tokenExpiryTimestamp = tokenCallback.tokenExpiryTimestamp();
                    } else {
                        credentialCallback = new ScramCredentialCallback();
                        callbackHandler.handle(new Callback[] { nameCallback, credentialCallback });
                        this.authorizationId = username;
                        this.tokenExpiryTimestamp = null;
                    }
                    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 (SaslException | AuthenticationException e) {
                    throw e;
                } catch (Throwable 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 | AuthenticationException e) {
        clearCredentials();
        setState(State.FAILED);
        throw e;
    }
}
Also used : ClientFirstMessage(org.apache.kafka.common.security.scram.internals.ScramMessages.ClientFirstMessage) SaslAuthenticationException(org.apache.kafka.common.errors.SaslAuthenticationException) AuthenticationException(org.apache.kafka.common.errors.AuthenticationException) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) SaslException(javax.security.sasl.SaslException) InvalidKeyException(java.security.InvalidKeyException) NameCallback(javax.security.auth.callback.NameCallback) ScramCredentialCallback(org.apache.kafka.common.security.scram.ScramCredentialCallback) ClientFinalMessage(org.apache.kafka.common.security.scram.internals.ScramMessages.ClientFinalMessage) ServerFinalMessage(org.apache.kafka.common.security.scram.internals.ScramMessages.ServerFinalMessage) DelegationTokenCredentialCallback(org.apache.kafka.common.security.token.delegation.internals.DelegationTokenCredentialCallback) ServerFirstMessage(org.apache.kafka.common.security.scram.internals.ScramMessages.ServerFirstMessage) SaslAuthenticationException(org.apache.kafka.common.errors.SaslAuthenticationException)

Example 15 with IllegalSaslStateException

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

the class SaslServerAuthenticatorTest method testUnexpectedRequestType.

@Test
public void testUnexpectedRequestType() throws IOException {
    TransportLayer transportLayer = mock(TransportLayer.class);
    Map<String, ?> configs = Collections.singletonMap(BrokerSecurityConfigs.SASL_ENABLED_MECHANISMS_CONFIG, Collections.singletonList(SCRAM_SHA_256.mechanismName()));
    SaslServerAuthenticator authenticator = setupAuthenticator(configs, transportLayer, SCRAM_SHA_256.mechanismName(), new DefaultChannelMetadataRegistry());
    RequestHeader header = new RequestHeader(ApiKeys.METADATA, (short) 0, "clientId", 13243);
    ByteBuffer headerBuffer = RequestTestUtils.serializeRequestHeader(header);
    when(transportLayer.read(any(ByteBuffer.class))).then(invocation -> {
        invocation.<ByteBuffer>getArgument(0).putInt(headerBuffer.remaining());
        return 4;
    }).then(invocation -> {
        // serialize only the request header. the authenticator should not parse beyond this
        invocation.<ByteBuffer>getArgument(0).put(headerBuffer.duplicate());
        return headerBuffer.remaining();
    });
    try {
        authenticator.authenticate();
        fail("Expected authenticate() to raise an exception");
    } catch (IllegalSaslStateException e) {
    // expected exception
    }
    verify(transportLayer, times(2)).read(any(ByteBuffer.class));
}
Also used : Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) ApiVersionsRequest(org.apache.kafka.common.requests.ApiVersionsRequest) AppInfoParser(org.apache.kafka.common.utils.AppInfoParser) RequestTestUtils(org.apache.kafka.common.requests.RequestTestUtils) HashMap(java.util.HashMap) AuthenticateCallbackHandler(org.apache.kafka.common.security.auth.AuthenticateCallbackHandler) ClientInformation(org.apache.kafka.common.network.ClientInformation) SecurityProtocol(org.apache.kafka.common.security.auth.SecurityProtocol) ByteBuffer(java.nio.ByteBuffer) InetAddress(java.net.InetAddress) ListenerName(org.apache.kafka.common.network.ListenerName) RequestHeader(org.apache.kafka.common.requests.RequestHeader) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) ApiVersionsResponse(org.apache.kafka.common.requests.ApiVersionsResponse) Map(java.util.Map) PlainLoginModule(org.apache.kafka.common.security.plain.PlainLoginModule) SCRAM_SHA_256(org.apache.kafka.common.security.scram.internals.ScramMechanism.SCRAM_SHA_256) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) DefaultChannelMetadataRegistry(org.apache.kafka.common.network.DefaultChannelMetadataRegistry) Answers(org.mockito.Answers) Time(org.apache.kafka.common.utils.Time) BrokerSecurityConfigs(org.apache.kafka.common.config.internals.BrokerSecurityConfigs) TransportLayer(org.apache.kafka.common.network.TransportLayer) IOException(java.io.IOException) Mockito.times(org.mockito.Mockito.times) InvalidReceiveException(org.apache.kafka.common.network.InvalidReceiveException) Mockito.when(org.mockito.Mockito.when) ApiKeys(org.apache.kafka.common.protocol.ApiKeys) Subject(javax.security.auth.Subject) Mockito.verify(org.mockito.Mockito.verify) Test(org.junit.jupiter.api.Test) ApiMessageType(org.apache.kafka.common.message.ApiMessageType) ChannelMetadataRegistry(org.apache.kafka.common.network.ChannelMetadataRegistry) Collections(java.util.Collections) Mockito.mock(org.mockito.Mockito.mock) TransportLayer(org.apache.kafka.common.network.TransportLayer) RequestHeader(org.apache.kafka.common.requests.RequestHeader) DefaultChannelMetadataRegistry(org.apache.kafka.common.network.DefaultChannelMetadataRegistry) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) ByteBuffer(java.nio.ByteBuffer) Test(org.junit.jupiter.api.Test)

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