/* * JBoss, Home of Professional Open Source. * Copyright 2016 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.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.Closeable; import java.io.InputStream; import java.net.InetAddress; import java.net.URI; import java.security.AccessController; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.PrivilegedAction; import java.security.Security; import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509TrustManager; import org.junit.BeforeClass; import org.junit.Test; import org.wildfly.security.WildFlyElytronProvider; import org.wildfly.security.auth.client.AuthenticationContext; import org.wildfly.security.auth.client.AuthenticationContextConfigurationClient; import org.wildfly.security.auth.realm.KeyStoreBackedSecurityRealm; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.auth.server.SecurityRealm; import org.wildfly.security.permission.PermissionVerifier; import org.wildfly.security.x500.X500AttributePrincipalDecoder; /** * Simple test case to test authentication occurring during the establishment of an {@link SSLSession}. * * @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a> */ public class SSLAuthenticationTest { private static SSLContext clientContext; private static SSLContext serverContext; private static final boolean IS_IBM = System.getProperty("java.vendor").contains("IBM"); @BeforeClass public static void setupServer() throws Exception { SecurityRealm securityRealm = new KeyStoreBackedSecurityRealm(loadKeyStore("/ca/jks/beetles.keystore")); SecurityDomain securityDomain = SecurityDomain.builder() .addRealm("KeystoreRealm", securityRealm) .build() .setDefaultRealmName("KeystoreRealm") .setPrincipalDecoder(new X500AttributePrincipalDecoder("2.5.4.3", 1)) .setPreRealmRewriter((String s) -> s.toLowerCase(Locale.ENGLISH)) .setPermissionMapper((permissionMappable, roles) -> PermissionVerifier.ALL) .build(); serverContext = new SSLContextBuilder() .setSecurityDomain(securityDomain) .setKeyManager(getKeyManager("/ca/jks/scarab.keystore")) .setTrustManager(getCATrustManager()) .setNeedClientAuth(true) .build().create(); } @BeforeClass public static void setupClient() throws Exception { System.setProperty("wildfly.config.url", SSLAuthenticationTest.class.getResource("wildfly-ssl-test-config.xml").toExternalForm()); AccessController.doPrivileged((PrivilegedAction<Integer>) () -> Security.insertProviderAt(new WildFlyElytronProvider(), 1)); AuthenticationContext context = AuthenticationContext.getContextManager().get(); AuthenticationContextConfigurationClient contextConfigurationClient = AccessController.doPrivileged(AuthenticationContextConfigurationClient.ACTION); clientContext = contextConfigurationClient.getSSLContext(URI.create("protocol://test.org"), context); } /** * Get the key manager backed by the specified key store. * * @param keystorePath the path to the keystore with X509 private key * @return the initialised key manager. */ private static X509ExtendedKeyManager getKeyManager(final String keystorePath) throws Exception { KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(IS_IBM ? "IbmX509" : "SunX509"); keyManagerFactory.init(loadKeyStore(keystorePath), "Elytron".toCharArray()); for (KeyManager current : keyManagerFactory.getKeyManagers()) { if (current instanceof X509ExtendedKeyManager) { return (X509ExtendedKeyManager) current; } } throw new IllegalStateException("Unable to obtain X509ExtendedKeyManager."); } /** * Get the trust manager that trusts all certificates signed by the certificate authority. * * @return the trust manager that trusts all certificates signed by the certificate authority. * @throws KeyStoreException */ private static X509TrustManager getCATrustManager() throws Exception { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(IS_IBM ? "IbmX509" : "SunX509"); trustManagerFactory.init(loadKeyStore("/ca/jks/ca.truststore")); for (TrustManager current : trustManagerFactory.getTrustManagers()) { if (current instanceof X509TrustManager) { return (X509TrustManager) current; } } throw new IllegalStateException("Unable to obtain X509TrustManager."); } private static KeyStore loadKeyStore(final String path) throws Exception { KeyStore keyStore = KeyStore.getInstance("jks"); try (InputStream caTrustStoreFile = SSLAuthenticationTest.class.getResourceAsStream(path)) { keyStore.load(caTrustStoreFile, "Elytron".toCharArray()); } return keyStore; } /** * @throws ExecutionException * @throws InterruptedException * */ @Test public void performConnectionTest() throws Exception { SSLServerSocketFactory sslServerSocketFactory = serverContext.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(1111, 10, InetAddress.getLoopbackAddress()); ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<SSLSocket> socketFuture = executorService.submit((Callable<SSLSocket>) () -> { try { System.out.println("About to connect client"); SSLSocket sslSocket = (SSLSocket) clientContext.getSocketFactory().createSocket(InetAddress.getLoopbackAddress(), 1111); sslSocket.getSession(); return sslSocket; } catch (Exception e) { throw new RuntimeException(e); } finally { System.out.println("Client connected"); } }); SSLSocket serverSocket = (SSLSocket) sslServerSocket.accept(); SSLSession serverSession = serverSocket.getSession(); assertTrue("Server SSL Session Valid", serverSession.isValid()); SecurityIdentity identity = (SecurityIdentity) serverSession.getValue(SSLUtils.SSL_SESSION_IDENTITY_KEY); assertNotNull(identity); assertEquals("Principal Name", "ladybird", identity.getPrincipal().getName()); SSLSocket clientSocket = socketFuture.get(); SSLSession clientSession = clientSocket.getSession(); assertTrue("Client SSL Session Valid", clientSession.isValid()); safeClose(serverSocket); safeClose(clientSocket); } private void safeClose(Closeable closeable) { try { closeable.close(); } catch (Exception ignored) {} } }