/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.core.user.ldap;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.MessageFormat;
import java.util.Comparator;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LDAPTrustAllSocketFactory extends SocketFactory implements Comparator<Object> {
private static final Logger LOG = LoggerFactory.getLogger(LDAPTrustAllSocketFactory.class);
@SuppressWarnings("nls")
private static final String[] SSL_PROTOCOLS = new String[] { "TLS", "SSLv3", "SSLv2", "SSL" };
private static final LDAPTrustAllSocketFactory INSTANCE = getInstance();
private SocketFactory contextFactory;
private LDAPTrustAllSocketFactory(SocketFactory contextFactory) {
this.contextFactory = contextFactory;
}
public static SocketFactory getDefault() {
return INSTANCE;
}
@Override
public Socket createSocket() throws IOException {
return INSTANCE.createSocket();
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
Socket socket = contextFactory.createSocket(host, port);
socket.setTcpNoDelay(true);
return socket;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket socket = contextFactory.createSocket(host, port);
socket.setTcpNoDelay(true);
return socket;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException {
Socket socket = contextFactory.createSocket(host, port, localHost, localPort);
socket.setTcpNoDelay(true);
return socket;
}
@Override
public Socket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
Socket socket = contextFactory.createSocket(address, port, localAddress, localPort);
socket.setTcpNoDelay(true);
return socket;
}
private static LDAPTrustAllSocketFactory getInstance() {
SSLContext sslContext = getSSLContext();
try {
sslContext.init(null, new TrustManager[]{ new LDAPTrustAllX509Manager() }, new SecureRandom());
} catch (KeyManagementException e) {
// should not happen since we do not use any keystore
throw new IllegalStateException("Failed to initialize SSL context", e);
}
return new LDAPTrustAllSocketFactory(sslContext.getSocketFactory());
}
private static SSLContext getSSLContext() {
SSLContext sslContext = null;
for (int i = 0; i < SSL_PROTOCOLS.length && sslContext == null; ++i) {
try {
sslContext = SSLContext.getInstance(SSL_PROTOCOLS[i]);
} catch (NoSuchAlgorithmException e) {
LOG.debug(MessageFormat.format("SSL protocol {0} is not supported by the platform", SSL_PROTOCOLS[i]));
}
}
if (sslContext == null) {
throw new IllegalStateException("Platform does not support a suitable SSL protocol");
}
return sslContext;
}
/**
* This is a workaround for the absolutely stupid SSL connection pooling
* handling in com.sun.jndi.ldap.ClientId. According to the LDAP documentation,
* one is supped to implement a Comparator<SocketFactory>, but then
* just the class names of the socket factories to compare are passed for
* comparision. Can't imagine what one is supposed to compare here, so we
* just compare the strings.
*/
@Override
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
}