/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.security.sasl.digest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.wildfly.security.sasl.digest.DigestCallbackHandlerUtils.createClearPwdClientCallbackHandler;
import static org.wildfly.security.sasl.digest.DigestCallbackHandlerUtils.createDigestPwdClientCallbackHandler;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.spec.KeySpec;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslServerFactory;
import org.jboss.logging.Logger;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.wildfly.security.WildFlyElytronProvider;
import org.wildfly.security.password.interfaces.DigestPassword;
import org.wildfly.security.password.spec.DigestPasswordSpec;
import org.wildfly.security.sasl.WildFlySasl;
import org.wildfly.security.sasl.test.BaseTestCase;
import org.wildfly.security.sasl.test.SaslServerBuilder;
import org.wildfly.security.sasl.util.SaslMechanismInformation;
import org.wildfly.security.sasl.util.UsernamePasswordHashUtil;
/**
* A test case to test the server side of the Digest mechanism.
*
* @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
*/
public class DigestTest extends BaseTestCase {
private static Logger log = Logger.getLogger(DigestTest.class);
private static final String DIGEST = SaslMechanismInformation.Names.DIGEST_MD5;
private static final String REALM_PROPERTY = "com.sun.security.sasl.digest.realm";
private static final String PRE_DIGESTED_PROPERTY = "org.wildfly.security.sasl.digest.pre_digested";
private static final String QOP_PROPERTY = "javax.security.sasl.qop";
private static final Provider provider = new WildFlyElytronProvider();
@BeforeClass
public static void registerPasswordProvider() {
Security.addProvider(provider);
}
@AfterClass
public static void removePasswordProvider() {
Security.removeProvider(provider.getName());
}
/*
* Mechanism selection tests.
*/
@Test
public void testPolicyIndirect_Server() throws Exception {
Map<String, Object> props = new HashMap<String, Object>();
// If we specify DIGEST with no policy restrictions an DigestSaslServer should be returned.
CallbackHandler serverCallback = new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
}
};
SaslServer server = Sasl.createSaslServer(DIGEST, "TestProtocol", "TestServer", props, serverCallback);
assertEquals(DigestSaslServer.class, server.getClass());
}
@Test
public void testPolicyDirect_Server() {
SaslServerFactory factory = obtainSaslServerFactory(DigestServerFactory.class);
assertNotNull("SaslServerFactory not registered", factory);
Map<String, Object> props = new HashMap<String, Object>();
// No properties.
String[] mechanisms = factory.getMechanismNames(props);
assertTrue(mechanisms.length > 0); // isn't NO_MECHS
}
/*
* Normal SASL Client/Server interaction.
*/
/**
* Test a successful exchange using the DIGEST mechanism.
*/
@Test
public void testSuccessfulExchange() throws Exception {
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("TestRealm")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", "TestRealm");
SaslClient client = Sasl.createSaslClient(new String[]{ DIGEST }, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:"+ new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:"+ new String(message, StandardCharsets.ISO_8859_1));
server.evaluateResponse(message);
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test a successful exchange using the DIGEST mechanism but the default realm.
*/
@Test
public void testSuccessfulExchange_DefaultRealm() throws Exception {
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:"+ new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:"+ new String(message, StandardCharsets.ISO_8859_1));
server.evaluateResponse(message);
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test a successful exchange using the DIGEST mechanism but with the server side supporting an alternative protocol.
*/
@Test
@Ignore("ELY-91")
public void testSuccessfulExchange_AlternativeProtocol() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put("org.wildfly.security.sasl.digest.alternative_protocols", "OtherProtocol DifferentProtocol");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "OtherProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:"+ new String(message, StandardCharsets.UTF_8));
message = client.evaluateChallenge(message);
log.debug("Client response:"+ new String(message, StandardCharsets.UTF_8));
server.evaluateResponse(message);
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test that verification fails for a bad password.
*/
@Test
public void testBadPassword() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("bad".toCharArray())
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test that verification fails for a bad username.
*/
@Test
public void testBadUsername() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("Borris")
.setPassword("gpwd".toCharArray())
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test that verification fails for a bad realm.
*/
@Test
public void testBadRealm() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", "BadRealm");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test a successful exchange with realm selection.
*/
@Test
public void testRealmSelection() throws Exception {
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("realm1")
.addMechanismRealm("second realm")
.addMechanismRealm("last\\ ")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", "last\\ ");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:"+ new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:" + new String(message, StandardCharsets.ISO_8859_1));
server.evaluateResponse(message);
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/*
* Repeat of the above tests but with pre-hashed passwords - server side.
*/
/**
* Test a successful exchange using the DIGEST mechanism with a pre-hashed password.
*/
@Test
public void testSuccessfulExchange_PreHashedServer() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.addMechanismRealm("TestRealm")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:"+ new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:"+ new String(message, StandardCharsets.ISO_8859_1));
message = server.evaluateResponse(message);
log.debug("Server response:"+ new String(message, StandardCharsets.ISO_8859_1));
client.evaluateChallenge(message);
assertTrue(server.isComplete());
assertTrue(client.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test a successful exchange using the DIGEST mechanism but the default realm with a pre-hashed password.
*/
@Test
public void testSuccessfulExchange_DefaultRealm_PreHashedServer() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestServer"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.addMechanismRealm("TestServer")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", "TestServer");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:"+ new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:" + new String(message, StandardCharsets.ISO_8859_1));
message = server.evaluateResponse(message);
log.debug("Server response:"+ new String(message, StandardCharsets.ISO_8859_1));
client.evaluateChallenge(message);
assertTrue(server.isComplete());
assertTrue(client.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test that verification fails for a bad password with a pre-hashed password.
*/
@Test
public void testBadPassword_PreHashedServer() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
serverProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "bad", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:" + new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:" + new String(message, StandardCharsets.ISO_8859_1));
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test that verification fails for a bad username with a pre-hashed password.
*/
@Test
public void testBadUsername_PreHashedServer() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(PRE_DIGESTED_PROPERTY, "true");
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("Borris")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "bad", null);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:" + new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:" + new String(message, StandardCharsets.ISO_8859_1));
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test that verification fails for a bad realm with a pre-hashed password
*/
@Test
public void testBadRealm_PreHashedServer() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
serverProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", "BadRealm");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
log.debug("Challenge:" + new String(message, StandardCharsets.ISO_8859_1));
message = client.evaluateChallenge(message);
log.debug("Client response:" + new String(message, StandardCharsets.ISO_8859_1));
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/*
* Repeat of the above tests but with pre-hashed passwords - client side.
*/
/**
* Test a successful exchange using the DIGEST mechanism with a pre-hashed password.
*/
@Test
public void testSuccessfulExchange_PreHashedClient() throws Exception {
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("TestRealm")
.build();
CallbackHandler clientCallback = createDigestPwdClientCallbackHandler("George", "gpwd", "TestRealm", null);
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
server.evaluateResponse(message);
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test a successful exchange using the DIGEST mechanism but the default realm with a pre-hashed password.
*/
@Test
public void testSuccessfulExchange_DefaultRealm_PreHashedClient() throws Exception {
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestServer"))
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("TestServer")
.addMechanismRealm("TestRealm")
.build();
CallbackHandler clientCallback = createDigestPwdClientCallbackHandler("George", "gpwd", "TestServer", null);
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
server.evaluateResponse(message);
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
}
/**
* Test that verification fails for a bad password with a pre-hashed password.
*/
@Test
public void testBadPassword_PreHashedClient() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createDigestPwdClientCallbackHandler("George", "bad", "TestRealm", null);
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test that verification fails for a bad username with a pre-hashed password.
*/
@Test
public void testBadUsername_PreHashedClient() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createDigestPwdClientCallbackHandler("Borris", "gpwd", "TestRealm", null);
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test that verification fails for a bad realm with a pre-hashed password
*/
@Test
public void testBadRealm_PreHashedClient() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(REALM_PROPERTY, "TestRealm");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword(DigestPassword.ALGORITHM_DIGEST_MD5, getDigestKeySpec("George", "gpwd", "TestRealm"))
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.build();
CallbackHandler clientCallback = createDigestPwdClientCallbackHandler("George", "gpwd", "BadRealm", "BadRealm");
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(PRE_DIGESTED_PROPERTY, "true");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = server.evaluateResponse(new byte[0]);
message = client.evaluateChallenge(message);
try {
server.evaluateResponse(message);
fail("Expection exception not thrown.");
} catch (IOException e) {
}
}
/**
* Test a successful exchange with integrity check
*/
@Test
public void testSuccessfulExchangeWithIntegrityCheck() throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(QOP_PROPERTY, "auth-int");
serverProps.put(WildFlySasl.SUPPORTED_CIPHER_NAMES, "des,3des,rc4,rc4-40,rc4-56");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(QOP_PROPERTY, "auth-int");
clientProps.put(WildFlySasl.SUPPORTED_CIPHER_NAMES, "des,3des,rc4,rc4-40,rc4-56");
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = new byte[0];
message = server.evaluateResponse(message);
message = client.evaluateChallenge(message);
message = server.evaluateResponse(message);
message = client.evaluateChallenge(message);
assertTrue(client.isComplete());
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
message = server.wrap(new byte[]{0x12,0x34,0x56}, 0, 3);
Assert.assertArrayEquals(new byte[]{0x12,0x34,0x56}, client.unwrap(message, 0, message.length));
message = client.wrap(new byte[]{(byte)0xAB,(byte)0xCD,(byte)0xEF}, 0, 3);
Assert.assertArrayEquals(new byte[]{(byte)0xAB,(byte)0xCD,(byte)0xEF}, server.unwrap(message, 0, message.length));
}
/**
* Test a successful exchange with privacy protection
*/
@Test
public void testSuccessfulExchangeWithPrivacyProtection() throws Exception {
testSuccessfulExchangeWithPrivacyProtection("3des");
testSuccessfulExchangeWithPrivacyProtection("des");
testSuccessfulExchangeWithPrivacyProtection("rc4");
testSuccessfulExchangeWithPrivacyProtection("rc4-40");
testSuccessfulExchangeWithPrivacyProtection("rc4-56");
}
private void testSuccessfulExchangeWithPrivacyProtection(String clientCipher) throws Exception {
Map<String, Object> serverProps = new HashMap<String, Object>();
serverProps.put(QOP_PROPERTY, "auth-conf");
serverProps.put(WildFlySasl.SUPPORTED_CIPHER_NAMES, "des,3des,rc4,rc4-40,rc4-56");
SaslServer server = new SaslServerBuilder(DigestServerFactory.class, DIGEST)
.setUserName("George")
.setPassword("gpwd".toCharArray())
.setProperties(serverProps)
.setProtocol("TestProtocol")
.setServerName("TestServer")
.addMechanismRealm("TestServer")
.build();
CallbackHandler clientCallback = createClearPwdClientCallbackHandler("George", "gpwd", null);
Map<String, Object> clientProps = new HashMap<String, Object>();
clientProps.put(QOP_PROPERTY, "auth-conf");
clientProps.put(WildFlySasl.SUPPORTED_CIPHER_NAMES, clientCipher);
SaslClient client = Sasl.createSaslClient(new String[]{DIGEST}, "George", "TestProtocol", "TestServer", clientProps, clientCallback);
assertFalse(client.hasInitialResponse());
byte[] message = new byte[0];
message = server.evaluateResponse(message);
message = client.evaluateChallenge(message);
message = server.evaluateResponse(message);
message = client.evaluateChallenge(message);
assertTrue(client.isComplete());
assertTrue(server.isComplete());
assertEquals("George", server.getAuthorizationID());
message = server.wrap(new byte[]{0x12,0x34,0x56}, 0, 3);
Assert.assertArrayEquals(new byte[]{0x12,0x34,0x56}, client.unwrap(message, 0, message.length));
message = client.wrap(new byte[]{(byte)0xAB,(byte)0xCD,(byte)0xEF}, 0, 3);
Assert.assertArrayEquals(new byte[]{(byte)0xAB,(byte)0xCD,(byte)0xEF}, server.unwrap(message, 0, message.length));
}
private KeySpec getDigestKeySpec(String username, String password, String realm) throws NoSuchAlgorithmException {
byte[] urpHash = new UsernamePasswordHashUtil().generateHashedURP(username, realm, password.toCharArray());
return new DigestPasswordSpec(username, realm, urpHash);
}
}