16

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?

JellicleCat
  • 28,480
  • 24
  • 109
  • 162

5 Answers5

12

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

cmbntr
  • 136
  • 4
  • 3
    It's fixed now, available in HttpComponents HttpClient 4.3.2. – Stefan L Jan 21 '14 at 08:46
  • 1
    Using HttpClient 4.3.2 in Tomcat on OpenJDK (up to version `1.7.0_111`), SNI would still fail. After switching to Oracle HotSpot (`1.7.0_80`), SNI worked. For anyone facing this on AWS Beanstalk, check out this ebextension to switch JVM to Oracle: https://gist.github.com/bremeld/6706980 – Sitati Nov 23 '16 at 08:19
5

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();
shreyas
  • 700
  • 8
  • 10
  • 2
    Please do not use `SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER`. – Bruno Aug 21 '14 at 15:23
  • Some clarifications for those who might be curious as I was: `PropertyUtils` is from `commons-beanutils` `String HOST = "host";` `Constants.SNI_HOST` is the DNS hostname of the server you want to connect to. Most importantly: **The custom factory is no longer necessary with httpclient 4.5.2** – Daan Reid Jun 01 '16 at 07:21
  • @DaanReid - What do you mean by "The custom factory is no longer needed"? Is there a default implementation that we could use. – Shyam Kumar Sundarakumar Jun 08 '16 at 18:26
  • 1
    @Shyam the default implementation works out of the box if your httpclient is up to date: `SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext)` – Daan Reid Jun 22 '16 at 08:24
  • 1
    SNI works in Java7, but... Note that someone might have disabled it. You might want to search for `jsse.enableSNIExtension`. And check if someone set it to false – Nux Oct 17 '20 at 19:56
1

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.

Community
  • 1
  • 1
SkateScout
  • 815
  • 14
  • 24
1

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.

Community
  • 1
  • 1
Giovanni Silva
  • 705
  • 5
  • 17
0

It appears that this issue is fixed in Java 7.

a.drew.b
  • 84
  • 2
  • 1
    Thanks. I see that to be the case. However, the RFC doesn't give me any hint as to how to achieve this (except by building my own client from the ground up). Any idea of an existing tool or how to use the Apache HttpClient for this? – JellicleCat Sep 11 '12 at 14:27