@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
    public void testNoInitialResponseWhileNotRequired() throws Exception
    {
        // Setup test fixture.
        final String streamID = "example.org";

        when(session.getSessionData(SASLAuthentication.SASL_LAST_RESPONSE_WAS_PROVIDED_BUT_EMPTY)).thenReturn(null);
        // TODO explicitly set SASLAuthentication#PROPERTY_SASL_EXTERNAL_SERVER_REQUIRE_AUTHZID instead of depending on the default value.

        // The following stubs are only used when the implementation under test progresses beyond the check for the
        // emptiness of the initial response. It should not progress beyond that point. I'm leaving the stubs in, for
        // the test to fail gracefully (rather than throw an exception) when the system under test misbehaves.
        when(session.getDefaultIdentity()).thenReturn(streamID);
        when(session.getConnection()).thenReturn(connection);
        saslAuthentication.when(() -> SASLAuthentication.verifyCertificates(any(), eq(streamID), anyBoolean())).thenReturn(true);

        final ExternalServerSaslServer server = new ExternalServerSaslServer(session);
        final byte[] input = new byte[]{};

        // Execute system under test.
        final byte[] response = server.evaluateResponse(input);

        // Verify results.
        assertNull(response);
    }