Axis2请求忽略SSL证书信任

技术背景

客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示
HTTPS通信过程

现象

业务上需要通过axis基于HTTPS调用某服务商的WSO2 server,但是服务方并没有提供证书,因此调用时会抛出异常如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
org.apache.axis2.AxisFault: Connection has been shutdown: 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
at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430)
at org.apache.axis2.transport.http.SOAPMessageFormatter.writeTo(SOAPMessageFormatter.java:78)
at org.apache.axis2.transport.http.AxisRequestEntity.writeRequest(AxisRequestEntity.java:84)
at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.axis2.transport.http.AbstractHTTPSender.executeMethod(AbstractHTTPSender.java:621)
at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:193)
at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:75)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:404)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:231)
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:443)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:406)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)

解决办法

  • 配置证书
    配置trustStore文件并导入

    1
    2
    String ssl = Settings.getString("ssl.trustStore.path");
    System.setProperty("javax.net.ssl.trustStore", ssl);
  • 忽略证书信任
    通过Google查了很多忽略证书信任的文章,例如如下SslUtils忽略ssl的办法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    package com.emchat.example.httpclient.utils;  

    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;

    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;

    public class SslUtils {
    private static void trustAllHttpsCertificates() throws Exception {
    TrustManager[] trustAllCerts = new TrustManager[1];
    TrustManager tm = new miTM();
    trustAllCerts[0] = tm;
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, null);
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    static class miTM implements TrustManager,X509TrustManager {
    public X509Certificate[] getAcceptedIssuers() {
    return null;
    }

    public boolean isServerTrusted(X509Certificate[] certs) {
    return true;
    }

    public boolean isClientTrusted(X509Certificate[] certs) {
    return true;
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType)
    throws CertificateException {

    return;
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType)
    throws CertificateException {

    return;
    }
    }

    /**
    * 忽略HTTPS请求的SSL证书,必须在openConnection之前调用
    * @throws Exception
    */

    public static void ignoreSsl() throws Exception{
    HostnameVerifier hv = new HostnameVerifier() {
    public boolean verify(String urlHostName, SSLSession session) {
    System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
    return true;
    }
    };
    trustAllHttpsCertificates();
    HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

    }

    这些大多是HttpsURLConnection的忽略办法,由于Axis2的客户端并不是基于HttpsURLConnection的忽略信任,因此需要如下设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public static SSLContext getSSLContext() {
    TrustManager[] customTrustManager = new TrustManager[] { new X509TrustManager() {

    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    return null;
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType) {
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }
    } };
    SSLContext sslCtx = null;
    try {
    sslCtx = SSLContext.getInstance("SSL");
    sslCtx.init(null, customTrustManager, null);
    } catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
    } catch (KeyManagementException e) {
    e.printStackTrace();
    }
    return sslCtx;
    }

    Stub._getServiceClient().getOptions().setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER,
    new Protocol("https", new SSLProtocolSocketFactory(getSSLContext()), 443));

参考资料

How to ignore trust store when connecting to a WSO2 server
java在访问https资源时,忽略证书信任问题