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.

13 comments:

Eclogue Chang said...

NOTE: This Unsername Token example has security vulnerability. It should not be used in the production environment.

weblogictips said...

This is only for the educational purpose.
None of the presented sample are for the production environment.
We can use the default available policy files with the weblogic server to secure the web services.

Thanks,
Sandeep

Nithin said...

We are getting one exception javax.xml.ws.WebServiceException: javax.xml.rpc.JAXRPCException: weblogic.xml.crypto.wss.WSSecurityException: Failed to add Signature.
at weblogic.wsee.jaxws.framework.jaxrpc.TubeFactory$JAXRPCTube.processRequest(TubeFactory.java:205)
at weblogic.wsee.jaxws.tubeline.FlowControlTube.processRequest(FlowControlTube.java:99)
at com.sun.xml.ws.api.pipe.Fiber.__doRun while trying to invoke a webservice from a webapp deployed on weblogic . What can be the issue ? While running the client as a standalone main class this issue doesn't occur.

weblogictips said...

hi Nitin,

The exception maybe coming while you are using the code as a webapp because weblogic is using the java net package when the code is executed from within the container.
Try using the flag: -Djava.protocol.handler.pkgs=weblogic.net

Thanks,
sandeep

Sanjeev said...

Hello Sandeep,

Thanks for these step-by-step articles, I like them very much and appreciate you effort.
I have a query related with the webservice security and single sing-on, I would like to implement single sign-on and also want that the web application that is hosting my webservice participates in it.

I have already configured the single sign-on for two web application, as per my knowledge, web browser plays a very important role in implementing the same. However, in case of web service, we can call the webservice from a servlet also.

To be more precise, suppose there are two web apllications:
Application A: is acting as SAML Identity provider and web application having a servlet which will call the web service deployed in the application B.
Application B: This is another web application deployed on a different domain and should participate in the single sign-on process. If I leave the webservice aside, I have configured the weblogic domains such that I can access a secured resource ( say jsp page) of Application B via application A without asking the authentication as I have already authenticated with application A. Actually Application A is passing the SAML authentication token to application B. So i can log in to application B without re-authentication. however, now I have added one web service in application and want it to be secured and participates in the single sign-on, that is, want to configure application A to send the token even in case of a web service call, and configure application B to accept and validate the token and execute the webservice if found a valid token.
Do you have any idea on this.
Please feel free to ask more clarification as I am bad in explaining the things.

Thanks & Regards,
Sanjeev

weblogictips said...

Hi Sanjeeev,

In case of web service, weblogic provides an option of using the following SAML configurations for enabling SSO:

http://download.oracle.com/docs/cd/E12840_01/wls/docs103/secintro/archtect.html#wp1068771

So you can try any one of them.

Thanks,
Sandeep

Rajesh said...

Sandeep, Thanks for the detailed information.

I was just wondering if there is any way to set custom UserName/Password for the Secure Webservice Client for them to invoke.

I tried above sample and its working like charm. But What if i don't want to share my Weblogic UserId/pwd with the clients OR it could be possible that i may have different clients for my WebService and i want all clients to use different set of Userid/pwd for authentication.

Any Idea ?

Thanks

embee said...

Anyone trying to do this with EAR in archived format, I believe you can create a "policies" directory in EJB's MET-INF or WAR's WEB-INF and place policy XML files there. Then in URI, specify "policy:filename.xml". There is also a classloader option documented in weblogic documentation... it involves setting a JVM property.

Dileep said...

Hi,
I am geting the following error while building the service, can you please help,

[jwsc] warning: Annotation types without processors: [javax.xml.bind.annotation.XmlRootElement, javax.xml.bind.annotation.XmlAccessorType, javax.xml.bind.annotation.XmlType, javax.xml.bind.annotation.XmlElement]

----------------------------------------------
posting the entire output logs of ant build command below,
[jwsc] warning: Annotation types without processors: [javax.xml.bind.annotation.XmlRootElement, javax.xml.bind.annotation.XmlAccessorType, javax.xml.bind.annotation.XmlType, javax.xml.bind.annotation.XmlElement]

clean:
[delete] Deleting directory D:\Dileep\Project\Telstra\WorkingFolder\JAXWSSecurity\JaxwsSecurity\Ear

server:
[mkdir] Created dir: D:\Dileep\Project\Telstra\WorkingFolder\JAXWSSecurity\JaxwsSecurity\Ear
[jwsc] JWS: processing module /Hello
[jwsc] Parsing source files
[jwsc] Parsing source files
[jwsc] 1 JWS files being processed for module /Hello
[jwsc] JWS: D:\Dileep\Project\Telstra\WorkingFolder\JAXWSSecurity\JaxwsSecurity\src\demo\Hello.java Validated.
[jwsc] Processing 1 JAX-WS web services...
[jwsc] warning: Annotation types without processors: [weblogic.jws.Policy,weblogic.jws.Policies]
[jwsc] 1 warning
[jwsc] warning: Annotation types without processors: [javax.xml.bind.annotation.XmlRootElement, javax.xml.bind.annotation.XmlAccessorType, javax.xml.bind.annotation.XmlType, javax.xml.bind.annotation.XmlElement]
[jwsc] 1 warning
[AntUtil.deleteDir] Deleting directory C:\Users\dileep_s\AppData\Local\Temp\_nek7oj
BUILD FAILED
D:\Dileep\Project\Telstra\WorkingFolder\JAXWSSecurity\JaxwsSecurity\build.xml:48
: weblogic.wsee.tools.WsBuildException: Error processing JAX-WS web services

Total time: 6 seconds

weblogictips said...

Have you used the setDomainEnv.cmd or setWLSEnv.cmd file to set the classpath before executing the ant ?
If not then please try the same.

Thanks,
Sandeep

Developing Web Services (JAX-WS) in WebLogic using Oracle Enterprise Pack for Eclipse(OEPE) – A Tutorial | My Experiments with Technology said...

[...] 1: How secure a JAX-WS web service on Weblogic URL 2: How to invoke a JAX-WS web service secured with username/password with another JAX-WS web [...]

raaja said...

What is the username and password and where to specify that in the usernametoken.xml???

weblogictips said...

The Username and password will be defined ih the weblogic security realm. there is no need to define username and password in policy file.