diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
index f461577e0c..cfcbe19540 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
@@ -260,15 +260,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/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java
new file mode 100644
index 0000000000..9ccbcde43a
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other 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.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 Marko Strukelj
+ */
+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() {
+ 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;
+ }
+}