如何使用httpClient4使用Axis2配置SSL

时间:2018-09-28 11:55:43

标签: ssl axis2 apache-httpclient-4.x

由于httpClient 3已过时,因此我需要替换代码:

SSLProtocolSocketFactory.setSSL(trustStore, keyStore, pasw);
ProtocolSocketFactory factory = new SSLProtocolSocketFactory();
Protocol.registerProtocol("https", new Protocol("https", factory, 443));

如果有人尝试过,请分享。

在Java代码中,我正在尝试使用OperationClient对象调用Web服务      operationClientObject.execute(true);

先谢谢了。

1 个答案:

答案 0 :(得分:1)

axis2 httpclient4迁移不是那么容易,因为它出现在“文档”中。

在此过程中,我使用了最新的Axis 2版本1.7.8。

第2轴1.7.0 release notes包含一个衬里,用于HttpClient v4集成:

Axis2 1.7.0 supports Apache HttpClient 4.x in addition to the no longer maintained Commons HttpClient 3.x. To enable the support for HttpClient 4.x, use org.apache.axis2.transport.http.impl.httpclient4.HTTPClient4TransportSender instead of org.apache.axis2.transport.http.CommonsHTTPTransportSender in axis2.xml. Please note that the code was written for HttpClient 4.2.x and should work with 4.3.x and 4.4.x, but is incompatible with 4.5.x.

当心最后的话。 Axis 2 1.7.8 pom文件,并且二进制发行版包含httpclient-4.5.3.jar,但不适用于它。因此,请改用httpclient 4.4.1

启用日志记录

在升级之前,我想您已经有一个工作中的axis 2项目。我建议启用2轴调试日志记录,以查看会发生什么。要启用日志记录,请使用jvm参数定义一个自定义log4j属性文件:

-Dlog4j.configuration=file:/c:/work/sources/debug_log4j.properties

debug_log4j.properties文件的内容为:

log4j.rootCategory=DEBUG, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%p] %m%n 

Axis2 + Httpclient4

如果没有axis2.xml,则可以在axis2 binary package中找到它(包含所有依赖项和示例配置)

根据发行说明,您需要将传输发件人从CommonsHTTPTransportSender更改为HTTPClient4TransportSender。

如果您查看(或调试)axis2配置器,就会看到,xml必须包含特定部分,否则axis2不会读取它。

因此,将我的axis2.xml内容配置为使用HttpClient4(并删除了未使用的部分,但保留了必不可少的部分):

<axisconfig name="AxisJava2.0">
    <!-- ================================================= -->
    <!-- Transport Outs -->
    <!-- ================================================= -->
    <parameter name="hotdeployment">true</parameter>
    <parameter name="hotupdate">false</parameter>
    <parameter name="enableMTOM">false</parameter>
    <parameter name="enableSwA">false</parameter>   

    <transportSender name="local"
                     class="org.apache.axis2.transport.local.LocalTransportSender"/>

    <transportSender name="http"
                     class="org.apache.axis2.transport.http.impl.httpclient4.HTTPClient4TransportSender">
        <parameter name="PROTOCOL">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding">chunked</parameter>

        <!-- If following is set to 'true', optional action part of the Content-Type will not be added to the SOAP 1.2 messages -->
        <!--  <parameter name="OmitSOAP12Action">true</parameter>  -->
    </transportSender>

    <transportSender name="https"
                     class="org.apache.axis2.transport.http.impl.httpclient4.HTTPClient4TransportSender">
        <parameter name="PROTOCOL">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding">chunked</parameter>
    </transportSender>

     <!-- ================================================= -->
    <!-- Phases  -->
    <!-- ================================================= -->
    <phaseOrder type="InFlow">
        <!--  System predefined phases       -->
        <phase name="Transport">
            <handler name="RequestURIBasedDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher">
                <order phase="Transport"/>
            </handler>
            <handler name="SOAPActionBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher">
                <order phase="Transport"/>
            </handler>
        </phase>
        <phase name="Addressing">
            <handler name="AddressingBasedDispatcher"
                     class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
                <order phase="Addressing"/>
            </handler>
        </phase>
        <phase name="Security"/>
        <phase name="PreDispatch"/>
        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
            <handler name="RequestURIBasedDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
            <handler name="SOAPActionBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
            <handler name="RequestURIOperationDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
            <handler name="SOAPMessageBodyBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
            <handler name="HTTPLocationBasedDispatcher"
                     class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
            <handler name="GenericProviderDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
            <handler name="MustUnderstandValidationDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
        </phase>
        <phase name="RMPhase"/>
        <!--  System predefined phases       -->
        <!--   After Postdispatch phase module author or service author can add any phase he want      -->
        <phase name="OperationInPhase">
            <handler name="MustUnderstandChecker"
                     class="org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker">
                <order phase="OperationInPhase"/>
            </handler>
        </phase>
        <phase name="soapmonitorPhase"/>
    </phaseOrder>
    <phaseOrder type="OutFlow">
        <!--      user can add his own phases to this area  -->
        <phase name="soapmonitorPhase"/>
        <phase name="OperationOutPhase"/>
        <!--system predefined phase-->
        <!--these phase will run irrespective of the service-->
        <phase name="RMPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
        <phase name="Security"/>
    </phaseOrder>
    <phaseOrder type="InFaultFlow">
        <phase name="Addressing">
            <handler name="AddressingBasedDispatcher"
                     class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
                <order phase="Addressing"/>
            </handler>
        </phase>
        <phase name="Security"/>
        <phase name="PreDispatch"/>
        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
            <handler name="RequestURIBasedDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
            <handler name="SOAPActionBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
            <handler name="RequestURIOperationDispatcher"
                     class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
            <handler name="SOAPMessageBodyBasedDispatcher"
                     class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
            <handler name="HTTPLocationBasedDispatcher"
                     class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
            <handler name="GenericProviderDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
            <handler name="MustUnderstandValidationDispatcher"
                     class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
        </phase>
        <phase name="RMPhase"/>
        <!--      user can add his own phases to this area  -->
        <phase name="OperationInFaultPhase"/>
        <phase name="soapmonitorPhase"/>
    </phaseOrder>
    <phaseOrder type="OutFaultFlow">
        <!--      user can add his own phases to this area  -->
        <phase name="soapmonitorPhase"/>
        <phase name="OperationOutFaultPhase"/>
        <phase name="RMPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
        <phase name="Security"/>
    </phaseOrder>
</axisconfig> 

在Java端,您需要创建一个自定义axis2配置上下文,以使用我们的自定义axis2.xml。 Axis2提供了多个配置器,我更喜欢基于文件的配置器:

final ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(
    "c:\\work\\sources\\axis2conf",
    "c:\\work\\sources\\axis2conf\\axis2.xml");

您可以在构造函数期间将配置上下文分配给客户端存根:

FileNet_UploadDocumentWSStub stub = new FileNet_UploadDocumentWSStub(ctx, "https://testserver/test.asp");

因此,如果您不想使用自定义ssl设置,则升级已完成。

Axis2 + Httpclient4 + SSL

升级到httpclient4后,该实现不再使用自定义协议处理程序属性(HTTPConstants.CUSTOM_PROTOCOL_HANDLER)。

org / apache / axis2 / transport / http / impl / httpclient3 / HTTPSenderImpl.java:524中的旧实现:

// one might need to set his own socket factory. Let's allow that case
// as well.
Protocol protocolHandler = (Protocol) msgCtx.getOptions().getProperty(
                HTTPConstants.CUSTOM_PROTOCOL_HANDLER);

新的实现org / apache / axis2 / transport / http / impl / httpclient4 / HTTPSenderImpl.java:583:

   // TODO : one might need to set his own socket factory. We have to allow that case as well.

您需要在httpclient4端设置ssl上下文。这不是问题,因为axis允许您使用HTTPConstants.CACHED_HTTP_CLIENT属性为ws调用定义httpclient:

options.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);

但是,如果您以标准方式创建httpclient4:

...
HttpClientBuilder builder = HttpClientBuilder.create(); 
...

并将其分配给axis2客户端存根,您将得到ClassCastException,因为所有新的httpclient Builder,factory等方法都基于ClosableHttpClient创建了httpclient的“现代”实现。但是axis2的实现取决于不推荐使用的AbstractHttpClient。因此,您需要创建旧版本的httpclient。

完整的示例:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.Security;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.httpclient.contrib.ssl.AuthSSLProtocolSocketFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.ssl.SSLContexts;

public class SslTest {

  public SslTest() {
    // TODO Auto-generated constructor stub
  }


  public static void main(String[] args) throws Exception {
    File keyFile = new File("c:\\work\\sources\\ConsoleApp25\\avp-pc.jks");

    final ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(
    "c:\\work\\sources\\axis2conf",
    "c:\\work\\sources\\axis2conf\\axis2.xml");    


    FileNet_UploadocumentWSStub stub = new FileNet_UploadDocumentWSStub(ctx, "https://testserver/test.asp");
    FileNet_UploadDocument wsMethodReq = new FileNet_UploadDocument();
    ServiceClient serviceClient = stub._getServiceClient();
    Options options = serviceClient.getOptions();

    //keystore types: https://docs.oracle.com/javase/9/docs/specs/security/standard-names.html#keystore-types
    KeyStore keyStore = KeyStore.getInstance("jks");
    InputStream in = null;
    try {
    in = new FileInputStream(keyFile);
    keyStore.load(in, "changeit".toCharArray());
    } finally {
        if (in != null) {
            in.close();
        }
    }

    //Factory instance types: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#T5
    //on IBM servers use IbmX509 instead of SunX509
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
    keyManagerFactory.init(keyStore, "changeit".toCharArray());
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
    trustManagerFactory.init(keyStore);

    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
    sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
    SSLSocketFactory sf = new SSLSocketFactory(sslContext);
    Scheme httpsScheme = new Scheme("https", 443, sf);
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(httpsScheme);
    ClientConnectionManager cm =  new SingleClientConnManager(schemeRegistry);
    HttpClient httpClient = new DefaultHttpClient(cm);


    options.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);
    stub.fileNet_UploadDocument(wsMethodReq);

    System.out.println("done");
  }