Axis 1.x 编写的client在测试https的webservice的时候, 由于client 代码建立SSL连接的时候没有对truststore进行设置,在与https部署的webservice 连接会在运行时报出:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
这是由于Axis的client用默认的SocketFactory,会对server端的证书进行验证,我们的测试server是自签名的,client检测到后自动断开连接,握手失败。
网上很多解决方案是用sun的keytool生成clientTrustStore和serverTrustStrore并把证书导进去,这些方法都稍显繁琐,我们这种client测试类没必要做一些程序之外的工作,所以综合了一个解决方案,想到这个办法。此方法的灵感来自于axis文档里的dirty solution。
核心思想是自己做一个不对证书做任何检查的SocketFactory,并用这个socket factory来替换Axis本身用的SocketFactory, 为了方便,MySocketFactory直接继承Axis的父类JSSESocketFactory 。并且重写父类方法
protected void initFactory() throws IOException
initFactory方法的内容,很簡單,就是让checkServerTrusted/checkClientTrusted什么都不返回,然后最后一行将这个SslSocketFactory赋给我们自定义类里的sslFactory变量。
// Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { // Trust always } public void checkServerTrusted(X509Certificate[] certs, String authType) { // Trust always } } }; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); // Create empty HostnameVerifier HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String arg0, SSLSession arg1) { return true; } }; sc.init(null, trustAllCerts, new java.security.SecureRandom());
sslFactory = sc.getSocketFactory;
Axis client测试类中用
AxisProperties.setProperty("axis.socketSecureFactory","my.test.MySocketFactory")来指定Axis类库要调用的SocketFactory,就是之前被我们改写的不对server certificate做任何验证的Factory。
这个解决方式绝对简单,不需要跟其他方式一样用sun的keytool建立导入一些本地证书,并利用了Axis自己的机制处理证书验证问题。