Showing posts with label JAX-WS. Show all posts
Showing posts with label JAX-WS. Show all posts

Monday, April 15, 2013

Let us write a document style Web Service

You might be aware that there are mainly four different styles of web services we can make use of. They are as follows;


  • Document/Literal
  • Document/Literal Wrapped
  • RPC/Encoded
  • RPC/Literal
Of course the RPC/Encoded style is now deprecated. If you are interested you can read up on the different styles of web services and their pros on cons on this very comprehensive article found here.

Today we will see how to write a Document/Literal wrapped kind of a web service. The agenda of this post is as follows;

  • Write a simple web service based on Document/Literal wrapped
  • How to host the simple web service on a tomcat web container
  • A simple test client to test our service
So let us begin our journey;

  • Write a simple web service based on Document/Literal wrapped

package com.wsbindings;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;

@WebService
@SOAPBinding(style = Style.DOCUMENT, use = Use.LITERAL, parameterStyle = ParameterStyle.WRAPPED)
public interface AddService {

 @WebMethod
 public int addIntegers(@WebParam(name = "intOne") int paramOne,
   @WebParam(name = "intTwo") int paramTwo);
}


So this is our basic web service. This is our base interface for our service. As you can see, we first annotate it with the @javax.jws.WebService to indicate that its a web service we are going to write. Then comes the interesting part where we define our SOAPBinding. Here we state that we want to write a DOCUMENT style web service which is LITERAL and is a WRAPPED style. One thing to note here is that all three attribute values specified within the Soap Binding annotation are the default values so you can get away without declaring them here explicitly. I have done so for the purpose of clarity of this article.

Moving on, let us see how the implementation will look like for this particular interface;


package com.wsbindings;

import javax.jws.WebService;

@WebService(endpointInterface="com.wsbindings.AddService")
public class AddServiceImpl implements AddService{

 public int addIntegers(int paramOne, int paramTwo) {
  return paramOne+paramTwo;
 }

}


Again nothing spectacular here in terms of what this service does. Just adds the two numbers passed in and send back the result of the addition. Note that here again we have to annotate the implementation class with the @WebService annotation.

Now that we have completed the initial part of writing our web service contract and the implementation, let us see how we can host this on a tomcat web container.


  • How to host the simple web service on a tomcat web container
As you know, by default tomcat does not come with a JAX-WS implementation unlike typical application servers such as JBoss, Glassfish. Hence to get it working you need to get an implementation of the JAX-WS specification. In this instance we will be using Metro. You can either copy the jar files from the download to your WEB-INF/lib directory or you can make use of Maven to do that for you, which is what i will be doing in this article. So to get the require jar files related to the Metro implementation i add the following dependency to my pom;


 <dependency>
   <groupId>com.sun.xml.ws</groupId>
   <artifactId>jaxws-rt</artifactId>
   <version>2.1.3</version>
   <exclusions>
    <exclusion>
     <groupId>com.sun.xml.stream</groupId>
     <artifactId>sjsxp</artifactId>

    </exclusion>
   </exclusions>
  </dependency>

Note that i have added one exclusion here for the sjsxp artifact since i needed a newer version than which was being drawn up from transitive dependency. Because else you will get the following exception;

 Could not initialize class javax.xml.stream.XMLStreamException: Underlying stream encoding UTF-8 and input paramter for writeStartDocument() method utf-8 do not match.

In order to overcome this issue i needed to add the following dependency to my pom;


 <dependency>
   <groupId>com.sun.xml.stream</groupId>
   <artifactId>sjsxp</artifactId>
   <version>1.0.1</version>
  </dependency>

I was able to find this solution thanks to this thread.

Moving on, we need to define a specific xml file which should go under the WEB-INF directory called sun-jaxws.xml. This XML specifies how we can access our web services and where the implmentation class is found. Lets look at the content of this file;


<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
  <endpoint
     name="AddWS"
     implementation="com.wsbindings.AddServiceImpl"
     url-pattern="/addws"/>
</endpoints> 

Here we give the package in which our web service implementation class resides in as well as the URL pattern on how to access the particular web service. One last thing we should do is to add the following to our web.xml in order to host our web service successfully;


<listener>
  <listener-class>
   com.sun.xml.ws.transport.http.servlet.WSServletContextListener
  </listener-class>
 </listener>
 <servlet>
  <servlet-name>AddWS</servlet-name>
  <servlet-class>
   com.sun.xml.ws.transport.http.servlet.WSServlet
  </servlet-class>
 </servlet>

 <servlet-mapping>
  <servlet-name>AddWS</servlet-name>
  <url-pattern>/addws</url-pattern>
 </servlet-mapping>

Note that we have to define a context listener and a Servlet class which will handle our web service invocations. If you look at the source of the WSServletContextListner you will see it reads the sun-jaxws.xml file from the WEB-INF directory and creates class loaders accordingly for the web service context.

One thing about Document style web services is that you need to generate some code for the request and response. If you do not do this, you will get the following error with the following message;

Have you run APT to generate them?

You can generate the required classes using the wsgen tool which comes bundled up with your JDK installation. You can also use Apache-CXF to generate these classes for you. We will use the latter approach by using the apache-cxf maven plugin which is available for us. Include the following to your pom and your good to go;


 <plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>2.0.9</version>
    <dependencies>
     <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxws</artifactId>
      <version>2.0.9</version>
     </dependency>
    </dependencies>
    <executions>
     <execution>
      <id>generate-wsdl</id>
      <phase>process-classes</phase>
      <configuration>
       <className>com.wsbindings.AddServiceImpl</className>
       <argline>-classdir ${project.build.directory}/classes</argline>

      </configuration>

      <goals>
       <goal>java2wsdl</goal>
      </goals>
     </execution>
    </executions>
   </plugin>

Here we are using the java2wsdl command to generate the required request and response objects for our web service. As you can see i have used the <argline> attribute to specify where i want my generated classes to go to. Since the normal maven compile task which is run when building the war file will look in the classes directory, i have specified our classes to be included in the same path as well so that they will be bundled along with our web service class when the war is created. You can see all possible commands you can issue by going through the parameters specified here.

My pom was indicating an error when i included my apache-cxf maven plugin as follows;

Plugin execution not covered by lifecycle configuration

 and after some research on the problem i stumbled upon a solution as stated here.Hence to overcome this issue you have to include the following snippet under the <build> tag of your pom;


 
<pluginManagement>
   <plugins>
    <!--This plugin's configuration is used to store Eclipse m2e settings 
     only. It has no influence on the Maven build itself. -->
    <plugin>
     <groupId>org.eclipse.m2e</groupId>
     <artifactId>lifecycle-mapping</artifactId>
     <version>1.0.0</version>
     <configuration>
      <lifecycleMappingMetadata>
       <pluginExecutions>
        <pluginExecution>
         <pluginExecutionFilter>
          <groupId>org.apache.cxf</groupId>
          <artifactId>cxf-codegen-plugin</artifactId>
          <version>2.0.9</version>
          <goals>
           <goal>test-compile</goal>
           <goal>compile</goal>
          </goals>
         </pluginExecutionFilter>
         <action>
          <execute />
         </action>
        </pluginExecution>
       </pluginExecutions>
      </lifecycleMappingMetadata>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>

That should get rid of that error for you though i cannot give you an exact reason to why that warning pops up. If any of you know the exact reason, i would appreciate if you could leave a comment for the benefit of us all.

After that you can simply generate the war file and copy it to the webapps directory of tomcat. Then you will be able to access the web service on the following path;

http://localhost:8080/ws-bindings/addws

Where 8080 is the port on which i have hosted tomcat on and ws-bindings is the name of my war file.

Lastly let us see how to generate the client stubs required for our service and then write a small client to test our web service.


  • A simple test client to test our service
We will yet again use the apache-cxf maven plugin to generate the client stubs using the wsdl2java command. Note that first we need to get the wsdl from the path where our web service is hosted. It will be located at;

http://localhost:8080/ws-bindings/addws?wsdl

Then i copied the content to a separate xml file and saved it under a resources directory on the separate maven project i created to generate the client stubs. Then all you need to do is add the configuration required to generate the stubs in the pom as follows;


 
<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>2.0.9</version>
    <executions>
     <execution>
      <id>generate-sources</id>
      <phase>generate-sources</phase>
      <configuration>
     
       <wsdlOptions>
        <wsdlOption>
         <wsdl>${project.basedir}/src/main/resources/AddService.wsdl</wsdl>
        </wsdlOption>
       </wsdlOptions>
      </configuration>
      <goals>
       <goal>wsdl2java</goal>
      </goals>
     </execution>
    </executions>
   </plugin>

This will generate the required stubs for you to test your web service. Lastly let us write a client to use the generated stub to access our web service;


 
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import com.wsbindings.AddService;


public class DocWrapperClient {

 public static void main(String[] args) throws MalformedURLException {
   URL wsdlLocation = new URL("http://localhost:8080/ws-bindings/addws?wsdl");  
    
         QName qName = new QName("http://wsbindings.com/", "AddServiceImplService");  

         Service service = null;  
         service = Service.create(wsdlLocation, qName);  
         
         AddService ser = service.getPort(AddService.class);
         System.out.println(ser.addIntegers(1, 1));
 }
}


That is about it guys, and i hope you found the content useful. You can check out the example by downloading the server related maven project from here and the client stub generation maven project from here.

Thank you for reading and hope you have a lovely day ahead of your. Comments and criticisms are welcome as always.

Thursday, April 28, 2011

Secure your webservices with JBoss

WS-SEC is a vast area in it self and trying to cover the whole topic in one blog post is just not possible. So ill be touching on a glimpse of it by showing you how to achieve ws-sec with Jboss with the least amount of effort.

In simplest terms WS-SEC is more or less the same as what you do when you log into a website by providing your user name and password. Only difference is in this case you provide your credentials to gain access to the web service you are trying to access.

People use WS-SEC in order to protect their web service from being used by unknown third parties. There always might be instances in which you would want to restrict access to certain web services as they process and handle confidential data. For this situation WS-SEC is a must. Adding HTTPS would guarantee transport leve security for your Web service as well. But in this article i will only focus on securing your web service through WS-SEC as there are many articles explaining how to expose it on HTTPS.

Note that i will be creating the web service using the @Webservice annotation(a.k.a code first approach). Following i have given the web service we are going to use for our example;

package com.myservices;
@WebService(serviceName = "MyService", portName = "MyServicePort", targetNamespace = "personlaservices")
@Stateless
@HandlerChain(file = "myconfigs/webservices/security_handler.xml")
public class MySecurityService {

 @WebMethod
 public String sayMyName(){
  return "Iron Man!!!";
 }

}

Note that i have just a simple method with a string output. The important thing to note here is the @HandlerChain attribute. This refers to an XML we define which i will show below which defines the class which will handle the authentication by reading the user name and password which comes in the header part of the soap message enclosed within the ws-sec tag. Note that the xml file path is relative to the classpath. I have placed the folder myconfigs within the conf directory of jboss.

The Configuration XML security_handler.xml is as follows;

<?xml version="1.0" encoding="UTF-8"?>



<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">



 <!-- Note:  The '*" denotes a wildcard. -->



 <handler-chain>

  <handler>

   <handler-name>com.myservice.security.AuthenticateHandler</handler-name>

   <handler-class>com.myservice.security.AuthenticateHandler

   </handler-class>

  </handler>

 </handler-chain>

</handler-chains>


This defines a class called AuthenticationHandler which will retrieve the user name and password contained within the soap message and do the authentication using the JBoss login module with the security realm defined which i will not go into detail as we all know how to handle security within JBoss. but you can use any authentication mechanism you want here.

/**
 * 
 */
package com.myservice.security;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.apache.log4j.Logger;



/**
 * Handler to authenticate the requests send in by the user from information provided through soap-headers.
 */
public class AuthenticateHandler implements SOAPHandler<SOAPMessageContext> {

    /** The Constant logger. */
    private static final Logger logger = Logger.getLogger(AuthenticateHandler.class);

    /** The Constant USERNAME_TOKEN_STRING. */
    private static final String USERNAME_TOKEN_STRING = "UsernameToken";

    /** The Constant USERNAME_STRING. */
    private static final String USERNAME_STRING = "Username";

    /** The Constant ARG_0_STRING. */
    private static final String ARG_0_STRING = "arg0";

    /** The Constant PASSWORD_STRING. */
    private static final String PASSWORD_STRING = "Password";


    private static final String HIGHPHEN = "-";

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#handleFault(javax.xml.ws.handler.MessageContext)
     */
    public boolean handleFault(SOAPMessageContext context) {
        // throw new UnsupportedOperationException("Not supported yet.");
        logger.debug("handleFault() is called");
        return true;
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext)
     */
    public boolean handleMessage(SOAPMessageContext smc) {

        SOAPMessage message = smc.getMessage();
        Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        boolean authenticated = false;

        try {

            // Let's extract information and try to log XML.
            SOAPPart sp = message.getSOAPPart();
            SOAPEnvelope envelope = sp.getEnvelope();

           
            if (!outboundProperty) {

                SOAPHeader header = envelope.getHeader();

                if (header != null) {
                    authenticated = processSOAPHeader(header);
                }

            }

        } catch (SOAPException se) {
            logger.error("SOAPException occured while processing the message", se);

        }
        return authenticated;
    }

    /**
     * Gets the sOAP message as string.
     * 
     * @param msg the msg
     * @return the sOAP message as string
     */
    private String getSOAPMessageAsString(SOAPMessage msg) {

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            msg.writeTo(baos);
            return baos.toString();

        } catch (IOException ioe) {
            logger.warn("Could not extract XML from soap message", ioe);
            return null;
        } catch (SOAPException se) {
            logger.warn("Could not extract XML from soap message", se);
            return null;
        }
    }

    /**
     * Process soap header. This method is called by handleRequest method It retrieves the SOAP headers in the message
     * and authenticates the client.
     * 
     * @param sh the soap header
     * @return true, if successful
     */
    private boolean processSOAPHeader(SOAPHeader sh) {
        boolean authenticated = false;

        // look for authentication header element inside the HEADER block
        Iterator childElems = sh.getChildElements();

        SOAPElement child = extractUserNameInfo(childElems);

        if (child != null) {

            // call method to perform authentication
            authenticated = authenticateRequest(child);
        }
        return authenticated;
    }

    /**
     * Extract user name info.
     * 
     * @param childElems the child elems
     * @return the sOAP element
     */
    private SOAPElement extractUserNameInfo(Iterator childElems) {

        logger.debug("extractUserNameInfo called.");

        SOAPElement child = null;
        Name sName;

        // iterate through child elements
        while (childElems.hasNext()) {
            Object elem = childElems.next();

            if (elem instanceof SOAPElement) {

                // Get child element and its name
                child = (SOAPElement) elem;
                sName = child.getElementName();

                // Check whether there is a UserNameToken element
                if (!USERNAME_TOKEN_STRING.equalsIgnoreCase(sName.getLocalName())) {

                    if (child.getChildElements().hasNext()) { // TODO check logic
                        return extractUserNameInfo(child.getChildElements());
                    }
                }
            }
        }

        return child;
    }

    /**
     * Authenticate request. This method retrieves the authentication information for the request header and validates
     * it.
     * 
     * @param element the element
     * @return true, if successful
     */
    private boolean authenticateRequest(SOAPElement element) {

        logger.debug("authenticateRequest called");
        boolean authenticated = false;

        // variable for user name and password
        String userName = null;
        String password = null;
        Name sName;

        // get an iterator on child elements of SOAP element
        Iterator childElems = element.getChildElements();

        SOAPElement child;
        // loop through child elements

        while (childElems.hasNext()) {
            // get next child element
            Object elem = childElems.next();

            if (elem instanceof SOAPElement) {
                child = (SOAPElement) elem;

                // get the name of SOAP element
                sName = child.getElementName();

                // get the value of username element
                if (USERNAME_STRING.equalsIgnoreCase(sName.getLocalName())) {
                    logger.debug("---UserName =" + child.getValue());
                    userName = child.getValue();
                } else if (PASSWORD_STRING.equalsIgnoreCase(sName.getLocalName())) {
                    // get the value of password element
                    password = child.getValue();
                }

                if (userName != null && password != null) {

                   
   /**
       Note that in this instance i have used my custom used class
       called ClientLoginModule whic wraps a JBossLoginModule instance.
         You can use your own authentication mechanism as you have the user name
        and password at this point.
   **/
                        ClientLoginModule.login("WEBSERVICE" + "^" + userName, password);
                        return true;
                  

                    break;
                }

            }
        }

        if (userName == null || password == null) {
            logger.warn("Username or password is empty. userName : [" + userName + "], password : [" + password + "]");
        }

        return authenticated;

    }

    

    /**
     * Extract TCI info.
     * 
     * @param childElems the child elems
     * @return the sOAP element
     */
    private SOAPElement extractTCIInfo(Iterator childElems) {

        logger.debug("extractTCIInfo called.");

        SOAPElement child = null;
        Name sName;

        // iterate through child elements
        while (childElems.hasNext()) {
            Object elem = childElems.next();

            if (elem instanceof SOAPElement) {

                // Get child element and its name
                child = (SOAPElement) elem;
                sName = child.getElementName();

                // Check whether there is a UserNameToken element
                if (!ARG_0_STRING.equalsIgnoreCase(sName.getLocalName())) {

                    if (child.getChildElements().hasNext()) {
                        return extractTCIInfo(child.getChildElements());
                    }
                }
            }
        }

        return child;
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.soap.SOAPHandler#getHeaders()
     */
    public Set<QName> getHeaders() {
        logger.debug("--- In AuthenticateHandler.getHeaders ()");
        // return headers;
        return null;
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#close(javax.xml.ws.handler.MessageContext)
     */
    public void close(MessageContext context) {
        logger.debug("close() is called");
        // throw new UnsupportedOperationException("Not supported yet.");
    }

}

This class extracts the user name and password as you can see within the method authenticateRequest() and authenticates the user. If authentication fails it will return false from within handleMessage(). Note that i have used a class called ClientLoginModule. This is a class i have written which extends JBoss Login Module. I did not go into much detail with that due to the fact that it is already known to anyone who has dealt with jboss user security handling.

Now that we have these two methods you just need to bundle this up and run jboss which will expose the wsdl of this service. In jboss you can see what current web services are being hosted on your server by going to the URL http://localhost:8080/jbossws/services where 8080 is the port you expose your jboss on.

After you get your wsdl you need to generate the stubs by running any tool such as wsimport which does the wsdl to java transformation for you. Check here for more information.

Assuming you got your stubs generated and constructed a jar containing your code i will show you how to consume this ws-sec enabled webservice through a client.


try {
            URL wsdlLocation = new URL("http://localhost:8080/MyService");

            QName qName = new QName("personlaservices", "MyService");

            Service service = null;
            service = Service.create(wsdlLocation, qName);
            
     /**
  HeaderHandlerResolve will pass this information to a HeaderHandler implementation
  class which will embed the user name and password passed in to the ws-security
  header within the soap header element
     **/
            HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver("myusername","mypassword");
            service.setHandlerResolver(handlerResolver);

            MySecurityService servicePort = service.getPort(MySecurityService.class);

     System.out.println(servicePort.sayMyName());
        } catch (MalformedURLException mue) {
            logger.warn("An error occurred while getting the wsdl location.", mue);
        }

Here i first create an instance of the javax.xml.ws.Service class using the URL, namespace and the service name we provided within our web service implementation we specified earlier. Next the important thing to note here is we define a custom HeaderHandlerResolver which we set to the service. I will show you the implementation of the HeaderhandlerResolver as well as the HeaderHandler which is used within the HeaderHandlerResolver class so that you can understand what happens.

/**
 * 
 */
package com.myservice.client;

import java.util.ArrayList;
import java.util.List;

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;

/**
 * Taken from www.javadb.com and modified.
 * 
 * @author www.javadb.com
 */
public class HeaderHandlerResolver implements HandlerResolver {

    private String userName;

    private String password;

    public HeaderHandlerResolver() {
        super();

    }

    public HeaderHandlerResolver(String userName,String password) {
        super();
 this.userName = userName;
 this.password = password;
    }

    @SuppressWarnings("unchecked")
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        List<Handler> handlerChain = new ArrayList<Handler>();

        HeaderHandler hh = new HeaderHandler(userName,password);

        handlerChain.add(hh);

        return handlerChain;
    }
}


The Header Handler implementation is the one which embeds the ws-security header to the soap header as you can see from the below code;


/**
 * 
 */
package com.myservice.client;

import java.io.ByteArrayOutputStream;
import java.util.Set;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.apache.log4j.Logger;



/**
 * Taken from www.javadb.com and modified.
 * 
 * @author www.javadb.com
 */
public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {

    /** The Constant logger. */
    private static final Logger logger = Logger.getLogger(HeaderHandler.class);

    /** The Constant WS_SECURITY_SECEXT_URI. */
    private static final String WS_SECURITY_SECEXT_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";

    /** The Constant WS_SECURITY_UTILITY_URI. */
    private static final String WS_SECURITY_UTILITY_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";

    /** The Constant WS_PASSWORD_TYPE_URI. */
    private static final String WS_PASSWORD_TYPE_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";

    /** The Constant WSSE_PREFIX. */
    private static final String WSSE_PREFIX = "wsse";

    /** The Constant SECURITY_LOCAL_NAME. */
    private static final String SECURITY_LOCAL_NAME = "Security";

    /** The Constant USERNAME_TOKEN_LOCAL_NAME. */
    private static final String USERNAME_TOKEN_LOCAL_NAME = "UsernameToken";

    /** The Constant LOCAL_PART_XMLNS_WSU. */
    private static final String LOCAL_PART_XMLNS_WSU = "wsu";

    /** The Constant USERNAME_LOCAL_NAME. */
    private static final String USERNAME_LOCAL_NAME = "Username";

    /** The Constant PASSWORD_LOCAL_NAME. */
    private static final String PASSWORD_LOCAL_NAME = "Password";

    /** The Constant PASSWORD_ATTRIBUTE_TYPE. */
    private static final String PASSWORD_ATTRIBUTE_TYPE = "Type";

    private static final String HIGHPHEN = "-";

    private String userName;

    private String password;

    public HeaderHandler(String userName,String password) {
        this.userName = userName;
 this.password = password;
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext)
     */
    public boolean handleMessage(SOAPMessageContext smc) {

        Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        SOAPMessage message = smc.getMessage();

        try {

            // Let's extract information and try to log XML.
            SOAPPart sp = message.getSOAPPart();
            SOAPEnvelope envelope = sp.getEnvelope();

         

            if (outboundProperty.booleanValue()) {

                SOAPHeader header = envelope.getHeader();

                if (header != null) {
                    header.detachNode();
                }

                header = envelope.addHeader();

                SOAPElement security = header.addChildElement(SECURITY_LOCAL_NAME, WSSE_PREFIX, WS_SECURITY_SECEXT_URI);

                SOAPElement usernameToken = security.addChildElement(USERNAME_TOKEN_LOCAL_NAME, WSSE_PREFIX);

                QName qName = new QName(XMLConstants.NULL_NS_URI, LOCAL_PART_XMLNS_WSU);
                usernameToken.addAttribute(qName, WS_SECURITY_UTILITY_URI);

                SOAPElement username = usernameToken.addChildElement(USERNAME_LOCAL_NAME, WSSE_PREFIX);

                username.addTextNode(userName);

                SOAPElement password = usernameToken.addChildElement(PASSWORD_LOCAL_NAME, WSSE_PREFIX);
                password.setAttribute(PASSWORD_ATTRIBUTE_TYPE, WS_PASSWORD_TYPE_URI);

                password.addTextNode(password);

            }

        } catch (SOAPException se) {
            logger.error("SOAPException occured while processing the message", se);

        }

        return outboundProperty;

    }

    /**
     * Gets the sOAP message as string.
     * 
     * @param msg the msg
     * @return the sOAP message as string
     */
    private String getSOAPMessageAsString(SOAPMessage msg) {

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            msg.writeTo(baos);
            return baos.toString();

        } catch (Exception e) {
            logger.warn("Could not extract XML from soap message");
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.soap.SOAPHandler#getHeaders()
     */
    public Set<QName> getHeaders() {
        // throw new UnsupportedOperationException("Not supported yet.");
        logger.info("getHeaders() is called");
        return null;
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#handleFault(javax.xml.ws.handler.MessageContext)
     */
    public boolean handleFault(SOAPMessageContext context) {
        // throw new UnsupportedOperationException("Not supported yet.");
        logger.info("handleFault() is called");
        return true;
    }

    /*
     * (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#close(javax.xml.ws.handler.MessageContext)
     */
    public void close(MessageContext context) {
        logger.info("close() is called");
        // throw new UnsupportedOperationException("Not supported yet.");
    }
}


Thats about it guys. Withing the handleMessage() method in the above class you can see we are embedding the user name and password to the ws-security header element which is part of the soap header. So now when you call your web service the message wil go through the HeaderHandlerResolver which will pass it on to the Header Handler which in turn will embed the ws-security header before passing on the soap request.

If you have any questions or if there are any areas of improvement you see please do leave a comment which is as always highly appreciated.


Cheers Guys!!!