Can anyone help me get started on carrying out HTTP connections with server name indication in Java?
I'm trying to request content from a site I'm adminstering. I've been using Apache's HttpClient library, but my request for secure content fails because the website only uses SNI for HTTPS, and SNI isn't enabled in the DefaultHttpClient. I've looked for instruction on how to approach this within Apache's HttpClient library, but I see end up with this document: http://hc.apache.org/httpclient-3.x/sslguide.html, which is out of date (referring to code back when HttpClient and HttpCore were part of Apache's commons package).
So... any help?
you might want to track https://issues.apache.org/jira/browse/HTTPCLIENT-1119
the underlying client implementation of Java 7 is capable to support it and exposes the feature via SSLSocketImpl#setHost (called by sun.net.www.protocol.https.HttpsClient
on Java 7 use
new URL("https://cmbntr.sni.velox.ch/").openStream()
until HTTPCLIENT-1119 is fixed
This is how I did it in org.apache.httpcomponents's httpclient v4.3+
private HttpClientConnectionManager createConnectionManager(final SSLContext ctx) {
LOG.info("Creating sslConnectionSocketFactory");
final SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(ctx) {
@Override
protected void prepareSocket(SSLSocket socket) throws IOException {
try {
System.out.println("************ setting socket HOST property *************");
PropertyUtils.setProperty(socket, HOST, Constants.SNI_HOST);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
LOG.error(ex.getMessage());
}
super.prepareSocket(socket);
}
};
LOG.info("Creating connectionRegistry");
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslSF)
.build();
LOG.info("Creating poolingConnectionManager");
final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);
connectionManager.setMaxTotal(MAX_CONNECTIONS);
return connectionManager;
}
And this is how I created the HttpClient
final KeyManager[] keyManagers = createKeyManagers();
final TrustManager[] trustManagers = createTrustManagers();
final SSLContext ctx = createSslContext(keyManagers, trustManagers);
final HttpClientConnectionManager connectionManager = createConnectionManager(ctx);
LOG.info("Creating httpClient");
HttpClient httpClient = HttpClients
.custom()
.setConnectionManager(connectionManager)
.build();
with an short fix as described under:
TLS with SNI in Java clients
It is Possible to add SNI Server Support to JDK 7 and USe it in the together with X509ExtendedKeyManager.
What worked for me was configuring the ServerName
correctly in the Apache configuration:
/etc/apache2/sites-avaible/default
<VirtualHost *:443>
ServerName foo.domain.com
...
</VirtualHost>
Like said in https://stackoverflow.com/a/8058839/2088282.
It appears that this issue is fixed in Java 7.