diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
index 97600a7..d6914e1 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
@@ -243,15 +243,15 @@ public class HttpClientBuilder {
theContext.init(null, new TrustManager[]{new PassthroughTrustManager()},
new SecureRandom());
verifier = new AllowAllHostnameVerifier();
- sslsf = new SSLSocketFactory(theContext, verifier);
+ sslsf = new SniSSLSocketFactory(theContext, verifier);
} else if (theContext != null) {
- sslsf = new SSLSocketFactory(theContext, verifier);
+ sslsf = new SniSSLSocketFactory(theContext, verifier);
} else if (clientKeyStore != null || truststore != null) {
- sslsf = new SSLSocketFactory(SSLSocketFactory.TLS, clientKeyStore, clientPrivateKeyPassword, truststore, null, verifier);
+ sslsf = new SniSSLSocketFactory(SSLSocketFactory.TLS, clientKeyStore, clientPrivateKeyPassword, truststore, null, verifier);
} else {
final SSLContext tlsContext = SSLContext.getInstance(SSLSocketFactory.TLS);
tlsContext.init(null, null, null);
- sslsf = new SSLSocketFactory(tlsContext, verifier);
+ sslsf = new SniSSLSocketFactory(tlsContext, verifier);
}
SchemeRegistry registry = new SchemeRegistry();
registry.register(
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java
new file mode 100644
index 0000000..fa44aad
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java
@@ -0,0 +1,117 @@
+package org.keycloak.adapters;
+
+import org.apache.http.HttpHost;
+import org.apache.http.conn.scheme.HostNameResolver;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.protocol.HttpContext;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.AccessController;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class SniSSLSocketFactory extends SSLSocketFactory {
+
+ private static Logger log = Logger.getLogger(SniSSLSocketFactory.class.getName());
+
+ public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, HostNameResolver nameResolver) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(algorithm, keystore, keyPassword, truststore, random, nameResolver);
+ }
+
+ public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, TrustStrategy trustStrategy, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(algorithm, keystore, keyPassword, truststore, random, trustStrategy, hostnameVerifier);
+ }
+
+ public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(algorithm, keystore, keyPassword, truststore, random, hostnameVerifier);
+ }
+
+ public SniSSLSocketFactory(KeyStore keystore, String keystorePassword, KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(keystore, keystorePassword, truststore);
+ }
+
+ public SniSSLSocketFactory(KeyStore keystore, String keystorePassword) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(keystore, keystorePassword);
+ }
+
+ public SniSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(truststore);
+ }
+
+ public SniSSLSocketFactory(TrustStrategy trustStrategy, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(trustStrategy, hostnameVerifier);
+ }
+
+ public SniSSLSocketFactory(TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(trustStrategy);
+ }
+
+ public SniSSLSocketFactory(SSLContext sslContext) {
+ super(sslContext);
+ }
+
+ public SniSSLSocketFactory(SSLContext sslContext, HostNameResolver nameResolver) {
+ super(sslContext, nameResolver);
+ }
+
+ public SniSSLSocketFactory(SSLContext sslContext, X509HostnameVerifier hostnameVerifier) {
+ super(sslContext, hostnameVerifier);
+ }
+
+ public SniSSLSocketFactory(SSLContext sslContext, String[] supportedProtocols, String[] supportedCipherSuites, X509HostnameVerifier hostnameVerifier) {
+ super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+ }
+
+ public SniSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier) {
+ super(socketfactory, hostnameVerifier);
+ }
+
+ public SniSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, String[] supportedProtocols, String[] supportedCipherSuites, X509HostnameVerifier hostnameVerifier) {
+ super(socketfactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+ }
+
+ @Override
+ public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) throws IOException {
+ return super.connectSocket(connectTimeout, applySNI(socket, host.getHostName()), host, remoteAddress, localAddress, context);
+ }
+
+ @Override
+ public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException {
+ return super.createLayeredSocket(applySNI(socket, target), target, port, context);
+ }
+
+ private Socket applySNI(final Socket socket, String hostname) {
+ if (socket instanceof SSLSocket) {
+ try {
+ Method setHostMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
+ public Method run() throws NoSuchMethodException {
+ return socket.getClass().getMethod("setHost", String.class);
+ }
+ });
+
+ setHostMethod.invoke(socket, hostname);
+ log.finest("Applied SNI to socket for: " + hostname);
+ } catch (Exception e) {
+ log.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e);
+ }
+ }
+ return socket;
+ }
+}