SSLを使用したHttpClient
1. 概要
この記事では、configure the Apache HttpClient 4 with “Accept All” SSL supportを実行する方法を説明します。 目標は単純です。有効な証明書を持たないHTTPS URLを使用します。
深く掘り下げて、HttpClientでできる他のクールなことを学びたい場合は、the main HttpClient guideに進んでください。
参考文献:
2. SSLPeerUnverifiedException
HttpClientでSSLを構成しないと、次のテスト(HTTPS URLを使用)は失敗します。
public class RestClientLiveManualTest {
@Test(expected = SSLPeerUnverifiedException.class)
public void whenHttpsUrlIsConsumed_thenException()
throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
String urlOverHttps
= "https://localhost:8082/httpclient-simple";
HttpGet getMethod = new HttpGet(urlOverHttps);
HttpResponse response = httpClient.execute(getMethod);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
}
}
正確な失敗は次のとおりです。
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)
...
javax.net.ssl.SSLPeerUnverifiedException exceptionは、URLに対して有効な信頼のチェーンを確立できなかった場合に発生します。
3. SSLの構成–すべて受け入れる(HttpClient <4.3)
次に、有効性に関係なくすべての証明書チェーンを信頼するようにHTTPクライアントを構成しましょう。
@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));
}
新しいTrustStrategyがoverriding the standard certificate verification processになりました(構成されたトラストマネージャーに相談する必要があります)–テストに合格し、the client is able to consume the HTTPS URLになりました。
4. SSLの構成–すべて受け入れる(HttpClient 4.4以降)
新しいHTTPClientにより、デフォルトのSSLホスト名検証機能が強化され、再設計されました。 また、SSLConnectionSocketFactoryとRegistryBuilderの導入により、SSLSocketFactoryを簡単に構築できます。 したがって、上記のテストケースは次のように記述できます。
@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. SSLを使用したSpringRestTemplate(HttpClient <4.3)
SSLサポートを使用して生のHttpClientを構成する方法を確認したので、より高いレベルのクライアントであるSpringRestTemplateを見てみましょう。
SSLが設定されていない場合、次のテストは期待どおりに失敗します。
@Test(expected = ResourceAccessException.class)
public void whenHttpsUrlIsConsumed_thenException() {
String urlOverHttps
= "https://localhost:8443/httpclient-simple/api/bars/1";
ResponseEntity response
= new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class);
assertThat(response.getStatusCode().value(), equalTo(200));
}
それでは、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
= "https://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));
}
ご覧のとおり、これはvery similar to the way we configured SSL for the raw HttpClientです。SSLサポートを使用してリクエストファクトリを構成してから、この事前構成済みファクトリを渡すテンプレートをインスタンス化します。
6. SSLを使用したSpringRestTemplate(HttpClient 4.4)
また、同じ方法を使用してRestTemplateを構成できます。
@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. 結論
このチュートリアルでは、証明書に関係なくHTTPS URLを使用できるようにApache HttpClientのSSLを構成する方法について説明しました。 SpringRestTemplateの同じ構成も示されています。
ただし、理解しておくべき重要なことは、this strategy entirely ignores certificate checkingであるということです。これにより、安全性が低下し、意味のある場合にのみ使用されます。
これらの例の実装はthe GitHub projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。