2012-09-11 14 views
8

¿Alguien puede ayudarme a comenzar a realizar conexiones HTTP con indicación de nombre de servidor en Java?Server Name Indication (SNI) en Java

Estoy tratando de solicitar contenido de un sitio que estoy administrando. He estado utilizando la biblioteca HttpClient de Apache, pero mi solicitud de contenido seguro falla porque el sitio web solo usa SNI para HTTPS y SNI no está habilitado en DefaultHttpClient. He buscado instrucciones sobre cómo abordar esto dentro de la biblioteca HttpClient de Apache, pero veo que termina con este documento: http://hc.apache.org/httpclient-3.x/sslguide.html, que está desactualizado (refiriéndose al código cuando HttpClient y HttpCore formaban parte del paquete commons de Apache).

Entonces ... ¿Alguna ayuda?

Respuesta

11

es posible que desee realizar un seguimiento de https://issues.apache.org/jira/browse/HTTPCLIENT-1119

la implementación de cliente subyacente de Java 7 es capaz de apoyarlo y expone a la función a través SSLSocketImpl # setHost (llamado por sun.net.www.protocol.https.HttpsClient

en Java 7 uso

new URL("https://cmbntr.sni.velox.ch/").openStream() 

hasta HttpClient-1119 se fija

+1

Se arregló ahora, disponible en HttpComponents HttpClient 4.3.2. –

+0

Usando HttpClient 4.3.2 en Tomcat en OpenJDK (hasta la versión '1.7.0_111'), SNI aún fallaría. Después de cambiar a Oracle HotSpot ('1.7.0_80'), SNI funcionó. Para cualquiera que enfrente esto en AWS Beanstalk, revise esta extensión para cambiar de JVM a Oracle: https://gist.github.com/bremeld/6706980 – Sitati

0

Parece que este problema está solucionado en Java 7.

+1

Gracias. Veo que ese es el caso. Sin embargo, el RFC no me da ninguna pista sobre cómo lograr esto (excepto construyendo mi propio cliente desde cero). ¿Alguna idea de una herramienta existente o cómo usar Apache HttpClient para esto? – JellicleCat

1

Lo que funcionó para mí fue la configuración de los ServerName correctamente en la configuración de Apache:

/etc/apache2/sites-avaible/default

<VirtualHost *:443> 
    ServerName foo.domain.com 
    ... 
</VirtualHost> 

Como dijo en https://stackoverflow.com/a/8058839/2088282.

4

Esta es la forma en que lo hice en v4.3 httpclient de org.apache.httpcomponents +

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; 
} 

Y esto es cómo creé el 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(); 
+0

No use 'SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER'. – Bruno

+0

Algunas aclaraciones para los que pudieron ser curiosos como yo: '' PropertyUtils' es de commons-beanutils' 'String host = "host";' ' Constants.SNI_HOST' es el nombre de host DNS del servidor quieres conectarte Lo más importante: ** La fábrica personalizada ya no es necesaria con httpclient 4.5.2 ** –

+0

@DaanReid - ¿Qué quiere decir con "La fábrica personalizada ya no es necesaria"? ¿Hay una implementación predeterminada que podríamos usar? – Shyam