Sunday, April 22, 2012

WS Security with Apache Rampart - Part 3/3 (Securing the Client)

Overview
This is part THREE and the last part of an article series that looks at how you can engage Apache Rampart to secure Web Service communication using Username Authentication. This post will focus on how we can access your secured Web Service using the secured client.

Also Refer to,
WS Security with Apache Rampart - Part 1/3 (Securing the Service) and,
WS Security with Apache Rampart - Part 2/3 (Generating Stub for the Service)

Sample code for this post can be found here.

This article applies to:
Version 1.6.0
Apache Axis2 1.6.0 and Apache Rampart 1.6.0

Version 1.6.1
Apache Axis2 1.6.1 and Apache Rampart 1.6.1

Project Structure: Following is the structure I have used for this post.


Step 1: Maven Dependencies (pom.xml)
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.secureservice.client</artifactId>  
   <version>1.0.0</version>  
   <packaging>jar</packaging>  
   <name>org.fazlan.secureservice.client</name>  
   <url>http://maven.apache.org</url>  
   <properties>  
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
     <axis2.version>1.6.1</axis2.version>  
     <rampart.version>1.6.1</rampart.version>  
   </properties>  
   <dependencies>  
     <dependency>  
       <groupId>org.fazlan</groupId>  
       <artifactId>org.fazlan.secureservice.stub</artifactId>  
       <version>1.0.0</version>  
     </dependency>  
     <!--axis2 dependencies-->  
     <dependency>  
       <groupId>org.apache.axis2</groupId>  
       <artifactId>axis2</artifactId>  
       <version>${axis2.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.apache.axis2</groupId>  
       <artifactId>axis2-transport-local</artifactId>  
       <version>${axis2.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.apache.axis2</groupId>  
       <artifactId>axis2-transport-http</artifactId>  
       <version>${axis2.version}</version>  
     </dependency>  
     <!--rampart-->  
     <dependency>  
       <groupId>org.apache.rampart</groupId>  
       <artifactId>rampart-core</artifactId>  
       <version>${rampart.version}</version>  
     </dependency>  
     <!--rampart dependencies-->  
     <dependency>  
       <groupId>org.apache.neethi</groupId>  
       <artifactId>neethi</artifactId>  
       <version>3.0.1</version>  
     </dependency>  
     <dependency>  
       <groupId>junit</groupId>  
       <artifactId>junit</artifactId>  
       <version>3.8.1</version>  
       <scope>test</scope>  
     </dependency>  
   </dependencies>  
 </project>  


Step 2: Username Token Policy File
To communicate via HTTPS, we need to generate the SOAP security header at the client end using the policy used by the WS. This policy is extracted out from the service exposed via http://localhost:8080/axis2/services/EmployeeSecureService?wsdl
Lets save this policy as a resource in the project.
e.i: src/main/resources/policies/employeeservice.xml

 <wsp:Policy xmlns:wsp="http://www.w3.org/ns/ws-policy"  
       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"  
       wsu:Id="UTOverTransport">  
   <wsp:ExactlyOne>  
     <wsp:All>  
       <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">  
         <wsp:Policy>  
           <sp:TransportToken>  
             <wsp:Policy>  
               <sp:HttpsToken RequireClientCertificate="false"/>  
             </wsp:Policy>  
           </sp:TransportToken>  
           <sp:AlgorithmSuite>  
             <wsp:Policy>  
               <sp:Basic256/>  
             </wsp:Policy>  
           </sp:AlgorithmSuite>  
           <sp:Layout>  
             <wsp:Policy>  
               <sp:Lax/>  
             </wsp:Policy>  
           </sp:Layout>  
           <sp:IncludeTimestamp/>  
         </wsp:Policy>  
       </sp:TransportBinding>  
       <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">  
         <wsp:Policy>  
           <sp:UsernameToken  
               sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"/>  
         </wsp:Policy>  
       </sp:SignedSupportingTokens>  
     </wsp:All>  
   </wsp:ExactlyOne>  
 </wsp:Policy>  


Step 3: Writing the Password Callback Handler for the Client
Since we are going to use username token authentication, we need to write a password callback class that will be used by the client to set the authenticate username tokens.

More about writing callback handlers can be found in this article: "Password Callback Handlers Explained"

 package org.fazlan.secureservice.client.util;  
 import org.apache.ws.security.WSPasswordCallback;  
 import javax.security.auth.callback.Callback;  
 import javax.security.auth.callback.CallbackHandler;  
 import javax.security.auth.callback.UnsupportedCallbackException;  
 import java.io.IOException;  
 import java.util.Map;  
 public class ClientPWCBHandler implements CallbackHandler {  
   private String password;  
   private Map properties;  
   public ClientPWCBHandler() {  
   }  
   public ClientPWCBHandler(String password, Map properties) {  
     this.password = password;  
     this.properties = properties;  
   }  
   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {  
     WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[0];  
     int usage = pwcb.getUsage();  
     if (usage == WSPasswordCallback.USERNAME_TOKEN) {  
       // user has provided the username and the password  
       if (password != null) {  
         pwcb.setPassword(password);  
       } else {  
         // user has provided only the username, get password from LDAP  
         pwcb.setPassword(LDAPUtil.getPassword(pwcb.getIdentifier()));  
       }  
     } else if (usage == WSPasswordCallback.SIGNATURE || usage == WSPasswordCallback.DECRYPT) {  
       // handle signature and decrypt type  
     }  
   }  
 }  

Step 4: Writing a Security Handler Class to Enforce Security Policy
The following class associates the policy and the above implemented CallbackHandler implementation to the underlying Axis2 service client.

 package org.fazlan.secureservice.client.util;  
 import org.apache.axiom.om.impl.builder.StAXOMBuilder;  
 import org.apache.axis2.client.Options;  
 import org.apache.axis2.client.ServiceClient;  
 import org.apache.neethi.Policy;  
 import org.apache.neethi.PolicyEngine;  
 import org.apache.rampart.RampartMessageData;  
 import org.apache.rampart.policy.model.RampartConfig;  
 import org.apache.ws.security.handler.WSHandlerConstants;  
 import javax.security.auth.callback.CallbackHandler;  
 import java.io.InputStream;  
 public class SecurityHandler {  
   private String user;  
   private CallbackHandler callbackHandler;  
   private ServiceClient serviceClient;  
   private InputStream policyStream;  
   public SecurityHandler(String user, ServiceClient serviceClient, CallbackHandler callbackHandler, InputStream policy) {  
     this.user = user;  
     this.serviceClient = serviceClient;  
     this.callbackHandler = callbackHandler;  
     this.policyStream = policy;  
   }  
   public void engage() {  
     try {  
       RampartConfig rc = new RampartConfig();  
       rc.setUser(user);  
       Policy policy = PolicyEngine.getPolicy(new StAXOMBuilder(policyStream).getDocumentElement());  
       policy.addAssertion(rc);  
       serviceClient.engageModule("rampart");  
       Options options = serviceClient.getOptions();  
       options.setProperty(WSHandlerConstants.PW_CALLBACK_REF, callbackHandler);  
       options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, policy);  
     } catch (Exception e) {  
       throw new RuntimeException(e);  
     }  
   }  
 }  

Step 5: Writing the Secure Service Client
Now, lets write the client class that wraps the stub for accessing the web service. Also, we are engaging security for the client.

The Client has TWO constructors,
1st:
That accepts ONLY the username - Internally, the password is set against the username from LDAP or other storage.
2nd:
Client provides both username as well as the password.

 package org.fazlan.secureservice.client;  
 import org.apache.axis2.AxisFault;  
 import org.apache.axis2.context.ConfigurationContext;  
 import org.fazlan.secureservice.client.util.ClientPWCBHandler;  
 import org.fazlan.secureservice.client.util.SecurityHandler;  
 import org.fazlan.secureservice.service.beans.xsd.Employee;  
 import org.fazlan.secureservice.stub.EmployeeSecureService;  
 import org.fazlan.secureservice.stub.EmployeeSecureServiceStub;  
 import java.rmi.RemoteException;  
 //EmployeeSecureService interface is generated by the wsdl2java code by AXIS2  
 public class EmployeeSecureServiceClient implements EmployeeSecureService {  
   private EmployeeSecureServiceStub stub;  
   public EmployeeSecureServiceClient(ConfigurationContext ctx, String epr, String username) {  
     this(ctx, epr, username, null);  
   }  
   public EmployeeSecureServiceClient(ConfigurationContext ctx, String epr, String username, String password) {  
     try {  
       stub = new EmployeeSecureServiceStub(ctx, epr);  
       new SecurityHandler(username, stub._getServiceClient(),  
           new ClientPWCBHandler(password, null),  
           getClass().getResourceAsStream("/policies/employeeservice.xml")).engage();  
     } catch (AxisFault afe) {  
       throw new RuntimeException(afe);  
     }  
   }  
   public long add(Employee employee) throws RemoteException {  
     return stub.add(employee);  
   }  
   public boolean update(Employee employee) throws RemoteException {  
     return stub.update(employee);  
   }  
   public Employee get(long id) throws RemoteException {  
     return stub.get(id);  
   }  
   public boolean delete(long id) throws RemoteException {  
     return stub.delete(id);  
   }  
   public Employee[] getAll() throws RemoteException {  
     return stub.getAll();  
   }  
 }  

Step 6: Building the Project
 mvn clean install

Step 7: Writing an Application to Consume the Web Service the Project
Download the corresponding Apache Rampart version for your Apache Axis2 version.

 package org.fazlan.secureservice.client;  
 import org.apache.axis2.context.ConfigurationContext;  
 import org.apache.axis2.context.ConfigurationContextFactory;  
 import org.fazlan.secureservice.service.beans.xsd.Employee;  
 public class Application {  
   private final static String EMPLOYEE_SERVICE_EPR = "https://localhost:8443/axis2/services/EmployeeSecureService/";  
   public static void main(String[] args) throws Exception {  
     System.setProperty("javax.net.ssl.trustStore", "/home/fazlan/sw-installs/apache-tomcat-6.0.32/security/server.jks");  
     System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");  
     ConfigurationContext ctx = ConfigurationContextFactory.  
         createConfigurationContextFromFileSystem("/home/fazlan/sw-installs/client-repo", null);  
     EmployeeSecureServiceClient client;  
     // get password from LDAP  
 //    client = new EmployeeSecureServiceClient(ctx, EMPLOYEE_SERVICE_EPR, "apache");  
     // user provides both username and password  
     client = new EmployeeSecureServiceClient(ctx, EMPLOYEE_SERVICE_EPR, "apache", "password");  
     Employee employee = new Employee();  
     employee.setFirstName("FN");  
     employee.setLastName("LN");  
     long result = client.add(employee);  
     System.out.println("id = " + result);  
   }  
 }  


Making a Secured Handshake with the Server.
Since, we are using HTTPS, we need to enable SSL communication, the following two lines achieve this.
 System.setProperty("javax.net.ssl.trustStore", "/home/fazlan/sw-installs/apache-tomcat-6.0.32/security/wso2carbon.jks");  
 System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");  

Also, we need to provide the path to the repository configuration context for the client. This should contain the Rampart modules directory: rampart-1.6.1.mar and rahas-1.6.1.mar.

 ConfigurationContext ctx = ConfigurationContextFactory.  
         createConfigurationContextFromFileSystem("/home/fazlan/sw-installs/client-repo", null);  

e.i: /home/fazlan/sw-installs/client-repo
                                                          - modules
                                                               - rampart-1.6.1.mar
                                                               - rahas-1.6.1.mar

Now, everything is in place, and you can run the application program.

Summary:
This article looked at how you can securely access your secured web service with Apache Rampart using username authentication.


Also Refer to,
WS Security with Apache Rampart - Part 1/3 (Securing the Service) and,
WS Security with Apache Rampart - Part 2/3 (Generating Stub for the Service)

Sample code for this post can be found here.

WS Security with Apache Rampart - Part 2/3 (Generating Stub for the Service)

Overview
This is part TWO of an article series that looks at how you can engage Apache Rampart to secure Web Service communication using Username Authentication. This post will focus on how we can generate the Web Service stub to access the secured Web Service.

Also Refer to,
WS Security with Apache Rampart - Part 1/3 (Securing the Service) and,
WS Security with Apache Rampart - Part 3/3 (Securing the Client)

Sample code for this post can be found here.

This article applies to:
Version 1.6.0
Apache Axis2 1.6.0 and Apache Rampart 1.6.0

Version 1.6.1
Apache Axis2 1.6.1 and Apache Rampart 1.6.1

Project Structure: Following is the structure I have used for this post.


Step 1: Maven Dependencies (pom.xml)

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.secureservice.stub</artifactId>  
   <version>1.0.0</version>  
   <packaging>jar</packaging>  
   <name>org.fazlan.secureservice.stub</name>  
   <url>http://maven.apache.org</url>  
   <properties>  
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
     <axis2.version>1.6.1</axis2.version>  
     <axiom.version>1.2.12</axiom.version>  
   </properties>  
   <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.axis2</groupId>  
         <artifactId>axis2-wsdl2code-maven-plugin</artifactId>  
         <version>${axis2.version}</version>  
         <executions>  
           <execution>  
             <goals>  
               <goal>wsdl2code</goal>  
             </goals>  
           </execution>  
         </executions>  
         <configuration>  
           <packageName>org.fazlan.secureservice.stub</packageName>  
           <wsdlFile>src/main/resources/EmployeeSecureService.wsdl</wsdlFile>  
           <namespaceToPackages>http://service.secureservice.fazlan.org=org.fazlan.secureservice.service</namespaceToPackages>  
           <unpackClasses>true</unpackClasses>  
           <unwrap>true</unwrap>  
           <syncMode>sync</syncMode>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
   <dependencies>  
     <dependency>  
       <groupId>org.apache.axis2</groupId>  
       <artifactId>axis2</artifactId>  
       <version>${axis2.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.apache.ws.commons.axiom</groupId>  
       <artifactId>axiom-api</artifactId>  
       <version>${axiom.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.apache.ws.commons.axiom</groupId>  
       <artifactId>axiom-impl</artifactId>  
       <version>${axiom.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>wsdl4j</groupId>  
       <artifactId>wsdl4j</artifactId>  
       <version>1.6.2</version>  
     </dependency>
   </dependencies>  
 </project>  

Step 2: Generating the Service Stub
You can access the service via http://localhost:8080/axis2/services/EmployeeSecureService?wsdl

And you should see the policy attached to the WSDL.
Save this WSDL file as EmployeeSecureService.wsdl under the resources folder
 e.i: org.fazlan.secureservice.stub/src/main/resources/EmployeeSecureService.wsdl Employee.java


Step 3: Building the Project
 mvn clean install

After executing the above goals, the service stub jar will be created under the target folder.
e.i: org.fazlan.secureservice.stub-1.0.0.jar

Summary:
This article looked at how you can secure your web service using Apache Rampart using username authentication.


Also Refer to,
WS Security with Apache Rampart - Part 1/3 (Securing the Service) and,
WS Security with Apache Rampart - Part 3/3 (Securing the Client)

Sample code for this post can be found here.

WS Security with Apache Rampart - Part 1/3 (Securing the Service)

Overview
This is part ONE of an article series that looks at how you can engage Apache Rampart to secure Web Service communication using Username Authentication. This post will focus on how we can secure the Web Service.

Also Refer to,
WS Security with Apache Rampart - Part 2/3 (Generating Stub for the Service) and,
WS Security with Apache Rampart - Part 3/3 (Securing the Client)

Sample code for this post can be found here.

This article applies to:
Version 1.6.0
Apache Axis2 1.6.0 and Apache Rampart 1.6.0

Version 1.6.1
Apache Axis2 1.6.1 and Apache Rampart 1.6.1

Project Structure: Following is the structure I have used for this post.


Step 1: Maven Dependencies (pom.xml)
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.secureservice.service</artifactId>  
   <version>1.0.0</version>  
   <packaging>jar</packaging>  
   <name>org.fazlan.secureservice.service</name>  
   <url>http://maven.apache.org</url>  
   <properties>  
     <org.apache.axis2.version>1.6.1</org.apache.axis2.version>  
   </properties>  
   <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.axis2</groupId>  
         <artifactId>axis2-aar-maven-plugin</artifactId>  
         <version>${org.apache.axis2.version}</version>  
         <extensions>true</extensions>  
         <configuration>  
           <aarName>org.fazlan.secureservice.service</aarName>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
   <dependencies>  
     <dependency>  
       <groupId>org.apache.ws.security</groupId>  
       <artifactId>wss4j</artifactId>  
       <version>1.6.4</version>  
     </dependency>  
     <dependency>  
       <groupId>junit</groupId>  
       <artifactId>junit</artifactId>  
       <version>4.8.1</version>  
     </dependency>  
   </dependencies>  
 </project>  

Step 2: Defining the Service Implementation
Employee.java
 package org.fazlan.secureservice.service.beans;  
 public class Employee {  
   private long id;  
   private String firstName;  
   private String lastName;  
   public long getId() {  
     return id;  
   }  
   public void setId(long id) {  
     this.id = id;  
   }  
   public String getFirstName() {  
     return firstName;  
   }  
   public void setFirstName(String firstName) {  
     this.firstName = firstName;  
   }  
   public String getLastName() {  
     return lastName;  
   }  
   public void setLastName(String lastName) {  
     this.lastName = lastName;  
   }  
 }  

IService.java
 package org.fazlan.secureservice.service;  
 import java.util.List;  
 public interface IService<T> {  
   Long add(T t);  
   boolean update(T t);  
   boolean delete(Long id);  
   T get(Long id);  
   List<T> getAll();  
 }  

EmployeeService.java
 package org.fazlan.secureservice.service;  
 import org.fazlan.secureservice.service.beans.Employee;  
 import java.util.ArrayList;  
 import java.util.HashMap;  
 import java.util.List;  
 import java.util.Map;  
 public class EmployeeService implements IService<Employee> {  
   private static Long ID = 0L;  
   private final static Map<Long, Employee> EMPLOYEE_MAP = new HashMap<Long,Employee>();  
   public Long add(Employee employee) {  
     employee.setId(++ID);  
     update(employee);  
     return ID;  
   }  
   public boolean update(Employee employee) {  
     EMPLOYEE_MAP.put(employee.getId(), employee);  
     return true;  
   }  
   public boolean delete(Long id) {  
     return EMPLOYEE_MAP.remove(id) instanceof Employee;  
   }  
   public Employee get(Long id) {  
     return EMPLOYEE_MAP.get(id);  
   }  
   public List<Employee> getAll() {  
     return new ArrayList<Employee>(EMPLOYEE_MAP.values());  
   }  
 }  

Step 3: Writing the Password Callback Handler for the Service
Since we are going to use username token authentication, we need to write a password callback class that will be used by the Web service to authenticate username tokens. Although the passwords are hard coded in this code snippet, passwords can be retrieved from a database, LDAP server or any other medium by implementing the relevant password retrieval logic in the password callback class.

More about writing Password Callback Handlers can be found in this article: "Password Callback Handlers Explained".

 package org.fazlan.secureservice.service.utils;  
 import org.apache.ws.security.WSPasswordCallback;  
 import javax.security.auth.callback.Callback;  
 import javax.security.auth.callback.CallbackHandler;  
 import javax.security.auth.callback.UnsupportedCallbackException;  
 import java.io.IOException;  
 public class PWCBHandler implements CallbackHandler {  
   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {  
     for(Callback cb : callbacks) {  
       WSPasswordCallback wscb = (WSPasswordCallback) cb;  
       if("apache".equals(wscb.getIdentifier())  
         && "password".equals(wscb.getPassword())) {  
         //hit LDAP here for authentication.  
         return;  
       }  
     }  
     throw new UnsupportedCallbackException(null, "Authentication check failed.");  
   }  
 }  

Step 4: The Security Policy
Following is the Security Policy we'll be using for this article. The policy contains two main security assertions,

Transport binding assertion        -  defines the requirement of using a SSL transport using the HTTPS transport token assertion.

Signed supporting token assertion  -  defines the requirement of a username token that should be integrity protected at the transport level.
You can find more information on constructing a security policy in this article: "Understanding WS-Security Policy Language"

 <wsp:Policy xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" wsu:Id="UTOverTransport">  
  <wsp:ExactlyOne>  
   <wsp:All>  
    <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">  
     <wsp:Policy>  
      <sp:TransportToken>  
       <wsp:Policy>  
        <sp:HttpsToken RequireClientCertificate="false"/>  
       </wsp:Policy>  
      </sp:TransportToken>  
      <sp:AlgorithmSuite>  
       <wsp:Policy>  
        <sp:Basic256/>  
       </wsp:Policy>  
      </sp:AlgorithmSuite>  
      <sp:Layout>  
       <wsp:Policy>  
        <sp:Lax/>  
       </wsp:Policy>  
      </sp:Layout>  
      <sp:IncludeTimestamp/>  
     </wsp:Policy>  
    </sp:TransportBinding>  
    <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">  
     <wsp:Policy>  
      <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"/>  
     </wsp:Policy>  
    </sp:SignedSupportingTokens>  
    <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">  
     <!--specifying the password callback handler class-->  
     <ramp:passwordCallbackClass>org.fazlan.secureservice.service.utils.PWCBHandler</ramp:passwordCallbackClass>  
    </ramp:RampartConfig>  
   </wsp:All>  
  </wsp:ExactlyOne>  
 </wsp:Policy>  

Step 5: Engaging Apache Rampart and Security Policy to the Service (WEB-INF/services.xml)
Now, we need to edit the service.xml to attach the above shown policy file. You can find more information on constructing a security policy in this article: "Applying policies at binding hierarchy in Apache Axis2"

 <serviceGroup>  
   <service name="EmployeeSecureService">  
     <description>  
       Weather Spring POJO Axis2 AAR deployment  
     </description>  
     <!--engaging security with rampart-->  
     <module ref="rampart"/>  
     <parameter name="ServiceClass" locked="false">org.fazlan.secureservice.service.EmployeeService</parameter>  
     <messageReceivers>  
       <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"  
                class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>  
       <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"  
                class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
     </messageReceivers>  
     <!--attaching the policy to the service-->  
     <wsp:PolicyAttachment xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">  
       <wsp:AppliesTo>  
         <policy-subject identifier="binding:soap11"/>  
         <policy-subject identifier="binding:soap12"/>  
       </wsp:AppliesTo>  
       <wsp:Policy xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"  
             xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" wsu:Id="UTOverTransport">  
          . . .  
       </wsp:Policy>  
     </wsp:PolicyAttachment>  
   </service>  
 </serviceGroup>  

Step 6: Building the Project
 mvn clean install

Before we can deploy the service on the Axis2 Engine, we need to do the followings.

Step 7: Deploying Rampart
Download the corresponding Apache Rampart version for your Apache Axis2 version.

Copying Rampart Modules
Rampart distribution contains two module files, rampart-1.3 and rahas-1.3.mar. Copy these module files to the "modules" directory of Axis2, that can be found in <TOMCAT_HOME>/webapps/axis2/WEB-INF/modules.

Copying Rampart Jars
Copy all the Apache Rampart dependency jars found under <RAMPART_HOME>/libs directory of the Rampart distribution to the "lib" directory of Axis2, which can found under <TOMCAT_HOME>/webapps/axis2/WEB-INF/lib.

You can verify whether Apache Rampart is successfully deployed by logging in to Axis2 as admin and using 'system components/available modules' option in admin Web console. Both "rampart" and "rahas" should be listed under available modules, after successfully deployed Rampart and Rahas modules.

Step 8: Configuring SSL in Tomcat (<TOMCAT_HOME>/conf/server.xml)
We need to enable HTTPS transport in Apache Tomcat to secure the transport. Lets modify the <TOMCAT_HOME>/conf/server.xml of Apache Tomcat to enable SSL configuration.
You can use the server.jks keytore which can be found in the source code zip file, as the keystore for this tutorial. Key store password is "wso2carbon". SSL configuration in the server should look like the one given below:

  <!-- Define a SSL HTTP/1.1 Connector on port 8443  
      This connector uses the JSSE configuration, when using APR, the   
      connector should be using the OpenSSL style configuration  
      described in the APR documentation -->  
   <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"  
         maxThreads="150" scheme="https" secure="true"  
         clientAuth="false" sslProtocol="TLS"   
         keystoreFile = "/home/fazlan/sw-installs/apache-tomcat-6.0.32/security/server.jks"  
         keystorePass="wso2carbon"/>  

Step 9: Configure HTTPS in Axis2 (<TOMCAT_HOME>/webapps/axis2/WEB-INF/conf/axis2.xml)
By default the HTTPS transport receiver on axis2 is disabled. We need to enable HTTPS transport receiver in Apache Axis2 to send messages in the HTTPS transport. Lets modify the <TOMCAT_HOME>/webapps/axis2/WEB-INF/conf/axis2.xml of Apache Axis2 deployment to enable HTTPS. Add the following entry:

 <transportReceiver name="https"  
             class="org.apache.axis2.transport.http.SimpleHTTPServer">  
     <parameter name="port">8443</parameter>  
 </transportReceiver>  

NOTE: The port is the HTTPS port of the TOMCAT server we configured previously.

Step 10: Deploying the Service 
Now, we have to deploy this service in the Axis2 server. Create a service archive org.fazlan.secureservice.service.aar and drop it into the services directory which can found at: TOMCAT_HOME/webapps/axis2/WEB-INF/services You can access the service via http://localhost:8080/axis2/services/EmployeeSecureService?wsdl

And you should see the policy attached to the WSDL.

Summary:
This article looked at how you can secure your web service using Apache Rampart using username authentication.

UPDATED SECTION - Upgrading the example to run with Apache Axis2 1.6.2

pom.xml - the plugin configuration
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.secureservice.service</artifactId>  
   <version>1.0.0</version>  
   <packaging>jar</packaging>  
   <name>org.fazlan.secureservice.service</name>  
   <url>http://maven.apache.org</url>  
   <properties>  
     <org.apache.axis2.version>1.6.2</org.apache.axis2.version>  
   </properties>  
   <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.axis2</groupId>  
         <artifactId>axis2-aar-maven-plugin</artifactId>  
         <version>${org.apache.axis2.version}</version>  
         <extensions>true</extensions>  
         <configuration>  
         <!-- Set true if you want Depending Jar to be included into AAR file-->  
         <includeDependencies>true</includeDependencies>  
           <aarName>${pom.name}</aarName>  
         </configuration>  
         <executions>  
           <execution>  
             <phase>prepare-package</phase>  
             <goals>  
               <goal>aar</goal>  
             </goals>  
           </execution>  
         </executions>  
       </plugin>  
     </plugins>  
   </build>  
   <dependencies>  
     <dependency>  
       <groupId>org.apache.ws.security</groupId>  
       <artifactId>wss4j</artifactId>  
       <version>1.6.4</version>  
     </dependency>  
     <dependency>  
       <groupId>junit</groupId>  
       <artifactId>junit</artifactId>  
       <version>4.8.1</version>  
     </dependency>  
   </dependencies>  
 </project>  

Step 9: Axis2 Receiver transport configuration


  <transportReceiver name="http"  
             class="org.apache.axis2.transport.http.AxisServletListener"/>  
   <transportReceiver name="https" class="org.apache.axis2.transport.http.AxisServletListener">  
            <parameter name="port">8443</parameter>  
    </transportReceiver>  

With Axis2 1.6.2, the transportReceiver configuration has changed compared to versions < 1.6.2. You need to update the  <TOMCAT_HOME>/webapps/axis2/WEB-INF/conf/axis2.xml as above.

Please refer to: http://axis.apache.org/axis2/java/core/docs/servlet-transport.html for more details.

Also Refer to,
WS Security with Apache Rampart - Part 2/3 (Generating Stub for the Service) and,
WS Security with Apache Rampart - Part 3/3 (Securing the Client)

Sample code for this post can be found here.

Sunday, April 15, 2012

Json Tutorial: Java to Json with Google Gson

Overview:
This article looks how you can easily transform Java objects into Json representation and vice versa using Google Gson library.

Project Structure:



Step 1: Maven Dependencies (pom.xml)
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>org.fazlan</groupId>  
  <artifactId>org.fazlan.json.gson</artifactId>  
  <packaging>jar</packaging>  
  <version>1.0.0-SNAPSHOT</version>  
  <name>org.fazlan.json.gson</name>  
  <url>http://maven.apache.org</url>  
  <dependencies>  
   <dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>3.8.1</version>  
    <scope>test</scope>  
   </dependency>  
   <dependency>  
    <groupId>com.google.code.gson</groupId>  
    <artifactId>gson</artifactId>  
    <version>2.1</version>  
    <scope>compile</scope>  
   </dependency>  
    <dependency>  
      <groupId>org.apache.ws.commons.schema</groupId>  
      <artifactId>XmlSchema</artifactId>  
      <version>1.4.7-wso2v1</version>  
    </dependency>  
  </dependencies>  
 </project>  

Step 2: The Java Class we wish to transform into Json and vice versa
 package org.fazlan.json;  
 public class Person {  
   private Long id;  
   private String firstName;  
   private String lastName;  
   public Person(Long id, String firstName, String lastName) {  
     this.id = id;  
     this.firstName = firstName;  
     this.lastName = lastName;  
   }  
   public Long getId() {  
     return id;  
   }  
   public void setId(Long id) {  
     this.id = id;  
   }  
   public String getFirstName() {  
     return firstName;  
   }  
   public void setFirstName(String firstName) {  
     this.firstName = firstName;  
   }  
   public String getLastName() {  
     return lastName;  
   }  
   public void setLastName(String lastName) {  
     this.lastName = lastName;  
   }  
   @Override  
   public String toString() {  
     return "Person{" +  
         "id=" + id +  
         ", firstName='" + firstName + '\'' +  
         ", lastName='" + lastName + '\'' +  
         '}';  
   }  
 }  

Step 3: The Util class that helps to do the transformation.
 package org.fazlan.json;  
 import com.google.gson.Gson;  
 public class Json {  
   private final Gson gson;  
   private static Json JSON;  
   private Json() {  
     gson = new Gson();  
   }  
   public static Json getInstance() {  
     if(JSON == null) {  
       JSON = new Json();  
     }  
     return JSON;  
   }  
   public String toJson(Object t) {  
      return gson.toJson(t);  
   }  
   public <T> T fromJson(String jsonString, Class<T> clazz) {  
     return gson.fromJson(jsonString, clazz);  
   }  
 }  

What's important to note is the following two methods in com.google.gson.Gson
 . . .  
   gson.toJson(t);  
 . . .  
   gson.fromJson(jsonString, clazz);  

Step 3: Writing a simple client to test application
 package org.fazlan.json;  
 public class Application {  
   public static void main(String... args) {  
     Json json = Json.getInstance();  
     System.out.println("Java to Json");  
     Person p1 = new Person(1L, "Json", "Json");  
     String jsonString = json.toJson(p1);  
     System.out.println(p1 + "\t-->\t" + jsonString);  
     System.out.println("-----------");  
     System.out.println("Json to Java");  
     String person2JsonString = "{\"id\":2,\"firstName\":\"Gson\",\"lastName\":\"Google\"}";  
     Person p2 = json.fromJson(person2JsonString, Person.class);  
     System.out.println(person2JsonString + "\t-->\t" + p2);  
   }  
 }  

Sample output from this application,
 Java to Json  
 Person{id=1, firstName='Json', lastName='Json'}     -->     {"id":1,"firstName":"Json","lastName":"Json"}  
 -----------  
 Json to Java  
 {"id":2,"firstName":"Gson","lastName":"Google"}     -->     Person{id=2, firstName='Gson', lastName='Google'}  

Saturday, April 14, 2012

Apache Axis2 Tutorial: Integrating with Spring 3 and Hibernate 3

Overview:
This article looks at how you can integrate Spring and Hibernate with Apache Axis2. Axis2 also enables making use of Spring and Hibernate mush similar to Apache CXF( Tutorial on Apache CXF with Spring and Hibernate). This is a simple but a comprehensive tutorial. We'll be testing the service's REST endpoint using CURL.

The sample code for this project can be found here.

Prerequisite:
JDK >= 1.5.x
Maven >= 2.2.x
MySQL

Project Structure: Following is the project structure I have used (Maven WAR project).
Java class structure:


Resource structure:


Step 1: Creating the Database Table
 CREATE TABLE PERSON (
PERSON_ID BIGINT AUTO_INCREMENT,
FIRST_NAME VARCHAR(30),
LAST_NAME VARCHAR(30),
PRIMARY KEY (PERSON_ID)
)

Step 2: Maven Dependencies (pom.xml)
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fazlan</groupId>
<artifactId>org.fazlan.employee.axis2.orm.spring.service</artifactId>
<packaging>aar</packaging>
<version>1.0-SNAPSHOT</version>
<name>org.fazlan.employee.axis2.orm.spring.service</name>
<url>http://maven.apache.org</url>
<build>
<plugins>
  <plugin>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-aar-maven-plugin</artifactId>
    <version>1.6.1</version>
    <!--<version>${orbit.version.axis2}</version>-->
    <extensions>true</extensions>
    <configuration>
      <aarName>org.fazlan.employee.axis2.orm.spring.service</aarName>
    </configuration>
  </plugin>
</plugins>
</build>
<dependencies>
<!-- Axis2 -->
<dependency>
  <groupId>org.apache.axis2</groupId>
  <artifactId>axis2</artifactId>
  <version>${org.apache.axis2.version}</version>
</dependency>
<dependency>
      <groupId>org.apache.axis2</groupId>
      <artifactId>axis2-spring</artifactId>
      <version>${org.apache.axis2.version}</version>
    </dependency>
<!-- Spring framework -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-tx</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<!-- MySQL database driver -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.9</version>
</dependency>
<!-- Hibernate framework -->
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>${org.hibernate.version}</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-entitymanager</artifactId>
  <version>${org.hibernate.version}</version>
</dependency>
<!-- Hibernate library dependecy start -->
<dependency>
  <groupId>dom4j</groupId>
  <artifactId>dom4j</artifactId>
  <version>1.6.1</version>
</dependency>
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.1.1</version>
</dependency>
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.2.1</version>
</dependency>
<dependency>
  <groupId>antlr</groupId>
  <artifactId>antlr</artifactId>
  <version>2.7.7</version>
</dependency>
<!-- Hibernate library dependency end -->
<!--AspectJ dependency-->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>${org.aspectj.version}</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>${org.aspectj.version}</version>
</dependency>
 <!-- JUnit testing framework -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.8.1</version>
</dependency>
</dependencies>
<properties>
<org.apache.axis2.version>1.6.1</org.apache.axis2.version>
<org.aspectj.version>1.6.11</org.aspectj.version>
<org.hibernate.version>3.6.0.Final</org.hibernate.version>
<org.springframework.version>3.1.1.RELEASE</org.springframework.version>
</properties>
</project>

Step 3: Defining the POJO, DAO and Service Implementation
- Employee.java

 package org.fazlan.employee.axis2.orm.spring.service.beans;
import java.io.Serializable;
public class Employee implements Serializable {
private Long id;
private String firstName;
private String lastName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
Employee employee = (Employee) o;
return !(firstName != null ? !firstName.equals(employee.firstName) : employee.firstName != null) && !(id != null ? !id.equals(employee.id) : employee.id != null) && !(lastName != null ? !lastName.equals(employee.lastName) : employee.lastName != null);
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
return result;
}
}

- DAO Interface and Implementation

IDao.java
 package org.fazlan.employee.axis2.orm.spring.service.dao;
import java.util.List;
public interface IDao<T> {
Long save(T t);
boolean update(T t);
boolean delete(T t);
T get(Long id);
List<T> getAll();
}

EmployeeDao.java

 package org.fazlan.employee.axis2.orm.spring.service.dao;
import org.fazlan.employee.axis2.orm.spring.service.beans.Employee;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import java.util.List;
public class EmployeeDao extends HibernateDaoSupport implements IDao<Employee>{
public Long save(Employee employee) {
return (Long) getHibernateTemplate().save(employee);
}
public boolean update(Employee employee) {
getHibernateTemplate().update(employee);
return true;
}
public boolean delete(Employee employee) {
getHibernateTemplate().delete(employee);
return true;
}
public Employee get(Long id) {
return getHibernateTemplate().get(Employee.class, id); //To change body of implemented methods use File | Settings | File Templates.
}
public List<Employee> getAll() {
return getHibernateTemplate().find("from Employee");
}
}

- Service Interface and Implementation

IService.java
 package org.fazlan.employee.axis2.orm.spring.service.services;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: fazlan
* Date: 3/9/12
* Time: 4:36 PM
* To change this template use File | Settings | File Templates.
*/
public interface IService<T> {
Long add(T t);
boolean update(T t);
boolean delete(T t);
T get(Long id);
List<T> getAll();
}

EmployeeService.java

 package org.fazlan.employee.axis2.orm.spring.service.services;
import org.fazlan.employee.axis2.orm.spring.service.beans.Employee;
import org.fazlan.employee.axis2.orm.spring.service.dao.IDao;
import java.util.List;
public class EmployeeService implements IService<Employee> {
private IDao<Employee> employeeDao;
public Long add(Employee employee) {
return employeeDao.save(employee);
}
public boolean update(Employee employee) {
employeeDao.update(employee);
return true;
}
public boolean delete(Employee employee) {
employeeDao.delete(employee);
return true;
}
public Employee get(Long id) {
return employeeDao.get(id);
}
public List<Employee> getAll() {
return employeeDao.getAll();
}
public void setEmployeeDao(IDao<Employee> employeeDao) {
this.employeeDao = employeeDao;
}
}

Step 4: Defining the Service class to load the Spring Context in Axis2 for this *.aar
EmployeeSpringInit.java

 package org.fazlan.employee.axis2.orm.spring.service.services;
import org.apache.axis2.engine.ServiceLifeCycle;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class EmployeeSpringInit implements ServiceLifeCycle {
private static Log logger = LogFactory
.getLog(EmployeeSpringInit.class);
/**
* this will be called during the deployement time of the service. irrespective
* of the service scope this method will be called
*/
public void startUp(ConfigurationContext ignore, AxisService service) {
ClassLoader classLoader = service.getClassLoader();
ClassPathXmlApplicationContext appCtx = new
  ClassPathXmlApplicationContext(new String[] {"classpath:spring/spring-app-context.xml"}, false);
appCtx.setClassLoader(classLoader);
appCtx.refresh();
if (logger.isDebugEnabled()) {
  logger.debug("\n\nstartUp() set spring classloader via axisService.getClassLoader() ... ");
}
}
/**
* this will be called during the deployement time of the service. irrespective
* of the service scope this method will be called
*/
public void shutDown(ConfigurationContext ignore, AxisService service) {
}
}

Step 5: MySQL Database Connection Properties (hibernate/hbm/db.properties)
 jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springhibernate
jdbc.username=root
jdbc.password=root123

Step 6: Hibernate Mapping of Employee POJO (hibernate/hbm/Employee.hbm.xml)
 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.fazlan.employee.axis2.orm.spring.service.beans.Employee" table="PERSON">
<id name="id" column="PERSON_ID" type="long" access="field">
  <generator class="increment" />
</id>
<property name="firstName" type="string">
  <column name="FIRST_NAME" />
</property>
<property name="lastName" type="string">
  <column name="LAST_NAME" />
</property>
</class>
</hibernate-mapping>

Step 7: Defining the Spring Configuration for the Application (spring/spring-app-context.xml)

This is the Spring bean definition file in our application containing all the beans required to run the application.

The following is very important, this class and the spring bean needed to wire it could be used as an alternative to getting the ApplicationContext from the ServletContext.

 <bean id="applicationContext"
class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />

Putting all together,
 <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="applicationContext"
class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="location" value="classpath:hibernate/properties/db.properties"/>
</bean>
<!-- MySQL datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory"
 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
  <ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
  <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.show_sql">true</prop>
  </props>
</property>
<property name="mappingLocations">
  <value>classpath:hibernate/hbm/Employee.hbm.xml</value>
</property>
</bean>
<bean id="employeeDao" class="org.fazlan.employee.axis2.orm.spring.service.dao.EmployeeDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="employeeSpringService" class="org.fazlan.employee.axis2.orm.spring.service.services.EmployeeService">
<property name="employeeDao" ref="employeeDao"/>
</bean>
</beans>

Step 8: Defining your Axis2 Service Configuration (META-INF/services.xml)

EmployeeSpringInit Service: Loading the Spring context
 <service name="EmployeeSpringInit" class="org.fazlan.employee.axis2.orm.spring.service.services.EmployeeSpringInit">
<description>
  This web service initializes Spring.
</description>
<parameter name="ServiceClass">org.fazlan.employee.axis2.orm.spring.service.services.EmployeeSpringInit
</parameter>
<parameter name="ServiceTCCL">composite</parameter>
<parameter name="load-on-startup">true</parameter>
<!--<operation name="springInit">
 <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>-->
</service>
Here, we use this service to load the Spring context at the startup of the application.

EmployeeService - The actual service definition.
 <service name="EmployeeService">
<description>
  Weather Spring POJO Axis2 AAR deployment
</description>
<parameter name="ServiceClass">org.fazlan.employee.axis2.orm.spring.service.services.EmployeeService</parameter>
<parameter name="ServiceObjectSupplier">
  org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier
</parameter>
<excludeOperations>
  <operation>setEmployeeDao</operation>
</excludeOperations>
<parameter name="SpringBeanName">employeeSpringService</parameter>
<parameter name="SpringContextLocation">spring/spring-app-context.xml</parameter>
<messageReceivers>
  <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
           class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
  <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
           class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
</service>

By default, the Axis2 Engine will look for <your.aar>/applicationContext.xml to load the Spring bean configurations.

You can change this by either defining the following property.
 <parameter name="SpringContextLocation">spring/spring-app-context.xml</parameter>

This tells the Axis2 Engine where to locate the Spring application context file for this service. This is very useful when you have multiple Spring application services in the same Axis3 Engine.
Or,
You can place the Spring configuration file alongside the service.xml as in the following format. Axis2 Engine will implicitly detect this.

META-INF/<service-name>-application-context.xml

Putting all together,
 <serviceGroup>
<service name="EmployeeSpringInit" class="org.fazlan.employee.axis2.orm.spring.service.services.EmployeeSpringInit">
<description>
  This web service initializes Spring.
</description>
<parameter name="ServiceClass">org.fazlan.employee.axis2.orm.spring.service.services.EmployeeSpringInit
</parameter>
<parameter name="ServiceTCCL">composite</parameter>
<parameter name="load-on-startup">true</parameter>
<!--<operation name="springInit">
 <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>-->
</service>
<service name="EmployeeService">
<description>
  Weather Spring POJO Axis2 AAR deployment
</description>
<parameter name="ServiceClass">org.fazlan.employee.axis2.orm.spring.service.services.EmployeeService</parameter>
<parameter name="ServiceObjectSupplier">
  org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier
</parameter>
<excludeOperations>
  <operation>setEmployeeDao</operation>
</excludeOperations>
<parameter name="SpringBeanName">employeeSpringService</parameter>
<parameter name="SpringContextLocation">spring/spring-app-context.xml</parameter>
<messageReceivers>
  <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
           class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
  <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
           class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
</service>
</serviceGroup>

Step 9: Building the Project
mvn clean install

Step 10: Deploying the Service
Now you can deploy this service on to any container. Here we'll deploy this on Tomcat server.

You need to copy the following *.jars to <TOMCAT_HOME>/axis2/WEB-INF/lib/ directory (e;i: /home/fazlan/apache-tomcat-6.0.32/webapps/axis2/WEB-INF/lib/)in your Axis2 WAR already deployed on Tomcat.

Spring 3.1.1.RELEASE jars
spring-aop-3.1.1.RELEASE.jar
spring-asm-3.1.1.RELEASE.jar
spring-beans-3.1.1.RELEASE.jar
spring-context-3.1.1.RELEASE.jar
spring-context-support-3.1.1.RELEASE.jar
spring-core-3.1.1.RELEASE.jar
spring-expression-3.1.1.RELEASE.jar
spring-jdbc-3.1.1.RELEASE.jar
spring-orm-3.1.1.RELEASE.jar
spring-tx-3.1.1.RELEASE.jar
spring-web-3.1.1.RELEASE.jar

Hibernate3 jars
hibernate-commons-annotations-3.2.0.Final.jar
hibernate-core-3.6.0.Final.jar
hibernate-entitymanager-3.6.0.Final.jar
hibernate-jpa-2.0-api-1.0.0.Final.jar

Hibernate3 dependent jars
dom4j-1.6.1.jar
slf4j-api-1.6.1.jar
commons-collections-3.2.1.jar
javassist-3.12.0.GA.jar

This is due to the fact Axis2 Engine tries to load the classes from the jars from /axis2/WEB-INF/lib/ rather than locally in the *.aar file. Although, I tried with the following property in the services.xml, it didn't start the service.
 <parameter name="EnableChildFirstClassLoading">true</parameter>

Once, all the above *.jars are copied to /axis2/WEB-INF/lib/ on Tomcat. We are good to deploy the service and test.

Step 11: Testing the Service

Option 1: Testing the SOAP EPR with SOAP UI.

You can use SOAP UI and test the service with http://localhost:8080/axis2/services/EmployeeService?wsdl SOAP endpoint

Option 2: Testing REFTful endpoint using CURL

Install CURL
sudo apt-get install curl

Now, after successfully installing CURL, we are ready to test the services.
Issue the following commands on the terminal.

POST a Resource: Adding a new employee resource.
- Adding the new employee record in the add.xml file.
 <ns:add xmlns:ns="http://services.service.spring.orm.axis2.employee.fazlan.org">
  <ns:employee xmlns:ax21="http://beans.service.spring.orm.axis2.employee.fazlan.org/xsd"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax21:Employee">
       <ax21:firstName>My FirstName</ax21:firstName>
       <ax21:id>1</ax21:id>
       <ax21:lastName>My LastName</ax21:lastName>
  </ns:employee>
</ns:add>

 curl -v -H "Accept: application/xml" -H "Content-type: application/xml" -X POST -d @add.xml http://localhost:8080/axis2/services/EmployeeService/add

GET Resources:
- Retrieving all the employee resources.
 curl -v -H "Accept: application/xml" http://localhost:8080/axis2/services/EmployeeService/getAll

- Retrieving a employee resource for a given id(id = 1).
 curl -v -H "Accept: application/xml" http://localhost:8080/axis2/services/EmployeeService/get?id=1


PUT a Resource: Updating an existing employee resource.
- Updating an existing employee record in the update.xml file.
 <ns:update xmlns:ns="http://services.service.spring.orm.axis2.employee.fazlan.org">
  <ns:employee xmlns:ax21="http://beans.service.spring.orm.axis2.employee.fazlan.org/xsd"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax21:Employee">
       <ax21:firstName>Update FirstName</ax21:firstName>
       <ax21:id>1</ax21:id>
       <ax21:lastName>Update LastName</ax21:lastName>
  </ns:employee>
</ns:update>

 curl -v -H "Accept: application/xml" -H "Content-type: application/xml" -X PUT -d @update.xml http://localhost:8080/axis2/services/EmployeeService/update

DELETE a Resource: Deleting an employee for a given id (id=1)
- Deleting an existing employee record in the delete.xml file.
 <ns:delete xmlns:ns="http://services.service.spring.orm.axis2.employee.fazlan.org">
  <ns:employee xmlns:ax21="http://beans.service.spring.orm.axis2.employee.fazlan.org/xsd"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax21:Employee">
       <ax21:firstName>Update FirstName</ax21:firstName>
       <ax21:id>1</ax21:id>
       <ax21:lastName>Update LastName</ax21:lastName>
  </ns:employee>
</ns:delete>

 curl -i -H "Accept: application/xml" -H "Content-type: application/xml" -X PUT -d @delete.xml http://localhost:8080/axis2/services/EmployeeService/delete

Summary:
This tutorial looked at how we can integrate Spring and Hibernate with Apache Axis2.

The sample code for this project can be found here.