1. 개요
이 문서에서는 "모두 수락" SSL 지원으로 Apache HttpClient 4를 구성하는 방법을 보여줍니다 . 목표는 간단합니다. 유효한 인증서가 없는 HTTPS URL을 사용하는 것입니다.
더 깊이 파고들고 HttpClient로 할 수 있는 다른 멋진 것들을 배우고 싶다면 – 메인 HttpClient 사용방법(예제) 로 넘어가십시오 .
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 예외 는 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<String> response = new RestTemplate(requestFactory).
exchange(urlOverHttps, HttpMethod.GET, null, String.class);
assertThat(response.getStatusCode().value(), equalTo(200));
}
이제 새로운 TrustStrategy 가 표준 인증서 확인 프로세스 (구성된 신뢰 관리자에게 문의해야 함)를 재정의하므로 이제 테스트가 통과되고 클라이언트가 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<ConnectionSocketFactory> socketFactoryRegistry =
RegistryBuilder.<ConnectionSocketFactory> 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<String> response = new RestTemplate(requestFactory)
.exchange(urlOverHttps, HttpMethod.GET, null, String.class);
assertThat(response.getStatusCode().value(), equalTo(200));
}
5. SSL을 사용하는 Spring RestTemplate (HttpClient < 4.3)
이제 SSL 지원으로 원시 HttpClient 를 구성하는 방법을 살펴보았 으므로 더 높은 수준의 클라이언트인 Spring RestTemplate 을 살펴보겠습니다 .
SSL이 구성되지 않은 경우 다음 테스트가 예상대로 실패합니다.
@Test(expected = ResourceAccessException.class)
public void whenHttpsUrlIsConsumed_thenException() {
String urlOverHttps
= "https://localhost:8443/httpclient-simple/api/bars/1";
ResponseEntity<String> 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<String> response = new RestTemplate(requestFactory).
exchange(urlOverHttps, HttpMethod.GET, null, String.class);
assertThat(response.getStatusCode().value(), equalTo(200));
}
보시다시피 이것은 원시 HttpClient에 대해 SSL을 구성한 방식과 매우 유사합니다. SSL 지원으로 요청 팩터리를 구성한 다음 이 미리 구성된 팩터리를 전달하는 템플릿을 인스턴스화합니다.
6. SSL을 사용하는 Spring RestTemplate (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<String> response
= new RestTemplate(requestFactory).exchange(
urlOverHttps, HttpMethod.GET, null, String.class);
assertThat(response.getStatusCode().value(), equalTo(200));
}
7. 결론
이 사용방법(예제)에서는 인증서에 관계없이 모든 HTTPS URL을 사용할 수 있도록 Apache HttpClient에 대해 SSL을 구성하는 방법에 대해 설명했습니다. Spring RestTemplate 에 대한 동일한 구성 도 설명되어 있습니다.
그러나 이해해야 할 중요한 점은 이 전략이 인증서 검사 를 완전히 무시한다는 것입니다. 따라서 안전하지 않고 합당한 경우에만 사용됩니다.
이러한 예제의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다. 이것은 Eclipse 기반 프로젝트이므로 그대로 가져오고 실행하기 쉬워야 합니다.