调用第三方服务时,厂商提供了一个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();