@Override
    public byte[] evaluateResponse( @Nonnull final byte[] response ) throws SaslException
    {
        if ( isComplete() )
        {
            throw new IllegalStateException( "Authentication exchange already completed." );
        }

        // The value as sent to us in the 'from' attribute of the stream element sent by the remote server.
        final String defaultIdentity = session.getDefaultIdentity();

        // RFC 6120 Section 4.7.1:
        //    "Because a server is a "public entity" on the XMPP network, it MUST include the 'from' attribute after the
        //     confidentiality and integrity of the stream are protected via TLS or an equivalent security layer."
        //
        // When doing SASL EXTERNAL, TLS must already have been negotiated, which means that the 'from' attribute must have been set.
        if (defaultIdentity == null || defaultIdentity.isEmpty()) {
            throw new SaslFailureException(Failure.NOT_AUTHORIZED, "Peer does not provide 'from' attribute value on stream.");
        }

        final String requestedId;
        if (response.length == 0 && session.getSessionData(SASLAuthentication.SASL_LAST_RESPONSE_WAS_PROVIDED_BUT_EMPTY) == null) {
            if (PROPERTY_SASL_EXTERNAL_SERVER_REQUIRE_AUTHZID.getValue()) {
                // No initial response. Send a challenge to get one, per RFC 4422 appendix-A.
                return new byte[0];
            } else {
                requestedId = defaultIdentity;
            }
        }
        else
        {
            requestedId = new String( response, StandardCharsets.UTF_8 );
        }

        complete = true;

        Log.trace("Completing handshake with '{}' using authzid value: '{}'", defaultIdentity, requestedId);

        // Added for backwards compatibility. Not required by XMPP, but versions of Openfire prior to 4.8.0 did require the authzid to be present.
        if (SASLAuthentication.EXTERNAL_S2S_REQUIRE_AUTHZID.getValue() && requestedId.isEmpty()) {
            throw new SaslFailureException(Failure.INVALID_AUTHZID, "Peer does not provide authzid, which is required by configuration.");
        }

        // When an authorization identity is provided, make sure that it matches the 'from' value from the session stream.
        if (!requestedId.isEmpty() && !requestedId.equals(defaultIdentity)) {
            throw new SaslFailureException(Failure.INVALID_AUTHZID, "Stream 'from' attribute value '" + defaultIdentity + "' does not equal SASL authzid '" + requestedId + "'");
        }

        if (!SASLAuthentication.verifyCertificates(session.getConnection().getPeerCertificates(), defaultIdentity, true)) {
            throw new SaslFailureException(Failure.NOT_AUTHORIZED, "Server-to-Server certificate verification failed.");
        }

        authorizationID = defaultIdentity;

        Log.trace("Successfully authenticated '{}'", authorizationID);
        return null; // Success!
    }
@Test(expected = SaslFailureException.class)
    public void testInitialResponseDifferentFromStreamID() throws Exception
    {
        // Setup test fixture.
        final String authzID = "foo.example.org";
        final String certID = "bar.example.com";

        when(session.getDefaultIdentity()).thenReturn(authzID);
        when(session.getConnection()).thenReturn(connection);
        saslAuthentication.when(() -> SASLAuthentication.verifyCertificates(any(), eq(certID), anyBoolean())).thenReturn(true);

        final ExternalServerSaslServer server = new ExternalServerSaslServer(session);
        final byte[] input = authzID.getBytes(StandardCharsets.UTF_8);

        // Execute system under test.
        server.evaluateResponse(input);
    }