Wednesday, June 23, 2010

JAX-WS Client to call Webservice secured with XWS-Security (plain text password)

Hello,

We will learn webservice client with security by a example, which can fetch data and save data using usernametoken security. For this we have some requirements, but you can use other build tool, it may require little more efforts.

This JAX-WS Client is to call the Webservice defined in previous post.

Requirements:

• jdk1.6, maven 2

• This is tested on jdk1.6.0_18, apache-maven-2.0.9.

Here, some steps to follow...

• Create "Webservice Client" folder.

• Create "work" under "Webservice Client".

• Create below files under "work".

This file contains information of handler like soap handler and logical handler to intercept request and response of webservice.
We will use only one soap handler to secure webservice.

• handlers.xml

<?xml version="1.0" encoding="UTF-8"?>
<jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee">
    <jws:handler-chain>
        <jws:handler>
            <jws:handler-class>com.samplews.person.handler.SecuritySOAPHandler</jws:handler-class>
        </jws:handler>
    </jws:handler-chain>
</jws:handler-chains>

This file specifies which type of security we requires like username token, signed message, encrypted message, etc.
We will use username token with plain text password security.

• security-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config" dumpMessages="true">
    <xwss:UsernameToken digestPassword="false" useNonce="false"/>
</xwss:SecurityConfiguration>

The xjb file specifies in which package the generated java classes resides for given targetnamespace of xsd specified in schema location.

• person.xjb

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0">
    <jaxb:bindings schemaLocation="http://localhost:8080/personwsapp-1.0/PersonWSService?xsd=1" node="/xsd:schema">
        <jaxb:schemaBindings>
            <jaxb:package name="com.samplews.person.beans"/>
        </jaxb:schemaBindings>
    </jaxb:bindings>
</jaxb:bindings>

• Change that schema location in xjb file appropriate to your configuration.

• Navigate to "Webservice Client" on command prompt.

• Execute the command. This will create a maven project under "Webservice Client".

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.samplews.person -DartifactId=personwsclientapp

• Replace generated pom.xml with this.

• 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>com.samplews.person</groupId>
    <artifactId>personwsclientapp</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <name>personwsclientapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.messaging.saaj</groupId>
            <artifactId>saaj-impl</artifactId>
            <version>1.3.2</version>
        </dependency>  
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.wss</groupId>
            <artifactId>xws-security</artifactId>
            <version>3.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.1</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib</classpathPrefix>
                            <mainClass>com.samplews.person.service.CallPersonWS</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>xws-security</groupId>
                                    <artifactId>xws-security</artifactId>
                                    <version>1.0</version>
                                    <type>jar</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>com.sun.xml.messaging.saaj</groupId>
                                    <artifactId>saaj-impl</artifactId>
                                    <version>1.3.2</version>
                                    <type>jar</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>javax.activation</groupId>
                                    <artifactId>activation</artifactId>
                                    <version>1.0.2</version>
                                    <type>jar</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>javax.xml.soap</groupId>
                                    <artifactId>saaj-api</artifactId>
                                    <version>1.3</version>
                                    <type>jar</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                            <overWriteReleases>false</overWriteReleases>
                            <overWriteSnapshots>true</overWriteSnapshots>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <targetPath>com/samplews/person/service</targetPath>
                <directory>../work</directory>
                <includes>
                    <include>handlers.xml</include>
                </includes>
            </resource>
            <resource>
                <targetPath>com/samplews/person/handler</targetPath>
                <directory>../work</directory>            
                <includes>
                    <include>security-config.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

• Create "generated" under "Webservice Client".

• Nevigate to "Webservice Client" on command prompt.

• Execute the cammand. This will generates client stuff for the webservices.
  Change that url according to your configuration.

wsimport http://localhost:8080/personwsapp-1.0/PersonWSService?wsdl -b work/person.xjb -d generated -s personwsclientapp/src/main/java

• Add @HandlerChain(file = "handlers.xml") to com/samplews/person/service/PersonWSService.java.

• Put this source files under appropriate package.

This is client to call webservice.

• CallPersonWS.java

package com.samplews.person.service;

import com.samplews.person.beans.*;

public class CallPersonWS {

    public static void main(String args[]) {
        PersonWSService service = new PersonWSService();
        PersonWS port=service.getPersonWSPort();
        PersonFetchRequest request=new PersonFetchRequest();
        request.setId(1);
        PersonDetail response=port.fetch(request);
        System.out.println(response.getId());
        System.out.println(response.getName());
        System.out.println(response.getPhoneNo());
        System.out.println(response.getEmail());
    }
}

This is soap handler which we have defined in handlers.xml file. The handler intercept request and response as SOAPMessage.

• SecuritySOAPHandler.java

package com.samplews.person.handler;

import com.sun.xml.wss.ProcessingContext;
import com.sun.xml.wss.XWSSProcessor;
import com.sun.xml.wss.XWSSecurityException;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.WebServiceException;
import java.util.HashSet;
import java.util.Set;


public class SecuritySOAPHandler implements SOAPHandler<SOAPMessageContext> {
    public Set<QName> getHeaders() {
        return new HashSet<QName>();
    }

    public boolean handleMessage(SOAPMessageContext soapMessageContext) {
        try {
            boolean outMessageIndicator = (Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
            if (outMessageIndicator) {
                XWSSProcessor xwssProcessor = SecurityConfigProcessorFactory.getXWSSProcessor();
                SOAPMessage message = soapMessageContext.getMessage();
                ProcessingContext context = xwssProcessor.createProcessingContext(message);
                context.setSOAPMessage(message);
                SOAPMessage securedMsg = xwssProcessor.secureOutboundMessage(context);
                soapMessageContext.setMessage(securedMsg);
            }
        } catch (XWSSecurityException ex) {
            throw new WebServiceException(ex);
        }
        return true;
    }

    public boolean handleFault(SOAPMessageContext soapMessageContext) {
        return true;
    }

    public void close(MessageContext messageContext) {

    }
}

• SecurityConfigProcessorFactory.java

package com.samplews.person.handler;

import com.sun.xml.wss.XWSSProcessor;
import com.sun.xml.wss.XWSSProcessorFactory;
import com.sun.xml.wss.XWSSecurityException;

import java.io.InputStream;

public class SecurityConfigProcessorFactory {
    protected static XWSSProcessor xwssProcessor;

    public static XWSSProcessor getXWSSProcessor() throws XWSSecurityException {
        if (xwssProcessor == null) {
            InputStream serverConfig = SecurityConfigProcessorFactory.class.getResourceAsStream("/com/samplews/person/handler/security-config.xml");
            XWSSProcessorFactory factory = XWSSProcessorFactory.newInstance();
            xwssProcessor = factory.createProcessorForSecurityConfiguration(serverConfig, new SecurityCallbackHandler());
        }
        return xwssProcessor;
    }
}


The framework passes callbacks according to "security-config.xml".

• SecurityCallbackHandler.java

package com.samplews.person.handler;

import com.sun.xml.wss.impl.callback.PasswordCallback;
import com.sun.xml.wss.impl.callback.UsernameCallback;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;

public class SecurityCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            if (callback instanceof UsernameCallback) {
                ((UsernameCallback)callback).setUsername("manan");
            } else if (callback instanceof PasswordCallback) {
                ((PasswordCallback)callback).setPassword("panchal");
            } else {
                throw new UnsupportedCallbackException(callback);
            }
        }
    }
}

• Navigate to "personwsclientapp" on command prompt.

• Execute the command. This will package the classes into jar under "target".

mvn package

• You may have to download and install activation.jar into repository, follow instruction of maven.
  After installing the jar try "mvn clean package" which clears all previous stuff.

• Navigate to "target" on command prompt.

• Execute the command. This will run the "CallPersonWS".

java -jar personwsclientapp-1.0.jar

• Note: The jar is dependent of lib directory.

I think this would help. Please put suggestions if this not helping you, so I can improve this.
Thanks...

No comments:

Post a Comment