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 index 9ccbcde43a..89b952e7e9 100644 --- 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 @@ -23,10 +23,12 @@ 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 org.keycloak.common.util.Environment; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.Socket; @@ -35,9 +37,11 @@ import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -46,7 +50,8 @@ import java.util.logging.Logger; */ public class SniSSLSocketFactory extends SSLSocketFactory { - private static Logger log = Logger.getLogger(SniSSLSocketFactory.class.getName()); + private static final Logger LOG = Logger.getLogger(SniSSLSocketFactory.class.getName()); + private static final AtomicBoolean skipSNIApplication = new AtomicBoolean(false); 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); @@ -115,18 +120,35 @@ public class SniSSLSocketFactory extends SSLSocketFactory { } private Socket applySNI(final Socket socket, String hostname) { + if (skipSNIApplication.get()) { + LOG.log(Level.FINE, "Skipping application of SNI because JDK is missing setHost() method."); + return socket; + } + if (socket instanceof SSLSocket) { try { Method setHostMethod = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override 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); + LOG.log(Level.FINE, "Applied SNI to socket for host {0}", hostname); + } catch (PrivilegedActionException e) { + if (e.getCause() instanceof NoSuchMethodException) { + // For IBM java there is no method with name setHost(), however we don't need to applySNI + // because IBM java is doing it automatically, so we can set lower level of this message + // See: KEYCLOAK-6817 + Level logLevel = Environment.IS_IBM_JAVA ? Level.FINE : Level.WARNING; + LOG.log(logLevel, "Failed to apply SNI to SSLSocket", e); + skipSNIApplication.set(true); + } else { + LOG.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e); + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + LOG.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e); } } return socket; diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java index 8c064b0ded..32a276c014 100644 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java @@ -23,6 +23,7 @@ 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 org.keycloak.common.util.Environment; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; @@ -40,6 +41,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -55,6 +57,7 @@ import java.util.logging.Logger; public class SniSSLSocketFactory extends SSLSocketFactory { private static final Logger LOG = Logger.getLogger(SniSSLSocketFactory.class.getName()); + private static final AtomicBoolean skipSNIApplication = new AtomicBoolean(false); 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); @@ -123,6 +126,11 @@ public class SniSSLSocketFactory extends SSLSocketFactory { } private Socket applySNI(final Socket socket, String hostname) { + if (skipSNIApplication.get()) { + LOG.log(Level.FINE, "Skipping application of SNI because JDK is missing setHost() method."); + return socket; + } + if (socket instanceof SSLSocket) { try { Method setHostMethod = AccessController.doPrivileged(new PrivilegedExceptionAction() { @@ -133,8 +141,19 @@ public class SniSSLSocketFactory extends SSLSocketFactory { }); setHostMethod.invoke(socket, hostname); - LOG.log(Level.FINEST, "Applied SNI to socket for host {0}", hostname); - } catch (PrivilegedActionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + LOG.log(Level.FINE, "Applied SNI to socket for host {0}", hostname); + } catch (PrivilegedActionException e) { + if (e.getCause() instanceof NoSuchMethodException) { + // For IBM java there is no method with name setHost(), however we don't need to applySNI + // because IBM java is doing it automatically, so we can set lower level of this message + // See: KEYCLOAK-6817 + Level logLevel = Environment.IS_IBM_JAVA ? Level.FINE : Level.WARNING; + LOG.log(logLevel, "Failed to apply SNI to SSLSocket", e); + skipSNIApplication.set(true); + } else { + LOG.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e); + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { LOG.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e); } }