1.概览
本文将演示如何配置Apache HttpClient 4 添加ssl支持.目的很简单----无需有效证书即可成功请求 HTTPS URLs.
如果你想深入挖掘和学习其他和HttpClient相关的酷知识,请点击httpclient-guide
延伸阅读:
httpclient-connection-management
httpclient-advanced-config
httpclient-4-cookies
2. SSLPeerUnverifiedException异常
使用httpclient若未配置SSL,下面的测试----请求一个HTTPS URL----将会失败:
1 public class HttpLiveTest { 2 ??3 ????@Test(expected = SSLPeerUnverifiedException.class) 4 ????public void whenHttpsUrlIsConsumed_thenException() ?5 ??????throws ClientProtocolException, IOException { 6 ???7 ????????DefaultHttpClient httpClient = new DefaultHttpClient(); 8 ????????String urlOverHttps 9 ??????????= "https://localhost:8080/spring-security-rest-basic-auth";10 ????????HttpGet getMethod = new HttpGet(urlOverHttps);11 ?????????12 ????????HttpResponse response = httpClient.execute(getMethod);13 ????????assertThat(response.getStatusLine().getStatusCode(), equalTo(200));14 ????}15 }
具体的异常是:
1 javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated2 ????at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)3 ????at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126)4 ????...
不管何时,URL不能建立一个信任的有效链时,都会出现javax.net.ssl.SSLPeerUnverifiedException exception异常.
3.配置SSL--Accept All(HttpClient的版本小于4.3)
下面通过配置HTTP client信任所有链(译者注:chains)无论他们是否有效.
1 @Test 2 public void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() ?3 ??throws IOException, GeneralSecurityException { 4 ????TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; 5 ????SSLSocketFactory sf = new SSLSocketFactory( 6 ??????acceptingTrustStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 7 ????SchemeRegistry registry = new SchemeRegistry(); 8 ????registry.register(new Scheme("https", 8443, sf)); 9 ????ClientConnectionManager ccm = new PoolingClientConnectionManager(registry);10 ?11 ????DefaultHttpClient httpClient = new DefaultHttpClient(ccm);12 ?13 ????String urlOverHttps 14 ??????= "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1";15 ????HttpGet getMethod = new HttpGet(urlOverHttps);16 ?????17 ????HttpResponse response = httpClient.execute(getMethod);18 ????assertThat(response.getStatusLine().getStatusCode(), equalTo(200));19 }
在新的信任策略下,覆盖了原有的标准证书验证过程(原本需要咨询一个配置好的信任管理器)----上面的测试通过则表明现在的client可以请求HTTPS URL了.
4.spring的RestTemplate配置SSL(HttpClient的版本小于4.3)
我们已经知晓如何给原生的HttpClient配置添加SSL支持,再看看一下更高级的client----the Spring RestTemplate.
没有配置SSL的情况下,如预期一致,下面的测试将不会通过:
1 @Test(expected = ResourceAccessException.class)2 public void whenHttpsUrlIsConsumed_thenException() {3 ????String urlOverHttps 4 ??????= "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1";5 ????ResponseEntity<String> response 6 ??????= new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class);7 ????assertThat(response.getStatusCode().value(), equalTo(200));8 }
下面配置SSL:
1 import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; 2 import java.security.GeneralSecurityException; 3 import java.security.cert.X509Certificate; 4 import org.apache.http.auth.AuthScope; 5 import org.apache.http.auth.UsernamePasswordCredentials; 6 import org.apache.http.conn.scheme.Scheme; 7 import org.apache.http.conn.ssl.SSLSocketFactory; 8 import org.apache.http.conn.ssl.TrustStrategy; 9 import org.apache.http.impl.client.DefaultHttpClient;10 import org.springframework.http.HttpMethod;11 import org.springframework.http.ResponseEntity;12 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;13 import org.springframework.web.client.ResourceAccessException;14 import org.springframework.web.client.RestTemplate;15 ?16 ...17 @Test18 public void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() 19 ??throws GeneralSecurityException {20 ????HttpComponentsClientHttpRequestFactory requestFactory 21 ??????= new HttpComponentsClientHttpRequestFactory();22 ????DefaultHttpClient httpClient23 ??????= (DefaultHttpClient) requestFactory.getHttpClient();24 ????TrustStrategy acceptingTrustStrategy = (cert, authType) -> true25 ????SSLSocketFactory sf = new SSLSocketFactory(26 ??????acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER);27 ????httpClient.getConnectionManager().getSchemeRegistry()28 ??????.register(new Scheme("https", 8443, sf));29 ?30 ????String urlOverHttps31 ??????= "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1";32 ????ResponseEntity<String> response = new RestTemplate(requestFactory).33 ??????exchange(urlOverHttps, HttpMethod.GET, null, String.class);34 ????assertThat(response.getStatusCode().value(), equalTo(200));35 }
正如你所见,这和原生的HttpClient配置SSL非常相像----我们给 request factory 添加了SSL支持,然后初始化模板时将配置好的factory作为入参.
5.配置SSL(HttpClient版本为4.4)
在4.4版本,不再使用SSLSocketFactory,可简单配置如下:
1 @Test 2 public void givenIgnoringCertificates_whenHttpsUrlIsConsumed_thenCorrect() 3 ??throws Exception { 4 ????SSLContext sslContext = new SSLContextBuilder() 5 ??????.loadTrustMaterial(null, (certificate, authType) -> true).build(); 6 ??7 ????CloseableHttpClient client = HttpClients.custom() 8 ??????.setSSLContext(sslContext) 9 ??????.setSSLHostnameVerifier(new NoopHostnameVerifier())10 ??????.build();11 ????HttpGet httpGet = new HttpGet(HOST_WITH_SSL);12 ????httpGet.setHeader("Accept", "application/xml");13 ?14 ????HttpResponse response = client.execute(httpGet);15 ????assertThat(response.getStatusLine().getStatusCode(), equalTo(200));16 }
6.Spring RestTemplate 配置 SSL (HttpClient 4.4)
我们可以使用同样的方式配置RestTemplate :
1 @Test 2 public void givenAcceptingAllCertificatesUsing4_4_whenUsingRestTemplate_thenCorrect() ?3 throws ClientProtocolException, IOException { 4 ????CloseableHttpClient httpClient 5 ??????= HttpClients.custom() 6 ????????.setSSLHostnameVerifier(new NoopHostnameVerifier()) 7 ????????.build(); 8 ????HttpComponentsClientHttpRequestFactory requestFactory ?9 ??????= new HttpComponentsClientHttpRequestFactory();10 ????requestFactory.setHttpClient(httpClient);11 ?12 ????ResponseEntity<String> response 13 ??????= new RestTemplate(requestFactory).exchange(14 ??????urlOverHttps, HttpMethod.GET, null, String.class);15 ????assertThat(response.getStatusCode().value(), equalTo(200));16 }
7.总结
本教程讨论了如何给 Apache HttpClient 配置SSL ,忽略校验以至于能够访问任何 HTTPS URL .并举例说明给Spring RestTemplate配置SSL.
然而需要明白的是:该策略完全忽略证书验证,这可能导致安全漏洞,因此只能用在需要的地方.
本文的示例代码可访问 the GitHub project ,工程基于Eclipse,因此可以轻松导入并运行.
8.原文地址:
传送门
[译]HttpClient请求HTTPS URL
原文地址:https://www.cnblogs.com/wangliangwu/p/8492426.html