/*
* JBoss, Home of Professional Open Source.
* Copyright 2015 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.entity;
import static org.junit.Assert.*;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslClientFactory;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslServerFactory;
import mockit.Mock;
import mockit.MockUp;
import mockit.integration.junit4.JMockit;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.security.auth.client.AuthenticationConfiguration;
import org.wildfly.security.auth.client.AuthenticationContext;
import org.wildfly.security.auth.client.ClientUtils;
import org.wildfly.security.auth.client.MatchRule;
import org.wildfly.security.auth.realm.KeyStoreBackedSecurityRealm;
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.util.CodePointIterator;
import org.wildfly.security.credential.X509CertificateChainPrivateCredential;
/**
* Client and server side tests for the ISO/IEC 9798-3 authentication SASL mechanism.
*
* @author <a href="mailto:fjuma@redhat.com">Farah Juma</a>
*/
@RunWith(JMockit.class)
public class EntityTest extends BaseTestCase {
private static final String SERVER_KEYSTORE_FILENAME = "/server.keystore";
private static final String CLIENT_KEYSTORE_FILENAME = "/client.keystore";
private static final String WRONG_KEYSTORE_FILENAME = "/wrong.keystore";
private static final String SERVER_TRUSTSTORE_FILENAME = "/server.truststore";
private static final String CLIENT_TRUSTSTORE_FILENAME = "/client.truststore";
private static final String SERVER_KEYSTORE_ALIAS = "testserver1";
private static final String CLIENT_KEYSTORE_ALIAS = "testclient1";
private static final String WRONG_KEYSTORE_ALIAS = "wrongone";
private static final String KEYSTORE_TYPE = "JKS";
private static final char[] KEYSTORE_PASSWORD = "password".toCharArray();
private File serverKeyStore = null;
private File clientKeyStore = null;
private File wrongKeyStore = null;
private File serverTrustStore = null;
private File clientTrustStore = null;
private File workingDir = null;
@Before
public void beforeTest() throws IOException {
workingDir = getWorkingDir();
serverKeyStore = copyKeyStore(SERVER_KEYSTORE_FILENAME);
clientKeyStore = copyKeyStore(CLIENT_KEYSTORE_FILENAME);
wrongKeyStore = copyKeyStore(WRONG_KEYSTORE_FILENAME);
serverTrustStore = copyKeyStore(SERVER_TRUSTSTORE_FILENAME);
clientTrustStore = copyKeyStore(CLIENT_TRUSTSTORE_FILENAME);
}
@After
public void afterTest() {
serverKeyStore.delete();
serverKeyStore = null;
clientKeyStore.delete();
clientKeyStore = null;
wrongKeyStore.delete();
wrongKeyStore = null;
serverTrustStore.delete();
serverTrustStore = null;
clientTrustStore.delete();
clientTrustStore = null;
workingDir.delete();
workingDir = null;
}
@Test
public void testServerAuthIndirect_Server() throws Exception {
Map<String, Object> props = new HashMap<String, Object>();
// No properties are set, an appropriate EntitySaslServer should be returned
SaslServer server = Sasl.createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, "TestProtocol", "TestServer", props, null);
assertEquals(EntitySaslServer.class, server.getClass());
assertEquals(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, server.getMechanismName());
// If we set SERVER_AUTH to true even though a unilateral mechanism is specified, no server should be returned
props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
server = Sasl.createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, "TestProtocol", "TestServer", props, null);
assertNull(server);
}
@Test
public void testServerAuthDirect_Server() {
SaslServerFactory factory = obtainSaslServerFactory(EntitySaslServerFactory.class);
assertNotNull("SaslServerFactory not registered", factory);
String[] mechanisms;
Map<String, Object> props = new HashMap<String, Object>();
// No properties set
mechanisms = factory.getMechanismNames(props);
assertMechanisms(new String[]{
SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_U_DSA_SHA1,
SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_U_ECDSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_M_ECDSA_SHA1
}, mechanisms);
// Request server auth
props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
mechanisms = factory.getMechanismNames(props);
assertMechanisms(new String[]{ SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_M_ECDSA_SHA1 }, mechanisms);
}
@Test
public void testServerAuthIndirect_Client() throws Exception {
Map<String, Object> props = new HashMap<String, Object>();
// No properties are set, an appropriate EntitySaslClient should be returned
SaslClient client = Sasl.createSaslClient(new String[]{ SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC }, "TestUser", "TestProtocol", "TestServer", props, null);
assertEquals(EntitySaslClient.class, client.getClass());
assertEquals(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, client.getMechanismName());
// If we set SERVER_AUTH to true even though only unilateral mechanisms are specified, no client should be returned
props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
client = Sasl.createSaslClient(new String[]{ SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_U_DSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_U_ECDSA_SHA1 },
"TestUser", "TestProtocol", "TestServer", props, null);
assertNull(client);
// If we set SERVER_AUTH to true, an appropriate EntitySaslClient should be returned
props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
client = Sasl.createSaslClient(new String[]{
SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_U_DSA_SHA1,
SaslMechanismInformation.Names.IEC_ISO_9798_U_ECDSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_M_ECDSA_SHA1
},
"TestUser", "TestProtocol", "TestServer", props, null);
assertEquals(EntitySaslClient.class, client.getClass());
assertEquals(SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, client.getMechanismName());
}
@Test
public void testServerAuthDirect_Client() {
SaslClientFactory factory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull("SaslClientFactory not registered", factory);
String[] mechanisms;
Map<String, Object> props = new HashMap<String, Object>();
// No properties set
mechanisms = factory.getMechanismNames(props);
assertMechanisms(new String[]{
SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_U_DSA_SHA1,
SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_U_ECDSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_M_ECDSA_SHA1
}, mechanisms);
// Request server auth
props.put(Sasl.SERVER_AUTH, Boolean.toString(true));
mechanisms = factory.getMechanismNames(props);
assertMechanisms(new String[]{ SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1, SaslMechanismInformation.Names.IEC_ISO_9798_M_ECDSA_SHA1 }, mechanisms);
}
// -- Successful authentication exchanges --
@Test
public void testSimpleUnilateralSha1WithRsaAuthentication() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), serverTrustStore);
assertNotNull(saslServer);
assertFalse(saslServer.isComplete());
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, null);
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "testserver1.example.com",
Collections.<String, Object>emptyMap(), cbh);
assertNotNull(saslClient);
assertTrue(saslClient instanceof EntitySaslClient);
assertFalse(saslClient.hasInitialResponse());
assertFalse(saslClient.isComplete());
byte[] message = saslServer.evaluateResponse(new byte[0]);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslClient.evaluateChallenge(message);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslServer.evaluateResponse(message);
assertTrue(saslServer.isComplete());
assertNull(message);
assertNull(saslClient.evaluateChallenge(message));
assertTrue(saslClient.isComplete());
assertEquals("cn=test client 1,ou=jboss,o=red hat,l=raleigh,st=north carolina,c=us", saslServer.getAuthorizationID());
}
@Test
public void testUnilateralSha1WithRsaAuthenticationWithTrustedAuthorities() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), serverTrustStore);
assertNotNull(saslServer);
assertFalse(saslServer.isComplete());
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, getX509KeyManager(clientKeyStore, KEYSTORE_PASSWORD), null);
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "testserver1.example.com",
Collections.<String, Object>emptyMap(), cbh);
assertNotNull(saslClient);
assertTrue(saslClient instanceof EntitySaslClient);
assertFalse(saslClient.hasInitialResponse());
assertFalse(saslClient.isComplete());
byte[] message = saslServer.evaluateResponse(new byte[0]);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslClient.evaluateChallenge(message);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslServer.evaluateResponse(message);
assertTrue(saslServer.isComplete());
assertNull(message);
assertNull(saslClient.evaluateChallenge(message));
assertTrue(saslClient.isComplete());
assertEquals("cn=signed test client,ou=jboss,o=red hat,st=north carolina,c=us", saslServer.getAuthorizationID());
}
@Test
public void testUnilateralSha1WithRsaAuthenticationWithAuthorizationId() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), serverTrustStore);
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, null);
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, "cn=test client 1,ou=jboss,o=red hat,l=raleigh,st=north carolina,c=us", "test", "testserver1.example.com",
Collections.<String, Object>emptyMap(), cbh);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
byte[] message = saslServer.evaluateResponse(new byte[0]);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslClient.evaluateChallenge(message);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslServer.evaluateResponse(message);
assertTrue(saslServer.isComplete());
assertNull(message);
assertNull(saslClient.evaluateChallenge(message));
assertTrue(saslClient.isComplete());
assertEquals("cn=test client 1,ou=jboss,o=red hat,l=raleigh,st=north carolina,c=us", saslServer.getAuthorizationID());
}
@Test
public void testSimpleMutualSha1WithRsaAuthentication() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), serverTrustStore);
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, getX509TrustManager(clientTrustStore));
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "testserver1.example.com", Collections.<String, Object>emptyMap(), cbh);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
byte[] message = saslServer.evaluateResponse(new byte[0]);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslClient.evaluateChallenge(message);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslServer.evaluateResponse(message);
assertNotNull(message);
message = saslClient.evaluateChallenge(message);
assertNull(message);
assertTrue(saslClient.isComplete());
assertTrue(saslServer.isComplete());
assertEquals("cn=test client 1,ou=jboss,o=red hat,l=raleigh,st=north carolina,c=us", saslServer.getAuthorizationID());
}
@Test
public void testMutualAuthenticationWithDNSInCNField() throws Exception {
// Although specifying a DNS name using the Common Name field has been deprecated, it is
// still used in practice (e.g., see http://tools.ietf.org/html/rfc2818). This test makes
// sure that general name matching during authentication still works in this case.
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final KeyStore keyStore = loadKeyStore(serverKeyStore);
final Certificate[] certificateChain = keyStore.getCertificateChain("dnsInCNServer");
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1, "testserver2.example.com",
serverTrustStore, (PrivateKey) keyStore.getKey("dnsInCNServer", KEYSTORE_PASSWORD),
Arrays.copyOf(certificateChain, certificateChain.length, X509Certificate[].class));
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_M_DSA_SHA1 };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, "dnsInCNClient", KEYSTORE_PASSWORD, getX509TrustManager(clientTrustStore));
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "testserver2.example.com",
Collections.<String, Object>emptyMap(), cbh);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
byte[] message = saslServer.evaluateResponse(new byte[0]);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslClient.evaluateChallenge(message);
assertFalse(saslServer.isComplete());
assertFalse(saslClient.isComplete());
message = saslServer.evaluateResponse(message);
assertNotNull(message);
message = saslClient.evaluateChallenge(message);
assertNull(message);
assertTrue(saslClient.isComplete());
assertTrue(saslServer.isComplete());
assertEquals("cn=testclient2.example.com,ou=jboss,o=red hat,l=raleigh,st=north carolina,c=us", saslServer.getAuthorizationID());
}
// -- Unsuccessful authentication exchanges --
@Test
public void testServerNameMismatch() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
// The server name specified by the client doesn't match the server's actual name
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), serverTrustStore);
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, getX509TrustManager(clientTrustStore));
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "anotherserver.example.com",
Collections.<String, Object>emptyMap(), cbh);
byte[] message = saslServer.evaluateResponse(new byte[0]);
try {
saslClient.evaluateChallenge(message);
fail("Expected SaslException not thrown");
} catch (SaslException expected) {
}
}
@Test
public void testClientNotTrustedByServer() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), (KeyStore) null);
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, getX509TrustManager(clientTrustStore));
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "testserver1.example.com",
Collections.<String, Object>emptyMap(), cbh);
byte[] message = saslServer.evaluateResponse(new byte[0]);
message = saslClient.evaluateChallenge(message);
try {
saslServer.evaluateResponse(message);
fail("Expected SaslException not thrown");
} catch (SaslException expected) {
}
}
@Test
public void testServerNotTrustedByClient() throws Exception {
final SaslClientFactory clientFactory = obtainSaslClientFactory(EntitySaslClientFactory.class);
assertNotNull(clientFactory);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC, "testserver1.example.com",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), serverTrustStore);
final String[] mechanisms = new String[] { SaslMechanismInformation.Names.IEC_ISO_9798_M_RSA_SHA1_ENC };
CallbackHandler cbh = createClientCallbackHandler(mechanisms, clientKeyStore, CLIENT_KEYSTORE_ALIAS, KEYSTORE_PASSWORD, null);
final SaslClient saslClient = clientFactory.createSaslClient(mechanisms, null, "test", "testserver1.example.com",
Collections.<String, Object>emptyMap(), cbh);
byte[] message = saslServer.evaluateResponse(new byte[0]);
message = saslClient.evaluateChallenge(message);
message = saslServer.evaluateResponse(message);
try {
saslClient.evaluateChallenge(message);
fail("Expected SaslException not thrown");
} catch (SaslException expected) {
}
}
@Test
public void testRfc3163Example() throws Exception {
// This test uses the example from page 10 in RFC 3163 (https://tools.ietf.org/html/rfc3163#section-5)
mockRandom(new byte[]{18, 56, -105, 88, 121, -121, 71, -104});
KeyStore emptyTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
emptyTrustStore.load(null, null);
final SaslServer saslServer = createSaslServer(SaslMechanismInformation.Names.IEC_ISO_9798_U_RSA_SHA1_ENC, "",
getX509KeyManager(serverKeyStore, KEYSTORE_PASSWORD), emptyTrustStore);
assertNotNull(saslServer);
assertFalse(saslServer.isComplete());
byte[] tokenBA1 = saslServer.evaluateResponse(new byte[0]);
byte[] expectedTokenBA1 = CodePointIterator.ofString("MAoECBI4l1h5h0eY").base64Decode().drain();
assertArrayEquals(expectedTokenBA1, tokenBA1);
assertFalse(saslServer.isComplete());
byte[] tokenAB = CodePointIterator.ofString("MIIBAgQIIxh5I0h5RYegD4INc2FzbC1yLXVzLmNvbaFPFk1odHRwOi8vY2VydHMtci11cy5jb20vY2VydD9paD1odmNOQVFFRkJRQURnWUVBZ2hBR2hZVFJna0ZqJnNuPUVQOXVFbFkzS0RlZ2pscjCBkzANBgkqhkiG9w0BAQUFAAOBgQCkuC2GgtYcxGG1NEzLA4bh5lqJGOZySACMmc+mDrV7A7KAgbpO2OuZpMCl7zvNt/L3OjQZatiX8d1XbuQ40l+g2TJzJt06o7ogomxdDwqlA/3zp2WMohlI0MotHmfDSWEDZmEYDEA3/eGgkWyi1v1lEVdFuYmrTr8E4wE9hxdQrA==").base64Decode().drain();
try {
saslServer.evaluateResponse(tokenAB);
fail("Expected SaslException not thrown");
} catch (SaslException expected) {
// The example specifies the client's certificate using a fake URL (http://certs-r-us.com/cert?ih=hvcNAQEFBQADgYEAghAGhYTRgkFj&sn=EP9uElY3KDegjlr)
// so we can actually make use of it.
assertTrue(expected.getCause().getMessage().contains("certificate"));
}
assertFalse(saslServer.isComplete());
}
private static File getWorkingDir() {
File workingDir = new File("./target/keystore");
if (workingDir.exists() == false) {
workingDir.mkdirs();
}
return workingDir;
}
private File copyKeyStore(String keyStoreFileName) throws IOException {
File keyStore = new File(workingDir, keyStoreFileName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(keyStore);
IOUtils.copy(getClass().getResourceAsStream(keyStoreFileName), fos);
} finally {
safeClose(fos);
}
return keyStore;
}
private void safeClose(Closeable c) {
if (c != null) {
try {
c.close();
} catch (Throwable ignored) {}
}
}
private void mockRandom(final byte[] randomStr){
new MockUp<EntityUtil>(){
@Mock
byte[] generateRandomString(int length, Random random){
return randomStr;
}
};
}
private KeyStore loadKeyStore(File keyStore) throws IOException, GeneralSecurityException {
if (keyStore == null) {
return null;
}
KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
FileInputStream fis = null;
try {
fis = new FileInputStream(keyStore);
ks.load(fis, KEYSTORE_PASSWORD);
} finally {
safeClose(fis);
}
return ks;
}
private SaslServer createSaslServer(final String mechanism, final String serverName, final X509KeyManager keyManager, final File trustStore) throws Exception {
return createSaslServer(mechanism, serverName, keyManager, loadKeyStore(trustStore));
}
private SaslServer createSaslServer(final String mechanism, final String serverName, final X509KeyManager keyManager, final KeyStore trustStore) throws Exception {
final String realmName = "keyStoreRealm";
return new SaslServerBuilder(EntitySaslServerFactory.class, mechanism)
.setProtocol("test")
.setServerName(serverName)
.addRealm(realmName, new KeyStoreBackedSecurityRealm(trustStore))
.setDefaultRealmName(realmName)
.setKeyManager(keyManager)
.setTrustManager(getX509TrustManager(trustStore))
.build();
}
private SaslServer createSaslServer(final String mechanism, final String serverName, final File trustStore, final PrivateKey privateKey,
final X509Certificate... certificateChain) throws Exception {
final String realmName = "keyStoreRealm";
final KeyStore ts = loadKeyStore(trustStore);
return new SaslServerBuilder(EntitySaslServerFactory.class, mechanism)
.setProtocol("test")
.setServerName(serverName)
.addRealm(realmName, new KeyStoreBackedSecurityRealm(ts))
.setDefaultRealmName(realmName)
.setCredential(new X509CertificateChainPrivateCredential(privateKey, certificateChain))
.setTrustManager(getX509TrustManager(ts))
.build();
}
private CallbackHandler createClientCallbackHandler(final String[] mechanisms, final File keyStore, final String keyStoreAlias,
final char[] keyStorePassword, final X509TrustManager trustManager) throws Exception {
final AuthenticationContext context = AuthenticationContext.empty()
.with(
MatchRule.ALL,
AuthenticationConfiguration.EMPTY
.useKeyStoreCredential(loadKeyStore(keyStore), keyStoreAlias, new KeyStore.PasswordProtection(keyStorePassword))
.useTrustManager(trustManager)
.allowSaslMechanisms(mechanisms));
return ClientUtils.getCallbackHandler(new URI("remote://localhost"), context);
}
private CallbackHandler createClientCallbackHandler(final String[] mechanisms, final X509KeyManager keyManager,
final X509TrustManager trustManager) throws Exception {
final AuthenticationContext context = AuthenticationContext.empty()
.with(
MatchRule.ALL,
AuthenticationConfiguration.EMPTY
.useKeyManagerCredential(keyManager)
.useTrustManager(trustManager)
.allowSaslMechanisms(mechanisms));
return ClientUtils.getCallbackHandler(new URI("remote://localhost"), context);
}
private CallbackHandler createClientCallbackHandler(final String[] mechanisms, final PrivateKey privateKey, final X509Certificate[] certificateChain,
final X509TrustManager trustManager) throws Exception {
final AuthenticationContext context = AuthenticationContext.empty()
.with(
MatchRule.ALL,
AuthenticationConfiguration.EMPTY
.useCertificateCredential(privateKey, certificateChain)
.useTrustManager(trustManager)
.allowSaslMechanisms(mechanisms));
return ClientUtils.getCallbackHandler(new URI("remote://localhost"), context);
}
private X509KeyManager getX509KeyManager(final File keyStore, final char[] keyStorePassword) throws GeneralSecurityException, IOException {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(loadKeyStore(keyStore), keyStorePassword);
for (KeyManager keyManager : keyManagerFactory.getKeyManagers()) {
if (keyManager instanceof X509KeyManager) {
return (X509KeyManager) keyManager;
}
}
return null;
}
private X509TrustManager getX509TrustManager(final File trustStore) throws GeneralSecurityException, IOException {
return getX509TrustManager(loadKeyStore(trustStore));
}
private X509TrustManager getX509TrustManager(final KeyStore trustStore) throws GeneralSecurityException, IOException {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
}