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...

Wednesday, June 2, 2010

JAX-WS Webservice secured With XWS-Security (plain text password)

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

Requirements:

• jdk1.6, glassfish, maven 2

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

Here, some steps to follow...

• Create "Webservice" folder.

• Create "work" under "Webservice".

• Create below files under "work".

• person.xsd

First we have to determine what we want to send and what we want back from webservice so for that purpose we have to define a xsd file.
The fetch request contains only id and we will get detail information.
The save request carries detail of person and we will get response message of success or failure.

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

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.samplews.com/person/beans"
    elementFormDefault="qualified" xmlns:tns="http://www.samplews.com/person/beans">
    <xsd:complexType name="PersonDetail">
        <xsd:sequence>
            <xsd:element name="Id" type="xsd:int"/>
            <xsd:element name="Name" type="xsd:string"/>
            <xsd:element name="Address" type="tns:Address"/>
            <xsd:element name="PhoneNo" type="xsd:decimal"/>
            <xsd:element name="Email" type="xsd:string"/>
            <xsd:element name="BirthDate" type="xsd:date"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="PersonSaveResponse">
        <xsd:sequence>
            <xsd:element name="Status" type="xsd:boolean"/>
            <xsd:element name="Message" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="PersonFetchRequest">
        <xsd:sequence>
            <xsd:element name="Id" type="xsd:int"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="Address">
        <xsd:sequence>
            <xsd:element name="Line1" type="xsd:string"/>
            <xsd:element name="Line2" type="xsd:string"/>
            <xsd:element name="Line3" type="xsd:string"/>
            <xsd:element name="City" type="xsd:string"/>
            <xsd:element name="Pincode" type="xsd:decimal"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

• person.xjb

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

<?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="person.xsd" node="/xsd:schema">
        <jaxb:schemaBindings>
            <jaxb:package name="com.samplews.person.beans"/>
        </jaxb:schemaBindings>
    </jaxb:bindings>
</jaxb:bindings>

• web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
</web-app>

• handlers.xml

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.

<?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>

• security-config.xml

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.

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

• Navigate to "Webservice" on command prompt.

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

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

• 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>personwsapp</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>
    <name>personwsapp</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>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-war-plugin</artifactId>
                <version>2.0</version>
                <configuration>
                    <webXml>../work/web.xml</webXml>
                </configuration>
            </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>

• Navigate to "work" on command prompt.

• Execute the command.

This command generates java classes according to xsd and configuration of xjb which we will use to pass into and to return from webservice. This will generates beans classes packaged in "com.samplews.person".

xjc person.xsd -b person.xjb -d ..\personwsapp\src\main\java

• Put this source files under appropriate packages under "personwsapp\src\main\java".

This is the webservice class.

• PersonWS.java

package com.samplews.person.service;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.HandlerChain;
import java.math.BigDecimal;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.DatatypeConfigurationException;
import com.samplews.person.beans.*;


@WebService(name = "PersonWS", serviceName = "PersonWSService", portName = "PersonWSPort", targetNamespace = "http://www.samplews.com/person/service")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.BARE)
@HandlerChain(file = "handlers.xml")

public class PersonWS {

    public PersonWS() {

    }

    @WebMethod(operationName = "Fetch")
    @WebResult(name = "PersonFetchResponse", targetNamespace = "http://www.samplews.com/person/beans", partName = "PersonFetchResponse")
    public PersonDetail fetch(@WebParam(name = "PersonFetchRequest", targetNamespace = "http://www.samplews.com/person/beans", partName = "PersonFetchRequest")PersonFetchRequest request) {
        PersonDetail response=new PersonDetail();
        response.setId(request.getId());
        response.setName("testperson");
        Address address=new Address();
        address.setLine1("Line1");
        address.setLine2("Line2");
        address.setLine3("Line3");
        address.setCity("Mahemdabad");
        address.setPincode(new BigDecimal("387130"));
        response.setAddress(address);
        response.setEmail("testperson@testemail.com");
        response.setPhoneNo(new BigDecimal("9999999999"));
        try {
            response.setBirthDate(DatatypeFactory.newInstance().newXMLGregorianCalendar("1985-01-11"));
        } catch(DatatypeConfigurationException ex) {
            ex.printStackTrace();
        }
        return response;
    }

    @WebMethod(operationName = "Save")
    @WebResult(name = "PersonSaveResponse", targetNamespace = "http://www.samplews.com/person/beans", partName = "PersonSaveResponse")
    public PersonSaveResponse save(@WebParam(name = "PersonSaveRequest", targetNamespace = "http://www.samplews.com/person/beans", partName = "PersonSaveRequest")PersonDetail request) {
        PersonSaveResponse response=new PersonSaveResponse();
        response.setStatus(true);
        response.setMessage("Person with Id:"+request.getId()+" saved.");
        return response;
    }

}

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() {
        QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", "wsse");
        HashSet<QName> headers = new HashSet<QName>();
        headers.add(securityHeader);
        return headers;
    }

    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 verifiedMsg = xwssProcessor.verifyInboundMessage(context);
                soapMessageContext.setMessage(verifiedMsg);
            }
        } 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.PasswordValidationCallback;

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 PasswordValidationCallback) {
                PasswordValidationCallback passwordValidationCallback = (PasswordValidationCallback) callback;
                passwordValidationCallback.setValidator(new PlainTextPasswordValidator());
            } else {
                throw new UnsupportedCallbackException(callback);
            }
        }
    }
}

• PlainTextPasswordValidator.java

package com.samplews.person.handler;

import com.sun.xml.wss.impl.callback.PasswordValidationCallback;

import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import java.util.HashMap;

public class PlainTextPasswordValidator implements PasswordValidationCallback.PasswordValidator {
    public boolean validate(PasswordValidationCallback.Request request) throws PasswordValidationCallback.PasswordValidationException {
        PasswordValidationCallback.PlainTextPasswordRequest passwordRequest = (PasswordValidationCallback.PlainTextPasswordRequest) request;
        String username = passwordRequest.getUsername();
        String password = passwordRequest.getPassword();
        if (username != null && password != null) {
            if (username.equals("manan") && password.equals("panchal")) {
                return true;
            }
        } else {
            return false;
            //throw new PasswordValidationCallback.PasswordValidationException("Username or/and Password in request is null.");
        }
        return false;
    }
}

• Navigate to "personwsapp" on command prompt.

• Execute the command. This will compile, and package the project into war file under "target".

mvn package

• Deploy the generated war file into glassfish.

When you deploy the war the glassfish internally uses wsgen to create server artifact like wsdl file, java file of request, java file of response, etc.

• Check webservice is deployed well by writing this url in address bar of browser.
  Change the url if your configuration is different.

http://localhost:8080/personwsapp-1.0/PersonWSService

• Create "client" directory under "Webservice".

• Put this files under "client" directory.

• CallPersonFetchWS.java

import java.io.*;
import java.net.*;

public class CallPersonFetchWS {

    public static void main(String args[]) throws Exception {
        //Change the url if your configuration is different
        URL url = new URL("http://localhost:8080/personwsapp-1.0/PersonWSService");
        URLConnection con = url.openConnection();
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        con.setDefaultUseCaches(false);
        con.setRequestProperty("content-type", "text/xml");
        /*
        Run alternatively save and fetch request.
        */
        FileInputStream requestIn = new FileInputStream("FetchRequest.xml");
        //FileInputStream requestIn = new FileInputStream("SaveRequest.xml");
        byte[] requestBytes=new byte[requestIn.available()];
        requestIn.read(requestBytes);
        requestIn.close();
        String request=new String(requestBytes);
        byte[] filebytes = request.getBytes();
        con.connect();
        OutputStream out = con.getOutputStream();
        try {
            out.write(filebytes);
            out.flush();
        } finally {
            out.close();
        }
        InputStream in = con.getInputStream();
        byte[] inbytes = new byte[in.available()];
        try {
            in.read(inbytes);
        } finally {
            in.close();
        }
        String resStr = new String(inbytes);
        System.out.println(resStr);
    }
}

• FetchRequest.xml

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://www.samplews.com/person/beans" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <soap:Header>
        <wsse:Security>
            <wsse:UsernameToken>
                <wsse:Username>manan</wsse:Username>
                <wsse:Password>panchal</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <ns1:PersonFetchRequest>
            <ns1:Id>1</ns1:Id>
        </ns1:PersonFetchRequest>
    </soap:Body>
</soap:Envelope>

• SaveRequest.xml

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://www.samplews.com/person/beans" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <soap:Header>
        <wsse:Security>
            <wsse:UsernameToken>
                <wsse:Username>manan</wsse:Username>
                <wsse:Password>panchal</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <ns1:PersonSaveRequest>
            <ns1:Id>1</ns1:Id>
            <ns1:Name>testperson</ns1:Name>
            <ns1:Address>
                <ns1:Line1>Line1</ns1:Line1>
                <ns1:Line2>Line2</ns1:Line2>
                <ns1:Line3>Line3</ns1:Line3>
                <ns1:City>Mahemdabad</ns1:City>
                <ns1:Pincode>387130</ns1:Pincode>
            </ns1:Address>
            <ns1:PhoneNo>9999999999</ns1:PhoneNo>
            <ns1:Email>testperson@testmail.com</ns1:Email>
            <ns1:BirthDate>1985-01-11</ns1:BirthDate>
        </ns1:PersonSaveRequest>
    </soap:Body>
</soap:Envelope>

• By running "CallPersonFetchWS", you can call the webservice.

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

JAX-WS client to call this service

Saturday, May 15, 2010

Webservices using JAX-WS

Hello All,

We are going to create a simple webservice using JAX-WS.
This requires jdk 1.6, glassfish sever.
This is tested on Windows XP SP2, jdk1.6.0_18, Glassfish-v2ur1

This Webservices fetches information of a person by id.

Please follow the instructions...

• Create a directory structure like this.

Webservice
 |
 |
 -----> PersonFetchService
             |
             |
             -----> work
             |            |
             |            |
             |            -----> personfetch.xsd
             |            |
             |            |
             |            -----> personfetch.xjb
             |            |
             |            |
             |            -----> compile.bat
             |
             |
             -----> PersonFetchApp
                         |
                         |
                         -----> WEB-INF
                                     |
                                     |
                                     -----> web.xml
                                     |
                                     |
                                     -----> classes

• personfetch.xsd

We have to determine the structure of request and response. What we want to send and what we want back, so we now define a xsd for that purpose.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.samplews.com/schema/personfetch" elementFormDefault="qualified" xmlns:tns="http://www.samplews.com/schema/personfetch">
    <xsd:complexType name="PersonFetchRequest">
        <xsd:sequence>
            <xsd:element name="Id" type="xsd:int"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="PersonFetchResponse">
        <xsd:sequence>
            <xsd:element name="Id" type="xsd:int"/>
            <xsd:element name="Name" type="xsd:string"/>
            <xsd:element name="Address" type="tns:Address"/>
            <xsd:element name="PhoneNo" type="xsd:decimal"/>
            <xsd:element name="Email" type="xsd:string"/>
            <xsd:element name="BirthDate" type="xsd:date"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="Address">
        <xsd:sequence>
            <xsd:element name="Line1" type="xsd:string"/>
            <xsd:element name="Line2" type="xsd:string"/>
            <xsd:element name="Line3" type="xsd:string"/>
            <xsd:element name="City" type="xsd:string"/>
            <xsd:element name="Pincode" type="xsd:decimal"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

• personfetch.xjb

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

<?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="personfetch.xsd" node="/xsd:schema">
        <jaxb:schemaBindings>
            <jaxb:package name="com.samplews.personfetch"/>
        </jaxb:schemaBindings>
    </jaxb:bindings>
</jaxb:bindings>

• compile.bat

This batch is to compile all java file under specified package.

javac com/samplews/personfetch/*.java
pause

• web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
</web-app>

• Navigate to "work" folder on command prompt.

• Execute this command.

This command generates java classes according to xsd and configuration of xjb which we will use to pass into and to return from webservice.

xjc personfetch.xsd -b personfetch.xjb -d .

You would get source files generated under "work".

• Create a java file under com --> samplews --> personfetch named "PersonFetchWS.java".

This is the webservice class. You can see the parameter and return type of the the fetchInfo method.

• PersonFetchWS.java

package com.samplews.personfetch;

import javax.jws.*;
import javax.jws.soap.SOAPBinding;
import java.math.BigDecimal;

@WebService(name = "PersonFetchWS", serviceName = "PersonFetchWSService", portName = "PersonFetchWSPort", targetNamespace = "http://www.samplews.com/webservice/personfetch")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)

public class PersonFetchWS {

    public PersonFetchWS() {

    }

    @WebMethod(operationName = "FetchInfo")
    public
    @WebResult(name = "PersonFetchResponse", targetNamespace = "http://www.samplews.com/schema/personfetch")
    PersonFetchResponse fetchInfo(@WebParam(name = "PersonFetchRequest", targetNamespace = "http://www.samplews.com/schema/personfetch")PersonFetchRequest request) {
        PersonFetchResponse response=new PersonFetchResponse();
        response.setId(request.getId());
        response.setName("TestPerson");
        Address address=new Address();
        address.setLine1("Line1");
        address.setLine2("Line2");
        address.setLine3("Line3");
        address.setCity("Mahemdabad");
        address.setPincode(new BigDecimal("387130"));
        response.setAddress(address);
        response.setPhoneNo(new BigDecimal("9999999999"));
        response.setEmail("testperson@testdomain.com");
        return response;
    }

}

• Execute the "compile.bat" to compile all source files.

• Copy the "com" folder and paste it to Webservices --> PersonFetchService --> PersonFetchApp --> WEB-INF --> classes

• Navidate to "PersonFetchService" on command prompt.

• Execute this command.

The command will package all stuff under "PersonFetchService" derectory and create a jar file.

jar cvf PersonFetchApp.war -C PersonFetchApp .

You would get "PersonFetchApp.war" under "PersonFetchService".

• Deploy this war file in glassfish.

When you deploy the war the glassfish internally uses wsgen to create server artifact like wsdl file, java file of request, java file of response, etc.

• Enter this url in browser's address bar.

http://[hostname]:[port]/PersonFetchApp/PersonFetchWSService

• You would see Webservice information.

• To call the webservices use the class.

• CallPersonFetchWS.java

import java.io.*;
import java.net.*;

public class CallPersonFetchWS {

    public static void main(String args[]) throws Exception {
        URL url = new URL("http://[host]:[port]/PersonFetchApp/PersonFetchWSService");
        URLConnection con = url.openConnection();
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        con.setDefaultUseCaches(false);
        con.setRequestProperty("content-type", "text/xml");
        String request="<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:ns1=\"http://www.samplews.com/schema/personfetch\">"+
        "<soap:Header/>"+
        "<soap:Body>"+
        "<ns1:PersonFetchRequest>"+
        "<ns1:Id>1</ns1:Id>"+
        "</ns1:PersonFetchRequest>"+
        "</soap:Body>"+
        "</soap:Envelope>";
        byte[] filebytes = request.getBytes();
        con.connect();
        OutputStream out = con.getOutputStream();
        try {
            out.write(filebytes);
            out.flush();
        } finally {
            out.close();
        }
        InputStream in = con.getInputStream();
        byte[] inbytes = new byte[in.available()];
        try {
            in.read(inbytes);
        } finally {
            in.close();
        }
        String resStr = new String(inbytes);
        System.out.println(resStr);
    }
}

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

Tuesday, April 27, 2010

Hello...

Hello... I am starting... I will try to publish some important information...