Skip to content

Instantly share code, notes, and snippets.

@jkuipers
Created September 7, 2015 20:03
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jkuipers/e0b35c21c466a9b4d88a to your computer and use it in GitHub Desktop.
Save jkuipers/e0b35c21c466a9b4d88a to your computer and use it in GitHub Desktop.
SNI (Server Name Identification) support for old Apache Commons HTTP Client (for use with Spring Security SAML)
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.ReflectionSocketFactory;
import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.security.ssl.SSLSocketImpl;
import javax.annotation.PostConstruct;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
/**
* Enables support for SNI (Server Name Indication) with Apache Commons HTTP Client.
*/
public class CommonsHttpClientSniSupport {
private Logger logger = LoggerFactory.getLogger(getClass());
@PostConstruct
public void enableSniSupport() {
// note that we're only overriding the createSocket-method that's actually used by the SAML code
ProtocolSocketFactory sniSupportingSSLProtocolSocketFactory = new SSLProtocolSocketFactory() {
/**
* Based on the code in {@link ReflectionSocketFactory#createSocket(java.lang.String, java.lang.String, int, java.net.InetAddress, int, int)}
* with SNI (Server Name Indication) support added.
*/
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException {
Socket socket = SSLSocketFactory.getDefault().createSocket();
enableSni(socket, host);
socket.bind(new InetSocketAddress(localAddress, localPort));
InetSocketAddress remoteSocketAddress = new InetSocketAddress(InetAddress.getByName(host), port);
try {
socket.connect(remoteSocketAddress, params.getConnectionTimeout());
return socket;
} catch (SocketTimeoutException e) {
throw new ConnectTimeoutException(
"The host did not accept the connection within timeout of "
+ params.getConnectionTimeout() + " ms", e);
}
}
void enableSni(Socket socket, String host) {
if (socket instanceof SSLSocketImpl) {
((SSLSocketImpl) socket).setHost(host);
} else {
logger.warn("No SNI support since SSLSocket implementation class {} is not supported", socket.getClass().getName());
}
}
};
Protocol.registerProtocol("https", new Protocol("https", sniSupportingSSLProtocolSocketFactory, 443));
logger.info("Registered SNI-supporting protocol for HTTPS with Apache Commons HTTP client");
}
}
@kcjl519
Copy link

kcjl519 commented Jun 8, 2018

How can I use this file in a normal setting like this?

        HttpClient httpclient = HttpClientBuilder.create().build();
        HttpPost httppost = new HttpPost("https://someurl.com");
        HttpResponse response = httpclient.execute(httppost);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment