Skip to content

Authentication

Aeron Cluster supports authenticating Client connections (ClusterSessions). When a client connects, encoded credentials can be passed in the SessionConnectRequest. Those can be authenticated, or followed by a challenge-response exchange.

There is a DefaultAuthenticator that does not authenticate and simply marks ClusterSessions as authenticated. There is also a SampleAuthenticator in Aeron Archive, but you are best to implement your own if you want authentication.

Authenticator

Aeron has an Authenticator interface, which is used in Aeron Cluster and Aeron Archive. The comments below describe how it's used in Aeron Cluster.

public interface Authenticator
{
    // called when SessionConnectRequest is received, but the Egress is not yet connected
    void onConnectRequest(long sessionId, byte[] encodedCredentials, long nowMs);

    // called when ChallengeResponse received on the Ingress
    void onChallengeResponse(long sessionId, byte[] encodedCredentials, long nowMs);

    // called repeatedly from slowTickWork (every 10 ms) after SessionConnectRequest
    // and Egress connected, but Challenge has not been sent
    void onConnectedSession(SessionProxy sessionProxy, long nowMs);

    // called repeatedly from slowTickWork (every 10ms) after SessionConnectRequest
    // and Egress connected, and Challenge has been sent
    void onChallengedSession(SessionProxy sessionProxy, long nowMs);
}

SessionProxy

The SessionProxy interface is implemented by ClusterSessionProxy when used in Aeron Cluster. It's a wrapper around the ClusterSession and EgressPublisher, which can send a Challenge request on the Egress, and mark the ClusterSession as authenticated or rejected.

public interface SessionProxy
{
    // Get the session's id
    long sessionId();

    // Ask the session to send a Challenge to the client
    boolean challenge(byte[] encodedChallenge);

    // Mark session as authenticated
    boolean authenticate(byte[] encodedPrincipal);

    // Mark session as rejected
    void reject();
}

Workflow

In Aeron Cluster, when the ConsensusModuleAgent receives the SessionConnectRequest on the Ingress, it calls onConnectRequest() on the Authenticator, passing in the encodedCredentials. The SessionProxy is not passed in at this stage (because the Egress is not yet connected), so the session can't be challenged, or marked authenticated / rejected, but the Authenticator can store the credentials for the session, keyed against the sessionId.

participant%20ConsensusModuleAgent%0Aparticipant%20Authenticator%0Aparticipant%20ClusterSessionProxy%0Aparticipant%20EgressPublisher%0Aparticipant%20ClusterSession%0A%0A%0AConsensusModuleAgent-%3EAuthenticator%3AonConnectRequest()%0AConsensusModuleAgentAuthenticatorClusterSessionProxyEgressPublisherClusterSessiononConnectRequest()

Slow tick work

Within slow tick work (covered later, but it's work that happens in the Consensus Module every 10 ms), the ConsensusModuleAgent checks whether the ClusterSession has established its Egress connection.

Once it has, then it calls one of onConnectedSession() or onChallengedSession(), depending on the state of the ClusterSession. To begin with, onConnectedSession() is called, which is passed a reference to the SessionProxy. Depending on how you implement the Authenticator, it can choose to authenticate the ClusterSession using the credentials it stored in onConnectRequest(), or ask the SessionProxy to challenge the client. If challenged, the SessionProxy sends a Challenge request on the Egress and moves the ClusterSession into the CHALLENGED state.

When in the CHALLENGED state, slow tick work calls onChallengedSession(). This gives the Authenticator an opportunity to time out the challenge and reject the ClusterSession, if so desired.

participant%20ConsensusModuleAgent%0Aparticipant%20Authenticator%0Aparticipant%20ClusterSessionProxy%0Aparticipant%20EgressPublisher%0Aparticipant%20ClusterSession%0A%0A%0AConsensusModuleAgent-%3EClusterSession%3AgetState()%0AConsensusModuleAgent-%3EAuthenticator%3AonConnectedSession()%0AAuthenticator-%3EClusterSessionProxy%3Achallenge()%0AClusterSessionProxy-%3EEgressPublisher%3AsendChallenge()%0AClusterSessionProxy-%3EClusterSession%3AsetState(CHALLENGED)%0AConsensusModuleAgent-%3EClusterSession%3AgetState()%0AConsensusModuleAgent-%3EAuthenticator%3AonChallengedSession()%0AConsensusModuleAgentAuthenticatorClusterSessionProxyEgressPublisherClusterSessiongetState()onConnectedSession()challenge()sendChallenge()setState(CHALLENGED)getState()onChallengedSession()

ChallengeResponse

If a Challenge was sent on the Egress, the client is expected to respond with a ChallengeResponse on the Ingress. When this is received, onChallengeResponse() is called, where the Authenticator can decide whether the ClusterSession should be authenticated or rejected. However, onChallengeResponse() isn't given the SessionProxy, so it needs to store decision and wait for the next call to onChallengedSession().

onChallengedSession() can then mark the session as authenticated or rejected, by calling the appropriate method on the SessionProxy.

participant%20ConsensusModuleAgent%0Aparticipant%20Authenticator%0Aparticipant%20ClusterSessionProxy%0Aparticipant%20EgressPublisher%0Aparticipant%20ClusterSession%0A%0A%0AConsensusModuleAgent-%3EAuthenticator%3AonChallengeResponse()%0AConsensusModuleAgent-%3EClusterSession%3AgetState()%0AConsensusModuleAgent-%3EAuthenticator%3AonChallengedSession()%0AAuthenticator-%3EClusterSessionProxy%3Aauthenticate()%0AClusterSessionProxy-%3EClusterSession%3Aauthenticate()ConsensusModuleAgentAuthenticatorClusterSessionProxyEgressPublisherClusterSessiononChallengeResponse()getState()onChallengedSession()authenticate()authenticate()