Wednesday, March 31, 2010

Example of WS-Trust web service security using Weblogic server

This article describes how to secure a Web Service using a central Token Server.

The standards WS-Trust, WS-Policy, WS-SecurityPolicy and Web Services Security, formerly known WS-Security, are used.

A simple scenario with a consumer, a web service and a Security Token Service (in short STS) would serve as an example.

What is WS-Trust?


-----------------------


This specification defines a standard where in a web- service requiring some sets of authentication and message level security can trust a third party web-service( called as Security Token Service-STS)  which is going to authenticate the actual request and will issue a token that can be accepted by the web –service.

The web-service should rely and trust the STS so that is can give response to the request authenticated by STS.

The Below Diagram shows the Flow of the Request between the components involved in a simple set-up showing WS-TRUST mechanism:

1: Web-Service Provider (WSP)

2: Web-Service Consumer (WSC)

3: Secure Token Service (STS)

Friday, March 26, 2010

How to invoke a JAX-WS web service secured with username/password with another JAX-WS web

Here it is assumed that you already have a JAX-WS web service deployed which requires username/password to get invoked.

If not then please follow the below link:

http://weblogictips.wordpress.com/2010/03/25/how-secure-a-jax-ws-web-service-on-weblogic/

Let us assume that the web service WSDL is located at URL:

http://137.72.242.156:7001/Hello/HelloService?WSDL

Now In order to invoke this web service we will be creating another JAX-WS web service as mentioned below:

Here

---------------------------------JaxWSClient.java--------------------------------------------------------------

package sandeep;

import javax.jws.WebService;

import javax.jws.WebMethod;

import weblogic.xml.crypto.wss.provider.CredentialProvider;

import weblogic.wsee.security.unt.ClientUNTCredentialProvider;

import weblogic.xml.crypto.wss.WSSecurityContext;

import javax.xml.ws.BindingProvider;

import java.util.List;

import java.util.ArrayList;

import java.util.Map;

// Import the JAX-WS Stubs for invoking the Hello Web Service.

// Stubs generated by clientgen

import demo.HelloService;

import demo.Hello;

@WebService

public class JaxWSClient {

@WebMethod()

public String callJAXWS()

{

HelloService myService = new HelloService();

Hello myServicePort = myService.getHelloPort();

List<CredentialProvider> credProviders = new ArrayList<CredentialProvider>();

String username = "weblogic";

String password = "weblogic";

CredentialProvider cp = new ClientUNTCredentialProvider(username.getBytes(),password.getBytes());

credProviders.add(cp);

Map<String,Object> rc = ((BindingProvider)myServicePort).getRequestContext();

rc.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credProviders);

System.out.println("calling the web service");

String result = myServicePort.sayHello("sandeep");

System.out.println("called " + result);

return result;

}

}

-------------------------------------------------------------------------------------------------------------------------------------

First let us look at the imports statements used in the above java class:

Below  imports are required to use the Weblogic specific annotations to make this class as a web service class and to create the username token provider(weblogic.wsee.security.unt.ClientUNTCredentialProvider) to be added to the generated port.

import javax.jws.WebService;

import javax.jws.WebMethod;

import weblogic.xml.crypto.wss.provider.CredentialProvider;

import weblogic.wsee.security.unt.ClientUNTCredentialProvider;

import weblogic.xml.crypto.wss.WSSecurityContext;

import javax.xml.ws.BindingProvider;

import java.util.List;

import java.util.ArrayList;

import java.util.Map;

below imports are used to get the web service object and the port object:

import demo.HelloService;

import demo.Hello;

Now after creating the above Class we will use the below JWSC  ant of Weblogic to make the web service artifacts from the above class:

<!-- building the JAXWS Client -->

<target name="JAXWS-build-client-service">

<mkdir dir="${JAXWSClient.ear.dir}"/>

<jwsc

srcdir="${JAXWS.client.dir}"

destdir="${JAXWSClient.ear.dir}" >

<jws

file="JaxWSClient.java">

<clientgen

type="JAXWS"

wsdl="http://137.72.242.156:7001/Hello/HelloService?WSDL"

packageName="demo" />

</jws>

</jwsc>

</target>

--------------------------------

You can notice that we have used the clientgen child ant task within the JWSC ant task here. This is the difference between the standalone client and a JAX-WS client.

The complete build.xml file for generating the complete JAX-WS client and deploying it on the Weblogic server is given below:

----------------------------------------------build.xml--------------------------------------------------------------------

<project default="all" basedir=".">

<property value="${basedir}/JAXWSWebServiceClient" />

<property name="JAXWSClient.ear.dir" value="${basedir}/JAXWS-client-ear" />

<property value="weblogic" />

<property name="wls.password" value="weblogic" />

<property name="wls.hostname" value="localhost" />

<property name="wls.port" value="7001" />

<property name="wls.server.name" value="AdminServer" />

<!-- building the JAXWS Client -->

<target name="JAXWS-build-client-service">

<mkdir dir="${JAXWSClient.ear.dir}"/>

<jwsc

srcdir="${JAXWS.client.dir}"

destdir="${JAXWSClient.ear.dir}" >

<jws

file="JaxWSClient.java">

<clientgen

type="JAXWS"

wsdl="http://137.72.242.156:7001/Hello/HelloService?WSDL"

packageName="demo" />

</jws>

</jwsc>

</target>

<target>

<javac

srcdir="${JAXWS.client.dir}" destdir="${JAXWS.client.dir}"

classpath="${java.class.path};${ JAXWS.client.dir }"

includes="JaxWSClient.java"/>

</target>

<!-- deploying the client web service -->

<target name="JAXWSdeploy">

<wldeploy

action="deploy"

verbose="true"

failonerror="true"

name="JAXWSClientEar"

source="${JAXWSClient.ear.dir}"

user="${wls.username}"

password="${wls.password}"

adminurl="t3://${wls.hostname}:${wls.port}"

targets="${wls.server.name}" />

</target>

</project>

------------------------------------------------------------------------------------------------------------------------------

Steps to follow:

1: Make sure that the JAX-WS web service that is to be called is active and accessible.

Assume that the WSDL URL for that web service is : http://137.72.242.156:7001/Hello/HelloService?WSDL

2: Create a dir :  sample and place the above mentioned build.xml file in this sample dir:

3: create another dir inside sample dir : JAXWSWebServiceClient and place the JaxWSClient.java class in this dir:

4: Now open a command prompt and run the setDomainEnv.cmd file on this command prompt to set the necessary classpath and other environment variables. setDomainEnv.cmd file is available in the domain_home/bin dir:

5: Then on the command prompt opened above move to the sample dir created above:

6: from the command prompt run the following task:

ant JAXWS-build-client-service

this task is going to build the web service war for the current java class and the clientgen child ant task used within this task is going to create the necessary client artifacts from the WSDL url:

7: After successful completion of the above task run the below task to deploy the created war file:

ant JAXWSdeploy

8: After the deployment is successful you can log in to the Weblogic Admin Server Console and go to the Deployments Summary to see the deployed Web Service.

9: When you will open the Weblogic Web Service Client for this deployed Web Service with name: JAXWSClientEar then you will see the below window:



10: Just Clicking on the callJAXWS button available on the Weblogic web service Client window will invoke this client web service which in turn will call the Secured Web Service and you can see the below output on the Weblogic Server Standard output:

How to invoke a Secured JAX-WS web service from Standalone Java Client:

How to invoke a Secured JAX-WS web service from Standalone Java Client:

It is assumed that you already have a secured JAX-WS web service deployed and ready to invoke.

If not then please follow the following link to create a JAX-WS web service which is secured for username/password authentication.

http://weblogictips.wordpress.com/2010/03/25/how-secure-a-jax-ws-web-service-on-weblogic/

As the Web service is already deployed let us assume that the WSDL URL of the web service to be invoked is as below:

http://localhost:7001/Hello/HelloService?WSDL

Now in order to create a client for this web service first of all we have to generate the client side artifacts that will be done using the clientgen ant task of Weblogic server.

For detailed reference please see the below link:

http://download.oracle.com/docs/cd/E13222_01/wls/docs81/webserv/anttasks.html#1080160

Steps:


1: Create a dir: BaseDir

2: Place the following build.xml file in the above BaseDir:

------------------------------------------BUILD.XML---------------------------------------------------------

<project default="all" basedir=".">

<!--Setting the Property Values-->

<property value="${basedir}/Clientdir" />

<!-- setting classpath for excecuting the client class -->

<path id="client.class.path">

<pathelement path="${client.dir}"/>

<pathelement path="${java.class.path}"/>

</path>

<!-- building the standalone client -->

<target name="build-client">

<clientgen

type="JAXWS"

wsdl="http://localhost:7001/Hello/HelloService?WSDL"

destDir="${client.dir}"

packageName=""

/>

</target>

<!--compiling the standalone client-->

<target name="client-comp">

<javac

srcdir="${client.dir}" destdir="${client.dir}"

classpath="${java.class.path};${client.dir}"

includes="MyClient.java"/>

</target>

<!-- excecuting the compiled client class -->

<target name="run">

<java

fork="true"

classname="MyClient"

failonerror="true" >

<classpath refid="client.class.path"/>

<arg line="

http://localhost:7001/Hello/HelloService?WSDL" />

</java>

</target>

</project>

----------------------------------------------------------------------------------------------------------------------------

3: Place the following Standalone java Client in the same BaseDir:

-----------------------------------------MyClient.java-----------------------------------------------------------------

//This is a standalone client to invoke the JAX-WS webservice secured with username/password

import demo.HelloService;

import demo.Hello;

import weblogic.xml.crypto.wss.provider.CredentialProvider;

import weblogic.wsee.security.unt.ClientUNTCredentialProvider;

import weblogic.xml.crypto.wss.WSSecurityContext;

import javax.xml.ws.BindingProvider;

import java.util.List;

import java.util.ArrayList;

import java.util.Map;

public class MyClient{

public static void main(String args[]){

HelloService myService = new HelloService();

Hello myServicePort = myService.getHelloPort();

List<CredentialProvider> credProviders = new ArrayList<CredentialProvider>();

String username = "weblogic";

String password = "weblogic";

CredentialProvider cp = new ClientUNTCredentialProvider(username.getBytes(),password.getBytes());

credProviders.add(cp);

Map<String,Object> rc = ((BindingProvider)myServicePort).getRequestContext();

rc.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credProviders);

System.out.println("calling the web service");

String result = myServicePort.sayHello("sandeep");

System.out.println("called " + result);

}

}

-------------------------------------------------------------------------------------------------------------------------------------

4: Now from a command prompt we have to run the ant task but before that we have to make sure that the Weblogic.jar and java class are in the classpath. The best way to set the classpath is to run the setDoaminEnv.cmd file on the command that is present in the Weblogic Domain Home / bin directory.

5: So from the command prompt we can run the following task from:

ant build-client

After successful generation of client artifacts we will compile the client class: MyClient.java :

ant client-comp

Then in order to execute the compiled class:

ant run

Here you can see that the Client MyCLient.java has invoked the web service and you can see the message  on the server standard output:

Hello: Sandeep

Thursday, March 25, 2010

How secure a JAX-WS web service on Weblogic

The Following will provide you step - by - step instructions to create a secured JAX-WS web service that can be accessed by providing user name and password:

I will be using Weblogic Server 10.3 to deploy and test the web service.

The web service will use the annotation @Policies and @Policy that are weblogic specific annotations.

Weblogic has enabled us to secure our web services by using the security policy file(It is an XML file that provides details about which kind of security has been enabled on the web service).

So the first step is to create a security.xml file, since we will be securing our web service only for username and password so I will be using the following usernametoken.xml file:

-------------------------------------usernametoken.xml----------------------------------------------------------------------------------------

<?xml version="1.0"?>

<wsp:Policy

xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"

xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512" >

<sp:SupportingTokens>

<wsp:Policy>

<sp:UsernameToken

sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512/IncludeToken/AlwaysToRecipient">

<wsp:Policy>

<sp:WssUsernameToken10/>

</wsp:Policy>

</sp:UsernameToken>

</wsp:Policy>

</sp:SupportingTokens>

</wsp:Policy>

------------------------------------------------------------------------------------------------------------------------------------

Now following is the directory structure used in this example:

---------------------------------------------



So, You have to place the above usernametoken.xml file in the policy dir within the base: Secure-JAX-WS-Example dir.

Now place the below mentioned Hello.java file in the src directory:

----------------------------------------Hello.java --------------------------------------------------------

//Web service Secured by username/password

//this web service uses a security policy file "username_policy.xml"

package demo;

import javax.jws.WebService;

import weblogic.jws.Policies;

import weblogic.jws.Policy;

@WebService

@Policies({ @Policy( uri = "../policy/usernametoken.xml" ) } )

public class Hello{

public String sayHello(String name){

return "Hello : " +name;

}

}

-------------------------------------------------------------------------------------------------

You can notice in the above java file the annotation @Policies is used to insert the security policy file to this web service.

And the @Policy file is used to provide the relative URI of the exact xml file with respect to the location of this Java file.

Now we have to build this policy file using the weblogic web service ant tasks. I am providing the snippet of the build.xml file

that can be used to build this web service and deploy it on to the weblogic server:

-----------------BUILD.XML file---------------------------------------------------------------------------------------------------

<project name="WebService_username_token" default="all" basedir=".">

<!--Setting the Property Values-->
<property name="ws.file" value="Hello" />
<property name="ws.file.dir" value="${basedir}/src" />
<property name="ear.dir" value="${basedir}/Ear" />
<property name="client.dir" value="${basedir}/Clientdir" />

<property name="wls.username" value="weblogic" />
<property name="wls.password" value="weblogic" />
<property name="wls.hostname" value="localhost" />
<property name="wls.port" value="7001" />
<property name="wls.server.name" value="AdminServer" />

<!--setting the classpath for the web service generation -->
<path id="service.class.path">
<pathelement path="${java.class.path}"/>
</path>

<!-- setting classpath for excecuting the client class -->
<path id="client.class.path">
<pathelement path="${client.dir}"/>
<pathelement path="${java.class.path}"/>
</path>

<taskdef name="jwsc" classname="weblogic.wsee.tools.anttasks.JwscTask" />

<target name="all" depends="clean,server,deploy" />

<target name="build" depends="clean,server" />

<target name="clean">
<delete dir="${ear.dir}"/>
<delete dir="${client.dir}"/>
</target>

<!-- building the service -->
<target name="server">
<mkdir dir="${ear.dir}"/>
<jwsc
srcdir="${ws.file.dir}"
destdir="${ear.dir}"
classpath="${java.class.path}"
fork="true"
keepGenerated="true"
deprecation="true"
debug="true"
verbose="false">
<jws file="${ws.file}.java" explode="true" type="JAXWS"/>
</jwsc>
</target>

<target name="deploy">
<wldeploy
action="deploy"
verbose="true"
failonerror="true"
name="UsernameTokenEar"
source="${ear.dir}"
user="${wls.username}"
password="${wls.password}"
adminurl="t3://${wls.hostname}:${wls.port}"
targets="${wls.server.name}" />
</target>

<!-- building the standalone client -->
<target name="build-client">
<clientgen
type="JAXWS"
wsdl="http://${wls.hostname}:${wls.port}/${ws.file}/${ws.file}Service?WSDL"
destDir="${client.dir}"
packageName=""
/>
</target>

<!--compiling the standalone client-->
<target name="client-comp">
<javac
srcdir="${client.dir}" destdir="${client.dir}"
classpath="${java.class.path};${client.dir}"
includes="MyClient.java"/>

</target>

<!-- excecuting the compiled client class -->
<target name="run">
<java
fork="true"
classname="MyClient"
failonerror="true" >
<classpath refid="client.class.path"/>
<arg line="
http://${wls.hostname}:${wls.port}/${ws.file}/${ws.file}Service?WSDL" />
</java>
</target>

</project>

-------------------------------------------------------------------------------------------------------------------------------

In order to execute the above example follow the following steps:

1: Create a dir : Secure-JAX-WS-Example directory:

2: With in this Directory create the following directories:

a) src----place the Hello.java in this src directory.

b) policy-- place the usernametoken.xml file in this policy directory.

and the build.xml should be placed directly under the Secure-JAX-WS-Example directory.

3:Make sure that the weblogic server is running and according to the values of weblogic username/password/localhost/port/  etc adjust the values in the build.xml file.

4:Now open a command prompt and run the setDomainEnv.cmd file to set the environment required for executing the ant task defined by weblogic and used in the build.xml file.

5: After running the setDomainEnv.cmd on the same command prompt move to your working dir i.e. Secure-JAX-WS-Example directory:

execute the following ant task one by one :

ant build-service(Press Enter)

If the result is successful the execute the next task:

ant deploy

Now you can login to the Admin Console of the weblogic server and go the Deployments tab:

Within Deployment summary we can the web service has been deployed :(See the below Snap Shot)



Now Click on the above UsernameTokenEar :

Then click on the Testing tab present on the top of the Weblogic Admin Console.

Then Expand the HelloService so that you can see the below page:



Now Click on the Test Client that is shown in front of /Hello/HelloService.

You will see another window showing some page like below:

[caption id="attachment_54" align="alignnone" width="300" caption="Weblogic Web Service Test Client window"][/caption]

Now type some string in the give space and click on the sayHello button available:

You will see the following response:



As you can clearly see the error message that the there is some invalid Security Fault.

This is because the web service is now expecting the username and password along with the SOAP request and since Weblogic Client does not has any way to pass the username/password token this web service is not invoked successfully.

So, following these steps you can make your JAX-WS web service secure.

Now In order to invoke this web service you will have to write some clients that can pass username and password with the request and can successfully invoke the service.