I've built my own solution that works for me but it's far from perfect. I'm actually afraid there's no perfect solution due to the unfortunate implementation in javax.naming
.
My SelectiveLdapSslSocketFactory
contains a static Map mapping hosts to different SSLSocketFactories. When any of the createSocket(...)
methods is called, the call is delegated to the corresponding SSLSocketFactory
. It also contains a defaultSslSocketFactory
used for hosts without any mapping and also in the getDefaultCipherSuites()
and getSupportedCipherSuites()
methods. I'm not sure, if it's correct but it works fine in my case so test it if you like:
public class SelectiveLdapSslSocketFactory extends SSLSocketFactory {
private static SSLSocketFactory defaultSslSocketFactory;
private static final Map<String, SSLSocketFactory> hostToSslSocketFactoryMap = new HashMap<>();
{
try {
defaultSslSocketFactory = <yourOwnDefaultSslSocketFactory>;
} catch (Exception ex) {
Logger.warn(ex, "Couldn't initialize a defaultSslSocketFactory for LDAP connections!");
}
}
public static SSLSocketFactory getRegisteredSslSocketFactory(String host) {
return hostToSslSocketFactoryMap.get(host);
}
public static void registerSslSocketFactory(String host, SSLSocketFactory sslSocketFactory) {
hostToSslSocketFactoryMap.put(host, sslSocketFactory);
}
public static void deregisterSslSocketFactory(String host) {
hostToSslSocketFactoryMap.remove(host);
}
public SelectiveLdapSslSocketFactory() {
}
public static SocketFactory getDefault() {
return new SelectiveLdapSslSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return defaultSslSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return defaultSslSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
SSLSocketFactory sslSocketFactory = Objects.requireNonNullElse(hostToSslSocketFactoryMap.get(host), defaultSslSocketFactory);
return sslSocketFactory.createSocket(s, host, port, autoClose);
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
SSLSocketFactory sslSocketFactory = Objects.requireNonNullElse(hostToSslSocketFactoryMap.get(host), defaultSslSocketFactory);
return sslSocketFactory.createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
SSLSocketFactory sslSocketFactory = Objects.requireNonNullElse(hostToSslSocketFactoryMap.get(host), defaultSslSocketFactory);
return sslSocketFactory.createSocket(host, port, localHost, localPort);
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
SSLSocketFactory sslSocketFactory = getSslSocketFactory(host);
return sslSocketFactory.createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
SSLSocketFactory sslSocketFactory = getSslSocketFactory(address);
return sslSocketFactory.createSocket(address, port, localAddress, localPort);
}
private SSLSocketFactory getSslSocketFactory(InetAddress inetAddress) {
SSLSocketFactory sslSocketFactory = hostToSslSocketFactoryMap.get(Objects.requireNonNullElse(inetAddress.getCanonicalHostName(), ""));
if (sslSocketFactory == null) {
sslSocketFactory = hostToSslSocketFactoryMap.get(Objects.requireNonNullElse(inetAddress.getHostName(), ""));
if (sslSocketFactory == null) {
sslSocketFactory = hostToSslSocketFactoryMap.get(Objects.requireNonNullElse(inetAddress.getHostAddress(), ""));
if (sslSocketFactory == null) {
sslSocketFactory = defaultSslSocketFactory;
}
}
}
return sslSocketFactory;
}
}
You can then use it like:
...
SelectiveLdapSslSocketFactory.registerSslSocketFactory(host01, sslSocketFactory01);
SelectiveLdapSslSocketFactory.registerSslSocketFactory(host02, sslSocketFactory02);
SelectiveLdapSslSocketFactory.registerSslSocketFactory(host03, sslSocketFactory03);
props.put("java.naming.ldap.factory.socket", SelectiveLdapSslSocketFactory.class.getName());