1. Übersicht
Dieser Artikel zeigt, wie Sie den Apache HttpClient 4 mit der SSL-Unterstützung "Alle akzeptieren" konfigurieren . Das Ziel ist einfach: Verwenden Sie HTTPS-URLs ohne gültige Zertifikate.
Wenn Sie tiefer graben und andere coole Dinge lernen möchten, die Sie mit dem HttpClient tun können, gehen Sie zum Haupthandbuch für HttpClient .
2. Die SSLPeerUnverifiedException
Ohne die Konfiguration von SSL mit dem HttpClient schlägt der folgende Test fehl, bei dem eine HTTPS-URL verwendet wird:
public class RestClientLiveManualTest { @Test(expected = SSLPeerUnverifiedException.class) public void whenHttpsUrlIsConsumed_thenException() throws ClientProtocolException, IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); String urlOverHttps = "//localhost:8082/httpclient-simple"; HttpGet getMethod = new HttpGet(urlOverHttps); HttpResponse response = httpClient.execute(getMethod); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); } }
Der genaue Fehler ist:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397) at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126) ...
Die Ausnahme javax.net.ssl.SSLPeerUnverifiedException tritt immer dann auf, wenn für die URL keine gültige Vertrauenskette hergestellt werden konnte.
3. Konfigurieren Sie SSL - Akzeptieren Sie alle (HttpClient <4.3)
Lassen Sie uns nun den HTTP-Client so konfigurieren, dass er allen Zertifikatketten unabhängig von ihrer Gültigkeit vertraut:
@Test public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); CloseableHttpClient httpClient = (CloseableHttpClient) requestFactory.getHttpClient(); TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER); httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 8443, sf)); ResponseEntity response = new RestTemplate(requestFactory). exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
Mit der neuen TrustStrategy, die jetzt den Standardprozess zur Zertifikatsüberprüfung überschreibt (der einen konfigurierten Vertrauensmanager konsultieren sollte), ist der Test nun erfolgreich und der Client kann die HTTPS-URL verwenden .
4. Konfigurieren Sie SSL - Alle akzeptieren (HttpClient 4.4 und höher)
Mit dem neuen HTTPClient haben wir jetzt einen erweiterten, neu gestalteten Standard-SSL-Hostnamen-Verifizierer. Mit der Einführung von SSLConnectionSocketFactory und RegistryBuilder ist es auch einfach, SSLSocketFactory zu erstellen. So können wir den obigen Testfall wie folgt schreiben:
@Test public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException { TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); Registry socketFactoryRegistry = RegistryBuilder. create() .register("https", sslsf) .register("http", new PlainConnectionSocketFactory()) .build(); BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf) .setConnectionManager(connectionManager).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); ResponseEntity response = new RestTemplate(requestFactory) .exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
5. Das Spring RestTemplate mit SSL (HttpClient <4.3)
Nachdem wir nun gesehen haben, wie ein roher HttpClient mit SSL-Unterstützung konfiguriert wird , werfen wir einen Blick auf einen übergeordneten Client - das Spring RestTemplate .
Wenn kein SSL konfiguriert ist, schlägt der folgende Test wie erwartet fehl:
@Test(expected = ResourceAccessException.class) public void whenHttpsUrlIsConsumed_thenException() { String urlOverHttps = "//localhost:8443/httpclient-simple/api/bars/1"; ResponseEntity response = new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
Konfigurieren wir also SSL:
@Test public void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() throws GeneralSecurityException { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); DefaultHttpClient httpClient = (DefaultHttpClient) requestFactory.getHttpClient(); TrustStrategy acceptingTrustStrategy = (cert, authType) -> true SSLSocketFactory sf = new SSLSocketFactory( acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER); httpClient.getConnectionManager().getSchemeRegistry() .register(new Scheme("https", 8443, sf)); String urlOverHttps = "//localhost:8443/httpclient-simple/api/bars/1"; ResponseEntity response = new RestTemplate(requestFactory). exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
Wie Sie sehen, ist dies der Art und Weise, wie wir SSL für den unformatierten HttpClient konfiguriert haben , sehr ähnlich. Wir konfigurieren die Anforderungsfactory mit SSL-Unterstützung und instanziieren dann die Vorlage, die diese vorkonfigurierte Factory übergibt.
6. Das Spring RestTemplate mit SSL (HttpClient 4.4)
Und wir können unser RestTemplate auf dieselbe Weise konfigurieren :
@Test public void givenAcceptingAllCertificatesUsing4_4_whenUsingRestTemplate_thenCorrect() throws ClientProtocolException, IOException { CloseableHttpClient httpClient = HttpClients.custom() .setSSLHostnameVerifier(new NoopHostnameVerifier()) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); ResponseEntity response = new RestTemplate(requestFactory).exchange( urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
7. Fazit
In diesem Lernprogramm wurde erläutert, wie Sie SSL für einen Apache HttpClient so konfigurieren, dass er unabhängig vom Zertifikat jede HTTPS-URL verwenden kann. Die gleiche Konfiguration für das Spring RestTemplate ist ebenfalls dargestellt.
Es ist jedoch wichtig zu verstehen, dass diese Strategie die Zertifikatsprüfung vollständig ignoriert - was sie unsicher macht und nur dort verwendet werden kann, wo dies sinnvoll ist.
Die Implementierung dieser Beispiele finden Sie im GitHub-Projekt - dies ist ein Eclipse-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.