@Test
    public void testSuccess() throws Exception
    {
        // Setup test fixture
        final SecretKeyFactory HmacSHA1Factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        final String hardCodedClientNonce = "fyko+d2lbbFgONRv9qkxdawL";
        final String hardCodedSalt = "QSXCR+Q6sek8bf92";
        final int hardCodedIterations = 4096;
        final String hardCodedPassword = "pencil";
        final String hardCodedClientKey = "Client Key";
        final String hardCodedServerKey = "Server Key";

        authFactory.when(() -> AuthFactory.getSalt(any())).thenReturn(hardCodedSalt);
        authFactory.when(() -> AuthFactory.getIterations(any())).thenReturn(hardCodedIterations);
        authFactory.when(() -> AuthFactory.getPassword(any())).thenReturn(hardCodedPassword);
        authFactory.when(() -> AuthFactory.getStoredKey(any())).thenReturn(DatatypeConverter.printBase64Binary(StringUtils.decodeHex("e9d94660c39d65c38fbad91c358f14da0eef2bd6")));
        authFactory.when(() -> AuthFactory.getServerKey(any())).thenReturn(DatatypeConverter.printBase64Binary(StringUtils.decodeHex("0fe09258b3ac852ba502cc62ba903eaacdbf7d31")));

        // Setup test fixture: prepare initial client message.
        final ScramSha1SaslServer server = new ScramSha1SaslServer();
        final byte[] initialMessage = ("n,,n=user,r=" + hardCodedClientNonce).getBytes(StandardCharsets.UTF_8);

        // Execute system under test: getting the first server message.
        final String firstServerResponse = new String(server.evaluateResponse(initialMessage), StandardCharsets.UTF_8); // r=%s,s=%s,i=%d

        // Verify result (first server message should match a pattern, and contain a number of properties)
        final Matcher firstServerResponseMatcher = Pattern.compile("r=([^,]*),s=([^,]*),i=(.*)$").matcher(firstServerResponse);
        if (!firstServerResponseMatcher.matches()) {
            fail("First server message does not match expected pattern.");
        }
        final String serverNonce = firstServerResponseMatcher.group(1);
        assertTrue("First server message should contain a non-empty server nonce (but did not)", serverNonce != null && !serverNonce.isBlank());
        assertTrue("First server message should contain a server nonce that starts with the client nonce, but did not.", serverNonce.startsWith(hardCodedClientNonce));


        byte[] salt = null;
        try {
            salt = DatatypeConverter.parseBase64Binary(firstServerResponseMatcher.group(2));
            assertEquals("First server message should include the 'salt' value configured for this unit test (but did not)", hardCodedSalt, firstServerResponseMatcher.group(2));
        } catch (IllegalArgumentException e) {
            fail("First server message should contain a valid 'salt' value (but did not).");
        }

        int iterations = -1;
        try {
            iterations = Integer.parseInt(firstServerResponseMatcher.group(3));
            assertEquals("First server message should include the 'iterations' value configured for this unit test (but did not)", hardCodedIterations, iterations);
        } catch (NumberFormatException e) {
            fail("First server message should contain a valid 'iterations' value (but did not).");
        }

        // Setup test fixture: prepare second client message.
        final String clientFinalMessageBare = "c=biws,r=" + serverNonce;

        final KeySpec saltedPasswordSpec = new PBEKeySpec(hardCodedPassword.toCharArray(), salt, iterations, 20*8);
        final byte[] saltedPassword = HmacSHA1Factory.generateSecret(saltedPasswordSpec).getEncoded();

        final byte[] clientKey = new HmacUtils(HmacAlgorithms.HMAC_SHA_1, saltedPassword).hmac(hardCodedClientKey);
        final byte[] storedKey = StringUtils.decodeHex(StringUtils.hash(clientKey, "SHA-1"));
        final String authMessage = new String(initialMessage, StandardCharsets.UTF_8).substring(3) + "," + firstServerResponse + "," + clientFinalMessageBare;

        final byte[] clientSignature = new HmacUtils(HmacAlgorithms.HMAC_SHA_1, storedKey).hmac(authMessage);
        final byte[] clientProof = new byte[clientKey.length];
        for (int i=0; i<clientKey.length; i++) {
            clientProof[i] = (byte) (clientKey[i] ^ clientSignature[i]);
        }

        final byte[] serverKey = new HmacUtils(HmacAlgorithms.HMAC_SHA_1, saltedPassword).hmac(hardCodedServerKey);
        final byte[] serverSignature = new HmacUtils(HmacAlgorithms.HMAC_SHA_1, serverKey).hmac(authMessage);
        final String clientFinalMessage = clientFinalMessageBare + ",p=" + Base64.getEncoder().encodeToString(clientProof);

        try {
            // Execute system under test: getting the final server message.
            final byte[] serverFinalMessage = server.evaluateResponse(clientFinalMessage.getBytes(StandardCharsets.UTF_8));

            // Verify result: final server message should contain the calculated server signature.
            assertEquals(StringUtils.encodeHex(serverSignature), StringUtils.encodeHex(DatatypeConverter.parseBase64Binary(new String(serverFinalMessage, StandardCharsets.UTF_8).substring(2))));
        } catch (SaslException e) {
            fail("Authentication should not fail (but it did)");
        }
    }
Implements the example on <a href="https://wiki.xmpp.org/web/SASL_Authentication_and_SCRAM">https://wiki.xmpp.org/web/SASL_Authentication_and_SCRAM</a>
xmppserver/src/test/java/org/jivesoftware/openfire/sasl/ScramSha1SaslServerTest.java