diff --git a/auth/client/pom.xml b/auth/client/pom.xml
index 5b4994afd41..2242098cf45 100644
--- a/auth/client/pom.xml
+++ b/auth/client/pom.xml
@@ -52,6 +52,10 @@
org.wildfly.security
wildfly-elytron-credential-store
+
+ org.wildfly.security
+ wildfly-elytron-dynamic-ssl
+
org.wildfly.security
wildfly-elytron-keystore
@@ -76,7 +80,7 @@
org.wildfly.security
wildfly-elytron-x500-cert
-
+
org.jboss.logging
jboss-logging-annotations
@@ -146,6 +150,14 @@
jmockit
test
+
+
+
+ org.mockito
+ mockito-all
+ 1.9.5
+ test
+
+
-
diff --git a/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContext.java b/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContext.java
index fc2c6b086b8..13d58004014 100644
--- a/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContext.java
+++ b/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContext.java
@@ -354,6 +354,10 @@ public T runAsSupplierEx(ExceptionSupplier action
return runExFunction(ExceptionSupplier::get, action);
}
+ RuleNode> getSslRules() {
+ return this.sslRules;
+ }
+
public ContextManager getInstanceContextManager() {
return getContextManager();
}
diff --git a/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContextConfigurationClient.java b/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContextConfigurationClient.java
index 3c1ecc883b4..dd56805e376 100644
--- a/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContextConfigurationClient.java
+++ b/auth/client/src/main/java/org/wildfly/security/auth/client/AuthenticationContextConfigurationClient.java
@@ -30,7 +30,9 @@
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.Provider;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
@@ -196,6 +198,21 @@ private static AuthenticationConfiguration initializeConfiguration(final URI uri
return configuration;
}
+
+ List getConfiguredSSLContexts(AuthenticationContext authenticationContext) {
+ List sslContexts = new ArrayList<>();
+ RuleNode> node = authenticationContext.getSslRules();
+ while (node != null) {
+ try {
+ sslContexts.add(node.getConfiguration().create());
+ } catch (GeneralSecurityException ignored) {
+ ignored.printStackTrace();
+ }
+ node = node.getNext();
+ }
+ return sslContexts;
+ }
+
/**
* Get the SSL context which matches the given URI, or {@link SSLContext#getDefault()} if there is none.
*
diff --git a/auth/client/src/main/java/org/wildfly/security/auth/client/DynamicSSLContextImpl.java b/auth/client/src/main/java/org/wildfly/security/auth/client/DynamicSSLContextImpl.java
new file mode 100644
index 00000000000..998f177442f
--- /dev/null
+++ b/auth/client/src/main/java/org/wildfly/security/auth/client/DynamicSSLContextImpl.java
@@ -0,0 +1,45 @@
+package org.wildfly.security.auth.client;
+
+import org.kohsuke.MetaInfServices;
+import org.wildfly.security.dynamic.ssl.ssl.DynamicSSLContextSPI;
+
+import javax.net.ssl.SSLContext;
+import java.net.URI;
+import java.security.AccessController;
+import java.security.GeneralSecurityException;
+import java.security.PrivilegedAction;
+import java.util.List;
+
+@MetaInfServices(value = DynamicSSLContextSPI.class)
+public class DynamicSSLContextImpl implements DynamicSSLContextSPI {
+
+ private SSLContext configuredDefaultSSLContext;
+ private final AuthenticationContextConfigurationClient AUTH_CONTEXT_CLIENT =
+ AccessController.doPrivileged((PrivilegedAction) AuthenticationContextConfigurationClient::new);
+ private AuthenticationContext authenticationContext = AuthenticationContext.captureCurrent();
+ private List configuredSSLContexts;
+
+ public DynamicSSLContextImpl() {
+ this.configuredSSLContexts = AUTH_CONTEXT_CLIENT.getConfiguredSSLContexts(authenticationContext);
+ }
+
+ @Override
+ public SSLContext getConfiguredDefault() {
+ return this.configuredDefaultSSLContext;
+ }
+
+ @Override
+ public List getConfiguredSSLContexts() {
+ return this.configuredSSLContexts;
+ }
+
+ @Override
+ public SSLContext getSSLContext(URI uri) {
+ try {
+ return AUTH_CONTEXT_CLIENT.getSSLContext(uri, authenticationContext);
+ } catch (GeneralSecurityException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/auth/client/src/test/java/org/wildfly/security/auth/client/DynamicSSLContextIntersectionTest.java b/auth/client/src/test/java/org/wildfly/security/auth/client/DynamicSSLContextIntersectionTest.java
new file mode 100644
index 00000000000..96610b7f2ac
--- /dev/null
+++ b/auth/client/src/test/java/org/wildfly/security/auth/client/DynamicSSLContextIntersectionTest.java
@@ -0,0 +1,106 @@
+package org.wildfly.security.auth.client;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.wildfly.security.dynamic.ssl.ssl.DynamicSSLContext;
+import org.wildfly.security.dynamic.ssl.ssl.DynamicSslContextSpi;
+import org.wildfly.security.SecurityFactory;
+import org.wildfly.security.auth.client.mocks.MockSSLContext;
+import org.wildfly.security.auth.client.mocks.MockSSLContextSPI;
+import org.wildfly.security.auth.client.mocks.MockSSLSocketFactory;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.security.GeneralSecurityException;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DynamicSSLContextIntersectionTest {
+
+ @Test
+ public void testIntersectionOfSupportedCipherSuites() throws GeneralSecurityException {
+
+ SSLSocketFactory sslSocketFactory0Ciphers = new MockSSLSocketFactory() {
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return new String[0];
+ }
+ };
+
+ SSLSocketFactory sslSocketFactory3Ciphers = new MockSSLSocketFactory() {
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return new String[]{"TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_CIPHER_SUITE_NOT_COMMON"};
+ }
+ };
+
+ SSLSocketFactory sslSocketFactory4Ciphers = new MockSSLSocketFactory() {
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return new String[]{"TLS_CHACHA20_POLY1305_SHA256", "TLS_AES_128_CCM_8_SHA256", "TLS_AES_128_GCM_SHA256", "TLS_AES_128_CCM_SHA256"};
+ }
+ };
+
+ SSLContext sslContext0Ciphers = new MockSSLContext(new MockSSLContextSPI() {
+ @Override
+ protected SSLSocketFactory engineGetSocketFactory() {
+ return sslSocketFactory0Ciphers;
+ }
+ });
+
+ SSLContext sslContext3Ciphers = new MockSSLContext(new MockSSLContextSPI() {
+ @Override
+ protected SSLSocketFactory engineGetSocketFactory() {
+ return sslSocketFactory3Ciphers;
+ }
+ });
+
+ SSLContext sslContext4Ciphers = new MockSSLContext(new MockSSLContextSPI() {
+ @Override
+ protected SSLSocketFactory engineGetSocketFactory() {
+ return sslSocketFactory4Ciphers;
+ }
+ });
+
+
+ SecurityFactory sslContextSecurityFactory0Ciphers = mock(SecurityFactory.class);
+ SecurityFactory sslContextSecurityFactoryt3Ciphers = mock(SecurityFactory.class);
+ SecurityFactory sslContextSecurityFactory4Ciphers = mock(SecurityFactory.class);
+
+ when(sslContextSecurityFactory0Ciphers.create()).thenReturn(sslContext0Ciphers);
+ when(sslContextSecurityFactoryt3Ciphers.create()).thenReturn(sslContext3Ciphers);
+ when(sslContextSecurityFactory4Ciphers.create()).thenReturn(sslContext4Ciphers);
+
+ AuthenticationContext ctx = AuthenticationContext.empty()
+ .withSsl(MatchRule.ALL.matchHost("host1"), sslContextSecurityFactory4Ciphers)
+ .withSsl(MatchRule.ALL.matchHost("host2"), sslContextSecurityFactoryt3Ciphers);
+ ctx.run(checkResultIntersectionSizeIs(2));
+ ctx = AuthenticationContext.empty()
+ .withSsl(MatchRule.ALL.matchHost("host1"), sslContextSecurityFactory4Ciphers)
+ .withSsl(MatchRule.ALL.matchHost("host2"), sslContextSecurityFactoryt3Ciphers)
+ .withSsl(MatchRule.ALL.matchHost("host3"), sslContextSecurityFactory0Ciphers);
+ ctx.run(checkResultIntersectionSizeIs(0));
+ ctx = AuthenticationContext.empty()
+ .withSsl(MatchRule.ALL.matchHost("host3"), sslContextSecurityFactory0Ciphers)
+ .withSsl(MatchRule.ALL.matchHost("host3"), sslContextSecurityFactory0Ciphers);
+ ctx.run(checkResultIntersectionSizeIs(0));
+ ctx = AuthenticationContext.empty()
+ .withSsl(MatchRule.ALL.matchHost("host1"), sslContextSecurityFactory4Ciphers)
+ .withSsl(MatchRule.ALL.matchHost("host1"), sslContextSecurityFactory4Ciphers);
+ ctx.run(checkResultIntersectionSizeIs(4));
+ }
+
+ private Runnable checkResultIntersectionSizeIs(int intersectionSize) {
+ return () -> {
+ try {
+ DynamicSslContextSpi dynamicSslContextSpi = new DynamicSslContextSpi(SSLContext.getDefault());
+ SSLContext dynamicSSLContext = new DynamicSSLContext(dynamicSslContextSpi, null, null);
+ Assert.assertEquals(dynamicSSLContext.getSocketFactory().getSupportedCipherSuites().length, intersectionSize);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail();
+ }
+ };
+ }
+}
diff --git a/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLContext.java b/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLContext.java
new file mode 100644
index 00000000000..cc542df5edb
--- /dev/null
+++ b/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLContext.java
@@ -0,0 +1,10 @@
+package org.wildfly.security.auth.client.mocks;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLContextSpi;
+
+public class MockSSLContext extends SSLContext {
+ public MockSSLContext(final SSLContextSpi mockContextSpi) {
+ super(mockContextSpi, null, null);
+ }
+}
diff --git a/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLContextSPI.java b/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLContextSPI.java
new file mode 100644
index 00000000000..935f0a1b7ab
--- /dev/null
+++ b/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLContextSPI.java
@@ -0,0 +1,40 @@
+package org.wildfly.security.auth.client.mocks;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.TrustManager;
+import java.security.SecureRandom;
+
+public abstract class MockSSLContextSPI extends SSLContextSpi {
+ @Override
+ protected void engineInit(KeyManager[] keyManagers, TrustManager[] trustManagers, SecureRandom secureRandom) {
+ }
+
+ @Override
+ protected SSLServerSocketFactory engineGetServerSocketFactory() {
+ return null;
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine() {
+ return null;
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine(String s, int i) {
+ return null;
+ }
+
+ @Override
+ protected SSLSessionContext engineGetServerSessionContext() {
+ return null;
+ }
+
+ @Override
+ protected SSLSessionContext engineGetClientSessionContext() {
+ return null;
+ }
+}
diff --git a/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLSocketFactory.java b/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLSocketFactory.java
new file mode 100644
index 00000000000..0a4da9ef235
--- /dev/null
+++ b/auth/client/src/test/java/org/wildfly/security/auth/client/mocks/MockSSLSocketFactory.java
@@ -0,0 +1,39 @@
+package org.wildfly.security.auth.client.mocks;
+
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+public abstract class MockSSLSocketFactory extends SSLSocketFactory {
+ @Override
+ public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
+ return null;
+ }
+
+ @Override
+ public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
+ return null;
+ }
+
+ @Override
+ public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
+ return null;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
+ return null;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
+ return null;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return new String[0];
+ }
+}
diff --git a/dynamic-ssl/pom.xml b/dynamic-ssl/pom.xml
new file mode 100644
index 00000000000..c2f4aad3c7e
--- /dev/null
+++ b/dynamic-ssl/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ org.wildfly.security
+ wildfly-elytron-parent
+ 1.11.3.CR1-SNAPSHOT
+
+
+ 4.0.0
+
+ wildfly-elytron-dynamic-ssl
+
+ WildFly Elytron - Dynamic SSL
+ WildFly Security Dynamic SSL Implementation
+
+
+ junit
+ junit
+
+
+
diff --git a/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSSLContext.java b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSSLContext.java
new file mode 100644
index 00000000000..0f8d3647b22
--- /dev/null
+++ b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSSLContext.java
@@ -0,0 +1,12 @@
+package org.wildfly.security.dynamic.ssl.ssl;
+
+import javax.net.ssl.SSLContext;
+import java.security.Provider;
+
+// TODO remove public and user will have to use AuthenticationContextConfigurationClient to get it
+public final class DynamicSSLContext extends SSLContext {
+
+ public DynamicSSLContext(DynamicSslContextSpi contextSpi, Provider provider, String protocol) {
+ super(contextSpi, provider, protocol);
+ }
+}
diff --git a/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSSLContextSPI.java b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSSLContextSPI.java
new file mode 100644
index 00000000000..8d9e7d91ad0
--- /dev/null
+++ b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSSLContextSPI.java
@@ -0,0 +1,12 @@
+package org.wildfly.security.dynamic.ssl.ssl;
+
+import javax.net.ssl.SSLContext;
+import java.net.URI;
+import java.util.List;
+
+public interface DynamicSSLContextSPI {
+
+ SSLContext getConfiguredDefault();
+ List getConfiguredSSLContexts();
+ SSLContext getSSLContext(URI uri);
+}
diff --git a/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSslContextSpi.java b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSslContextSpi.java
new file mode 100644
index 00000000000..593df04e0e6
--- /dev/null
+++ b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSslContextSpi.java
@@ -0,0 +1,91 @@
+package org.wildfly.security.dynamic.ssl.ssl;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.SecureRandom;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.ServiceLoader;
+
+// TODO remove public
+public final class DynamicSslContextSpi extends SSLContextSpi {
+
+ private final DynamicSSLContextSPI dynamicSSLContextImpl;
+ private final SSLContext configuredDefaultSSLContext;
+ private volatile SSLSocketFactory sslSocketFactory;
+
+ public DynamicSslContextSpi(final SSLContext configuredDefaultSSLContext) throws Exception{
+ Objects.requireNonNull(configuredDefaultSSLContext);
+ this.configuredDefaultSSLContext = configuredDefaultSSLContext;
+ Iterator dynamicSSLContextSPIIterator = ServiceLoader.load(DynamicSSLContextSPI.class).iterator();
+ if(dynamicSSLContextSPIIterator.hasNext()) {
+ dynamicSSLContextImpl = dynamicSSLContextSPIIterator.next();
+ } else {
+ throw new Exception("must be provided");
+ }
+ }
+
+ @Override
+ protected void engineInit(KeyManager[] keyManagers, TrustManager[] trustManagers, SecureRandom secureRandom) {
+ // ignore
+ }
+
+ @Override
+ protected SSLSocketFactory engineGetSocketFactory() {
+ if (sslSocketFactory == null) {
+ synchronized (this) {
+ if (sslSocketFactory == null) {
+ sslSocketFactory = new DynamicSslSocketFactory(configuredDefaultSSLContext.getSocketFactory(), dynamicSSLContextImpl);
+ }
+ }
+ }
+ return sslSocketFactory;
+ }
+
+ @Override
+ protected SSLServerSocketFactory engineGetServerSocketFactory() {
+ return this.configuredDefaultSSLContext.getServerSocketFactory();
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine() {
+ return this.configuredDefaultSSLContext.createSSLEngine();
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine(String host, int port) {
+ try {
+ return dynamicSSLContextImpl
+ .getSSLContext(new URI(null, null, host, port, null, null, null))
+ .createSSLEngine(host, port);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ protected SSLSessionContext engineGetServerSessionContext() {
+ throw new UnsupportedOperationException("Dynamic SSLContext does not support sessions");
+ }
+
+ @Override
+ protected SSLSessionContext engineGetClientSessionContext() {
+ throw new UnsupportedOperationException("Dynamic SSLContext does not support sessions");
+
+ }
+
+ @Override
+ protected SSLParameters engineGetSupportedSSLParameters() {
+ return this.configuredDefaultSSLContext.getSupportedSSLParameters();
+ }
+}
diff --git a/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSslSocketFactory.java b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSslSocketFactory.java
new file mode 100644
index 00000000000..e452bbd7c3b
--- /dev/null
+++ b/dynamic-ssl/src/main/java/org/wildfly/security/dynamic/ssl/ssl/DynamicSslSocketFactory.java
@@ -0,0 +1,122 @@
+package org.wildfly.security.dynamic.ssl.ssl;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// TODO remove public
+public final class DynamicSslSocketFactory extends SSLSocketFactory {
+
+ private DynamicSSLContextSPI dynamicSSLContextImpl;
+ private volatile String[] intersectionCipherSuite;
+ private SSLSocketFactory configuredDefaultSslSocketFactory;
+
+ public DynamicSslSocketFactory(SSLSocketFactory configuredDefaultSslSocketFactory, DynamicSSLContextSPI dynamicSSLContextImpl) {
+ super();
+ this.configuredDefaultSslSocketFactory = configuredDefaultSslSocketFactory;
+ this.dynamicSSLContextImpl = dynamicSSLContextImpl;
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ return configuredDefaultSslSocketFactory.createSocket();
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port) throws IOException {
+ return createSocketBasedOnPeerInfo(null, port, address, null, null, null, null);
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ return createSocketBasedOnPeerInfo(host, port, null, null, null, null, null);
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException {
+ return createSocketBasedOnPeerInfo(host, port, null, localAddress, localPort, null, null);
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
+ return createSocketBasedOnPeerInfo(null, port, address, localAddress, localPort, null, null);
+
+ }
+
+ @Override
+ public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
+ return createSocketBasedOnPeerInfo(host, port, null, null, null, socket, autoClose);
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return dynamicSSLContextImpl.getConfiguredDefault().getSocketFactory().getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ String[] val = intersectionCipherSuite;
+ if (val == null) {
+ synchronized (this) {
+ val = intersectionCipherSuite;
+ if (intersectionCipherSuite == null) {
+ val = intersectionCipherSuite = getIntersection();
+ }
+ }
+ }
+ return val;
+ }
+
+ private Socket createSocketBasedOnPeerInfo(String hostname, Integer port, InetAddress address, InetAddress localAddress, Integer localPort, Socket socket, Boolean autoClose) throws IOException {
+ try {
+ SSLSocketFactory socketFactory = this.dynamicSSLContextImpl.getSSLContext(new URI(null, null, hostname == null ? address.getHostName() : hostname, port, null, null, null))
+ .getSocketFactory();
+
+ // resolve socket
+ if (socket != null && autoClose != null) {
+ return socketFactory.createSocket(socket, hostname, port, autoClose);
+ }
+
+ // resolves InetAddresses callbacks
+ if (address != null) {
+ return localAddress == null ?
+ socketFactory.createSocket(address, port) : socketFactory.createSocket(address, port, localAddress, localPort);
+ }
+ if (localAddress != null && localPort != null) {
+ return socketFactory.createSocket(hostname, port, localAddress, localPort);
+ }
+
+ // default
+ return socketFactory.createSocket(hostname, port);
+ } catch (URISyntaxException e) {
+ throw new UnknownHostException(e.getMessage());
+ }
+ }
+
+ private String[] getIntersection() {
+ List sslContexts = dynamicSSLContextImpl.getConfiguredSSLContexts();
+ Map counts = new HashMap<>();
+ List intersection = new ArrayList<>();
+ sslContexts.forEach(c -> {
+ String[] cipherSuites = c.getSocketFactory().getSupportedCipherSuites();
+ for (String cipherSuite : cipherSuites) {
+ counts.merge(cipherSuite, 1, (a, b) -> a + b);
+ }
+ });
+ counts.forEach((c, v) -> {
+ if (sslContexts.size() == v) {
+ intersection.add(c);
+ }
+ });
+ return intersection.toArray(new String[0]);
+ }
+}
diff --git a/dynamic-ssl/src/test/java/org/wildfly/security/dynamic/ssl/DynamicSSLContextTest.java b/dynamic-ssl/src/test/java/org/wildfly/security/dynamic/ssl/DynamicSSLContextTest.java
new file mode 100644
index 00000000000..7a433e8f2cc
--- /dev/null
+++ b/dynamic-ssl/src/test/java/org/wildfly/security/dynamic/ssl/DynamicSSLContextTest.java
@@ -0,0 +1,28 @@
+package org.wildfly.security.dynamic.ssl;
+
+import org.junit.Test;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+
+public class DynamicSSLContextTest {
+ // create multiple SSLServerSockets on diff ports wid different ssls. use client to connect to each successfully
+ // hosts i would have to create new virtual network interface which would be difficult to port with tests and so on?
+ // sni uses different hostnames so i will not use it in my tests
+ // maybe for different hosts i can look at mock servers and farah i think used example.com for letsencrypt
+
+ @Test
+ public void testServer() throws IOException, NoSuchAlgorithmException {
+ SSLServerSocketHelper server1 = new SSLServerSocketHelper("src/test/resources/server1.keystore.jks", "src/test/resources/server1.truststore.jks", 10000);
+ server1.run();
+ // Create socket factory
+ SSLSocketFactory sslSocketFactory = SSLContext.getDefault().getSocketFactory();
+
+ // Create socket
+ SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket("localhost", 10000);
+ sslSocket.startHandshake();
+ }
+}
diff --git a/pom.xml b/pom.xml
index 7aa688acd22..c3b4b700e69 100644
--- a/pom.xml
+++ b/pom.xml
@@ -515,6 +515,11 @@
wildfly-elytron-digest
${project.version}
+
+ org.wildfly.security
+ wildfly-elytron-dynamic-ssl
+ ${project.version}
+
org.wildfly.security
wildfly-elytron-http
@@ -1284,6 +1289,7 @@
credential/source/deprecated
credential/source/impl
digest
+ dynamic-ssl
http/base
http/basic
http/bearer
diff --git a/wildfly-elytron/pom.xml b/wildfly-elytron/pom.xml
index 19029a0e426..98f70eeb058 100644
--- a/wildfly-elytron/pom.xml
+++ b/wildfly-elytron/pom.xml
@@ -289,6 +289,10 @@
org.wildfly.security
wildfly-elytron-digest
+
+ org.wildfly.security
+ wildfly-elytron-dynamic-ssl
+
org.wildfly.security
wildfly-elytron-http
@@ -617,6 +621,11 @@
wildfly-elytron-digest
${project.version}
+
+ org.wildfly.security
+ wildfly-elytron-dynamic-ssl
+ ${project.version}
+
org.wildfly.security
wildfly-elytron-http