Search in sources :

Example 1 with ServerFirstMessage

use of org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage in project kafka by apache.

the class ScramFormatterTest method rfc7677Example.

/**
     * Tests that the formatter implementation produces the same values for the
     * example included in <a href="https://tools.ietf.org/html/rfc5802#section-5">RFC 7677</a>
     */
@Test
public void rfc7677Example() throws Exception {
    ScramFormatter formatter = new ScramFormatter(ScramMechanism.SCRAM_SHA_256);
    String password = "pencil";
    String c1 = "n,,n=user,r=rOprNGfwEbeRWgbNEkqO";
    String s1 = "r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096";
    String c2 = "c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=";
    String s2 = "v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4=";
    ClientFirstMessage clientFirst = new ClientFirstMessage(formatter.toBytes(c1));
    ServerFirstMessage serverFirst = new ServerFirstMessage(formatter.toBytes(s1));
    ClientFinalMessage clientFinal = new ClientFinalMessage(formatter.toBytes(c2));
    ServerFinalMessage serverFinal = new ServerFinalMessage(formatter.toBytes(s2));
    String username = clientFirst.saslName();
    assertEquals("user", username);
    String clientNonce = clientFirst.nonce();
    assertEquals("rOprNGfwEbeRWgbNEkqO", clientNonce);
    String serverNonce = serverFirst.nonce().substring(clientNonce.length());
    assertEquals("%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0", serverNonce);
    byte[] salt = serverFirst.salt();
    assertArrayEquals(DatatypeConverter.parseBase64Binary("W22ZaJ0SNY7soEsUEjb6gQ=="), salt);
    int iterations = serverFirst.iterations();
    assertEquals(4096, iterations);
    byte[] channelBinding = clientFinal.channelBinding();
    assertArrayEquals(DatatypeConverter.parseBase64Binary("biws"), channelBinding);
    byte[] serverSignature = serverFinal.serverSignature();
    assertArrayEquals(DatatypeConverter.parseBase64Binary("6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4="), serverSignature);
    byte[] saltedPassword = formatter.saltedPassword(password, salt, iterations);
    byte[] serverKey = formatter.serverKey(saltedPassword);
    byte[] computedProof = formatter.clientProof(saltedPassword, clientFirst, serverFirst, clientFinal);
    assertArrayEquals(clientFinal.proof(), computedProof);
    byte[] computedSignature = formatter.serverSignature(serverKey, clientFirst, serverFirst, clientFinal);
    assertArrayEquals(serverFinal.serverSignature(), computedSignature);
    // Minimum iterations defined in RFC-7677
    assertEquals(4096, ScramMechanism.SCRAM_SHA_256.minIterations());
}
Also used : ClientFinalMessage(org.apache.kafka.common.security.scram.ScramMessages.ClientFinalMessage) ClientFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ClientFirstMessage) ServerFinalMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFinalMessage) ServerFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage) Test(org.junit.Test)

Example 2 with ServerFirstMessage

use of org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage in project kafka by apache.

the class ScramMessagesTest method validServerFirstMessage.

@Test
public void validServerFirstMessage() throws SaslException {
    String clientNonce = formatter.secureRandomString();
    String serverNonce = formatter.secureRandomString();
    String nonce = clientNonce + serverNonce;
    String salt = randomBytesAsString();
    ServerFirstMessage m = new ServerFirstMessage(clientNonce, serverNonce, toBytes(salt), 8192);
    checkServerFirstMessage(m, nonce, salt, 8192);
    // Default format used by Kafka clients, only nonce, salt and iterations are specified
    String str = String.format("r=%s,s=%s,i=4096", nonce, salt);
    m = createScramMessage(ServerFirstMessage.class, str);
    checkServerFirstMessage(m, nonce, salt, 4096);
    m = new ServerFirstMessage(m.toBytes());
    checkServerFirstMessage(m, nonce, salt, 4096);
    // Optional reserved value
    for (String reserved : VALID_RESERVED) {
        str = String.format("%s,r=%s,s=%s,i=4096", reserved, nonce, salt);
        checkServerFirstMessage(createScramMessage(ServerFirstMessage.class, str), nonce, salt, 4096);
    }
    // Optional extension
    for (String extension : VALID_EXTENSIONS) {
        str = String.format("r=%s,s=%s,i=4096,%s", nonce, salt, extension);
        checkServerFirstMessage(createScramMessage(ServerFirstMessage.class, str), nonce, salt, 4096);
    }
}
Also used : ServerFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage) Test(org.junit.Test)

Example 3 with ServerFirstMessage

use of org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage in project apache-kafka-on-k8s by banzaicloud.

the class ScramMessagesTest method validServerFirstMessage.

@Test
public void validServerFirstMessage() throws SaslException {
    String clientNonce = formatter.secureRandomString();
    String serverNonce = formatter.secureRandomString();
    String nonce = clientNonce + serverNonce;
    String salt = randomBytesAsString();
    ServerFirstMessage m = new ServerFirstMessage(clientNonce, serverNonce, toBytes(salt), 8192);
    checkServerFirstMessage(m, nonce, salt, 8192);
    // Default format used by Kafka clients, only nonce, salt and iterations are specified
    String str = String.format("r=%s,s=%s,i=4096", nonce, salt);
    m = createScramMessage(ServerFirstMessage.class, str);
    checkServerFirstMessage(m, nonce, salt, 4096);
    m = new ServerFirstMessage(m.toBytes());
    checkServerFirstMessage(m, nonce, salt, 4096);
    // Optional reserved value
    for (String reserved : VALID_RESERVED) {
        str = String.format("%s,r=%s,s=%s,i=4096", reserved, nonce, salt);
        checkServerFirstMessage(createScramMessage(ServerFirstMessage.class, str), nonce, salt, 4096);
    }
    // Optional extension
    for (String extension : VALID_EXTENSIONS) {
        str = String.format("r=%s,s=%s,i=4096,%s", nonce, salt, extension);
        checkServerFirstMessage(createScramMessage(ServerFirstMessage.class, str), nonce, salt, 4096);
    }
}
Also used : ServerFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage) Test(org.junit.Test)

Example 4 with ServerFirstMessage

use of org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage 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 5 with ServerFirstMessage

use of org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage 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:");
                try {
                    callbackHandler.handle(new Callback[] { nameCallback });
                } catch (IOException | UnsupportedCallbackException e) {
                    throw new SaslException("User name could not be obtained", e);
                }
                String username = nameCallback.getName();
                String saslName = formatter.saslName(username);
                this.clientFirstMessage = new ScramMessages.ClientFirstMessage(saslName, clientNonce);
                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 (IOException | UnsupportedCallbackException 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 : NameCallback(javax.security.auth.callback.NameCallback) ServerFinalMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFinalMessage) PasswordCallback(javax.security.auth.callback.PasswordCallback) ServerFirstMessage(org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage) IOException(java.io.IOException) UnsupportedCallbackException(javax.security.auth.callback.UnsupportedCallbackException) IllegalSaslStateException(org.apache.kafka.common.errors.IllegalSaslStateException) SaslException(javax.security.sasl.SaslException)

Aggregations

ServerFirstMessage (org.apache.kafka.common.security.scram.ScramMessages.ServerFirstMessage)8 ServerFinalMessage (org.apache.kafka.common.security.scram.ScramMessages.ServerFinalMessage)6 IOException (java.io.IOException)4 NameCallback (javax.security.auth.callback.NameCallback)4 UnsupportedCallbackException (javax.security.auth.callback.UnsupportedCallbackException)4 SaslException (javax.security.sasl.SaslException)4 IllegalSaslStateException (org.apache.kafka.common.errors.IllegalSaslStateException)4 ClientFinalMessage (org.apache.kafka.common.security.scram.ScramMessages.ClientFinalMessage)4 ClientFirstMessage (org.apache.kafka.common.security.scram.ScramMessages.ClientFirstMessage)4 Test (org.junit.Test)4 InvalidKeyException (java.security.InvalidKeyException)2 PasswordCallback (javax.security.auth.callback.PasswordCallback)2 SaslAuthenticationException (org.apache.kafka.common.errors.SaslAuthenticationException)1 DelegationTokenCredentialCallback (org.apache.kafka.common.security.token.delegation.DelegationTokenCredentialCallback)1