Автор оригинала: Eugen Paraschiv.
1. Обзор
В этой статье будет показано, как настроить Apache HttpClient 4 с поддержкой SSL “Принять все” . Цель проста – использовать URL-адреса HTTPS, которые не имеют действительных сертификатов.
Если вы хотите копнуть глубже и узнать другие интересные вещи, которые вы можете сделать с помощью HttpClient – перейдите к главному руководству HttpClient .
Дальнейшее чтение:
Управление подключением HttpClient
Расширенная конфигурация HttpClient
HttpClient 4 – Отправка пользовательских файлов Cookie
2. Исключение SSLPeerUnverifiedException
Без настройки SSL с помощью HttpClient следующий тест – использование URL – адреса HTTPS-завершится неудачей:
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)
Теперь давайте настроим HttpClient так, чтобы он доверял всем цепочкам сертификатов независимо от их действительности:
@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)); ResponseEntityresponse = new RestTemplate(requestFactory). exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
С новой TrustStrategy теперь переопределяющей стандартный процесс проверки сертификата (который должен консультироваться с настроенным менеджером доверия) – тест теперь проходит, и клиент может использовать URL-адрес HTTPS .
4. Настройте SSL – Примите все (HttpClient 4.4 и выше)
С новым HttpClient теперь у нас есть улучшенный, переработанный верификатор имени хоста SSL по умолчанию. Также с введением SSLConnectionSocketFactory и Registry Builder легко построить 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); RegistrysocketFactoryRegistry = 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. Spring RestTemplate с SSL (HttpClient < 4.3)
Теперь, когда мы увидели, как настроить raw HttpClient с поддержкой SSL давайте рассмотрим клиент более высокого уровня – Spring RestTemplate .
Если SSL не настроен, следующий тест завершится неудачей, как и ожидалось:
@Test(expected = ResourceAccessException.class) public void whenHttpsUrlIsConsumed_thenException() { String urlOverHttps = "https://localhost:8443/httpclient-simple/api/bars/1"; ResponseEntityresponse = 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"; ResponseEntityresponse = new RestTemplate(requestFactory). exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
Как вы можете видеть, это очень похоже на то, как мы настроили SSL для необработанного HttpClient – мы настраиваем фабрику запросов с поддержкой SSL, а затем создаем экземпляр шаблона, передавая эту предварительно настроенную фабрику.
6. Spring RestTemplate с SSL (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); ResponseEntityresponse = new RestTemplate(requestFactory).exchange( urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }
7. Заключение
В этом руководстве обсуждалось, как настроить SSL для Apache HttpClient, чтобы он мог использовать любой URL-адрес HTTPS, независимо от сертификата. Та же конфигурация для пружины RestTemplate также проиллюстрирована.
Однако важно понимать, что эта стратегия полностью игнорирует проверку сертификатов , что делает ее небезопасной и может использоваться только там, где это имеет смысл.
Реализацию этих примеров можно найти в проекте GitHub – это проект, основанный на Eclipse, поэтому его должно быть легко импортировать и запускать как есть.