調用第三方服務時,廠商提供了一個WSDL文件、調用的地址和一個后綴為pfx的證書文件,通過SOUPUI記載證書是可以正常調用WebService服務,那么如何將該服務轉換為代碼呢?
咨詢了廠商的支持,廠商說直接發送報文即可。
觀察SOUPUI的調用發現直接發送的SOUP報文,那么決定使用HttpClient進行服務調用,調用HTTPS好說、發送報文也好說,關鍵問題卡在了pfx證書上面。
百度了很多例子,說JAVA無法直接攜帶pfx的證書,那么就在pfx證書轉換方面嘗試了一些,最終沒有轉換成功。
繼續觀察SOUPUI的調用模式,SOUPUI可以在PERFERENCE的SSL中可以直接配置keystore和password,就可以攜帶證書,而且SOUPUI調用各種服務主要是使用HTTPClient完成的的,他可以實現,那就說明通過HTTPClient是可以直接攜帶pfx格式的證書的,基本思路確定,那就全力在這條路上繼續折騰吧。
整理一下尷尬的情況:
資源:HTTPS協議、WebService服務、需要pfx證書認證;
目標:通過HttpClient構建SSL通道調用HTTPS的WebService接口,攜帶pfx證書信息,直接發送SOUP報文調用接口;
難點:pfx證書如何處理?
百度了好久,有相應的解決方案,但實驗后均不行;后在bing的國際版中進行搜索,結果中stackoverflow中有了大收獲。
地址:https://stackoverflow.com/questions/44493040/apache-httpclient-pfx-file
該國際友人碰到了和我一樣的問題,通過SOUPUI攜帶pfx證書調用Https的WebService服務沒有問題,使用HttpClient模擬報文的時候無法攜帶證書,但是該哥們自行解決了該問題,而且還無私的把源代碼整個貼在了論壇上,我用顫抖的雙手復制粘貼了該代碼,稍作修改執行發現問題解決。天哪,折騰了一個下午加晚上,終於算是解決了。
在此特意轉發一下這位大神的佳作:
KeyStore clientStore = KeyStore.getInstance("PKCS12");
InputStream instream = Thread.currentThread().getContextClassLoader().getResourceAsStream(keystoreName);
try {
clientStore.load(instream, keyStorePwd.toCharArray());
} finally {
instream.close();
}
//Trust everybody
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {return null;}
};
SSLContext sslCtx = SSLContext.getInstance("TLS");
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(clientStore, keyStorePwd != null ? keyStorePwd.toCharArray() : null);
KeyManager[] keymanagers = kmfactory.getKeyManagers();
sslCtx.init(keymanagers, new TrustManager[]{tm}, null);
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslCtx);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionFactory).register("http", new PlainConnectionSocketFactory()).build();
PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager(registry);
HttpClientBuilder hcb = HttpClientBuilder.create();
hcb.setConnectionManager(pcm);
CloseableHttpClient httpClient = hcb.build();
