Sunday, November 21, 2010

Enabling SSL for AXIS2 service and client

We often encounter the satuation where requirement is to consume webservice exposed on https. In this article we will investigate how to consume webservice exposed over https using axis2. First lets see how to enable SSL for AXIS2 services:

Enabling SSL on server side for AXIS2 in tomcat:

You really don't need to do much enable SSL for services deplyed in AXIS2. Just follow how to enable SSL in tamcat.Add following in Server.xml of tamcat.

<Connector
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="test.jks" keystorePass="test123"
clientAuth="false" sslProtocol="TLS"/>


Use axis2 1.5.3 in which axis2.xml has https transportReceiver enabled by default, listening on 8443 port so you don't need any configuration change in axis2.xml.
<transportReceiver name="https"
class="org.apache.axis2.transport.http.AxisServletListener">
<parameter name="port">8443</parameter>
</transportReceiver>

Prior to this version of axis2 was using org.apache.axis2.transport.nhttp.HttpCoreNIOSSLListener as transportReceive which was having issues and not generating https endpoint correctly.

SSL on client side:

Axis2 uses http commons to transfer SOAP message over http. Apache http common uses JSSE(java secure socket extension) library for SSL.
JSSE is integrated with JDK since version 1.4.

Ideally if we just provide end point URL starting with https, SSL connection will be started and we don’t need any additional configuration. Creation of secure connection will be taken care by JSSE. But then trust store and keystore used by the JSSE would be default keystores shipped with JDK.

In the practical/production scenarios user should have capability to choose his truststore/keystore.
user may decide to trust a self signed certificate and keep it his local truststore or different applications may use different keystore/truststore.
Above can be achieved by two ways:
Approach 1:
We can set truststore, password etc in system properties. This will be picked by JSSE in SSL handshake.
Ex.
System.setProperty("javax.net.ssl.trustStore","Your truststore path");
System.setProperty("javax.net.ssl.trustStorePassword","your trust store password");
This approach will not be appropriate for tooling since it sets keystore on JVM level. We should have flexibility where we could attach different keystore/truststore for different axis2 clint running in same JVM.

Approach 2:
Apache commons provide facility which allows us to customize the SSL socket factory responsible for creation of secure socket. By customization I mean ability to use user truststore/keystore in SSL handshake. To achieve it we need to extend SecureProtocolSocketFactory interface. In our custom socket factory implementation user refer its Keystore/Truststore against default keystores.
Apache commons provide a reference implementation class named AuthSSLProtocolSocketFactory for this purpose.

This class takes Truststore/Keystore as argument to constructor which will be referred later while initiating SSLContext. SSLContext is used to create SSL Socket Factory.
In your axis2 client code you need to add following:
Protocol authhttps = new Protocol ("https", new AuthSSLProtocolSocketFactory (new url("keystore URL"), "pwd", newURL("truststore URL"), "pwd"), 443);
Protocol.registerProtocol("https", authhttps);

And you are all set to consume secure webservice.

12 comments:

  1. Thank you!
    For some reason the transportReceiver in my axis2.xml file was set up for http only, and your article helped me spot that after almost an hour of being struggling.
    Keep the goos work!

    ReplyDelete
  2. hello,

    Thanks for the post. Do you perhaps have a full code example of this ?

    Regards
    Mz

    ReplyDelete
  3. Thanks for the post, it was very helpful to me.

    Regards,
    Swathi

    ReplyDelete
  4. Hi,

    I'm new to web services and also to SSL. Please post some working code for the client side...

    Thank you very much!

    Dan

    ReplyDelete
  5. You can have a look at
    http://techtidbitsbyshiv.blogspot.com/2010/11/axis2java-client-code-for-basic.html

    ReplyDelete
  6. This looks great! Thank you! I'll try it. :)
    Have a great day!

    ReplyDelete
  7. I have the root.cer, chain.cer and certificates how do i make use of these certificates provided to comsume a https service ?? please let me know if the keystore would need to import all these certificates

    ReplyDelete
  8. Can you show a sample of approach 2. I am using Axis2 1.6 and my stub looks like this
    code
    org.apache.axis2.client.OperationClient _operationClient =
    _serviceClient.createClient(_operations[0].getName());
    _operationClient.getOptions().setAction("http://SignOn_H2H/SignonPortType/signOn_Input");
    code

    I placed the your first approach here and it didn't work.

    ReplyDelete
    Replies
    1. you could have a look at http://techtidbitsbyshiv.blogspot.in/2010/11/axis2java-client-code-for-basic.html

      Delete
  9. Hi,

    I implemented a Axis2 SSL conection using WS-Trusted. In your approach num2, you can set up the stub with a SSLContext like this:

    To acces to the trustManager using java read about JSSE
    link: http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html

    with this approach you don't need to use the System.propertiers, the trusstore and the keystore are load in code.

    KeyManager[] keyManagers = null;
    TrustManager[] trustManagers = null;

    SSLContext context = SSLContext.getInstance("SSLv3");
    context.init(keyManagers, trustManagers, null);

    stub._getServiceClient().getOptions().setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER,
    new Protocol("https",(ProtocolSocketFactory)new SSLProtocolSocketFactory(context),20540));


    This solution it works fine for us. Before we access to the JSSE using the System.properties but this approach interferes with another webservices deployed in the server that don't used WS-Trust.

    ReplyDelete
  10. I have standalone java application making soap calls to apache. Now we have requirement to disable sslv3,tls1.0 support..So at apache side we have made changes in httpd-ssl.conf to accept only tls1.1 and tls 1.2..

    Application is using axis2 libraries for making soap call..version of axis2 is 1.4 and other axis related libraries are of verison 1.6.1.

    I am getting below exception when sending post request: Its seem like application is still sending req using protocol tls 1.0 ..Which I feel internally axis2 is using.. How can disable tls1.0 support in axis2 and ask it start sending req using tls 1.1/1.2 only.

    Exception : Connection has been shutdown: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

    Things tried out:

    I have made code level changes for tls 1.2 that is :

    SSLContext context = SSLContext.getInstance("TLSv1.2");
    Also tried running application with Dhttps.protocols=TLSv1.1,TLSv1.2
    Upgraded axis libraries to version 1.7.1 from 1.6.1 and axis2 root lib i.e axis-1.4.jar replaced it with axis2-1.6.3 as axis2-1.7.1 was not available.

    ReplyDelete
  11. https://stackoverflow.com/questions/14395947/private-keystore-for-truststore-with-client-axis2-stub/52003365#52003365 provides a better solution for using the newly made authhttps object. Bind it to the ServiceClient object with serviceClient.getOptions().setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER, authhttps).

    In this way you can use multiple ServiceClient objects with different key- en truststores.

    ReplyDelete