Thursday, September 30, 2010

Making CXF Web service accept SOAP 1.2 request


By default CXF Web Service provides SOAP 1.1 end point. In order for your web service to expose SOAP 1.2 endpoint and accept SOAP 1.2 request configure the following settings in server side CXF config file of the Web Service:

Creating SOAP 1.2 end point

<jaxws:endpoint id="auth" implementor="#AuthService" address="/cxfSearch12">
<jaxws:binding>
         <soap:soapBinding version="1.2" mtomEnabled="true"/>jaxws:binding>
<jaxws:features>
        <bean class="org.apache.cxf.feature.LoggingFeature"/>
      jaxws:features>
      <jaxws:inInterceptors>
               <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>  <ref bean="wss4jInConfiguration"/>
      jaxws:inInterceptors>
 jaxws:endpoint>

Calling SSL enabled CXF Web Service From Java Client

Calling a SSL enabled service which also expects UserToken to be passed can be very frustrating. It has been really painful for me to consume SSL enabled CXF service and I spent nearly 1 week to get it working.


Environment
Apache Tomcat 6.0.28
JDK 1.6
CXF 2.2.3
IBM Rational Developer 7.5.2
Spring Web 2.5.6


We deployed the CXF Web Service with SSL and installed the security certificate (self signed) on the client machine.

I was able to view the WSDL coming in the browser but the problem started when I tried to call Web Service from Java Client. I was getting “Message could not sent”. I set the proxy in RAD and imported the client certificate in the JVM. Configured following JVM arguments:

-Djavax.net.ssl.trustStore="C:\Program Files\IBM\SDP\jdk\bin\mykeystore"
-Djavax.net.ssl.trustStorePassword="password"

But this configuration did not change the error message.

My next attempt was to configure proxy arguments in addition to the above JVM arguments for my program

-Djavax.net.ssl.trustStore="C:\Program Files\IBM\SDP\jdk\bin\mykeystore"
-Djavax.net.ssl.trustStorePassword="password"
-Dhttp.proxyHost=yourproxy
-Dhttp.proxyPort=8080
-Dhttps.proxyHost=yourproxy
-Dhttps.proxyPort=8080

Now I started getting ‘SSLHandshakeException’, ‘javax.net.ssl.SSLHandshakeException: Couldn't find trusted certificate’ . It confirmed that the client was trying to use the certificate to reach Web Service but due to self signed certificate it was getting invalidated.

Then I found a link on internet which covered my problem scenario and suggested to accept whatever certificate your application is trying to use instead of JVM trying to validate it. I used following code to accept the certificate with out checking its validity and I was able to reach Web Service successfully.


import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public static void main(String[] args)
  {
ApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");

InfoService client = (InfoService) context.getBean("client");
ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
Client proxy = ClientProxy.getClient( client );
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
TLSClientParameters tcp = new TLSClientParameters();

//Creating Trust Manager
TrustManager[] trustAllCerts = new TrustManager[] {
      new X509TrustManager()
         {
          public java.security.cert.X509Certificate[] getAcceptedIssuers()
           {
              return null;
           }
          public void checkClientTrusted(
                                                      java.security.cert.X509Certificate[] certs, String authType)  {      }
             
          public void checkServerTrusted(
                                                       java.security.cert.X509Certificate[] certs, String authType)
{
     System.out.println("authType is " + authType);
     System.out.println("cert issuers");
     for (int i = 0; i < certs.length; i++) {
     System.out.println("\t" + certs[i].getIssuerX500Principal().getName());
     System.out.println("\t" + certs[i].getIssuerDN().getName());
                }
           }
    }
};
                           
                        
tcp.setTrustManagers(trustAllCerts);
conduit.setTlsClientParameters( tcp );

client.callWebServiceMethod();
  }
}

Resources used:


Read Posting from Daniel