2012-09-11 6 views
8

Kann mir jemand helfen, mit HTTP-Verbindungen mit Servernamenangabe in Java zu beginnen?Server Name Indication (SNI) auf Java

Ich versuche, Inhalte von einer Website anzufordern, die ich betreue. Ich habe die Apache-HttpClient-Bibliothek verwendet, aber meine Anfrage für sicheren Inhalt schlägt fehl, da die Website nur SNI für HTTPS verwendet und SNI nicht im DefaultHttpClient aktiviert ist. Ich habe nach einer Anleitung gesucht, wie man das in der HttpClient-Bibliothek von Apache angehen kann, aber ich sehe am Ende dieses Dokument: http://hc.apache.org/httpclient-3.x/sslguide.html, das veraltet ist (Verweis auf Code zurück, als HttpClient und HttpCore Teil des Apaches commons-Pakets waren).

Also ... irgendwelche Hilfe?

Antwort

11

Sie könnten https://issues.apache.org/jira/browse/HTTPCLIENT-1119

die zugrunde liegende Client-Implementierung von Java verfolgen möchten 7 ist in der Lage, sie zu unterstützen und setzt das Feature über SSLSocketImpl # setHost (genannt von sun.net.www.protocol.https.HttpsClient

auf Java 7 Verwendung

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

bis Httpclient-1119 ist fest

+1

Es ist jetzt behoben, verfügbar in HttpComponents HttpClient 4.3.2. –

+0

Mit HttpClient 4.3.2 in Tomcat auf OpenJDK (bis zur Version "1.7.0_111") würde SNI immer noch fehlschlagen. Nach dem Wechsel zu Oracle HotSpot ('1.7.0_80') arbeitete SNI. Für jeden, der sich mit AWS Beanstalk konfrontiert sieht, sollten Sie sich diese Erweiterung ansehen, um JVM auf Oracle umzustellen: https://gist.github.com/bremeld/6706980 – Sitati

0

Es scheint, dass dieses Problem in Java 7 behoben ist.

+1

Dank HttpClient erstellt. Ich sehe das so. Der RFC gibt mir jedoch keinen Hinweis darauf, wie dies zu erreichen ist (außer, dass ich meinen eigenen Client von Grund auf erstelle). Irgendeine Idee von einem vorhandenen Werkzeug oder wie man den Apache HttpClient dafür benutzt? – JellicleCat

1

mit einem kurzen fix als de Geschrieben unter: TLS with SNI in Java clients Es ist möglich, SNI Server Support zu JDK 7 hinzuzufügen und es zusammen mit X509ExtendedKeyManager zu verwenden.

1

Was für mich gearbeitet wurde die ServerName richtig in der Konfiguration Apache Konfiguration:

sagte

/etc/apache2/sites-avaible/default

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

Wie in https://stackoverflow.com/a/8058839/2088282. Diese

4

ist, wie ich es in org.apache.httpcomponents der Httpclient v4.3 tat +

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

Und das ist, wie ich die

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

Bitte verwenden Sie nicht 'SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER'. – Bruno

+0

Einige Erklärungen für diejenigen, die neugierig sein könnte, wie ich war: 'PropertyUtils' ist von' commons-beanutils' 'String HOST = "host";' ' Constants.SNI_HOST' ist der DNS-Hostnamen des Servers mit dem du dich verbinden willst. Am wichtigsten: ** Die benutzerdefinierte Fabrik ist nicht mehr notwendig mit httpclient 4.5.2 ** –

+0

@DaanReid - Was meinst du mit "Die benutzerdefinierte Fabrik wird nicht mehr benötigt"? Gibt es eine Standardimplementierung, die wir verwenden könnten? – Shyam