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.

10 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