CXF With UsernameToken (Interceptor)

CXF With UsernameToken (Interceptor) explains about step by step details of securing a Web service using UsernameToken Interceptor

CXF gives two different techniques for adding UsernameToken

1) WS-SecurityPolicy -> In WS-SecurityPolicy, we are applying on WSDL 
level, Here we are defining WS-SecurityPolicy elements on WSDL and 
implement the security mechanism. This could be the best approach 
because client can able to understand which security mechanism is 
implemented and client can able to proceed accordingly.

2) Using CXF interceptors -> Here we are manually adding security 
mechanism to CXF interceptors,the problem on this approach client 
cant able to understand which security mechanism is implemented 
because it is not available on wsdl
Note

If you are interested to add WS-Security on WSDL level using WS-SecurityPolicy, you can use following article

CXF With UsernameToken (WS-Security Policy)

Required Libraries

You need to download

  1. JDK 6
  2. Eclipse 3.7
  3. CXF-2.7.3
  4. Tomcat 7

Following jar must be in ClassPath

  1. commons-logging-1.1.1.jar
  2. cxf-2.7.3.jar
  3. httpasyncclient-4.0-beta3.jar
  4. httpclient-4.2.1.jar
  5. httpcore-4.2.2.jar
  6. httpcore-nio-4.2.2.jar
  7. jaxb-api-2.2.6.jar
  8. jaxb-impl-2.2.6.jar
  9. neethi-3.0.2.jar
  10. spring-aop-3.0.7.RELEASE.jar
  11. spring-asm-3.0.7.RELEASE.jar
  12. spring-beans-3.0.7.RELEASE.jar
  13. spring-context-3.0.7.RELEASE.jar
  14. spring-core-3.0.7.RELEASE.jar
  15. spring-expression-3.0.7.RELEASE.jar
  16. spring-web-3.0.7.RELEASE.jar
  17. wsdl4j-1.6.2.jar
  18. wss4j-1.6.9.jar
  19. xmlschema-core-2.0.3.jar
  20. xmlsec-1.5.3.jar

CXF With UsernameToken (Interceptor) Tutorial

I am creating a sample web service project that pass Student object and return with some changes on that object. The service is using simple POJO (Plain Old Java Object) bean.

Firstly create a Dynamic Web Project (File->New->Dynamic Web Project) named "CXFTutorial" according to following screenshot

CXF With UsernameToken (Interceptor) CXF With UsernameToken (Interceptor)

Create a Student Object

package com.student;

public class Student {
 
private String name;
 
public String getName() {
   
return name;
 
}
 
public void setName(String name) {
   
this.name = name;
 
}
}

Create a Service Interface

This service interface will defines which methods of web service, to be invoked by the client

package com.student;

import javax.jws.WebService;

@WebService
public interface ChangeStudentDetails {
 
Student changeName(Student student);
}

Implement the Service Interface

Here we implement the service interface created on the previous step

package com.student;

import javax.jws.WebService;

@WebService(endpointInterface = "com.student.ChangeStudentDetails")
public class ChangeStudentDetailsImpl implements ChangeStudentDetails {
   
public Student changeName(Student student) {
     
student.setName("Hello "+student.getName());
     
return student;
   
}
}

Create ServerPasswordCallback

package service;

import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;

public class ServerPasswordCallback implements CallbackHandler {

   
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
       
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

       
if ("joe".equals(pc.getIdentifier())) {
           
System.out.println("pc.getPassword() " + pc.getPassword());
            pc.setPassword
("joespassword");
       
}
       
    }
}

Create a cxf.xml

Here we are adding

<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackRef">
	<ref bean="myPasswordCallback" />
</entry>

created myPasswordCallback bean in order to check the username token credentials

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:cxf="http://cxf.apache.org/core"
	xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:soap="http://cxf.apache.org/bindings/soap"
	xmlns:wsa="http://cxf.apache.org/ws/addressing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
 http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	
	<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" id="loggingInInterceptor" />
	<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" id="logOutInterceptor" />
	<cxf:bus>
		<cxf:inInterceptors>
			<ref bean="loggingInInterceptor" />
		</cxf:inInterceptors>
		<cxf:outInterceptors>
			<ref bean="logOutInterceptor" />
		</cxf:outInterceptors>
	</cxf:bus>
	<jaxws:endpoint address="/ChangeStudent" id="changeStudent"
		implementor="com.student.ChangeStudentDetailsImpl">
		<jaxws:properties>
			<entry key="ws-security.callback-handler" value-ref="myPasswordCallback" />
		</jaxws:properties>
		<!--Added interceptor below -->
		<jaxws:inInterceptors>
			<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
				<constructor-arg>
					<map>
						<entry key="action" value="UsernameToken" />
						<entry key="passwordType" value="PasswordText" />
						<entry key="passwordCallbackRef">
							<ref bean="myPasswordCallback" />
						</entry>
					</map>
				</constructor-arg>
			</bean>
		</jaxws:inInterceptors>
	</jaxws:endpoint> 
	<!--Added callback for checking the usernametoken credential -->
	<bean class="com.student.ServerPasswordCallback" id="myPasswordCallback" />
</beans>

web.xml

Change the web.xml file to find CXF servlet and cxf.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/cxf.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Publishing CXF Web Service

CXF UsernameToken Interceptor structure

Note

You can Find all the deployed JAX-WS/JAX-RS services you need to append 'services' at the end of the URL so URL will become following

http://localhost:8080/CXFTutorial/services

Deployed CXF Web Service

Deployed CXF With UsernameToken (Interceptor)

Now we are using soapUI for testing CXF UsernameToken example

Create soapUI Project and add WSDL

New soapUI Project CXF With UsernameToken (Interceptor) soapUI

Run

On following screenshot, you can see the blue lines, which is specifying username as "joe", password as "joespassword" and WSS-Password Type as "PasswordText"

soapUI With UsernameToken

Run

You can also use wsimport tool for testing this service. Only thing need to change is modify the Main class according to below class

package com.client;

import java.util.Map;

import com.student.ChangeStudentDetails;
import com.student.ChangeStudentDetailsImplService;
import com.student.Student;
import javax.xml.ws.BindingProvider;
//CXF With UsernameToken (Interceptor)
public class Main {
 
public static void main(String[] args) {
   
ChangeStudentDetailsImplService service = new ChangeStudentDetailsImplService();
    ChangeStudentDetails changeStudentDetailsImplPort = service.getChangeStudentDetailsImplPort
();

    Map ctx =
((BindingProvider) changeStudentDetailsImplPort).getRequestContext();
    ctx.put
("ws-security.username", "joe");
    ctx.put
("ws-security.password", "joespassword");

    Student student =
new Student();
    student.setName
("Rockey");
    student = changeStudentDetailsImplPort.changeName
(student);
    System.out.println
(student.getName());

 
}

}
Output
Hello Rockey

 











4 Responses to "CXF With UsernameToken (Interceptor)"
  1. Kumar 2012-08-17 09:57:29.0
  1. admin 2012-08-18 09:57:29.0
  1. Sunil Gulabani 2012-08-19 09:57:29.0
  1. admin 2012-08-20 09:57:29.0

Your email address will not be published. Required fields are marked *