Integrating JSF, Spring Security and LDAP
Integrating JSF, Spring Security and LDAP
Introduction
In this article we are going to develop sample web application by using JSF, Spring Security with LDAP Connection. This article provides steps (step by step) to create & deploy web application. Please go through below to find sample web application.
Software Requirements
- EClipse (Java IDE)- Optional
- Maven
- Tomcat Latest Web server
- Ant
- JDK 1.6
The Code
In this example, we are going to create sample login page. For Authentication and for authorization we will be using spring security and LDAP.
Step 1: Copy following pom.xml in project root folder.
<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/maven-v4_0_0.xsd”>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>Greenwich</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>JSF Web ApplicationMaven Webapp</name>
<url>http://maven.apache.org</url>
<repositories>
<repository>
<id>jboss-repository</id>
<name>jboss-repository</name>
<url>http://repository.jboss.com/maven2/</url>
<layout>default</layout>
</repository>
<repository>
<id>java-repository</id>
<name>java-repository</name>
<url>http://download.java.net/maven/2</url>
<layout>default</layout>
</repository>
<repository>
<id>ibiblio-repository</id>
<name>ibiblio-repository</name>
<url>http://mirrors.ibiblio.org/pub/mirrors/maven2/</url>
<layout>default</layout>
</repository>
<repository>
<id>repo1.maven.org</id>
<name>Maven Repository</name>
<url>http://repo1.maven.org/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate3</artifactId>
<version>3.2.3.GA</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.2.0</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springmodules</groupId>
<artifactId>spring-modules-validation</artifactId>
<version>0.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.directwebremoting</groupId>
<artifactId>dwr</artifactId>
<version>2.0.rc1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.4.GA</version>
</dependency>
<dependency>
<groupId>org.directwebremoting</groupId>
<artifactId>dwr</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflow</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>myfaces</groupId>
<artifactId>myfaces-all</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<artifactId>xml–apis</artifactId>
<groupId>xml–apis</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.myfaces.tomahawk</groupId>
<artifactId>tomahawk</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.el</groupId>
<artifactId>el-ri</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.ajax4jsf</groupId>
<artifactId>ajax4jsf</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>opensymphony</groupId>
<artifactId>oscache</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
<build>
<finalName>greenwich</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>false</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
<wtpversion>1.5</wtpversion>
</configuration>
</plugin>
<plugin>
<artifactId>maven-idea-plugin</artifactId>
<version>2.1</version>
<configuration>
<downloadSources>false</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
<dependenciesAsLibraries>true</dependenciesAsLibraries>
<useFullNames>false</useFullNames>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven–plugin</artifactId>
<version>2.1</version>
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<implementation>annotationconfiguration</implementation>
<!– Use ‘jpaconfiguration‘ if you’re using JPA. –>
<!–<implementation>jpaconfiguration</implementation>–>
</component>
</components>
<componentProperties>
<drop>true</drop>
<jdk5>true</jdk5>
<propertyfile>target/classes/jdbc.properties</propertyfile>
<skip>${maven.test.skip}</skip>
</componentProperties>
</configuration>
<executions>
<execution>
<phase>process-test-resources</phase>
<goals>
<goal>hbm2ddl</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>${jdbc.groupId}</groupId>
<artifactId>${jdbc.artifactId}</artifactId>
<version>${jdbc.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-1</version>
<configuration>
<warSourceExcludes>WEB-INF/lib/el-api-1.0.jar</warSourceExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven–surefire–plugin</artifactId>
<configuration>
<!–
<includes> <include> **/WelcomePageControllerTest.java </include>
</includes>
–>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 2: Run following command in project root folder. (To run the following command set apache-maven\bin directory in system path. I hope you guys might know it how to set.)
mvn eclipse:eclipse
Step 3: Create following LoginBacking.java for Login and Logout. Create this file under src folder of root directory.
Package Name: com.sample.bpbgp.security
Class Name: LoginBacking
package com.sample.bpbgp.security;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.security.ui.AbstractProcessingFilter;
public class LoginBacking {
// properties
private String userId;
private String password;
/**
* default empty constructor
*/
public LoginBacking() {
Exception ex = (Exception) FacesContext
.getCurrentInstance()
.getExternalContext()
.getSessionMap()
.get(
AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
if (ex != null)
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, ex
.getMessage(), ex.getMessage()));
}
public void login() throws java.io.IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect(
“/bpbgp/j_spring_security_check?j_username=” + userId
+ “&j_password=” + password);
}
public void logout() throws java.io.IOException {
// FacesContext.getCurrentInstance().getExternalContext().redirect(
// “/bpbgp/j_spring_security_logout”);
ExternalContext ectx = FacesContext.getCurrentInstance()
.getExternalContext();
HttpServletResponse response = (HttpServletResponse) ectx.getResponse();
HttpSession session = (HttpSession) ectx.getSession(false);
session.invalidate();
FacesContext.getCurrentInstance().getExternalContext().redirect(
“/bpbgp/login.jsf”);
}
public String loginagain() {
return “success”;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
Step 4: Create following BPBGPSessionListener.java to monitor sessions. Create this file under src folder of root directory.
Package Name: com.sample.bpbgp.security
Class Name: BPBGPSessionListener
package com.sample.bpbgp.security;
import java.util.Date;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class BPBGPSessionListener implements HttpSessionListener {
public BPBGPSessionListener() {
}
public void sessionCreated(HttpSessionEvent event) {
System.out.println(“Current Session created : ”
+ event.getSession().getId() + ” at ” + new Date());
}
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
System.out.println(“Current Session destroyed :” + session.getId()
+ ” Logging out user”);
}
}
Step 5: Create following SessionTimeoutFilter.java. If session timeout happens then this class will redirect to login page. Create this file under src folder of root directory.
Package Name: com.sample.bpbgp.security
Class Name: SessionTimeoutFilter
package com.sample.bpbgp.security;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
public class SessionTimeoutFilter implements Filter {
private String timeoutPage = “login.jsf”;
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
if ((request instanceof HttpServletRequest)
&& (response instanceof HttpServletResponse)) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (isSessionControlRequiredForThisResource(httpServletRequest)) {
if (isSessionInvalid(httpServletRequest)) {
String timeoutUrl = httpServletRequest.getContextPath()
+ “/” + getTimeoutPage();
System.out
.println(“Session is invalid, redirecting to timeout page::”
+ timeoutUrl);
httpServletResponse.sendRedirect(timeoutUrl);
return;
}
}
}
filterChain.doFilter(request, response);
}
private boolean isSessionControlRequiredForThisResource(
HttpServletRequest httpServletRequest) {
String requestPath = httpServletRequest.getRequestURI();
boolean controlRequired = !StringUtils.contains(requestPath,
getTimeoutPage());
return controlRequired;
}
private boolean isSessionInvalid(HttpServletRequest httpServletRequest) {
boolean sessionInValid = (httpServletRequest.getRequestedSessionId() != null)
&& !httpServletRequest.isRequestedSessionIdValid();
return sessionInValid;
}
public void destroy() {
}
public String getTimeoutPage() {
return timeoutPage;
}
public void setTimeoutPage(String timeoutPage) {
this.timeoutPage = timeoutPage;
}
}
Step 6: Create following SGDefaultLdapAuthoritiesPopulator.java. This class we used to retrieve roles for the particular user. This is not required if user groups and roles are maintained in correct format. Instance of this class you can use DefaultLdapAuthoritiesPopulator. We have role value in users attribute, that’s why I have created this class. You may not need to customize this DefaultLdapAuthoritiesPopulator class for your project. Create this file under src folder of root directory.
Package Name: com.sample.bpbgp.security
Class Name: SGDefaultLdapAuthoritiesPopulator
package com.sample.bpbgp.security;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
public class SGDefaultLdapAuthoritiesPopulator extends
DefaultLdapAuthoritiesPopulator {
private String rolePrefix = “ROLE_”;
public SGDefaultLdapAuthoritiesPopulator(ContextSource contextSource,
String groupSearchBase) {
super(contextSource, groupSearchBase);
// TODO Auto-generated constructor stub
}
@Override
protected Set getAdditionalRoles(DirContextOperations user, String username) {
Set authorities = new HashSet();
Set roleName = user.getAttributeSortedStringSet(“pdsRole”);
Iterator it = roleName.iterator();
while (it.hasNext()) {
String role = (String) it.next();
role = role.toUpperCase();
authorities.add(new GrantedAuthorityImpl(rolePrefix + role));
}
return authorities;
}
}
Step 7: Now Create login.jsp . Create this file under src\main\webapp folder from root directory.
File Name: login.jsp
<%@ taglib uri=“http://java.sun.com/jsf/html” prefix=“h”%>
<%@ taglib uri=“http://java.sun.com/jsf/core” prefix=“f”%>
<%@ taglib uri=“http://myfaces.apache.org/tomahawk” prefix=“t”%>
<html>
<head>
<title>System Login</title>
<LINK href=“css/style1.css” rel=“stylesheet” type=“text/css”>
</head>
<body>
<f:view>
<h:form>
<center><h:outputLabel
value=“Welcome to University of Greenwich” styleClass=“loginhead” /></center>
<br>
<table class=“login” align=“center”>
<tr>
<td align=“center”><h:panelGrid columns=“1”
styleClass=“panelGridClass”>
<p><t:messages showDetail=“true” showSummary=“false”/></p>
<h:outputLabel value=“User Name” for=“j_username”
styleClass=“login” />
<t:inputText id=“j_username” forceId=“true”
value=”#{loginBacking.userId}” size=“40” maxlength=“80”
required=“true”></t:inputText>
<h:outputLabel value=“Password” for=“j_password” styleClass=“login” />
<t:inputSecret id=“j_password” forceId=“true”
value=”#{loginBacking.password}” size=“40” maxlength=“80”
redisplay=“true” required=“true”></t:inputSecret>
</h:panelGrid></td>
</tr>
<tr>
<td align=“center”><h:commandButton
action=”#{loginBacking.login}” value=“Login” /></td>
</tr>
</table>
</h:form>
</f:view>
</body>
</html>
Step 8: Now Create accessDenied.jsp. Create this file under src\main\webapp folder from root directory.
File Name: accessDenied.jsp
<%@ taglib uri=“http://java.sun.com/jsf/html” prefix=“h”%>
<%@ taglib uri=“http://java.sun.com/jsf/core” prefix=“f”%>
<html>
<head>
<title>Access Denied</title>
</head>
<body>
<f:view>
<h:form id=“form”>
<h:panelGrid id=“grid” columns=“1”>
<h:outputText id=“output1”
value=“Sorry, You don’t have the permissions.” />
</h:panelGrid>
<h:commandButton action=”#{loginBacking.logout}” value=“Logout” />
</h:form>
</f:view>
</body>
</html>
Step 9: Now Create logoutSuccess.jsp. Create this file under src\main\webapp folder from root directory.
File Name: logoutSuccess.jsp
<%@ taglib uri=“http://java.sun.com/jsf/html” prefix=“h” %>
<%@ taglib uri=“http://java.sun.com/jsf/core” prefix=“f”%>
<html>
<head>
<title>Logged out</title>
</head>
<body>
<f:view>
<h:form id=“form”>
<h:panelGrid id=“grid” columns=“1”>
<h:outputText id=“output1” value=“You have successfully logged out.”/>
</h:panelGrid>
</h:form>
</f:view>
</body>
</html>
Step 10: Now Create sessionExpired.jsp. Create this file under src\main\webapp folder from root directory.
File Name: sessionExpired.jsp
<%@page contentType=“text/html” pageEncoding=“UTF-8”%>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”
“http://www.w3.org/TR/html4/loose.dtd”>
<%@ taglib uri=“http://java.sun.com/jstl/core” prefix=“c”%>
<%
System.out.println(“Session Expired Redirecting to Login.jsf”);
%>
<c:redirect url=“/login.jsf” />
Step 11: Now Create hello.jsp. Create this file under src\main\webapp\pages folder from root directory.
File Name: hello.jsp
<%@ taglib uri=“http://java.sun.com/jsf/html” prefix=“h”%>
<%@ taglib uri=“http://java.sun.com/jsf/core” prefix=“f”%>
<html>
<head><title>Hello World</title>
</head>
<body>
<f:view>
<h:form id=“form”>
<h:panelGrid id=“grid” columns=“1”>
<h:outputText value=”HELLO #{sessionScope.SPRING_SECURITY_LAST_USERNAME}” />
<h:outputText value=“HELLO Welcome To Sample Application”/>
</h:panelGrid>
</h:form>
</f:view>
</body>
</html>
Step 12: Now we have to create config file for JSF(faces-config.xml). Create this file under src\main\webapp\WEB-INF folder from root directory.
File Name: faces-config.xml
<?xml version=“1.0” encoding=“UTF-8”?>
<!DOCTYPE faces-config PUBLIC
“-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN”
“http://java.sun.com/dtd/web-facesconfig_1_1.dtd”>
<faces-config>
<application>
<message-bundle>ValidationResources</message-bundle>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
<locale-config>
<default-locale>en_US</default-locale>
<supported-locale>fr</supported-locale>
</locale-config>
</application>
<managed-bean>
<managed-bean-name>loginBacking</managed-bean-name>
<managed-bean-class>com.sample.bpbgp.security.LoginBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-outcome>login</from-outcome>
<to-view-id>/j_spring_security_check.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/accessDenied.jsp</from-view-id>
<navigation-case>
<from-outcome>logout</from-outcome>
<to-view-id>/j_spring_security_logout</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>logout</from-outcome>
<to-view-id>/j_spring_security_logout</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>accessDenied</from-outcome>
<to-view-id>/accessDenied.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Step 13: Now we have to create config file for Spring(webContext.xml). Create this file under src\main\webapp\WEB-INF folder from root directory.
File Name: webContext.xml
<?xml version=“1.0” encoding=“UTF-8”?>
<beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:aop=“http://www.springframework.org/schema/aop”
xmlns:jee=“http://www.springframework.org/schema/jee” xmlns:lang=“http://www.springframework.org/schema/lang”
xmlns:tx=“http://www.springframework.org/schema/tx” xmlns:util=“http://www.springframework.org/schema/util”
xmlns:security=“http://www.springframework.org/schema/security”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd”>
<!– LDAP Security Start–>
<bean id=“filterChainProxy” class=“org.springframework.security.util.FilterChainProxy”>
<security:filter-chain-map path-type=“ant”>
<security:filter-chain pattern=“/**”
filters=“
httpSessionContextIntegrationFilterWithASCTrue,
authenticationProcessingFilter,
exceptionTranslationFilter,
anonymousProcessingFilter,
filterSecurityInterceptor” />
</security:filter-chain-map>
</bean>
<bean id=“httpSessionContextIntegrationFilterWithASCTrue”
class=“org.springframework.security.context.HttpSessionContextIntegrationFilter”>
<property name=“allowSessionCreation” value=“true” />
</bean>
<bean id=“authenticationProcessingFilter”
class=“org.springframework.security.ui.webapp.AuthenticationProcessingFilter”>
<property name=“authenticationManager” ref=“authenticationManager” />
<property name=“authenticationFailureUrl” value=“/accessDenied.jsf” />
<property name=“defaultTargetUrl” value=“/pages/hello.jsf” />
<property name=“filterProcessesUrl” value=“/j_spring_security_check” />
</bean>
<bean id=‘authenticationManager’ class=‘org.springframework.security.providers.ProviderManager’>
<property name=‘providers’>
<list>
<ref bean=‘ldapAuthProvider’ />
</list>
</property>
</bean>
<bean id=“exceptionTranslationFilter”
class=“org.springframework.security.ui.ExceptionTranslationFilter”>
<property name=“authenticationEntryPoint”>
<ref bean=“formLoginAuthenticationEntryPoint” />
</property>
<property name=“accessDeniedHandler”>
<bean class=“org.springframework.security.ui.AccessDeniedHandlerImpl”>
<property name=“errorPage” value=“/accessDenied.jsf” />
</bean>
</property>
</bean>
<bean id=“formLoginAuthenticationEntryPoint”
class=“org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint”>
<property name=“loginFormUrl”>
<value>/login.jsp</value>
</property>
<property name=“forceHttps”>
<value>false</value>
</property>
</bean>
<bean id=“filterSecurityInterceptor”
class=“org.springframework.security.intercept.web.FilterSecurityInterceptor”>
<property name=“authenticationManager” ref=“authenticationManager” />
<property name=“accessDecisionManager” ref=“accessDecisionManager” />
<property name=“objectDefinitionSource”>
<security:filter-invocation-definition-source>
<security:intercept-url pattern=“/pages/**”
access=“ROLE_ADMIN” />
<security:intercept-url pattern=“/facality/**”
access=“ROLE_FACULTY” />
<security:intercept-url pattern=“/**”
access=“IS_AUTHENTICATED_ANONYMOUSLY” />
</security:filter-invocation-definition-source>
</property>
</bean>
<bean id=“accessDecisionManager” class=“org.springframework.security.vote.AffirmativeBased”>
<property name=“decisionVoters”>
<list>
<bean class=“org.springframework.security.vote.RoleVoter” />
<bean class=“org.springframework.security.vote.AuthenticatedVoter” />
</list>
</property>
</bean>
<bean id=“anonymousProcessingFilter”
class=“org.springframework.security.providers.anonymous.AnonymousProcessingFilter”>
<property name=“key” value=“anonymousUser” />
<property name=“userAttribute” value=“ANONYMOUSUSER,PRIV_ANONYMOUS” />
</bean>
<bean id=“contextSource”
class=“org.springframework.security.ldap.DefaultSpringSecurityContextSource”>
<constructor-arg value=“ldap://metal.sct.co.in:389” />
<property name=“userDn” value=“cn=Directory Manager” />
<property name=“password” value=“pipeline” />
</bean>
<bean id=“ldapAuthProvider” class=“org.springframework.security.providers.ldap.LdapAuthenticationProvider”>
<constructor-arg ref=“authenticator” />
<constructor-arg ref=“populator” />
<security:custom-authentication-provider />
</bean>
<bean id=“authenticator”
class=“org.springframework.security.providers.ldap.authenticator.BindAuthenticator”>
<constructor-arg ref=“contextSource” />
<property name=“userSearch”>
<bean id=“userSearch”
class=“org.springframework.security.ldap.search.FilterBasedLdapUserSearch”>
<constructor-arg index=“0” value=“ou=People,o=sct.co.in,o=cp” />
<constructor-arg index=“1” value=“(uid={0})” />
<constructor-arg index=“2” ref=“contextSource” />
<property name=“searchSubtree” value=“true” />
</bean>
</property>
<!– If you they want userid as login then uncomment this –>
<!–
<property> <list>
<value>uid={0},ou=People,o=sct.co.in,o=cp</value> </list> </property>
–>
</bean>
<bean id=“populator”
class=“com.sample.bpbgp.security.SGDefaultLdapAuthoritiesPopulator”>
<constructor-arg ref=“contextSource” />
<constructor-arg value=“ou=AccessGroups,o=sct.co.in,o=cp” />
<property name=“groupRoleAttribute” value=“cn” />
<property name=“searchSubtree” value=“false” />
<property name=“convertToUpperCase” value=“true” />
<property name=“rolePrefix” value=“ROLE_” />
<property name=“groupSearchFilter” value=“(member={0})” />
</bean>
<!– Ldap Security End –>
</beans>
Step 14: Now we have to create config file for our web application(web.xml). Create this file under src\main\webapp\WEB-INF folder from root directory.
File Name: web.xml
<?xml version=“1.0” encoding=“UTF-8”?>
<web-app id=“WebApp_ID” version=“2.4”
xmlns=“http://java.sun.com/xml/ns/j2ee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd”>
<display-name>JSF Web ApplicationJSF App</display-name>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/webContext.xml</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
<listener>
<listener-class>com.sample.bpbgp.security.BPBGPSessionListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<filter>
<filter-name>filterChainProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>SessionTimeoutFilter</filter-name>
<filter-class>com.sample.bpbgp.security.SessionTimeoutFilter</filter-class>
</filter>
<filter>
<display-name>Ajax4jsf Filter</display-name>
<filter-name>ajax4jsf</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>filterChainProxy</filter-name>
<url-pattern>/pages/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>SessionTimeoutFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/sessionExpired.jsf</location>
</error-page>
</web-app>
Step 15: Now we have to create css file for our application. Create this file under src\main\webapp\css folder from root directory.
File Name: style1.css
/* CSS file */
table.login {
width: 30%;
border: 1px solid #e5eff8;
text-align: center;
align: center
}
TABLE.panelGridClass {
width: 300px;
margin: 0px auto;
}
TABLE.panelGridClass TR TD {
width: 100%;
}
TABLE.panelGridClass TR TD INPUT {
width: 100%;
}
Lable.login {
font-size: 14 position : absolute;
text-align: center;
}
Lable.loginhead {
font-size: 18 position : absolute;
text-align: center;
}
Step 16: Now we have to create build properties file for our application. Create this file under src\main\assembly folder from root directory.
File Name: build.properties
### Commonly used directory structures used across the Flex Reg projects…
PROJECT_SRC_DIR=../src
PROJECT_MN_DIR=../src/main
JAVA_SRC_DIR=../src/main/java
FILTERS_DIR=../src/main/filters
CONFIG_DIR=../src/main/config
WEBAPP_DIR=../src/main/webapp
WEBAPP_PAGES_DIR=../src/main/webapp/pages
WEBAPP_IMGS_DIR=../src/main/webapp/imgs
WEBAPP_CSS_DIR=../src/main/webapp/css
WEB-INF_DIR=../src/main/webapp/WEB-INF
ASSMBLY_META-INF_DIR=../src/main/assembly/META-INF
PROJECT_TEST_DIR=../src/test
TEST_JAVA_DIR=../src/test/java
TEST_RSCRS_DIR=../src/test/resources
TEST_FILTERS_DIR=../src/test/filters
PROJECT_SITE_DIR=../src/site
RSRCS_DIR=../src/main/resources
# Target folders
ASSMBLY_DIR=../target/assembly
CLASSES_DIR=../target/classes
TARGET_DIR=../target
WEBAPP_TARGET_DIR=../target/webapp
WEBAPP_PAGES_TARGET_DIR=../target/webapp/pages
WEBAPP_IMGS_TARGET_DIR=../target/webapp/imgs
WEBAPP_CSS_TARGET_DIR=../target/webapp/css
# Replaces WEB-INF_DIR
WEB-INF_TARGET_DIR=../target/webapp/WEB-INF/
# Replaces WEB-INF_CLASSES_DIR
WEB-INF_CLASSES_TARGET_DIR=../target/webapp/WEB-INF/classes
# Replaces WEB-INF_LIB_TARGET_DIR
WEB-INF_LIB_TARGET_DIR=../target/webapp/WEB-INF/lib
WAR_TARGET_DIR=../target
javac.debug=on
javac.deprecation=on
javac.nowarn=off
Step 17: Now create build file for our application. Create this file under src\main\assembly folder from root directory.
File Name: build.xml
<?xml version=”1.0″?>
<!– ======================================================================
${date} ${time}
${project}
${description}
${user}
====================================================================== –>
<project name=”Sample JSF Web Application” default=”ALL” basedir=”../../” xmlns:artifact=”antlib:org.apache.maven.artifact.ant”>
<property name=”PROJECT_ROOT” value=”${basedir}” />
<property name=”RSRCS_DIR” value=”${PROJECT_ROOT}/main/resources” />
<property file=”${PROJECT_ROOT}/main/assembly/build.properties” />
<artifact:pom id=”maven.project” file=”../pom.xml” />
<artifact:dependencies pathId=”maven.dependency.classpath” filesetId=”maven.dependency.fileset” verbose=”false”>
<pom refid=”maven.project” />
</artifact:dependencies>
<path id=”classpath”>
<path refid=”maven.dependency.classpath” />
</path>
<target name=”init”>
<echo message=”Initializing directories under Sample JSF Web Application Project Root: ${PROJECT_ROOT}” />
<tstamp />
<mkdir dir=”${CLASSES_DIR}” />
<mkdir dir=”${PROJECT_SRC_DIR}” />
<mkdir dir=”${PROJECT_MN_DIR}” />
<mkdir dir=”${JAVA_SRC_DIR}” />
<mkdir dir=”${RSRCS_DIR}” />
<mkdir dir=”${FILTERS_DIR}” />
<mkdir dir=”${CONFIG_DIR}” />
<mkdir dir=”${WEBAPP_DIR}” />
<mkdir dir=”${WEB-INF_DIR}” />
<mkdir dir=”${WEB-INF_LIB_TARGET_DIR}” />
<mkdir dir=”${ASSMBLY_DIR}” />
<mkdir dir=”${ASSMBLY_META-INF_DIR}” />
<mkdir dir=”${PROJECT_TEST_DIR}” />
<mkdir dir=”${TEST_JAVA_DIR}” />
<mkdir dir=”${TEST_RSCRS_DIR}” />
<mkdir dir=”${TEST_FILTERS_DIR}” />
<mkdir dir=”${PROJECT_SITE_DIR}” />
</target>
<target name=”ALL” description=”Build and package the project”>
<echo message=”Executing Sample JSF Web Application WAR file build…” />
<antcall target=”assembleWar” />
</target>
<target name=”clean” description=”Clean the project”>
<echo message=”Cleaning web app assembly folder… ${ASSMBLY_DIR}” />
<echo message=”Cleaning classes folder… ${CLASSES_DIR}” />
<echo message=”Cleaning web inf lib folder… ${WEB-INF_LIB_TARGET_DIR}” />
<delete includeemptydirs=”true” quiet=”true”>
<fileset dir=”${ASSMBLY_DIR}” includes=”**/*” />
<fileset dir=”${CLASSES_DIR}” includes=”**/*” />
<fileset dir=”${WEB-INF_LIB_TARGET_DIR}” includes=”**/*” />
</delete>
</target>
<target name=”compile” description=”Compile Java source files” depends=”init”>
<echo message=”Compiling Java source files…” />
<javac destdir=”${CLASSES_DIR}” classpathref=”classpath” debug=”${javac.debug}” nowarn=”${javac.nowarn}” deprecation=”${javac.deprecation}” encoding=”default” source=”1.5″ target=”1.5″>
<src path=”${JAVA_SRC_DIR}” />
<src path=”${TEST_JAVA_DIR}” />
</javac>
<copy todir=”${CLASSES_DIR}”>
<fileset dir=”${JAVA_SRC_DIR}”>
<patternset>
<include name=”**/*.properties” />
<include name=”**/*.xml” />
</patternset>
</fileset>
<fileset dir=”${TEST_JAVA_DIR}”>
<patternset>
<include name=”**/*.properties” />
<include name=”**/*.xml” />
</patternset>
</fileset>
</copy>
</target>
<target name=”copyWebAppToAssemblyDir” description=”Copying web app files to the assembly directory…”>
<echo message=”Copying web app files to the assembly directory…” />
<copy todir=”${WEBAPP_TARGET_DIR}”>
<fileset dir=”${WEBAPP_DIR}”>
<include name=”*” />
<include name=”**/*.xml” />
</fileset>
</copy>
</target>
<target name=”copyWebAppPagesToAssemblyDir” description=”Copying web app page files to the assembly directory…”>
<echo message=”Copying web app pages to the assembly directory…” />
<copy todir=”${WEBAPP_PAGES_TARGET_DIR}”>
<fileset dir=”${WEBAPP_PAGES_DIR}”>
<include name=”*” />
</fileset>
</copy>
</target>
<target name=”copyWebAppImagesToAssemblyDir” description=”Copying web app image files to the assembly directory…”>
<echo message=”Copying web app image files to the assembly directory…” />
<copy todir=”${WEBAPP_IMGS_TARGET_DIR}”>
<fileset dir=”${WEBAPP_IMGS_DIR}”>
<include name=”*” />
</fileset>
</copy>
</target>
<target name=”copyWebAppCSSToAssemblyDir” description=”Copying web app CSS files to the assembly directory…”>
<echo message=”Copying web app CSS files to the assembly directory…” />
<copy todir=”${WEBAPP_CSS_TARGET_DIR}”>
<fileset dir=”${WEBAPP_CSS_DIR}”>
<include name=”*” />
</fileset>
</copy>
</target>
<target name=”copyResourcesToAssemblyDir” description=”Copying Hibernate resource files to the assembly directory…”>
<echo message=”Copying Hibernate resource files to the assembly directory…” />
<echo message=”… copying spring files to WEB-INF” />
<copy todir=”${WEB-INF_CLASSES_TARGET_DIR}”>
<fileset dir=”${RSRCS_DIR}”>
<include name=”**/*” />
</fileset>
</copy>
</target>
<target name=”copyHibernateResourcesToAssemblyDir” description=”Copying web app CSS files to the assembly directory…”>
<echo message=”Copying web app CSS files to the assembly directory…” />
<copy todir=”${WEBAPP_CSS_TARGET_DIR}”>
<fileset dir=”${WEBAPP_CSS_DIR}”>
<include name=”*” />
</fileset>
</copy>
</target>
<target name=”copyConfigFilesToAssmblyDir” description=”Copies the config files to the Assembly dir”>
<echo message=”Copying config files to root assembly directory…” />
<copy todir=”${ASSMBLY_DIR}” overwrite=”true”>
<fileset dir=”${JAVA_SRC_DIR}”>
<include name=”*.xml” />
<include name=”*.properties” />
</fileset>
</copy>
</target>
<target name=”copyClassFilesToWebInfClassesDir” description=”Copies the compiled class files to the WEB-INF/classes dir”>
<echo message=”Copying compiled class files to the WEB-INF/classes directory…” />
<copy todir=”${WEB-INF_CLASSES_TARGET_DIR}” overwrite=”true”>
<fileset dir=”${CLASSES_DIR}” />
<fileset dir=”${CLASSES_DIR}”>
<patternset>
<include name=”**/*.xml” />
<include name=”**/*.properties” />
</patternset>
</fileset>
</copy>
</target>
<target name=”copyJarFilesToWebInfLibDir” description=”Copies the jar files from the maven dependencies to the WEB-INF/lib dir”>
<echo message=”Copying maven dependency jar files to the WEB-INF/lib directory…” />
<copy todir=”${WEB-INF_LIB_TARGET_DIR}” overwrite=”true”>
<fileset refid=”maven.dependency.fileset” />
<!– This mapper strips off all leading directory information –>
<mapper type=”flatten” />
</copy>
</target>
<target name=”assembleWar” description=”Assembles the Sample JSF Web Application WAR file” depends=”clean, compile, copyWebAppToAssemblyDir, copyWebAppPagesToAssemblyDir, copyWebAppImagesToAssemblyDir, copyWebAppCSSToAssemblyDir, copyClassFilesToWebInfClassesDir, copyHibernateResourcesToAssemblyDir, copyConfigFilesToAssmblyDir, copyResourcesToAssemblyDir, copyJarFilesToWebInfLibDir”>
<echo message=”Assembling Sample JSF Web Application War file…” />
<delete file=”${WAR_TARGET_DIR}/bpbgp.war” />
<war destfile=”${WAR_TARGET_DIR}/bpbgp.war” webxml=”${WEB-INF_TARGET_DIR}/web.xml” excludes=”build.xml, build.properties”>
<webinf dir=”${WEB-INF_TARGET_DIR}”>
<include name=”*.xml” />
<include name=”*.properties” />
</webinf>
<lib dir=”${WEB-INF_LIB_TARGET_DIR}”>
<include name=”*.jar” />
<exclude name=”el-api-1.0.jar”/>
</lib>
<fileset dir=”${WEBAPP_TARGET_DIR}”>
<include name=”**/*.*” />
<include name=”*.html” />
<include name=”*.jsp” />
<include name=”*.properties” />
<exclude name=”WEB-INF/*.*” />
<exclude name=”WEB-INF/**/*.*” />
</fileset>
<classes dir=”${WEB-INF_CLASSES_TARGET_DIR}” />
</war>
</target>
</project>
Step 18: Now run ant build. Using ant command.
Step 19: Deploy the application war file in tomcat webapps directory.
Step 20: type following URL in brower
http://localhost:8080/bpbgp/login.jsf
Step 21: Give your LDAP userID, Password for login.
Developing Web Services by using Mule, CXF, and Spring
Introduction
In this article we are going to develop a web service by using Spring with CXF and the Mule Enterprise Service Bus. This article provides steps (step by step) to create & deploy web services by using Spring,CXF and mule. Please go through below to find sample web services.
Software Requirements
- EClipse (Java IDE)- Optional
- Mule ESB (Download from http://www.mulesoft.org/display/MULE/Download)
- CXF Jars (Required for Compilation-Download from http://cxf.apache.org/download.html)
The Code
In this example, we are going to create a Student service, where students can register for particular course. In this example, we are going to use a code-first approach for this service using JAX-WS annotations.
First, we will need to create following classes and interface
- Our User-Defined Exception
- The interface for our service
- The implementation class for our service
- Our Student bean
Step 1: Create new java project in EClipse
Step 2: Create the Exception class for our service (NotEnoughValueException.java)
package com.peter.cxf.sample;
public class NotEnoughValueException extends Exception {
String detail;
public NotEnoughValueException (String message, String detail) {
super (message);
this.detail = detail;
}
public String getDetail () {
return detail;
}
}
Step 3: Create the interface for our service (StudentService.java)
package com.peter.cxf.sample;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
@WebService
public interface StudentService {
@WebResult(name = “registrationstatus”)
public String registerStudent(@WebParam(name = “student”) Student stu)
throws NotEnoughValueException;
}
Step 4: Create the implementation class for our service (StudentServiceImpl.java)
package com.peter.cxf.sample;
import javax.jws.WebService;
@WebService(endpointInterface = “com.peter.cxf.sample.StudentService”, serviceName = “StudentService”)
public class StudentServiceImpl {
/**
*
* @param stu
* @return
* @throws NotEnoughValueException
*/
public String registerStudent(Student stu) throws NotEnoughValueException {
if (validate(stu)) {
return “Hi ” + stu.getFirstName() + ” ” + stu.getLastName()
+ ” Your registertion is accepted. You Can join the course”;
} else {
throw new NotEnoughValueException(“Input values are not enough”,
“Please check you data”);
}
}
private boolean validate(Student stu) {
if ((stu.getFirstName() != null || stu.getFirstName().trim().equals(“”))
&& (stu.getLastName() != null || stu.getLastName().trim()
.equals(“”))
&& (stu.getPhoneNumber() != null || stu.getPhoneNumber().trim()
.equals(“”)))
return true;
else
return false;
}
}
Configuration
To run our service under Mule, we need to create following configuration files:
- Spring configuration file
- Mule configuration file
Step 5: Create the Spring Configuration file in project root folder (studentContext.xml)
<?xml version=“1.0” encoding=“UTF-8”?>
<beans xmlns=“http://www.springframework.org/schema/beans”
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-2.5.xsd”>
<bean id=“studentService” class=“com.peter.cxf.sample.StudentServiceImpl”
scope=“singleton”>
</bean>
</beans>
Step 6: Create the Mule Configuration file in project root folder (studentservice-config.xml)
<?xml version=“1.0” encoding=“UTF-8”?>
<mule xmlns=“http://www.mulesource.org/schema/mule/core/2.2”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:spring=“http://www.springframework.org/schema/beans”
xmlns:soap=“http://www.mulesource.org/schema/mule/soap/2.2” xmlns:cxf=“http://www.mulesource.org/schema/mule/cxf/2.2”
xsi:schemaLocation=“
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd
http://www.mulesource.org/schema/mule/soap/2.2 http://www.mulesource.org/schema/mule/soap/2.2/mule-soap.xsd
http://www.mulesource.org/schema/mule/cxf/2.2 http://www.mulesource.org/schema/mule/cxf/2.2/mule-cxf.xsd”>
<spring:beans>
<spring:import resource=“studentContext.xml” />
</spring:beans>
<model name=“services”>
<service name=“StudentService”>
<inbound>
<cxf:inbound-endpoint
address=“http://localhost:65082/services/StudentService” />
</inbound>
<component>
<spring-object bean=“studentService” />
</component>
</service>
</model>
</mule>
Build and Deployment
Step 7: Create the folder ‘ant’ inside the project root folder
Step 8: Create the build.xml file inside ant folder.
<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”ws” basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”cxfstudentservices.jar”>
<fileset dir=”${basedir}\bin”>
<include name=”**/*.class” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml” />
<exclude name=”**/*build*” />
</fileset>
</jar>
</target>
</project>
Step 9: run Ant build
Step 10: Copy cxfstudentservices.jar file from project root folder and copy it in MULE_HOME/lib/user folder.
Starting the service
To start the service in mule you have run following command in command prompt.
In Windows: MULE_HOME/bin/mule.bat -config <path-to-config-file>\studentservice-config.xml
For Example:
c:\mule-standalone-2.2.1\bin\mule.bat -config D:\Java Code\CXFMuleStudentService\studentservice-config.xml
Please ensure that your service is up and running by opening following url in your web browser.
http://localhost:65082/services/StudentService?wsdl
Testing the service
To test your service, please check my previous posts, to create client program for web services.
Developing Web Services by Using Metro Webservices Framework
Introduction
In this article we are going to develop a web service by using Metro Web Services framework. This article provides steps (step by step ) to create & deploy web services by using Metro. Please go through below to find sample web services.
Software Requirements
- EClipse (Java IDE)- Optional
- Metro Web services framework (Download from https://metro.dev.java.net/)
The Code
In this example, we are going to create a Arithmetic service, to add two numbers. In this example, we are going to use a code-first approach for this service using JAX-WS annotations.
Creating Server Application
Step 1: Download Following Jar files.
activation.jar
FastInfoset.jar
http.jar
jaxb-api.jar
jaxb-impl.jar
jaxb-xjc.jar
jaxws-api.jar
jsr181-api.jar
jsr250-api.jar
saaj-api.jar
saaj-impl.jar
jsr173_api.jar
woodstox.jar
resolver.jar
stax-ex.jar
streambuffer.jar
jaxws-rt.jar
mimepull.jar
webservices-api.jar
webservices-extra-api.jar
webservices-extra.jar
webservices-rt.jar
webservices-tools.jar
activation.jar
FastInfoset.jar
http.jar
jaxb-api.jar
jaxb-impl.jar
jaxb-xjc.jar
jaxws-api.jar
jsr181-api.jar
jsr250-api.jar
saaj-api.jar
saaj-impl.jar
jsr173_api.jar
woodstox.jar
resolver.jar
stax-ex.jar
streambuffer.jar
jaxws-rt.jar
mimepull.jar
webservices-api.jar
webservices-extra-api.jar
webservices-extra.jar
webservices-rt.jar
webservices-tools.jar
Step 2: Create New Java project in eclipse (MetroWebServices).
Step 3: Create WEB-INF,ant folder inside project folder.
Step 4: Create classes folder inside WEB-INF folder.
Step 5: Create lib folder inside WEB-INF folder.
Step 6: Copy all the jar file into lib folder.
Step 7: Add all jar files into classpath (In Eclipse set java build path->Libraries). Add set Default output folder into MetroWebServices/WEB-INF/classes
Step 8: Create ArithmeticException.java for user defined exception.
package com.sungard.sample.metro.webservices;
public class ArithmeticException extends Exception {
String detail;
public ArithmeticException (String message, String detail) {
super (message);
this.detail = detail;
}
public String getDetail () {
return detail;
}
}
Step 9: Create Web services class ArithmeticImpl.java
package com.sungard.sample.metro.webservices;
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService
public class ArithmeticImpl {
/**
* @param number1
* @param number2
* @return The sum
* @throws ArithmeticException
* if any of the numbers to be added is negative.
*/
@WebMethod
public int addTwoNumbers(int number1, int number2) throws ArithmeticException {
if (number1 < 0 || number2 < 0) {
throw new ArithmeticException(“Negative number cant be added!”,
“Numbers: ” + number1 + “, ” + number2);
}
return number1 + number2;
}
}
Step 10: Inside Web-Inf folder create following xml to define endpoint class.
sun-jaxws.xml
<?xml version=“1.0” encoding=“UTF-8”?>
<endpoints xmlns=‘http://java.sun.com/xml/ns/jax-ws/ri/runtime’ version=‘2.0’>
<endpoint
name=‘sungardServices’
implementation=‘com.sungard.sample.metro.webservices.ArithmeticImpl’
url-pattern=‘/addTwoNumbers’/>
</endpoints>
Step 11: Create Web.xml file inside web-inf folder as follows.
web.xml
<?xml version=“1.0” encoding=“UTF-8”?>
<web-app version=“2.4” xmlns=“http://java.sun.com/xml/ns/j2ee”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd”>
<description>sungardServices</description>
<display-name>sungardServices</display-name>
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<description>JAX-WS endpoint – sungardServices</description>
<display-name>sungardServices</display-name>
<servlet-name>sungardServices</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>sungardServices</servlet-name>
<url-pattern>/addTwoNumbers</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
Step 12: Create build.xml file inside ant folder.
build.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”ws” basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”metroservices.war”>
<fileset dir=”${basedir}”>
<include name=”**/*.class” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml” />
<exclude name=”**/*build*” />
</fileset>
</jar>
</target>
</project>
Step 13: Run ant build
Step 14: Deploy metroservices.war file in tomcat server (or in some web server).
Step 15: To verify application deployed successfully or not use following url.
http://localhost:8080/metroservices/addTwoNumbers?wsdl
Step 16: Browser will show wsdl file our web service.
Creating Client Application
Step 1: Create customizationfiles folder inside project folder.
Step 2: Crate following xml file inside customizationfiles folder.
custom-client.xml
<?xml version=“1.0” encoding=“UTF-8” standalone=“yes”?>
<bindings
xmlns:xsd=“http://www.w3.org/2001/XMLSchema”
xmlns:wsdl=“http://schemas.xmlsoap.org/wsdl/”
wsdlLocation=“http://localhost:8080/metroservices/addTwoNumbers?wsdl”
xmlns=“http://java.sun.com/xml/ns/jaxws”>
<bindings node=“wsdl:definitions”>
<package name=“com.sungard.sample.metro.webservices.client”/>
</bindings>
</bindings>
Step 3: Crate following xml file inside customizationfiles folder.
custom-schema.xml
<?xml version=“1.0” encoding=“UTF-8” standalone=“yes”?>
<bindings
xmlns:xsd=“http://www.w3.org/2001/XMLSchema”
xmlns=“http://java.sun.com/xml/ns/jaxb”
version=“1.0”>
<bindings schemaLocation=“http://localhost:8080/metroservices/addTwoNumbers?xsd=1” node=“/xsd:schema”>
<schemaBindings>
<package name=“com.sungard.sample.metro.webservices.client”/>
</schemaBindings>
</bindings>
</bindings>
Step 4: Create following build xml for client application inside ant folder.
buildclient.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”ws” basedir=”../” default=”generate-client”>
<path id=”wsit.classpath”>
<pathelement location=”${java.home}/../lib/tools.jar” />
<fileset dir=”${basedir}/WEB-INF/lib/”>
<include name=”jaxb-xjc.jar” />
<include name=”jaxb-api.jar” />
<include name=”jaxb-impl.jar” />
<include name=”webservices-api.jar” />
<include name=”webservices-rt.jar” />
<include name=”webservices-tools.jar” />
<include name=”webservices-extra.jar” />
<include name=”webservices-extra-api.jar” />
<include name=”javaee.jar” />
<include name=”activation.jar” />
</fileset>
</path>
<taskdef name=”wsimport” classname=”com.sun.tools.ws.ant.WsImport”>
<classpath refid=”wsit.classpath” />
</taskdef>
<target name=”generate-client”>
<wsimport debug=”false” verbose=”false” keep=”true”
extension=”${extension}” destdir=”${basedir}/src”
wsdl=”http://localhost:8080/metroservices/addTwoNumbers?wsdl”>
<binding dir=”${basedir}/customizationfiles” includes=”custom-client.xml, custom-schema.xml” />
</wsimport>
</target>
</project>
Step 5: Run buildclient.xml file using ant.
Step 6: Create Client.java file to invoke webservices.
package com.sungard.sample.metro.webservices.client;
public class Client {
public static void main(String[] args) {
try {
ArithmeticImpl impl = new ArithmeticImplService()
.getArithmeticImplPort();
int number1 = 10;
int number2 = 20;
System.out
.printf(“Invoking addNumbers(%d, %d)\n”, number1, number2);
int result;
result = impl.addTwoNumbers(number1, number2);
System.out.printf(“The result of adding %d and %d is %d.\n\n”,
number1, number2, result);
number1 = -10;
System.out
.printf(“Invoking addNumbers(%d, %d)\n”, number1, number2);
result = impl.addTwoNumbers(number1, number2);
System.out.printf(“The result of adding %d and %d is %d.\n”,
number1, number2, result);
} catch (ArithmeticException_Exception e) {
e.printStackTrace();
}
}
}
Step 7: run Client.java file in your eclipse. You will be getting following output.
Invoking addNumbers(10, 20)
The result of adding 10 and 20 is 30.
Invoking addNumbers(-10, 20)
com.sungard.sample.metro.webservices.client.ArithmeticException_Exception: Negative number cant be added!
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:141)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
at $Proxy38.addTwoNumbers(Unknown Source)
at com.sungard.sample.metro.webservices.client.Client.main(Client.java:24)
Caused by: com.sungard.sample.metro.webservices.ArithmeticException: Negative number cant be added!
at com.sungard.sample.metro.webservices.ArithmeticImpl.addTwoNumbers(ArithmeticImpl.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.sun.xml.ws.api.server.InstanceResolver$1.invoke(InstanceResolver.java:246)
at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:146)
at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:257)
at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:93)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:598)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:557)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:542)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:439)
at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:243)
at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:471)
at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:135)
at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:129)
at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doPost(WSServletDelegate.java:160)
at com.sun.xml.ws.transport.http.servlet.WSServlet.doPost(WSServlet.java:75)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:595)
Developing CXF WS-Security with Spring & Acegi Security
Introduction
In this article we are going to develop a web service by using Spring with CXF and the Acegi Security. This article provides steps (step by step) to create & deploy web services by using Spring,CXF andAcegi Security. Please go through below to find sample web services.
Software Requirements
- EClipse (Java IDE)- Optional
- CXF Jars (Required for Compilation-Download from http://cxf.apache.org/download.html)
The Code
In this example, we are going to create a Hello service. In this example, we are going to use a code-first approach for this service using JAX-WS annotations.
Creating Server Application
Step 1: Download Following Jar files.
activation.jar
aopalliance-1.0.jar
commons-collections-3.2.jar
commons-lang-2.1.jar
commons-logging-1.1.jar
geronimo-activation-2.0.1.jar
geronimo-annotation_1.0_spec-1.1.jar
geronimo-javamail_1.4_mail-1.2.jar
geronimo-servlet_2.5_spec-1.1.jar
geronimo-ws-metadata_2.0_spec-1.1.1.jar
jaxb-api.jar
jaxb-api-2.0.jar
jaxb-impl-2.0.5.jar
jaxb-xjc.jar
jaxws-api.jar
mail.jar
neethi-2.0.jar
opensaml-1.0.1.jar
saaj-api.jar
saaj-impl.jar
spring-beans-2.0.6.jar
spring-context-2.0.6.jar
spring-core-2.0.6.jar
spring-web-2.0.6.jar
stax-api-1.0.1.jar
velocity-1.5.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.1.jar
xalan-2[1].6.0.jar
xalan-2[1].7.0.jar
xml-resolver-1.2.jar
xmlsec-1.2.1.jar
cxf-bundle-2.0.4-incubator.jar
XmlSchema-1.3.2.jar
wss4j-1.5.1.jar
acegi-security-1.0.5.jar
spring-dao-2.0.7.jar
Step 2: Create New Java project in eclipse (CXFAcegiSecurity).
Step 3: Create WEB-INF folder inside project folder.
Step 4: Create classes folder inside WEB-INF folder.
Step 5: Create lib folder inside WEB-INF folder.
Step 6: Copy all the jar file into lib folder.
Step 7: Add all jar files into classpath (In Eclipse set java build path->Libraries). Add set Default output folder into CXFAcegiSecurity/WEB-INF/classes
Step 8: Create Remote Interface IHello.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 9: Create Implementation Class IHello_Impl.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService(endpointInterface = “com.sungard.cxf.example.server.IHello”)
public class IHello_Impl implements IHello {
public String sayHello(String value) {
return “You Said” + value;
}
}
Step 10: Create User.java to store User details in java object. Acegi Security Service is using this object.
package com.sungard.cxf.example.server;
public class User {
private String userId;
private String password;
private String role;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public User(String userId, String password, String role) {
super();
this.userId = userId;
this.password = password;
this.role = role;
}
}
Step 11: Create MyGrantedAuthority.java to grand Authority.
package com.sungard.cxf.example.server;
import org.acegisecurity.GrantedAuthority;
public class MyGrantedAuthority implements GrantedAuthority {
private String authority = null;
public MyGrantedAuthority(String authority) {
this.authority = authority;
}
public String getAuthority() {
return authority;
}
}
Step 12: Create MyUserDetails.java class to Store User details.
package com.sungard.cxf.example.server;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;
public class MyUserDetails implements UserDetails {
private GrantedAuthority[] authorities = null;
private String password = null;
private String username = null;
private String additionalData = null;
public MyUserDetails(GrantedAuthority[] authorities, String password,
String username, String additionalData) {
super();
this.authorities = authorities;
this.password = password;
this.username = username;
this.additionalData = additionalData;
}
public GrantedAuthority[] getAuthorities() {
return authorities;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return true;
}
}
Step 13: Create MyUserDetailsService.java to load user details. By creating these classes we are customizing Acegi security framework
In this class I have used peter as user. You can use any name.
tUsers.put(“peter”, new User(“peter”, “arockiaraj”, “ROLE_ADMIN”));
package com.sungard.cxf.example.server;
import java.util.HashMap;
import java.util.Map;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
public class MyUserDetailsService implements UserDetailsService {
private Map users = init();
private Map init() {
Map tUsers = new HashMap();
tUsers.put(“scott”, new User(“scott”, “tiger”, “ROLE_USER”));
tUsers.put(“harry”, new User(“harry”, “potter”, “ROLE_ADMIN”));
tUsers.put(“frodo”, new User(“frodo”, “baggins”, “ROLE_USER”));
tUsers.put(“peter”, new User(“peter”, “arockiaraj”, “ROLE_ADMIN”));
return tUsers;
}
public UserDetails loadUserByUsername(String s)
throws UsernameNotFoundException, DataAccessException {
User user = (User) users.get(s);
GrantedAuthority authority = new MyGrantedAuthority(user.getRole());
UserDetails userDetails = new MyUserDetails(
new GrantedAuthority[] { authority }, user.getUserId(), user
.getPassword(), “Additional Data”);
return userDetails;
}
}
Step 14: Create PasswordHandler.java file to handle usernames and passwords.
if (pc.getIdentifer().equals(“satnewpubcert”)) {
pc.setPassword(“satsat”);
}
package com.sungard.cxf.example.server;
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 PasswordHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println(“Enterd PasswordHandler::handle”);
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (pc.getIdentifer().equals(“satnewpubcert”)) {
pc.setPassword(“satsat”);
}
System.out.println(“Leaving PasswordHandler::handle”);
}
}
Step 15: Create ValidateUserTokenAcegiInterceptor.java class to handle soap requests. If you have proper Acegi Database setup then in this you have to UserDetailsService instead of MyUserDetailsService class. And MyGrantedAuthority.java, MyUserDetails.java, MyUserDetailsService.java, User.java classes are not required in this project.
package com.sungard.cxf.example.server;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSUsernameTokenPrincipal;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
/**
* A WS-Security handler used to validate the user token passed in to the web
* service via the header of the soap packet.
*
* You shouldn’t have to change this class at all unless you want to inspect
* specific properties of the incoming WS-Security message.
*
*/
public class ValidateUserTokenAcegiInterceptor extends AbstractSoapInterceptor {
private MyUserDetailsService userDetailsService=new MyUserDetailsService();
public ValidateUserTokenAcegiInterceptor(String s) {
super(s);
}
public ValidateUserTokenAcegiInterceptor() {
super(Phase.UNMARSHAL);
}
public void handleMessage(SoapMessage message) throws Fault {
boolean userTokenValidated = false;
// if user still has a security context session open from a previous
// request, we probably don’t need to re-auth them
// debug stuff the message has…
// for(String key: message.keySet()) {
// System.out.println(“key: [“+key+”,”+message.get(key)+”]”);
// }
Vector result = (Vector) message
.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
for (int i = 0; i < result.size(); i++) {
WSHandlerResult res = (WSHandlerResult) result.get(i);
for (int j = 0; j < res.getResults().size(); j++) {
WSSecurityEngineResult secRes = (WSSecurityEngineResult) res
.getResults().get(j);
WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes
.getPrincipal();
// hack, we are just doing plain text…
if (principal.getPassword() != null) {
userTokenValidated = true;
} else {
throw new RuntimeException(
“Invalid Security Header: Please use a password”);
}
// old code to make sure all WS-Security headers are passed in
// and aren’t null
/*
* if(!principal.isPasswordDigest() || principal.getNonce() ==
* null || principal.getPassword() == null) { ||
* principal.getCreatedTime() == null) { throw new
* RuntimeException(“Invalid Security Header”); } else {
* userTokenValidated = true; }
*/
if (userTokenValidated) {
HttpServletRequest request = (HttpServletRequest) message
.get(“HTTP.REQUEST”);
request.getSession(true).getId();// hack to make sure we
// get a session id for
// acegi to use – this
// is needed for the
// concurrent filter
// authenticate with acegi
final UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(
principal.getName(), principal.getPassword());
// message.HTTP_REQUEST_METHOD
authReq.setDetails(new WebAuthenticationDetails(request));
SecurityContextHolder.getContext().setAuthentication(
authReq);
System.out
.println(“ValidateUserTokenAcegiInterceptor::handleMessage::principal.getName()=”
+ principal.getName());
userDetailsService.loadUserByUsername(
principal.getName());
}
}
}
if (!userTokenValidated) {
throw new RuntimeException(“Security processing failed”);
}
}
}
Step 16: Create beans.xml file to setup the application context for the server. If you are proper Acegi Database setup then you have to configure data source.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<import resource=”classpath:META-INF/cxf/cxf.xml” />
<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />
<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />
<jaxws:endpoint id=”helloWorld”
implementor=”com.sungard.cxf.example.server.IHello_Impl”
address=”/HelloService”>
<jaxws:inInterceptors>
<bean id=”logIn”
/>
<bean id=”logOut”
/>
<bean
/>
<bean
>
<property name=”properties”>
<map>
<entry key=”action”
value=”UsernameToken” />
<entry key=”passwordType” value=”PasswordText” />
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.PasswordHandler” />
</map>
</property>
</bean>
<bean
/>
</jaxws:inInterceptors>
</jaxws:endpoint>
<bean id=”userDetailsService”
>
</bean>
</beans>
Step 17: Create web.xml file
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!DOCTYPE web-app
PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-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>
Step 18: Create ant folder inside project. And Create build.xml file inside ant folder.
<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”ws” basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”acegisecurity.war”>
<fileset dir=”${basedir}”>
<include name=”**/*.class” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml” />
<exclude name=”**/*build*” />
</fileset>
</jar>
</target>
</project>
Step 19: Run build.xml using Ant.
Step 20: Deploy acegisecurity.war into Web/Application Server (Tomcat/JBoss).
Step 21: Verify application deployed successfully or by using following url.
http://localhost:8080/acegisecurity/HelloService?wsdl
Step 22: Browser will show wsdl file our web service.
Creating Client Application.
Step 1: Create New Java project in Eclipse
Step 2: Create folder Structure as like above application
Step 3: Use same jar files used for Server application.
Step 4: Set all the jars files into classpath.
Step 5: Create Remote Interface in client (IHello.java) (You can use wsdl2java for creating same)
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 6: Create ClientPasswordCallback.java for handling soap request in client side.
pc.setPassword(“arockiaraj”);
package com.sungard.cxf.example.server;
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 ClientPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// set the password for our message.
pc.setPassword(“arockiaraj”);
}
}
Step 7: Create the service factory (AuthServiceFactory.java), which is extremely easy since all the work was done in the Spring file:
package com.sungard.cxf.example.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class AuthServiceFactory {
private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { “cxfClient.xml” });
public AuthServiceFactory() {
}
public IHello getService() {
return (IHello) context.getBean(“client”);
}
}
Step 8: Create Client.java to invoke the service.
package com.sungard.cxf.example.server;
public final class Client {
private Client() {
}
public static void main(String args[]) throws Exception {
AuthServiceFactory af = new AuthServiceFactory();
IHello client1 = af.getService();
String response1 = client1.sayHello(“Hello”);
System.out.println(“Response: ” + response1);
}
}
Step 9: Create cxfClient.xml to setup the application context for the client.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<bean id=”proxyFactory”
>
<property name=”serviceClass”
value=”com.sungard.cxf.example.server.IHello” />
<property name=”address”
value=”http://localhost:8080/acegisecurity/HelloService” />
<property name=”inInterceptors”>
<list>
<ref bean=”logIn” />
</list>
</property>
<property name=”outInterceptors”>
<list>
<ref bean=”logOut” />
<ref bean=”saajOut” />
<ref bean=”wss4jOut” />
</list>
</property>
</bean>
<bean id=”client”
factory-bean=”proxyFactory” factory-method=”create” />
<bean id=”logIn”
/>
<bean id=”logOut”
/>
<bean id=”saajOut”
/>
<bean id=”wss4jOut”
>
<constructor-arg>
<map>
<entry key=”action” value=”UsernameToken” />
<entry key=”user” value=”peter” />
<entry key=”passwordType” value=”PasswordDigest” />
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.ClientPasswordCallback” />
</map>
</constructor-arg>
</bean>
</beans>
Step 10: Run Client.java
You will get response like as follows.
Response: You SaidHello
Note:
Client Side:
We Set User name in client cxfClient.xml file. (We can set the same through program also and we can read it xml/properties files. We can pass the same in runtime also)
<entry key=“user” value=“peter”/>
We Set password in ClientPasswordCallback.java class (We can pass same in runtime also)
// set the password for our message.
pc.setPassword(“arockiaraj”);
You can see the In & Outbound Messages in Client Side.
INFO: Outbound Message
—————————
Encoding: UTF-8
Headers: {SOAPAction=[“”], Accept=[*]}
Messages:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Header>
<wsse:Security xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” soap:mustUnderstand=”1″><wsse:UsernameToken xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”UsernameToken-23954271″ xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”><wsse:Username xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>arsenal</wsse:Username><wsse:Password Type=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest” xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>U6FK/CmMuPoKaB+SzgY4VNYed2U=</wsse:Password><wsse:Nonce xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>CdPEvSgU87L+4VR4SZxPQQ==</wsse:Nonce><wsu:Created xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”>2008-03-27T12:53:36.713Z</wsu:Created></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ns1:sayHello xmlns:ns1=”http://server.example.cxf.sungard.com/”><arg0>Hello</arg0></ns1:sayHello></soap:Body></soap:Envelope>
————————————–
Mar 27, 2008 6:23:37 PM org.apache.cxf.interceptor.LoggingInInterceptor logging
INFO: Inbound Message
—————————-
Encoding: UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Thu, 27 Mar 2008 12:53:37 GMT], Content-Length=[230], SOAPAction=[“”], Server=[Apache-Coyote/1.1]}
Messages:
Message:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”><soap:Body><ns1:sayHelloResponse xmlns:ns1=”http://server.example.cxf.sungard.com/”><return>You SaidHello</return></ns1:sayHelloResponse></soap:Body></soap:Envelope>
————————————–
Server Side:
User Name and password are got validated in PasswordHandler.java file. These values we can read it from xml/properties or from configuration files.
if (pc.getIdentifer().equals(“peter”)) {
pc.setPassword(“arockiaraj”);
}
Developing CXF WS-Security with SAML
Introduction
In this article we are going to develop a web service by using Spring and CXF with WS-Security (SAML). This article provides steps (step by step) to create & deploy web services by usingSpring and CXF with WS-Security (SAML). Please go through below to find sample web services.
Software Requirements
- EClipse (Java IDE)- Optional
- CXF Jars (Required for Compilation-Download from http://cxf.apache.org/download.html)
The Code
In this example, we are going to create a Hello service. In this example, we are going to use a code-first approach for this service using JAX-WS annotations.
Creating Server and Client Certificates
For the Signature and Encryption actions, you’ll need to create a public & private key for the entities involved. You can generate a key pair for the development environment via the following steps. Keep in mind these will not be signed by an external authority like Verisign
Keytool is inbuild tool which is comes with jdk.
Follow the steps to create client and server certificates (Refer following site)
When urgently you need some keystores and truststores to test out some security related java code this is a useful bat file to have. Copy the code below and create a bat file. run it and you got your stuff.
keytool -genkey -alias serverkeys -keyalg RSA -keystore server.keystore -storepass changeit -keypass changeit -dname “CN=localhost, OU=MYOU, O=MYORG, L=MYCITY, ST=MYSTATE, C=MY”
keytool -export -alias serverkeys -keystore server.keystore -storepass changeit -file server.cer
keytool -genkey -alias clientkeys -keyalg RSA -keystore client.keystore -storepass changeit -keypass changeit -dname “CN=localhost, OU=MYOU, O=MYORG, L=MYCITY, S=MY
STATE, C=MY”
keytool -export -alias clientkeys -keystore client.keystore -storepass changeit -file client.cer
keytool -import -v -keystore client.truststore -storepass changeit -file server.cer
keytool -import -v -keystore server.truststore -storepass changeit -file client.cer
It generates a keystore called server.keystore with password changeit. Then it creates server certificate server.cer.
Then it generates a keystore called client.keystore with password changeit. Creates a client certificate named client.cer
Next it imports server certificate into client truststore and client certificate into server truststore.
These are self signed certificates. Good for internal use. You can use open ssl
and create certificates. But this bat file is short and sweet for immediate use.
When you paste it you do have to be careful about keywords not getting split up like wordpress does.
Creating Server Application
Step 1: Download Following Jar files.
activation.jar
aopalliance-1.0.jar
commons-collections-3.2.jar
commons-lang-2.1.jar
commons-logging-1.1.jar
geronimo-activation-2.0.1.jar
geronimo-annotation_1.0_spec-1.1.jar
geronimo-javamail_1.4_mail-1.2.jar
geronimo-servlet_2.5_spec-1.1.jar
geronimo-ws-metadata_2.0_spec-1.1.1.jar
jaxb-api.jar
jaxb-api-2.0.jar
jaxb-impl-2.0.5.jar
jaxb-xjc.jar
jaxws-api.jar
mail.jar
neethi-2.0.jar
opensaml-1.0.1.jar
saaj-api.jar
saaj-impl.jar
spring-beans-2.0.6.jar
spring-context-2.0.6.jar
spring-core-2.0.6.jar
spring-web-2.0.6.jar
stax-api-1.0.1.jar
velocity-1.5.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.1.jar
xalan-2[1].6.0.jar
xalan-2[1].7.0.jar
xml-resolver-1.2.jar
cxf-bundle-2.0.4-incubator.jar
XmlSchema-1.3.2.jar
wss4j-1.5.1.jar
keyexport.jar
pkcs12import.jar
security-plugin.jar
wss-provider-update.jar
xws-security_jaxrpc.jar
xws-security.jar
xmlsec-1.3.0.jar
Step 2: Create New Java project in eclipse (CXFSAMLSecurity).
Step 3: Create WEB-INF folder inside project folder.
Step 4: Create classes folder inside WEB-INF folder.
Step 5: Create lib folder inside WEB-INF folder.
Step 6: Copy all the jar file into lib folder.
Step 7: Add all jar files into classpath (In Eclipse set java build path->Libraries). Add set Default output folder into CXFSAMLSecurity/WEB-INF/classes
Step 8: Create Remote Interface IHello.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 9: Create Implementation Class IHello_Impl.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService(endpointInterface = “com.sungard.cxf.example.server.IHello”)
public class IHello_Impl implements IHello {
public String sayHello(String value) {
return “You Said” + value;
}
}
Step 10: Create ServerSecurityEnvironmentHandler.java file to handle usernames and passwords. Here you have to give server certificate, server trust certificate alias name for checking. Password is alias password. Also you have to give client keystore file passwords also.
private String keyStorePassword = “changeit”;
private String trustStorePassword = “changeit”;
else if (callbacks[i] instanceof WSPasswordCallback) {
System.out.println(“handle::WSPasswordCallback”);
WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];
cb.setPassword(“changeit”);
}
package com.sungard.cxf.example.server;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.CertPathBuilder;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
//import com.sun.org.apache.xml.internal.security.utils.RFC2253Parser;
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
import com.sun.xml.wss.impl.misc.SecurityUtil;
/**
* A sample implementation of a CallbackHandler.
*/
public class ServerSecurityEnvironmentHandler implements CallbackHandler {
private KeyStore keyStore;
private KeyStore trustStore;
private String keyStorePassword = “changeit”;
private String trustStorePassword = “changeit”;
private static final UnsupportedCallbackException unsupported = new UnsupportedCallbackException(
null, “Unsupported Callback Type Encountered”);
public ServerSecurityEnvironmentHandler() throws Exception {
initTrustStore();
initKeyStore();
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println(“Entered::ServerSecurityEnvironmentHandler::handle”);
for (int i = 0; i < callbacks.length; i++) {
System.out.println(“handle::For-1”);
if (callbacks[i] instanceof PasswordValidationCallback) {
System.out.println(“handle::PasswordValidationCallback”);
PasswordValidationCallback cb = (PasswordValidationCallback) callbacks[i];
if (cb.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
System.out.println(“handle::PlainTextPasswordRequest”);
cb.setValidator(new PlainTextPasswordValidator());
} else if (cb.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {
System.out.println(“handle::DigestPasswordRequest”);
PasswordValidationCallback.DigestPasswordRequest request = (PasswordValidationCallback.DigestPasswordRequest) cb
.getRequest();
String username = request.getUsername();
if (“Ron”.equals(username)) {
request.setPassword(“noR”);
cb
.setValidator(new PasswordValidationCallback.DigestPasswordValidator());
}
} else {
throw unsupported;
}
} else if (callbacks[i] instanceof TimestampValidationCallback) {
System.out.println(“handle::TimestampValidationCallback”);
TimestampValidationCallback cb = (TimestampValidationCallback) callbacks[i];
cb.setValidator(new DefaultTimestampValidator());
} else if (callbacks[i] instanceof SignatureVerificationKeyCallback) {
System.out.println(“handle::SignatureVerificationKeyCallback”);
SignatureVerificationKeyCallback cb = (SignatureVerificationKeyCallback) callbacks[i];
if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) {
System.out.println(“handle::X509SubjectKeyIdentifierBasedRequest”);
// subject keyid request
SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb
.getRequest();
X509Certificate cert = getCertificateFromTrustStore(request
.getSubjectKeyIdentifier());
request.setX509Certificate(cert);
} else if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) {
// issuer serial request
System.out.println(“handle::X509IssuerSerialBasedRequest”);
SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request = (SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) cb
.getRequest();
X509Certificate cert = getCertificateFromTrustStore(request
.getIssuerName(), request.getSerialNumber());
request.setX509Certificate(cert);
} else {
throw unsupported;
}
} else if (callbacks[i] instanceof SignatureKeyCallback) {
System.out.println(“handle::SignatureKeyCallback”);
SignatureKeyCallback cb = (SignatureKeyCallback) callbacks[i];
if (cb.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) {
System.out.println(“handle::DefaultPrivKeyCertRequest”);
// default priv key cert req
SignatureKeyCallback.DefaultPrivKeyCertRequest request = (SignatureKeyCallback.DefaultPrivKeyCertRequest) cb
.getRequest();
getDefaultPrivKeyCert(request);
} else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) {
System.out.println(“handle::AliasPrivKeyCertRequest”);
SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb
.getRequest();
String alias = request.getAlias();
try {
X509Certificate cert = (X509Certificate) keyStore
.getCertificate(alias);
request.setX509Certificate(cert);
// Assuming key passwords same as the keystore password
PrivateKey privKey = (PrivateKey) keyStore.getKey(
alias, keyStorePassword.toCharArray());
request.setPrivateKey(privKey);
} catch (Exception e) {
System.out.println(“handle::AliasPrivKeyCertRequest::Exception”);
throw new IOException(e.getMessage());
}
} else {
System.out.println(“handle::AliasPrivKeyCertRequest::Exception::own::1”);
throw unsupported;
}
} else if (callbacks[i] instanceof DecryptionKeyCallback) {
DecryptionKeyCallback cb = (DecryptionKeyCallback) callbacks[i];
System.out.println(“handle::DecryptionKeyCallback”);
if (cb.getRequest() instanceof DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) {
System.out.println(“handle::X509SubjectKeyIdentifierBasedRequest”);
DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb
.getRequest();
byte[] ski = request.getSubjectKeyIdentifier();
PrivateKey privKey = getPrivateKey(ski);
request.setPrivateKey(privKey);
} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509IssuerSerialBasedRequest) {
System.out.println(“handle::X509IssuerSerialBasedRequest”);
DecryptionKeyCallback.X509IssuerSerialBasedRequest request = (DecryptionKeyCallback.X509IssuerSerialBasedRequest) cb
.getRequest();
String issuerName = request.getIssuerName();
BigInteger serialNumber = request.getSerialNumber();
PrivateKey privKey = getPrivateKey(issuerName, serialNumber);
request.setPrivateKey(privKey);
} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509CertificateBasedRequest) {
System.out.println(“handle::X509CertificateBasedRequest”);
DecryptionKeyCallback.X509CertificateBasedRequest request = (DecryptionKeyCallback.X509CertificateBasedRequest) cb
.getRequest();
X509Certificate cert = request.getX509Certificate();
PrivateKey privKey = getPrivateKey(cert);
request.setPrivateKey(privKey);
} else {
System.out.println(“handle::X509CertificateBasedRequest::Exception::own:2”);
throw unsupported;
}
} else if (callbacks[i] instanceof EncryptionKeyCallback) {
EncryptionKeyCallback cb = (EncryptionKeyCallback) callbacks[i];
System.out.println(“handle::EncryptionKeyCallback”);
if (cb.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {
System.out.println(“handle::AliasX509CertificateRequest”);
EncryptionKeyCallback.AliasX509CertificateRequest request = (EncryptionKeyCallback.AliasX509CertificateRequest) cb
.getRequest();
String alias = request.getAlias();
if (alias == null) {
System.out.println(“handle::AliasX509CertificateRequest::read”);
// plugin code here to read the cert from the
// ThreadLocal
} else {
try {
System.out.println(“handle::AliasX509CertificateRequest:try”);
X509Certificate cert = (X509Certificate) trustStore
.getCertificate(alias);
request.setX509Certificate(cert);
} catch (Exception e) {
System.out.println(“handle::AliasX509CertificateRequest::Exception”);
throw new IOException(e.getMessage());
}
}
} else {
System.out.println(“handle::AliasX509CertificateRequest::Exception::own::3”);
throw unsupported;
}
} else if (callbacks[i] instanceof CertificateValidationCallback) {
System.out.println(“handle::CertificateValidationCallback”);
CertificateValidationCallback cb = (CertificateValidationCallback) callbacks[i];
cb.setValidator(new X509CertificateValidatorImpl());
} else if (callbacks[i] instanceof CertificateValidationCallback) {
System.out.println(“handle::CertificateValidationCallback”);
CertificateValidationCallback cb = (CertificateValidationCallback) callbacks[i];
cb.setValidator(new X509CertificateValidatorImpl());
} else if (callbacks[i] instanceof WSPasswordCallback) {
System.out.println(“handle::WSPasswordCallback”);
WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];
System.out.println(“handle::cb.getPassword()”+cb.getPassword());
cb.setPassword(“changeit”);
} else {
System.out.println(“handle::CallBack Class Name::”+callbacks[i].getClass().getName());
System.out.println(“handle::CertificateValidationCallback::Exception::own::4”);
throw unsupported;
}
}
System.out.println(“Leaving::ServerSecurityEnvironmentHandler::handle”);
}
private void initTrustStore() throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::initTrustStore”);
try {
URL truststoreURL = SecurityUtil
.loadFromClasspath(“server-truststore.jks”);
trustStore = KeyStore.getInstance(“JKS”);
trustStore.load(truststoreURL.openStream(), trustStorePassword
.toCharArray());
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::initTrustStore”);
}
private void initKeyStore() throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::initKeyStore”);
try {
URL keystoreURL = SecurityUtil
.loadFromClasspath(“server-keystore.jks”);
keyStore = KeyStore.getInstance(“JKS”);
keyStore.load(keystoreURL.openStream(), keyStorePassword
.toCharArray());
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::initKeyStore”);
}
private X509Certificate getCertificateFromTrustStore(byte[] ski)
throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore”);
try {
Enumeration aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
Certificate cert = trustStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
byte[] keyId = getSubjectKeyIdentifier(x509Cert);
if (keyId == null) {
// Cert does not contain a key identifier
continue;
}
if (Arrays.equals(ski, keyId)) {
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::1”);
return x509Cert;
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::2”);
return null;
}
private X509Certificate getCertificateFromTrustStore(String issuerName,
BigInteger serialNumber) throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::Multiple”);
try {
Enumeration aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
Certificate cert = trustStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser.normalize(x509Cert
.getIssuerDN().getName());
BigInteger thisSerialNumber = x509Cert.getSerialNumber();
if (thisIssuerName.equals(issuerName)
&& thisSerialNumber.equals(serialNumber)) {
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::Multiple::1”);
return x509Cert;
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getCertificateFromTrustStore::Multiple::2”);
return null;
}
public PrivateKey getPrivateKey(byte[] ski) throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getPrivateKey”);
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (!keyStore.isKeyEntry(alias))
continue;
Certificate cert = keyStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
byte[] keyId = getSubjectKeyIdentifier(x509Cert);
if (keyId == null) {
// Cert does not contain a key identifier
continue;
}
if (Arrays.equals(ski, keyId)) {
// Asuumed key password same as the keystore password
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::2”);
return (PrivateKey) keyStore.getKey(alias, keyStorePassword
.toCharArray());
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::2”);
return null;
}
public PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber)
throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getPrivateKey::multiple”);
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (!keyStore.isKeyEntry(alias))
continue;
Certificate cert = keyStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser.normalize(x509Cert
.getIssuerDN().getName());
BigInteger thisSerialNumber = x509Cert.getSerialNumber();
if (thisIssuerName.equals(issuerName)
&& thisSerialNumber.equals(serialNumber)) {
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::multiple::1”);
return (PrivateKey) keyStore.getKey(alias, keyStorePassword
.toCharArray());
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::multiple::1”);
return null;
}
public PrivateKey getPrivateKey(X509Certificate certificate)
throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getPrivateKey::certificate”);
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (!keyStore.isKeyEntry(alias))
continue;
Certificate cert = keyStore.getCertificate(alias);
if (cert != null && cert.equals(certificate))
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::certificate::1”);
return (PrivateKey) keyStore.getKey(alias, keyStorePassword
.toCharArray());
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getPrivateKey::certificate::2”);
return null;
}
private void getDefaultPrivKeyCert(
SignatureKeyCallback.DefaultPrivKeyCertRequest request)
throws IOException {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getDefaultPrivKeyCert”);
String uniqueAlias = null;
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String currentAlias = (String) aliases.nextElement();
if (keyStore.isKeyEntry(currentAlias)) {
Certificate thisCertificate = keyStore
.getCertificate(currentAlias);
if (thisCertificate != null) {
if (thisCertificate instanceof X509Certificate) {
if (uniqueAlias == null) {
uniqueAlias = currentAlias;
} else {
// Not unique!
uniqueAlias = null;
break;
}
}
}
}
}
if (uniqueAlias != null) {
request.setX509Certificate((X509Certificate) keyStore
.getCertificate(uniqueAlias));
request.setPrivateKey((PrivateKey) keyStore.getKey(uniqueAlias,
keyStorePassword.toCharArray()));
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getDefaultPrivKeyCert”);
}
private static byte[] getSubjectKeyIdentifier(X509Certificate cert) {
System.out
.println(“Entered::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier”);
String SUBJECT_KEY_IDENTIFIER_OID = “2.5.29.14”;
byte[] subjectKeyIdentifier = cert
.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);
if (subjectKeyIdentifier == null)
return null;
try {
sun.security.x509.KeyIdentifier keyId = null;
sun.security.util.DerValue derVal = new sun.security.util.DerValue(
new sun.security.util.DerInputStream(subjectKeyIdentifier)
.getOctetString());
keyId = new sun.security.x509.KeyIdentifier(derVal.getOctetString());
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier::1”);
return keyId.getIdentifier();
} catch (NoClassDefFoundError ncde) {
if (subjectKeyIdentifier == null)
return null;
byte[] dest = new byte[subjectKeyIdentifier.length – 4];
System.arraycopy(subjectKeyIdentifier, 4, dest, 0,
subjectKeyIdentifier.length – 4);
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier::2”);
return dest;
} catch (java.io.IOException ex) {
// ignore
System.out
.println(“Leaving::ServerSecurityEnvironmentHandler::getSubjectKeyIdentifier::3”);
return null;
}
}
private class PlainTextPasswordValidator implements
PasswordValidationCallback.PasswordValidator {
public boolean validate(PasswordValidationCallback.Request request)
throws PasswordValidationCallback.PasswordValidationException {
System.out.println(“Entered::PlainTextPasswordValidator::validate”);
PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest = (PasswordValidationCallback.PlainTextPasswordRequest) request;
if (“Ron”.equals(plainTextRequest.getUsername())
&& “noR”.equals(plainTextRequest.getPassword())) {
System.out
.println(“Leaving::PlainTextPasswordValidator::validate::true”);
return true;
}
System.out
.println(“Leaving::PlainTextPasswordValidator::validate::false”);
return false;
}
}
private class DefaultTimestampValidator implements
TimestampValidationCallback.TimestampValidator {
public void validate(TimestampValidationCallback.Request request)
throws TimestampValidationCallback.TimestampValidationException {
System.out.println(“Entered::DefaultTimestampValidator::validate”);
// validate timestamp creation and expiration time.
TimestampValidationCallback.UTCTimestampRequest utcTimestampRequest = (TimestampValidationCallback.UTCTimestampRequest) request;
SimpleDateFormat calendarFormatter2 = new SimpleDateFormat(
“yyyy-MM-dd’T’HH:mm:ss’Z'”);
SimpleDateFormat calendarFormatter1 = new SimpleDateFormat(
“yyyy-MM-dd’T’HH:mm:ss’.’SSS’Z'”);
Date created = null;
Date expired = null;
try {
try {
created = calendarFormatter1.parse(utcTimestampRequest
.getCreated());
if (utcTimestampRequest.getExpired() != null)
expired = calendarFormatter1.parse(utcTimestampRequest
.getExpired());
} catch (java.text.ParseException pe) {
created = calendarFormatter2.parse(utcTimestampRequest
.getCreated());
if (utcTimestampRequest.getExpired() != null)
expired = calendarFormatter2.parse(utcTimestampRequest
.getExpired());
}
} catch (java.text.ParseException pe) {
throw new TimestampValidationCallback.TimestampValidationException(
pe.getMessage());
}
long maxClockSkew = utcTimestampRequest.getMaxClockSkew();
long timestampFreshnessLimit = utcTimestampRequest
.getTimestampFreshnessLimit();
// validate creation time
validateCreationTime(created, maxClockSkew, timestampFreshnessLimit);
// validate expiration time
if (expired != null)
validateExpirationTime(expired, maxClockSkew,
timestampFreshnessLimit);
System.out.println(“Leaving::DefaultTimestampValidator::validate”);
}
}
public void validateExpirationTime(Date expires, long maxClockSkew,
long timestampFreshnessLimit)
throws TimestampValidationCallback.TimestampValidationException {
System.out
.println(“Enterd::DefaultTimestampValidator::validateExpirationTime”);
Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),
maxClockSkew, false);
if (expires.before(currentTime)) {
throw new TimestampValidationCallback.TimestampValidationException(
“The current time is ahead of the expiration time in Timestamp”);
}
System.out
.println(“Leaving::DefaultTimestampValidator::validateExpirationTime”);
}
public void validateCreationTime(Date created, long maxClockSkew,
long timestampFreshnessLimit)
throws TimestampValidationCallback.TimestampValidationException {
System.out
.println(“Enterd::DefaultTimestampValidator::validateCreationTime”);
Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew,
timestampFreshnessLimit);
System.out.println(“Validate Creation time called current=” + current);
System.out.println(“Validate Creation time called created=” + created);
if (created.before(current)) {
throw new TimestampValidationCallback.TimestampValidationException(
“The creation time is older than ”
+ ” currenttime – timestamp-freshness-limit – max-clock-skew”);
}
Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),
maxClockSkew, true);
System.out.println(“Validate Creation time called currentTime=”
+ currentTime);
System.out.println(“Validate Creation time called created=” + created);
if (currentTime.before(created)) {
throw new TimestampValidationCallback.TimestampValidationException(
“The creation time is ahead of the current time.”);
}
System.out
.println(“Leaving::DefaultTimestampValidator::validateCreationTime”);
}
private static Date getFreshnessAndSkewAdjustedDate(long maxClockSkew,
long timestampFreshnessLimit) {
System.out
.println(“Enterd::DefaultTimestampValidator::getFreshnessAndSkewAdjustedDate”);
Calendar c = new GregorianCalendar();
long offset = c.get(Calendar.ZONE_OFFSET);
if (c.getTimeZone().inDaylightTime(c.getTime())) {
offset += c.getTimeZone().getDSTSavings();
}
long beforeTime = c.getTimeInMillis();
long currentTime = beforeTime – offset;
System.out.println(“MaxSkew=” + maxClockSkew + ” freshness=”
+ timestampFreshnessLimit);
long adjustedTime = currentTime – maxClockSkew
– timestampFreshnessLimit;
c.setTimeInMillis(adjustedTime);
System.out
.println(“Leaving::DefaultTimestampValidator::getFreshnessAndSkewAdjustedDate”);
return c.getTime();
}
private static Date getGMTDateWithSkewAdjusted(Calendar c,
long maxClockSkew, boolean addSkew) {
System.out
.println(“Enterd::DefaultTimestampValidator::getGMTDateWithSkewAdjusted”);
long offset = c.get(Calendar.ZONE_OFFSET);
if (c.getTimeZone().inDaylightTime(c.getTime())) {
offset += c.getTimeZone().getDSTSavings();
}
long beforeTime = c.getTimeInMillis();
long currentTime = beforeTime – offset;
if (addSkew)
currentTime = currentTime + maxClockSkew;
else
currentTime = currentTime – maxClockSkew;
c.setTimeInMillis(currentTime);
System.out
.println(“Leaving::DefaultTimestampValidator::getGMTDateWithSkewAdjusted”);
return c.getTime();
}
private class X509CertificateValidatorImpl implements
CertificateValidationCallback.CertificateValidator {
public boolean validate(X509Certificate certificate)
throws CertificateValidationCallback.CertificateValidationException {
System.out
.println(“Enterd::X509CertificateValidatorImpl::validate”);
if (isSelfCert(certificate)) {
System.out
.println(“Leaving::X509CertificateValidatorImpl::validate::1”);
return true;
}
try {
certificate.checkValidity();
} catch (CertificateExpiredException e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
“X509Certificate Expired”, e);
} catch (CertificateNotYetValidException e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
“X509Certificate not yet valid”, e);
}
X509CertSelector certSelector = new X509CertSelector();
certSelector.setCertificate(certificate);
PKIXBuilderParameters parameters;
CertPathBuilder builder;
try {
parameters = new PKIXBuilderParameters(trustStore, certSelector);
parameters.setRevocationEnabled(false);
builder = CertPathBuilder.getInstance(“PKIX”);
} catch (Exception e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
e.getMessage(), e);
}
try {
PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder
.build(parameters);
} catch (Exception e) {
e.printStackTrace();
System.out
.println(“Leaving::X509CertificateValidatorImpl::validate::2”);
return false;
}
System.out
.println(“Leaving::X509CertificateValidatorImpl::validate::3”);
return true;
}
private boolean isSelfCert(X509Certificate cert)
throws CertificateValidationCallback.CertificateValidationException {
System.out
.println(“Entered::X509CertificateValidatorImpl::isSelfCert”);
try {
if (keyStore == null)
initKeyStore();
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
X509Certificate x509Cert = (X509Certificate) keyStore
.getCertificate(alias);
if (x509Cert != null) {
if (x509Cert.equals(cert))
System.out
.println(“Leaving::X509CertificateValidatorImpl::isSelfCert::1”);
return true;
}
}
}
System.out
.println(“Leaving::X509CertificateValidatorImpl::isSelfCert::2”);
return false;
} catch (Exception e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
e.getMessage(), e);
}
}
}
private String getContainerHome() {
System.out
.println(“Entered::X509CertificateValidatorImpl::getContainerHome”);
String _home = “”;
String fileSeparator = System.getProperty(“file.separator”);
String contHome = System.getProperty(“catalina.home”);
if (contHome != null) {
String isAS = System.getProperty(“com.sun.aas.instanceRoot”);
if (isAS != null) {
_home = contHome + fileSeparator + “..” + fileSeparator + “..”;
} else {
_home = contHome;
}
} else {
_home = System.getProperty(“jwsdp.home”);
if (_home == null) {
_home = System.getProperty(“as.home”);
}
}
System.out
.println(“Leaving::X509CertificateValidatorImpl::getContainerHome”);
return _home;
}
}
Step 11: Create Interceptor class to handle soap requests ValidateUserTokenInterceptor.java.
package com.sungard.cxf.example.server;
import java.util.Vector;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSUsernameTokenPrincipal;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
public class ValidateUserTokenInterceptor extends AbstractPhaseInterceptor {
public ValidateUserTokenInterceptor(String s) {
super(s);
}
public ValidateUserTokenInterceptor() {
super(Phase.UNMARSHAL);
}
public void handleMessage(Message message) {
System.out
.println(“Enterd ValidateUserTokenInterceptor::handleMessage”);
boolean userTokenValidated = false;
Vector result = (Vector) message
.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
for (int i = 0; i < result.size(); i++) {
WSHandlerResult res = (WSHandlerResult) result.get(i);
for (int j = 0; j < res.getResults().size(); j++) {
WSSecurityEngineResult secRes = (WSSecurityEngineResult) res
.getResults().get(j);
if (secRes.getPrincipal() != null) {
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::Class”
+ secRes.getPrincipal().getClass());
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::ClassName”
+ secRes.getPrincipal().getClass()
.getName());
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::Name”
+ secRes.getPrincipal().getName());
if (secRes.getPrincipal().getClass().getName().equals(
“org.apache.ws.security.WSUsernameTokenPrincipal”)) {
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::WSUsernameTokenPrincipal”
+ secRes.getPrincipal().getName());
WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes
.getPrincipal();
System.out.println(“principal.isPasswordDigest”
+ principal.isPasswordDigest());
System.out.println(“principal.getNonce()”
+ principal.getNonce());
System.out.println(“principal.getPassword()”
+ principal.getPassword());
System.out.println(“principal.getCreatedTime()”
+ principal.getCreatedTime());
if (principal.getPassword() == null) {
throw new RuntimeException(
“Invalid Security Header”);
} else {
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::userTokenValidated = true”);
userTokenValidated = true;
}
}
}
}
}
if (!userTokenValidated) {
throw new RuntimeException(“Security processing failed::Peter”);
}
System.out
.println(“Leaving ValidateUserTokenInterceptor::handleMessage”);
}
}
Step 12: Create beans.xml file to setup the application context for the server.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<import resource=”classpath:META-INF/cxf/cxf.xml” />
<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />
<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />
<jaxws:endpoint id=”helloWorld”
implementor=”com.sungard.cxf.example.server.IHello_Impl”
address=”/HelloService”>
<jaxws:inInterceptors>
<bean id=”logIn”
/>
<bean id=”logOut”
/>
<bean
/>
<bean
>
<property name=”properties”>
<map>
<entry key=”action”
value=”UsernameToken SAMLTokenUnsigned” />
<entry key=”passwordType” value=”PasswordText” />
<entry key=”enableNamespacePrefixOptimization”
value=”true” />
<entry key=”disablePrettyXML” value=”true” />
<entry key=”sendXsiTypes” value=”true” />
<entry key=”sendMultiRefs” value=”true” />
<entry key=”sendXMLDeclaration” value=”true” />
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.ServerSecurityEnvironmentHandler” />
<entry key=”signaturePropFile”
value=”server_sign.properties”>
</entry>
</map>
</property>
</bean>
<bean
/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
Step 13: Create server_sign.properties under WEB-INF\classes folder to mention private keystore file details.
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=changeit
org.apache.ws.security.crypto.merlin.file=server-keystore.jks
Step 14: Copy all keystore and certificate files under WEB-INF\classes folder.
Step 15: Create web.xml file
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!DOCTYPE web-app
PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-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>
Step 16: Create ant folder inside project. And Create build.xml file inside ant folder.
<?xml version=”1.0″ encoding=”UTF-8″?>
<project basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”samlnormalsecurity.war”>
<fileset dir=”${basedir}”>
<include name=”**/*.class” />
<include name=”**/*.jks*” />
<include name=”**/*.properties*” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml” />
<exclude name=”**/*build*” />
</fileset>
</jar>
</target>
</project>
Step 17: Run build.xml using Ant.
Step 18: Deploy samlnormalsecurity.war into Web/Application Server (Tomcat/JBoss).
Step 19: Verify application deployed successfully or by using following url.
http://localhost:8080/samlnormalsecurity/HelloService?wsdl
Step 20: Browser will show wsdl file our web service.
Creating Client Application.
Step 1: Create New Java project in Eclipse
Step 2: Create folder Structure as like above application
Step 3: Use same jar files used for Server application.
Step 4: Set all the jars files into classpath.
Step 5: Create Remote Interface in client (IHello.java) (You can use wsdl2java for creating same)
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 6: Create ClientSecurityEnvironmentHandler.java for handling soap request in client side. Here you have set the password what you are given client alias. You have tomention client ketstore passwords also here.
private String keyStorePassword = “changeit”;
private String trustStorePassword = “changeit”;
else if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];
System.out.println(“cb.getPassword()” + cb.getPassword());
cb.setPassword(“changeit”);
}
package com.sungard.cxf.example.server;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.CertPathBuilder;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.xml.ws.BindingProvider;
import org.apache.ws.security.WSPasswordCallback;
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
import com.sun.xml.wss.impl.callback.PasswordCallback;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
import com.sun.xml.wss.impl.callback.UsernameCallback;
import com.sun.xml.wss.impl.misc.SecurityUtil;
/**
* A sample implementation of a CallbackHandler.
*/
public class ClientSecurityEnvironmentHandler implements CallbackHandler {
private KeyStore keyStore;
private KeyStore trustStore;
private String keyStorePassword = “changeit”;
private String trustStorePassword = “changeit”;
private static final UnsupportedCallbackException unsupported = new UnsupportedCallbackException(
null, “Unsupported Callback Type Encountered”);
public ClientSecurityEnvironmentHandler() throws Exception {
System.out.println(“Entered::ClientSecurityEnvironmentHandler”);
initTrustStore();
initKeyStore();
System.out.println(“Leaving::ClientSecurityEnvironmentHandler”);
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println(“Entered::ClientSecurityEnvironmentHandler::handle”);
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof PasswordValidationCallback) {
PasswordValidationCallback cb = (PasswordValidationCallback) callbacks[i];
if (cb.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
cb.setValidator(new PlainTextPasswordValidator());
} else if (cb.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {
PasswordValidationCallback.DigestPasswordRequest request = (PasswordValidationCallback.DigestPasswordRequest) cb
.getRequest();
String username = request.getUsername();
if (“Ron”.equals(username)) {
request.setPassword(“noR”);
cb
.setValidator(new PasswordValidationCallback.DigestPasswordValidator());
}
} else {
System.out
.println(“ClientSecurityEnvironmentHandler::Handle::1”);
throw unsupported;
}
} else if (callbacks[i] instanceof TimestampValidationCallback) {
TimestampValidationCallback cb = (TimestampValidationCallback) callbacks[i];
cb.setValidator(new DefaultTimestampValidator());
} else if (callbacks[i] instanceof SignatureVerificationKeyCallback) {
SignatureVerificationKeyCallback cb = (SignatureVerificationKeyCallback) callbacks[i];
if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) {
// subject keyid request
SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb
.getRequest();
X509Certificate cert = getCertificateFromTrustStore(request
.getSubjectKeyIdentifier());
request.setX509Certificate(cert);
} else if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) {
// issuer serial request
SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request = (SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) cb
.getRequest();
X509Certificate cert = getCertificateFromTrustStore(request
.getIssuerName(), request.getSerialNumber());
request.setX509Certificate(cert);
} else {
System.out
.println(“ClientSecurityEnvironmentHandler::Handle::2”);
throw unsupported;
}
} else if (callbacks[i] instanceof SignatureKeyCallback) {
SignatureKeyCallback cb = (SignatureKeyCallback) callbacks[i];
if (cb.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) {
// default priv key cert req
SignatureKeyCallback.DefaultPrivKeyCertRequest request = (SignatureKeyCallback.DefaultPrivKeyCertRequest) cb
.getRequest();
getDefaultPrivKeyCert(request);
} else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) {
SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb
.getRequest();
String alias = request.getAlias();
try {
X509Certificate cert = (X509Certificate) keyStore
.getCertificate(alias);
request.setX509Certificate(cert);
// Assuming key passwords same as the keystore password
PrivateKey privKey = (PrivateKey) keyStore.getKey(
alias, keyStorePassword.toCharArray());
request.setPrivateKey(privKey);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
} else {
System.out
.println(“ClientSecurityEnvironmentHandler::Handle::3”);
throw unsupported;
}
} else if (callbacks[i] instanceof DecryptionKeyCallback) {
DecryptionKeyCallback cb = (DecryptionKeyCallback) callbacks[i];
if (cb.getRequest() instanceof DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) {
DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb
.getRequest();
byte[] ski = request.getSubjectKeyIdentifier();
PrivateKey privKey = getPrivateKey(ski);
request.setPrivateKey(privKey);
} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509IssuerSerialBasedRequest) {
DecryptionKeyCallback.X509IssuerSerialBasedRequest request = (DecryptionKeyCallback.X509IssuerSerialBasedRequest) cb
.getRequest();
String issuerName = request.getIssuerName();
BigInteger serialNumber = request.getSerialNumber();
PrivateKey privKey = getPrivateKey(issuerName, serialNumber);
request.setPrivateKey(privKey);
} else if (cb.getRequest() instanceof DecryptionKeyCallback.X509CertificateBasedRequest) {
DecryptionKeyCallback.X509CertificateBasedRequest request = (DecryptionKeyCallback.X509CertificateBasedRequest) cb
.getRequest();
X509Certificate cert = request.getX509Certificate();
PrivateKey privKey = getPrivateKey(cert);
request.setPrivateKey(privKey);
} else {
System.out
.println(“ClientSecurityEnvironmentHandler::Handle::4”);
throw unsupported;
}
} else if (callbacks[i] instanceof EncryptionKeyCallback) {
EncryptionKeyCallback cb = (EncryptionKeyCallback) callbacks[i];
if (cb.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {
EncryptionKeyCallback.AliasX509CertificateRequest request = (EncryptionKeyCallback.AliasX509CertificateRequest) cb
.getRequest();
String alias = request.getAlias();
if (alias == null) {
// plugin code here to read the cert from the
// ThreadLocal
} else {
try {
X509Certificate cert = (X509Certificate) trustStore
.getCertificate(alias);
request.setX509Certificate(cert);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
} else {
System.out
.println(“ClientSecurityEnvironmentHandler::Handle::5”);
throw unsupported;
}
} else if (callbacks[i] instanceof CertificateValidationCallback) {
CertificateValidationCallback cb = (CertificateValidationCallback) callbacks[i];
cb.setValidator(new X509CertificateValidatorImpl());
} else if (callbacks[i] instanceof UsernameCallback) {
UsernameCallback cb = (UsernameCallback) callbacks[i];
String username = (String) cb.getRuntimeProperties().get(
BindingProvider.USERNAME_PROPERTY);
System.out.println(“Got Username……… : ” + username);
cb.setUsername(username);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback cb = (PasswordCallback) callbacks[i];
String password = (String) cb.getRuntimeProperties().get(
BindingProvider.PASSWORD_PROPERTY);
System.out.println(“Got Password……… : ” + password);
cb.setPassword(password);
} else if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback cb = (WSPasswordCallback) callbacks[i];
System.out.println(“cb.getPassword()” + cb.getPassword());
cb.setPassword(“changeit”);
} else {
System.out.println(callbacks[i].getClass().getName());
System.out
.println(“ClientSecurityEnvironmentHandler::Handle::6”);
throw unsupported;
}
}
}
private void initTrustStore() throws IOException {
try {
URL truststoreURL = SecurityUtil
.loadFromClasspath(“client-truststore.jks”);
trustStore = KeyStore.getInstance(“JKS”);
trustStore.load(truststoreURL.openStream(), trustStorePassword
.toCharArray());
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
private void initKeyStore() throws IOException {
try {
URL keystoreURL = SecurityUtil
.loadFromClasspath(“client-keystore.jks”);
keyStore = KeyStore.getInstance(“JKS”);
keyStore.load(keystoreURL.openStream(), keyStorePassword
.toCharArray());
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
private X509Certificate getCertificateFromTrustStore(byte[] ski)
throws IOException {
try {
Enumeration aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
Certificate cert = trustStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
byte[] keyId = getSubjectKeyIdentifier(x509Cert);
if (keyId == null) {
// Cert does not contain a key identifier
continue;
}
if (Arrays.equals(ski, keyId)) {
return x509Cert;
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
return null;
}
private X509Certificate getCertificateFromTrustStore(String issuerName,
BigInteger serialNumber) throws IOException {
try {
Enumeration aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
Certificate cert = trustStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser
.normalize(x509Cert.getIssuerDN().getName());
BigInteger thisSerialNumber = x509Cert.getSerialNumber();
if (thisIssuerName.equals(issuerName)
&& thisSerialNumber.equals(serialNumber)) {
return x509Cert;
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
return null;
}
public PrivateKey getPrivateKey(byte[] ski) throws IOException {
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (!keyStore.isKeyEntry(alias))
continue;
Certificate cert = keyStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
byte[] keyId = getSubjectKeyIdentifier(x509Cert);
if (keyId == null) {
// Cert does not contain a key identifier
continue;
}
if (Arrays.equals(ski, keyId)) {
// Asuumed key password same as the keystore password
return (PrivateKey) keyStore.getKey(alias, keyStorePassword
.toCharArray());
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
return null;
}
public PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber)
throws IOException {
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (!keyStore.isKeyEntry(alias))
continue;
Certificate cert = keyStore.getCertificate(alias);
if (cert == null || !”X.509″.equals(cert.getType())) {
continue;
}
X509Certificate x509Cert = (X509Certificate) cert;
String thisIssuerName = org.apache.xml.security.utils.RFC2253Parser
.normalize(x509Cert.getIssuerDN().getName());
BigInteger thisSerialNumber = x509Cert.getSerialNumber();
if (thisIssuerName.equals(issuerName)
&& thisSerialNumber.equals(serialNumber)) {
return (PrivateKey) keyStore.getKey(alias, keyStorePassword
.toCharArray());
}
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
return null;
}
public PrivateKey getPrivateKey(X509Certificate certificate)
throws IOException {
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (!keyStore.isKeyEntry(alias))
continue;
Certificate cert = keyStore.getCertificate(alias);
if (cert != null && cert.equals(certificate))
return (PrivateKey) keyStore.getKey(alias, keyStorePassword
.toCharArray());
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
return null;
}
private void getDefaultPrivKeyCert(
SignatureKeyCallback.DefaultPrivKeyCertRequest request)
throws IOException {
String uniqueAlias = null;
try {
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String currentAlias = (String) aliases.nextElement();
if (keyStore.isKeyEntry(currentAlias)) {
Certificate thisCertificate = keyStore
.getCertificate(currentAlias);
if (thisCertificate != null) {
if (thisCertificate instanceof X509Certificate) {
if (uniqueAlias == null) {
uniqueAlias = currentAlias;
} else {
// Not unique!
uniqueAlias = null;
break;
}
}
}
}
}
if (uniqueAlias != null) {
request.setX509Certificate((X509Certificate) keyStore
.getCertificate(uniqueAlias));
request.setPrivateKey((PrivateKey) keyStore.getKey(uniqueAlias,
keyStorePassword.toCharArray()));
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
private static byte[] getSubjectKeyIdentifier(X509Certificate cert) {
String SUBJECT_KEY_IDENTIFIER_OID = “2.5.29.14”;
byte[] subjectKeyIdentifier = cert
.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);
if (subjectKeyIdentifier == null)
return null;
try {
sun.security.x509.KeyIdentifier keyId = null;
sun.security.util.DerValue derVal = new sun.security.util.DerValue(
new sun.security.util.DerInputStream(subjectKeyIdentifier)
.getOctetString());
keyId = new sun.security.x509.KeyIdentifier(derVal.getOctetString());
return keyId.getIdentifier();
} catch (NoClassDefFoundError ncde) {
if (subjectKeyIdentifier == null)
return null;
byte[] dest = new byte[subjectKeyIdentifier.length – 4];
System.arraycopy(subjectKeyIdentifier, 4, dest, 0,
subjectKeyIdentifier.length – 4);
return dest;
} catch (java.io.IOException ex) {
// ignore
return null;
}
}
private class PlainTextPasswordValidator implements
PasswordValidationCallback.PasswordValidator {
public boolean validate(PasswordValidationCallback.Request request)
throws PasswordValidationCallback.PasswordValidationException {
PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest = (PasswordValidationCallback.PlainTextPasswordRequest) request;
if (“Ron”.equals(plainTextRequest.getUsername())
&& “noR”.equals(plainTextRequest.getPassword())) {
return true;
}
return false;
}
}
private class DefaultTimestampValidator implements
TimestampValidationCallback.TimestampValidator {
public void validate(TimestampValidationCallback.Request request)
throws TimestampValidationCallback.TimestampValidationException {
// validate timestamp creation and expiration time.
TimestampValidationCallback.UTCTimestampRequest utcTimestampRequest = (TimestampValidationCallback.UTCTimestampRequest) request;
SimpleDateFormat calendarFormatter2 = new SimpleDateFormat(
“yyyy-MM-dd’T’HH:mm:ss’Z'”);
SimpleDateFormat calendarFormatter1 = new SimpleDateFormat(
“yyyy-MM-dd’T’HH:mm:ss’.’SSS’Z'”);
Date created = null;
Date expired = null;
try {
try {
created = calendarFormatter1.parse(utcTimestampRequest
.getCreated());
if (utcTimestampRequest.getExpired() != null)
expired = calendarFormatter1.parse(utcTimestampRequest
.getExpired());
} catch (java.text.ParseException pe) {
created = calendarFormatter2.parse(utcTimestampRequest
.getCreated());
if (utcTimestampRequest.getExpired() != null)
expired = calendarFormatter2.parse(utcTimestampRequest
.getExpired());
}
} catch (java.text.ParseException pe) {
throw new TimestampValidationCallback.TimestampValidationException(
pe.getMessage());
}
long maxClockSkew = utcTimestampRequest.getMaxClockSkew();
long timestampFreshnessLimit = utcTimestampRequest
.getTimestampFreshnessLimit();
// validate creation time
validateCreationTime(created, maxClockSkew, timestampFreshnessLimit);
// validate expiration time
if (expired != null)
validateExpirationTime(expired, maxClockSkew,
timestampFreshnessLimit);
}
}
public void validateExpirationTime(Date expires, long maxClockSkew,
long timestampFreshnessLimit)
throws TimestampValidationCallback.TimestampValidationException {
// System.out.println(“Validate Expiration time called”);
Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),
maxClockSkew, false);
if (expires.before(currentTime)) {
throw new TimestampValidationCallback.TimestampValidationException(
“The current time is ahead of the expiration time in Timestamp”);
}
}
public void validateCreationTime(Date created, long maxClockSkew,
long timestampFreshnessLimit)
throws TimestampValidationCallback.TimestampValidationException {
// System.out.println(“Validate Creation time called”);
Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew,
timestampFreshnessLimit);
if (created.before(current)) {
throw new TimestampValidationCallback.TimestampValidationException(
“The creation time is older than ”
+ ” currenttime – timestamp-freshness-limit – max-clock-skew”);
}
Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(),
maxClockSkew, true);
if (currentTime.before(created)) {
throw new TimestampValidationCallback.TimestampValidationException(
“The creation time is ahead of the current time.”);
}
}
private static Date getFreshnessAndSkewAdjustedDate(long maxClockSkew,
long timestampFreshnessLimit) {
Calendar c = new GregorianCalendar();
long offset = c.get(Calendar.ZONE_OFFSET);
if (c.getTimeZone().inDaylightTime(c.getTime())) {
offset += c.getTimeZone().getDSTSavings();
}
long beforeTime = c.getTimeInMillis();
long currentTime = beforeTime – offset;
long adjustedTime = currentTime – maxClockSkew
– timestampFreshnessLimit;
c.setTimeInMillis(adjustedTime);
return c.getTime();
}
private static Date getGMTDateWithSkewAdjusted(Calendar c,
long maxClockSkew, boolean addSkew) {
long offset = c.get(Calendar.ZONE_OFFSET);
if (c.getTimeZone().inDaylightTime(c.getTime())) {
offset += c.getTimeZone().getDSTSavings();
}
long beforeTime = c.getTimeInMillis();
long currentTime = beforeTime – offset;
if (addSkew)
currentTime = currentTime + maxClockSkew;
else
currentTime = currentTime – maxClockSkew;
c.setTimeInMillis(currentTime);
return c.getTime();
}
private class X509CertificateValidatorImpl implements
CertificateValidationCallback.CertificateValidator {
public boolean validate(X509Certificate certificate)
throws CertificateValidationCallback.CertificateValidationException {
if (isSelfCert(certificate)) {
return true;
}
try {
certificate.checkValidity();
} catch (CertificateExpiredException e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
“X509Certificate Expired”, e);
} catch (CertificateNotYetValidException e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
“X509Certificate not yet valid”, e);
}
X509CertSelector certSelector = new X509CertSelector();
certSelector.setCertificate(certificate);
PKIXBuilderParameters parameters;
CertPathBuilder builder;
try {
parameters = new PKIXBuilderParameters(trustStore, certSelector);
parameters.setRevocationEnabled(false);
builder = CertPathBuilder.getInstance(“PKIX”);
} catch (Exception e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
e.getMessage(), e);
}
try {
PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder
.build(parameters);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private boolean isSelfCert(X509Certificate cert)
throws CertificateValidationCallback.CertificateValidationException {
try {
if (keyStore == null)
initKeyStore();
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
X509Certificate x509Cert = (X509Certificate) keyStore
.getCertificate(alias);
if (x509Cert != null) {
if (x509Cert.equals(cert))
return true;
}
}
}
return false;
} catch (Exception e) {
e.printStackTrace();
throw new CertificateValidationCallback.CertificateValidationException(
e.getMessage(), e);
}
}
}
private String getContainerHome() {
String _home = “”;
String fileSeparator = System.getProperty(“file.separator”);
String contHome = System.getProperty(“catalina.home”);
if (contHome != null) {
String isAS = System.getProperty(“com.sun.aas.instanceRoot”);
if (isAS != null) {
_home = contHome + fileSeparator + “..” + fileSeparator + “..”;
} else {
_home = contHome;
}
} else {
_home = System.getProperty(“jwsdp.home”);
if (_home == null) {
_home = System.getProperty(“as.home”);
}
}
return _home;
}
}
Step 7: Create the service factory (AuthServiceFactory.java), which is extremely easy since all the work was done in the Spring file:
package com.sungard.cxf.example.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class AuthServiceFactory {
private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { “cxfClient.xml” });
public AuthServiceFactory() {
}
public IHello getService() {
return (IHello) context.getBean(“client”);
}
}
Step 8: Create Client.java to invoke the service.
package com.sungard.cxf.example.server;
public final class Client {
private Client() {
}
public static void main(String args[]) throws Exception {
AuthServiceFactory af = new AuthServiceFactory();
IHello client1 = af.getService();
String response1 = client1.sayHello(“Hello”);
System.out.println(“Response: ” + response1);
}
}
Step 9: Create cxfClient.xml to setup the application context for the client.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<bean id=”proxyFactory”
>
<property name=”serviceClass”
value=”com.sungard.cxf.example.server.IHello” />
<property name=”address”
value=”http://localhost:8080/samlnormalsecurity/HelloService” />
<property name=”inInterceptors”>
<list>
<ref bean=”logIn” />
</list>
</property>
<property name=”outInterceptors”>
<list>
<ref bean=”logOut” />
<ref bean=”saajOut” />
<ref bean=”wss4jOut” />
</list>
</property>
</bean>
<bean id=”client”
factory-bean=”proxyFactory” factory-method=”create” />
<bean id=”logIn”
/>
<bean id=”logOut”
/>
<bean id=”saajOut”
/>
<bean id=”wss4jOut”
>
<constructor-arg>
<map>
<entry key=”action” value=”UsernameToken SAMLTokenUnsigned” />
<entry key=”user” value=”xws-security-client” />
<entry key=”passwordType” value=”PasswordText” />
<entry key=”samlPropFile” value=”saml2.properties”/>
<entry key=”enableNamespacePrefixOptimization” value=”true”/>
<entry key=”disablePrettyXML” value=”true”/>
<entry key=”sendXsiTypes” value=”true”/>
<entry key=”sendMultiRefs” value=”true”/>
<entry key=”sendXMLDeclaration” value=”true”/>
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.ClientSecurityEnvironmentHandler” />
</map>
</constructor-arg>
</bean>
</beans>
Step 11: Create client_sign.properties file under WEB-INF\classes folder. To give public keystore file details.
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=changeit
org.apache.ws.security.crypto.merlin.keystore.alias=xws-security-client
org.apache.ws.security.crypto.merlin.file=client-keystore.jks
Step 12: Create saml2.properties file under WEB-INF\classes folder. To give public keystore file details.
org.apache.ws.security.saml.issuerClass=org.apache.ws.security.saml.SAMLIssuerImpl
org.apache.ws.security.saml.issuer.cryptoProp.file=client_sign.properties
org.apache.ws.security.saml.issuer=www.example.com
org.apache.ws.security.saml.subjectNameId.name=xws-security-client
org.apache.ws.security.saml.subjectNameId.qualifier=www.example.com
org.apache.ws.security.saml.authenticationMethod=password
org.apache.ws.security.saml.confirmationMethod=senderVouches
org.apache.ws.security.saml.issuer.key.name=xws-security-client
org.apache.ws.security.saml.issuer.key.password=changeit
Step 13: Copy keystore and certificates in WEB-INF\classes folder. (Or set it in classpath)
Step 14: Run Client.java
You will get response like as follows.
Response: You SaidHello
Note:
Client Side:
We Set User name in client cxfClient.xml file. That is public alias name. (We can set the same through program also and we can read it xml/properties files. We can pass the same in runtime also)
<entry key=”user” value=”xws-security-client” />
We Set password in ClientSecurityEnvironmentHandler.java class (We can pass same in runtime also)
// set the password for our message.
pc.setPassword(“changeit”);
You can see the In & Outbound Messages in Client Side. As like as follows. This will go with signature.
INFO: Outbound Message
—————————
Encoding: UTF-8
Headers: {SOAPAction=[“”], Accept=[*]}
Messages:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Header>
<wsse:Security xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” soap:mustUnderstand=”1″><Assertion xmlns=”urn:oasis:names:tc:SAML:1.0:assertion” xmlns:saml=”urn:oasis:names:tc:SAML:1.0:assertion” xmlns:samlp=”urn:oasis:names:tc:SAML:1.0:protocol” AssertionID=”b58cef8ed07e7a8c1be2d099e73ba075″ IssueInstant=”2008-04-04T05:13:59.068Z” Issuer=”www.example.com” MajorVersion=”1″ MinorVersion=”1″><AuthenticationStatement AuthenticationInstant=”2008-04-04T05:13:58.896Z” AuthenticationMethod=”urn:oasis:names:tc:SAML:1.0:am:password”><Subject><NameIdentifier NameQualifier=”www.example.com”>xws-security-client</NameIdentifier><SubjectConfirmation><ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod></SubjectConfirmation></Subject></AuthenticationStatement></Assertion><wsse:UsernameToken xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”UsernameToken-24451742″ xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”><wsse:Username xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>xws-security-client</wsse:Username><wsse:Password Type=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText” xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>changeit</wsse:Password></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ns1:sayHello xmlns:ns1=”http://server.example.cxf.sungard.com/”><arg0>Hello</arg0></ns1:sayHello></soap:Body></soap:Envelope>
————————————–
Apr 4, 2008 10:44:10 AM org.apache.cxf.interceptor.LoggingInInterceptor logging
INFO: Inbound Message
—————————-
Encoding: UTF-8
Headers: {Content-Length=[230], Date=[Fri, 04 Apr 2008 05:14:10 GMT], SOAPAction=[“”], Server=[Apache-Coyote/1.1], content-type=[text/xml;charset=UTF-8]}
Messages:
Message:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”><soap:Body><ns1:sayHelloResponse xmlns:ns1=”http://server.example.cxf.sungard.com/”><return>You SaidHello</return></ns1:sayHelloResponse></soap:Body></soap:Envelope>
————————————–
Developing CXF WS-Security with Signature(Certificates)
Creating Server and Client Certificates
For the Signature and Encryption actions, you’ll need to create a public & private key for the entities involved. You can generate a key pair for the development environment via the following steps. Keep in mind these will not be signed by an external authority like Verisign
Keytool is inbuild tool which is comes with jdk.
Step1 : First Create private keystore by using Java Keytool.
keytool -genkey -alias satnewprivkey -keystore satnewprivkeystore -dname “cn=satnewprivkey” -keypass satsat -storepass satsat -keyalg RSA
Step 2: Create public keystore
keytool -genkey -alias satnewpubcert -keystore satnewpubcertkeystore -dname “cn=satnewpubcert” -keypass satsat -storepass satsat -keyalg RSA
Step 3: Print created private keystore by running following command.
keytool -list -keystore satnewprivkeystore
Above command will ask password. Type “satsat” (This is keystore password which we are given while creating private keystore.)
This will give output like as follows after giving password.
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
satnewprivkey, Mar 26, 2008, PrivateKeyEntry,
Certificate fingerprint (MD5): 46:BB:AF:49:1B:13:45:13:DB:E8:DF:96:96:D7:F3:CD
Step 4: Print created public keystore by running following command.
keytool -list -keystore satnewpubcertkeystore
Above command will ask password. Type “satsat” (This is keystore password which we are given while creating public keystore.)
This will give output like as follows after giving password.
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
satnewpubcert, Mar 26, 2008, PrivateKeyEntry,
Certificate fingerprint (MD5): 62:50:10:D8:3A:E8:17:56:88:8E:14:C7:86:A6:4B:4F
Step 5: Export private keystore file by using following command.
keytool -export -keystore satnewprivkeystore -alias satnewprivkey -storepass satsat –rfc
This will give output like as follows.
—–BEGIN CERTIFICATE—–
MIIBpzCCARCgAwIBAgIER+o+UDANBgkqhkiG9w0BAQUFADAYMRYwFAYDVQQDEw1zYXRuZXdwcml2
a2V5MB4XDTA4MDMyNjEyMTUxMloXDTA4MDYyNDEyMTUxMlowGDEWMBQGA1UEAxMNc2F0bmV3cHJp
dmtleTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAhVpc7/Zw+vxfFFmuP18/4rHP5goeKgIt
jP7uAyMmd4gF8cP0vjUehWOYjVOPEGyoP3K6TXS0/RKA1uUVV5Hjk3A5fFWwjSZ/SVIpKDj1ob29
sfojEY4aEAdLI0dqe2jy+bYpg/hU0j1R3VpYlCip39VnYfZHViC8hZj4FoLqjJMCAwEAATANBgkq
hkiG9w0BAQUFAAOBgQABIFTiJp5XzPpNhS/tVx4nS7X33BzaYI90hY8ZZubuj8SCybhV2fFKC+MS
ZtM1gvPTLEdBLVvM2yixfIRA/2yHPAX0O4Y4t0/I59eUYknI9GgNAIaDbZMGE7NqqPr8ilJBAeKq
P4v+IQEmI7VaX8SSpOA0wUZqs76LfhKQ1GLL9A==
—–END CERTIFICATE—–
Step 6: Make private keystore file certified by using following command.
keytool -selfcert -alias satnewprivkey -keystore satnewprivkeystore -keypass satsat -storepass satsat
Step 7: Make public keystore file certified by using following command.
keytool -selfcert -alias satnewpubcert -keystore satnewpubcertkeystore -keypass satsat -storepass satsat
Step 8: Export public keytore into private keystore file. After running following command public keystore will be exported into private keystore file.
keytool -export -keystore satnewpubcertkeystore -alias satnewpubcert -storepass satsat -file satnewpubcert
This will give output as like as follows
Certificate stored in file <satnewpubcert>
Step 9: Print public certificate by using following command.
keytool -printcert -file satnewpubcert
This will give output as like as follows
Owner: CN=satnewpubcert
Issuer: CN=satnewpubcert
Serial number: 47ea3e8e
Valid from: Wed Mar 26 17:46:14 GMT+05:30 2008 until: Tue Jun 24 17:46:14 GMT+05:30 2008
Certificate fingerprints:
MD5: D6:24:38:53:47:96:C6:D6:D3:D3:6B:3E:B6:74:CD:8E
SHA1: C7:61:E9:6A:6E:FB:F6:B0:8B:52:C3:0F:C2:03:49:D3:1D:41:36:58
Signature algorithm name: SHA1withRSA
Version: 3
Step 10: Make public certificate as trusted by using following command.
keytool -import -alias satnewpubcert -trustcacerts -file satnewpubcert -keystore satnewprivkeystore -storepass satsat
This command will ask question to trust certificate give yes.
You will get output as like as follows.
Owner: CN=satnewpubcert
Issuer: CN=satnewpubcert
Serial number: 47ea3e8e
Valid from: Wed Mar 26 17:46:14 GMT+05:30 2008 until: Tue Jun 24 17:46:14 GMT+05:30 2008
Certificate fingerprints:
MD5: D6:24:38:53:47:96:C6:D6:D3:D3:6B:3E:B6:74:CD:8E
SHA1: C7:61:E9:6A:6E:FB:F6:B0:8B:52:C3:0F:C2:03:49:D3:1D:41:36:58
Signature algorithm name: SHA1withRSA
Version: 3
Trust this certificate? [no]: yes
Certificate was added to keystore
Step 11: Print created private keystore by running following command.
keytool -list -keystore satnewprivkeystore
Above command will ask password. Type “satsat” (This is keystore password which we are given while creating private keystore.)
This will give output like as follows after giving password. Now you can private keystore has public certificate entry also.
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
satnewprivkey, Mar 26, 2008, PrivateKeyEntry,
Certificate fingerprint (MD5): 00:86:1C:32:26:01:00:C2:FB:15:FE:EC:B5:17:03:E2
satnewpubcert, Mar 26, 2008, trustedCertEntry,
Certificate fingerprint (MD5): D6:24:38:53:47:96:C6:D6:D3:D3:6B:3E:B6:74:CD:8E
Step 12: Change store type JKS by using following command.
keytool -list -v -keystore satnewprivkeystore -storepass satsat -storetype JKS
This will give output like as follows.
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
Alias name: satnewprivkey
Creation date: Mar 26, 2008
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=satnewprivkey
Issuer: CN=satnewprivkey
Serial number: 47ea3e86
Valid from: Wed Mar 26 17:46:06 GMT+05:30 2008 until: Tue Jun 24 17:46:06 GMT+05:30 2008
Certificate fingerprints:
MD5: 00:86:1C:32:26:01:00:C2:FB:15:FE:EC:B5:17:03:E2
SHA1: 45:33:11:1A:5E:9D:66:C9:55:7A:73:08:64:DE:63:BD:1C:C0:F9:41
Signature algorithm name: SHA1withRSA
Version: 3
*******************************************
*******************************************
Alias name: satnewpubcert
Creation date: Mar 26, 2008
Entry type: trustedCertEntry
Owner: CN=satnewpubcert
Issuer: CN=satnewpubcert
Serial number: 47ea3e8e
Valid from: Wed Mar 26 17:46:14 GMT+05:30 2008 until: Tue Jun 24 17:46:14 GMT+05:30 2008
Certificate fingerprints:
MD5: D6:24:38:53:47:96:C6:D6:D3:D3:6B:3E:B6:74:CD:8E
SHA1: C7:61:E9:6A:6E:FB:F6:B0:8B:52:C3:0F:C2:03:49:D3:1D:41:36:58
Signature algorithm name: SHA1withRSA
Version: 3
*******************************************
*******************************************
Creating Server Application
Step 1: Download Following Jar files.
activation.jar
aopalliance-1.0.jar
commons-collections-3.2.jar
commons-lang-2.1.jar
commons-logging-1.1.jar
geronimo-activation-2.0.1.jar
geronimo-annotation_1.0_spec-1.1.jar
geronimo-javamail_1.4_mail-1.2.jar
geronimo-servlet_2.5_spec-1.1.jar
geronimo-ws-metadata_2.0_spec-1.1.1.jar
jaxb-api.jar
jaxb-api-2.0.jar
jaxb-impl-2.0.5.jar
jaxb-xjc.jar
jaxws-api.jar
mail.jar
neethi-2.0.jar
opensaml-1.0.1.jar
saaj-api.jar
saaj-impl.jar
spring-beans-2.0.6.jar
spring-context-2.0.6.jar
spring-core-2.0.6.jar
spring-web-2.0.6.jar
stax-api-1.0.1.jar
velocity-1.5.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.1.jar
xalan-2[1].6.0.jar
xalan-2[1].7.0.jar
xml-resolver-1.2.jar
xmlsec-1.2.1.jar
cxf-bundle-2.0.4-incubator.jar
XmlSchema-1.3.2.jar
wss4j-1.5.1.jar
Step 2: Create New Java project in eclipse (CXFServerSecurity).
Step 3: Create WEB-INF folder inside project folder.
Step 4: Create classes folder inside WEB-INF folder.
Step 5: Create lib folder inside WEB-INF folder.
Step 6: Copy all the jar file into lib folder.
Step 7: Add all jar files into classpath (In Eclipse set java build path->Libraries). Add set Default output folder into CXFServerSecurity/WEB-INF/classes
Step 8: Create Remote Interface IHello.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 9: Create Implementation Class IHello_Impl.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService(endpointInterface = “com.sungard.cxf.example.server.IHello”)
public class IHello_Impl implements IHello {
public String sayHello(String value) {
return “You Said” + value;
}
}
Step 10: Create PasswordHandler.java file to handle usernames and passwords. Here you have to give public certificate alias name for checking. Password is alias password.
if (pc.getIdentifer().equals(“satnewpubcert”)) {
pc.setPassword(“satsat”);
}
package com.sungard.cxf.example.server;
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 PasswordHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println(“Enterd PasswordHandler::handle”);
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (pc.getIdentifer().equals(“satnewpubcert”)) {
pc.setPassword(“satsat”);
}
System.out.println(“Leaving PasswordHandler::handle”);
}
}
Step 11: Create Interceptor class to handle soap requests ValidateUserTokenInterceptor.java.
package com.sungard.cxf.example.server;
import java.util.Vector;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSUsernameTokenPrincipal;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
public class ValidateUserTokenInterceptor extends AbstractPhaseInterceptor {
public ValidateUserTokenInterceptor(String s) {
super(s);
}
public ValidateUserTokenInterceptor() {
super(Phase.UNMARSHAL);
}
public void handleMessage(Message message) {
System.out
.println(“Enterd ValidateUserTokenInterceptor::handleMessage”);
boolean userTokenValidated = false;
Vector result = (Vector) message
.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
for (int i = 0; i < result.size(); i++) {
WSHandlerResult res = (WSHandlerResult) result.get(i);
for (int j = 0; j < res.getResults().size(); j++) {
WSSecurityEngineResult secRes = (WSSecurityEngineResult) res
.getResults().get(j);
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::Class”
+ secRes.getPrincipal().getClass());
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::ClassName”
+ secRes.getPrincipal().getClass().getName());
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::Name”
+ secRes.getPrincipal().getName());
if (secRes.getPrincipal().getClass().getName().equals(
“org.apache.ws.security.WSUsernameTokenPrincipal”)) {
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::WSUsernameTokenPrincipal”
+ secRes.getPrincipal().getName());
WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes
.getPrincipal();
if (!principal.isPasswordDigest()
|| principal.getNonce() == null
|| principal.getPassword() == null
|| principal.getCreatedTime() == null) {
throw new RuntimeException(“Invalid Security Header”);
} else {
System.out
.println(“ValidateUserTokenInterceptor::handleMessage::userTokenValidated = true”);
userTokenValidated = true;
}
}
}
}
if (!userTokenValidated) {
throw new RuntimeException(“Security processing failed”);
}
System.out
.println(“Leaving ValidateUserTokenInterceptor::handleMessage”);
}
}
Step 12: Create beans.xml file to setup the application context for the server.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<import resource=”classpath:META-INF/cxf/cxf.xml” />
<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />
<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />
<jaxws:endpoint id=”helloWorld”
implementor=”com.sungard.cxf.example.server.IHello_Impl”
address=”/HelloService”>
<jaxws:inInterceptors>
<bean id=”logIn”
/>
<bean id=”logOut”
/>
<bean
/>
<bean
>
<property name=”properties”>
<map>
<entry key=”action”
value=”UsernameToken Signature” />
<entry key=”passwordType” value=”PasswordText” />
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.PasswordHandler” />
<entry key=”signaturePropFile”
value=”server_sign.properties”>
</entry>
</map>
</property>
</bean>
<bean
/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
Step 13: Create server_sign.properties under WEB-INF\classes folder to mention private keystore file details.
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=satsat
org.apache.ws.security.crypto.merlin.file=satnewprivkeystore
Step 14: Copy all keystore and certificate files under WEB-INF\classes folder.
Step 15: Create web.xml file
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!DOCTYPE web-app
PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-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>
Step 16: Create ant folder inside project. And Create build.xml file inside ant folder.
<?xml version=”1.0″ encoding=”UTF-8″?>
<project basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”securityservice.war”>
<fileset dir=”${basedir}”>
<include name=”**/*.class” />
<include name=”**/*sat*” />
<include name=”**/*.properties*” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml” />
<exclude name=”**/*build*” />
</fileset>
</jar>
</target>
</project>
Step 17: Run build.xml using Ant.
Step 18: Deploy securityservice.war into Web/Application Server (Tomcat/JBoss).
Step 19: Verify application deployed successfully or by using following url.
http://localhost:8080/securityservice/HelloService?wsdl
Step 20: Browser will show wsdl file our web service.
Creating Client Application.
Step 1: Create New Java project in Eclipse
Step 2: Create folder Structure as like above application
Step 3: Use same jar files used for Server application.
Step 4: Set all the jars files into classpath.
Step 5: Create Remote Interface in client (IHello.java) (You can use wsdl2java for creating same)
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 6: Create ClientPasswordCallback.java for handling soap request in client side. Here you have set the password what you are given public alias.
pc.setPassword(“satsat”);
package com.sungard.cxf.example.server;
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 ClientPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// set the password for our message.
pc.setPassword(“satsat”);
}
}
Step 7: Create the service factory (AuthServiceFactory.java), which is extremely easy since all the work was done in the Spring file:
package com.sungard.cxf.example.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class AuthServiceFactory {
private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { “cxfClient.xml” });
public AuthServiceFactory() {
}
public IHello getService() {
return (IHello) context.getBean(“client”);
}
}
Step 8: Create Client.java to invoke the service.
package com.sungard.cxf.example.server;
public final class Client {
private Client() {
}
public static void main(String args[]) throws Exception {
AuthServiceFactory af = new AuthServiceFactory();
IHello client1 = af.getService();
String response1 = client1.sayHello(“Hello”);
System.out.println(“Response: ” + response1);
}
}
Step 9: Create cxfClient.xml to setup the application context for the client.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<bean id=”proxyFactory”
>
<property name=”serviceClass”
value=”com.sungard.cxf.example.server.IHello” />
<property name=”address”
value=”http://localhost:8080/securityservice/HelloService” />
<property name=”inInterceptors”>
<list>
<ref bean=”logIn” />
</list>
</property>
<property name=”outInterceptors”>
<list>
<ref bean=”logOut” />
<ref bean=”saajOut” />
<ref bean=”wss4jOut” />
</list>
</property>
</bean>
<bean id=”client”
factory-bean=”proxyFactory” factory-method=”create” />
<bean id=”logIn”
/>
<bean id=”logOut”
/>
<bean id=”saajOut”
/>
<bean id=”wss4jOut”
>
<constructor-arg>
<map>
<entry key=”action” value=”UsernameToken Signature” />
<entry key=”user” value=”satnewpubcert” />
<entry key=”passwordType” value=”PasswordDigest” />
<entry key=”signaturePropFile”
value=”client_sign.properties” />
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.ClientPasswordCallback” />
</map>
</constructor-arg>
</bean>
</beans>
Step 11: Create client_sign.properties file under WEB-INF\classes folder. To give public keystore file details.
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=satsat
org.apache.ws.security.crypto.merlin.keystore.alias=satnewpubcert
org.apache.ws.security.crypto.merlin.file=satnewpubcertkeystore
Step 12: Copy keystore and certificates in WEB-INF\classes folder. (Or set it in classpath)
Step 13: Run Client.java
You will get response like as follows.
Response: You SaidHello
Note:
Client Side:
We Set User name in client cxfClient.xml file. That is public alias name. (We can set the same through program also and we can read it xml/properties files. We can pass the same in runtime also)
<entry key=“user” value=“satnewpubcert”/>
We Set password in ClientPasswordCallback.java class (We can pass same in runtime also)
// set the password for our message.
pc.setPassword(“satsat”);
You can see the In & Outbound Messages in Client Side. As like as follows. This will go with signature.
INFO: Outbound Message
—————————
Encoding: UTF-8
Headers: {SOAPAction=[“”], Accept=[*]}
Messages:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Header>
<wsse:Security xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” soap:mustUnderstand=”1″><ds:Signature xmlns:ds=”http://www.w3.org/2000/09/xmldsig#” Id=”Signature-7859095″>
<ds:SignedInfo xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
<ds:CanonicalizationMethod Algorithm=”http://www.w3.org/2001/10/xml-exc-c14n#” xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/>
<ds:SignatureMethod Algorithm=”http://www.w3.org/2000/09/xmldsig#rsa-sha1″ xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/>
<ds:Reference URI=”#id-26564976″ xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
<ds:Transforms xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
<ds:Transform Algorithm=”http://www.w3.org/2001/10/xml-exc-c14n#” xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/>
</ds:Transforms>
<ds:DigestMethod Algorithm=”http://www.w3.org/2000/09/xmldsig#sha1″ xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/>
<ds:DigestValue xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>rU2PYdKHS7wdWvzrSl4fiH90AQc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
UU0q/hQFWYrOMt+iPHiuuc0ffb6iqbJu1A115gGO4DHlt850pRQVMJGxn1f+XQaxjLjJRqzYa1lC
HQdZyavkLwpMWK1M/VLCn/2M9sS/c64wEIrLhE8vq9jO31O1Ms17KamgdvV9ThpR3sD4BUg3Q3Q1
vyi5+YVroHBBgqtVmFg=
</ds:SignatureValue>
<ds:KeyInfo xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
<wsse:SecurityTokenReference xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”STRId-29118152″ xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”><ds:X509Data xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
<ds:X509IssuerSerial xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>
<ds:X509IssuerName xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>CN=satnewpubcert</ds:X509IssuerName>
<ds:X509SerialNumber xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>1206533774</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data></wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature><wsse:UsernameToken xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”UsernameToken-7189308″ xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”><wsse:Username xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>satnewpubcert</wsse:Username><wsse:Password Type=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest” xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>MSsmgsLBGcV+gKRTWBRsKKTrpQw=</wsse:Password><wsse:Nonce xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>q/4pOweIQLxL+VWqik5Pag==</wsse:Nonce><wsu:Created xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”>2008-03-26T13:26:12.813Z</wsu:Created></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”id-26564976″><ns1:sayHello xmlns:ns1=”http://server.example.cxf.sungard.com/”><arg0>Hello</arg0></ns1:sayHello></soap:Body></soap:Envelope>
————————————–
Mar 26, 2008 6:56:14 PM org.apache.cxf.interceptor.LoggingInInterceptor logging
INFO: Inbound Message
—————————-
Encoding: UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Wed, 26 Mar 2008 13:26:14 GMT], Content-Length=[230], SOAPAction=[“”], Server=[Apache-Coyote/1.1]}
Messages:
Message:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”><soap:Body><ns1:sayHelloResponse xmlns:ns1=”http://server.example.cxf.sungard.com/”><return>You SaidHello</return></ns1:sayHelloResponse></soap:Body></soap:Envelope>
————————————–
Server Side:
User Name and password are got validated in PasswordHandler.java file. These values we can read it from xml/properties or from configuration files. Identifier value is public alias name and password is public alias password.
if (pc.getIdentifer().equals(“satnewpubcert”)) {
pc.setPassword(“satsat”);
}
Developing CXF Web services with WS-Security
Creating Server Application
Step 1: Download Following Jar files.
activation.jar
aopalliance-1.0.jar
commons-collections-3.2.jar
commons-lang-2.1.jar
commons-logging-1.1.jar
geronimo-activation-2.0.1.jar
geronimo-annotation_1.0_spec-1.1.jar
geronimo-javamail_1.4_mail-1.2.jar
geronimo-servlet_2.5_spec-1.1.jar
geronimo-ws-metadata_2.0_spec-1.1.1.jar
jaxb-api.jar
jaxb-api-2.0.jar
jaxb-impl-2.0.5.jar
jaxb-xjc.jar
jaxws-api.jar
mail.jar
neethi-2.0.jar
opensaml-1.0.1.jar
saaj-api.jar
saaj-impl.jar
spring-beans-2.0.6.jar
spring-context-2.0.6.jar
spring-core-2.0.6.jar
spring-web-2.0.6.jar
stax-api-1.0.1.jar
velocity-1.5.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.1.jar
xalan-2[1].6.0.jar
xalan-2[1].7.0.jar
xml-resolver-1.2.jar
xmlsec-1.2.1.jar
cxf-bundle-2.0.4-incubator.jar
XmlSchema-1.3.2.jar
wss4j-1.5.1.jar
Step 2: Create New Java project in eclipse (CXFServer).
Step 3: Create WEB-INF folder inside project folder.
Step 4: Create classes folder inside WEB-INF folder.
Step 5: Create lib folder inside WEB-INF folder.
Step 6: Copy all the jar file into lib folder.
Step 7: Add all jar files into classpath (In Eclipse set java build path->Libraries). Add set Default output folder into CXFServer/WEB-INF/classes
Step 8: Create Remote Interface IHello.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 9: Create Implementation Class IHello_Impl.java
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService(endpointInterface = “com.sungard.cxf.example.server.IHello”)
public class IHello_Impl implements IHello {
public String sayHello(String value) {
return “You Said” + value;
}
}
Step 10: Create PasswordHandler.java file to handle usernames and passwords.
package com.sungard.cxf.example.server;
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 PasswordHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println(“Enterd PasswordHandler::handle”);
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (pc.getIdentifer().equals(“arsenal”)) {
pc.setPassword(“gunners”);
}
System.out.println(“Leaving PasswordHandler::handle”);
}
}
Step 11: Create Interceptor class to handle soap requests ValidateUserTokenInterceptor.java.
package com.sungard.cxf.example.server;
import java.util.Vector;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSUsernameTokenPrincipal;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
public class ValidateUserTokenInterceptor extends AbstractPhaseInterceptor {
public ValidateUserTokenInterceptor(String s) {
super(s);
}
public ValidateUserTokenInterceptor(){
super(Phase.UNMARSHAL);
}
public void handleMessage(Message message) {
System.out.println(“Enterd ValidateUserTokenInterceptor::handleMessage”);
boolean userTokenValidated = false;
Vector result = (Vector) message
.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
for (int i = 0; i < result.size(); i++) {
WSHandlerResult res = (WSHandlerResult) result.get(i);
for (int j = 0; j < res.getResults().size(); j++) {
WSSecurityEngineResult secRes = (WSSecurityEngineResult) res
.getResults().get(j);
WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes.getPrincipal();
if (!principal.isPasswordDigest()
|| principal.getNonce() == null
|| principal.getPassword() == null
|| principal.getCreatedTime() == null) {
throw new RuntimeException(“Invalid Security Header”);
} else {
userTokenValidated = true;
}
}
}
if (!userTokenValidated) {
throw new RuntimeException(“Security processing failed”);
}
System.out.println(“Leaving ValidateUserTokenInterceptor::handleMessage”);
}
}
Step 12: Create beans.xml file to setup the application context for the server.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<import resource=”classpath:META-INF/cxf/cxf.xml” />
<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />
<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />
<jaxws:endpoint id=”helloWorld”
implementor=”com.sungard.cxf.example.server.IHello_Impl”
address=”/HelloService”>
<jaxws:inInterceptors>
<bean
/>
<bean
>
<property name=”properties”>
<map>
<entry key=”action” value=”UsernameToken” />
<entry key=”passwordType” value=”PasswordText” />
<entry key=”passwordCallbackClass”
value=”com.sungard.cxf.example.server.PasswordHandler” />
</map>
</property>
</bean>
<bean
/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
Step 13: Create web.xml file
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!DOCTYPE web-app
PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-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>
Step 14: Create ant folder inside project. And Create build.xml file inside ant folder.
<?xml version=”1.0″ encoding=”UTF-8″?>
<project basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”helloservice.war”>
<fileset dir=”${basedir}”>
<include name=”**/*.class” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar” />
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml” />
<exclude name=”**/*build*” />
</fileset>
</jar>
</target>
</project>
Step 15: Run build.xml using Ant.
Step 16: Deploy helloservice.war into Web/Application Server (Tomcat/JBoss).
Step 17: Verify application deployed successfully or by using following url.
http://localhost:8080/helloservice/HelloService?wsdl
Step 18: Browser will show wsdl file our web service.
Creating Client Application.
Step 1: Create New Java project in Eclipse
Step 2: Create folder Structure as like above application
Step 3: Use same jar files used for Server application.
Step 4: Set all the jars files into classpath.
Step 5: Create Remote Interface in client (IHello.java) (You can use wsdl2java for creating same)
package com.sungard.cxf.example.server;
import javax.jws.WebService;
@WebService
public interface IHello {
public String sayHello(String value);
}
Step 6: Create ClientPasswordCallback.java for handling soap request in client side.
package com.sungard.cxf.example.server;
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 ClientPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// set the password for our message.
pc.setPassword(“gunners”);
}
}
Step 7: Create the service factory (AuthServiceFactory.java), which is extremely easy since all the work was done in the Spring file:
package com.sungard.cxf.example.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class AuthServiceFactory {
private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { “cxfClient.xml” });
public AuthServiceFactory() {
}
public IHello getService() {
return (IHello) context.getBean(“client”);
}
}
Step 8: Create Client.java to invoke the service.
package com.sungard.cxf.example.server;
public final class Client {
private Client() {
}
public static void main(String args[]) throws Exception {
AuthServiceFactory af = new AuthServiceFactory();
IHello client1 = af.getService();
String response1 = client1.sayHello(“Hello”);
System.out.println(“Response: ” + response1);
}
}
Step 9: Create cxfClient.xml to setup the application context for the client.
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<bean id=”proxyFactory”>
<property name=”serviceClass” value=”com.sungard.cxf.example.server.IHello”/>
<property name=”address” value=”http://localhost:8080/helloservice/HelloService”/>
<property name=”inInterceptors”>
<list>
<ref bean=”logIn” />
</list>
</property>
<property name=”outInterceptors”>
<list>
<ref bean=”logOut” />
<ref bean=”saajOut” />
<ref bean=”wss4jOut” />
</list>
</property>
</bean>
<bean id=”client” factory-bean=”proxyFactory” factory-method=”create” />
<bean id=”logIn” />
<bean id=”logOut” />
<bean id=”saajOut” />
<bean id=”wss4jOut”>
<constructor-arg>
<map>
<entry key=”action” value=”UsernameToken” />
<entry key=”user” value=”arsenal” />
<entry key=”passwordType” value=”PasswordDigest” />
<entry key=”passwordCallbackClass” value=”com.sungard.cxf.example.server.ClientPasswordCallback” />
</map>
</constructor-arg>
</bean>
</beans>
Step 10: Run Client.java
You will get response like as follows.
Response: You SaidHello
Note:
Client Side:
We Set User name in client cxfClient.xml file. (We can set the same through program also and we can read it xml/properties files. We can pass the same in runtime also)
<entry key=“user” value=“arsenal” />
We Set password in ClientPasswordCallback.java class (We can pass same in runtime also)
// set the password for our message.
pc.setPassword(“gunners”);
You can see the In & Outbound Messages in Client Side. As like as follows.
INFO: Outbound Message
—————————
Encoding: UTF-8
Headers: {SOAPAction=[“”], Accept=[*]}
Messages:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Header>
<wsse:Security xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd” soap:mustUnderstand=”1″><wsse:UsernameToken xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd” wsu:Id=”UsernameToken-9702276″ xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”><wsse:Username xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>arsenal</wsse:Username><wsse:Password Type=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest” xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>3bQTW92CrAxUt9rgqvqyY4pfJi8=</wsse:Password><wsse:Nonce xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”>hxV58wDgiNTf4tcypfiN6Q==</wsse:Nonce><wsu:Created xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd”>2008-03-25T11:04:15.111Z</wsu:Created></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ns1:sayHello xmlns:ns1=”http://server.example.cxf.sungard.com/”><arg0>Hello</arg0></ns1:sayHello></soap:Body></soap:Envelope>
————————————–
Mar 25, 2008 4:34:15 PM org.apache.cxf.interceptor.LoggingInInterceptor logging
INFO: Inbound Message
—————————-
Encoding: UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Tue, 25 Mar 2008 11:04:15 GMT], Content-Length=[230], SOAPAction=[“”], Server=[Apache-Coyote/1.1]}
Messages:
Message:
Payload: <soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”><soap:Body><ns1:sayHelloResponse xmlns:ns1=”http://server.example.cxf.sungard.com/”><return>You SaidHello</return></ns1:sayHelloResponse></soap:Body></soap:Envelope>
————————————–
Server Side:
User Name and password are got validated in PasswordHandler.java file. These values we can read it from xml/properties or from configuration files.
if (pc.getIdentifer().equals(“arsenal”)) {
pc.setPassword(“gunners”);
}
RESTful web services using the Jersey framework
Brief Description
This sample application provides the below services
- Displays the list of employees in the organization
- Append new employee to the system
- Get the specific employee information based on the employee id
Restful Web Service:
REpresentational State Transfer (REST) is a key design idiom that embraces a stateless client-server architecture in which the web services are viewed as resources and can be identified by their URLs. Web service clients that want to use these resources access a particular representation by transferring application content using a small globally defined set of remote methods that describe the action to be performed on the resource. REST is an analytical description of the existing web architecture, and thus the interplay between the style and the underlying HTTP protocol appears seamless.
Jersey Framework:
Jersey is the open source (under the CDDL license) JAX-RS (JSR 311) Reference Implementation for building RESTful Web services. But, it is also more than the Reference Implementation. Jersey provides additional APIs and extension points (SPIs) so that developers may extend Jersey to suite their needs.
Jersey is currently available as an early access implementation. Jersey cannot go to version 1.0 until JAX-RS reaches the final release and is an approved JSR. Until that point Jersey will track the JSR 311 API and will regularly update according to 311 Expert Group agreed snapshots of the API.
Latest Jersey snapshot can be downloaded from https://jersey.dev.java.net/files/documents/7056/73619/jersey-0.4-ea.zip
Follow the below Steps to create a sample RESTful application
Step1: Create a web project with the below directory structure
Step2: Create a java file to make it as a RESTful web service
In this sample application we have taken the EmployeeService.java as the web service.
Below is the code for the EmployeeService.java
package com.peter.sample;
import javax.ws.rs.ConsumeMime;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.ProduceMime;
import javax.ws.rs.UriParam;
import javax.ws.rs.UriTemplate;
import javax.ws.rs.WebApplicationException;
import com.sun.ws.rest.api.representation.FormURLEncodedProperties;
/**
*
* @author Peter Arockiaraj Employee service
*
*/
@UriTemplate(“/employee”)
public class EmployeeService {
@HttpMethod(“GET”)
@ProduceMime(“text/html”)
public String listEmployees() {
String result = “Satyam Employee list”;
result += ”
“;
for (Employee employee : Employee.EMPLOYEE_LIST) {
result += ”
“;
result += ”
“;
result += ”
“;
}
result += ”
” + employee.getId() + “ | ” + employee.getName() + “ | ” + employee.getDesignation() + “ |
“;
return result;
}
@HttpMethod(“GET”)
@UriTemplate(“/{id}”)
@ProduceMime(“text/json”)
public String listEmployee(@UriParam(“id”)
String idString) {
int id = 0;
try {
id = Integer.parseInt(idString);
} catch (NumberFormatException e) {
throw new WebApplicationException(405);
}
try {
return Employee.getEmployee(id).toJson();
} catch (IndexOutOfBoundsException e) {
throw new WebApplicationException(404);
}
}
@HttpMethod(“GET”)
@UriTemplate(“/new”)
@ProduceMime(“text/html”)
public String formForEmployee() {
String result = “Create New Employee”;
result += “”;
result += “Name :
“;
result += “Designation :
“;
result += “”;
return result;
}
@UriTemplate(“/add”)
@HttpMethod(“POST”)
@ProduceMime(“text/plain”)
@ConsumeMime(“text/html”)
public String addEmployee(FormURLEncodedProperties formData) {
String name = formData.get(“name”);
String designation = formData.get(“designation”);
if ((name == null) || (designation == null)) {
throw new WebApplicationException(405);
} else {
Employee.addEmployee(name, designation);
}
return “Added OK”;
}
}
EmployeeService uses Employee.java
package com.peter.sample;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Peter Arockiaraj
* A model class for this very simple Jersey REST example.
*
*/
public class Employee {
/**
* In memory list. In a real world example this might
* be backed by a database
*/
public static List EMPLOYEE_LIST = new ArrayList();
/**
* Method to get the Employee Details based on the Employee ID
* @param id
* @return Employee
*/
public static Employee getEmployee(int id) {
return EMPLOYEE_LIST.get(id);
}
/**
* Method to add the new employee details to the Employee List
* @param Name
* @param Designation
*/
public static void addEmployee(String Name, String Designation) {
EMPLOYEE_LIST.add(new Employee(EMPLOYEE_LIST.size(), Name, Designation));
}
/**
* Create some data
*/
static {
EMPLOYEE_LIST.add(new Employee(71503,”Hari”,”Business Analyst”));
EMPLOYEE_LIST.add(new Employee(14352,”Mathew”,”Business Analyst”));
EMPLOYEE_LIST.add(new Employee(17689,”Vamsi”,”Business Analyst”));
EMPLOYEE_LIST.add(new Employee(36157,”Naveen”,”Business Analyst”));
}
private int id;
private String name;
private String designation;
/**
* Creates an Employee Instance
* @param id
* @param name
* @param designation
*/
public Employee(int id, String name, String designation) {
super();
this.id = id;
this.name = name;
this.designation = designation;
}
/**
* @return
*/
public String toJson() {
String result = “{ ‘id’ : ” + this.id + ” , “;
result += ” ‘Name’ : ” + this.name + ” , “;
result += “‘Designation’ : ” + this.designation + ” }”;
return result;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
}
Step4: Create a webresouce class
package com.peter.sample;
import com.sun.ws.rest.api.core.DefaultResourceConfig;
/**
*
* @author Peter Arockiaraj
* WebResource definition for the Employee Service example.
*/
public class WebResources extends DefaultResourceConfig {
public WebResources() {
getResourceClasses().add(EmployeeService.class);
// getResourceClasses().add(OtherService.class);
// can add any number of Web services here.
}
}
Step3: Make sure that the below jars files in the classpath
• jeesey.jar
• jsr311-api.jar
• jettison-1.0-RC1.jar
Step4: create the web.xml with the following code
<?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”>
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.ws.rest.impl.container.servlet.ServletAdaptor</servlet-class>
<init-param>
<param-name>webresourceclass</param-name>
<param-value>com.satyam.adms.WebResources</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
Step5: Build the war file and deploy in the web server.
Step6: Below are the URLs to access the application
http://localhost:8080/EmployeeProject/resources/employee : To view the list of employees
http://localhost:8080/EmployeeProject/resources/employee/new : To append the new employee
http://localhost:8080/EmployeeProject/resources/employee/1 : To get the employee id =1 info
Developing Web Services By Using Spring and CXF
Step 1: Download Following Jar files.
Open up your favorite IDE and create a new project. The first thing we need to do is add the necessary CXF dependencies to the project. You can find these dependencies in the CXF distribution in the lib directory.
commons-logging-1.1.jar
geronimo-activation_1.1_spec-1.0-M1.jar (or Sun’s Activation jar)
geronimo-annotation_1.0_spec-1.1.jar (JSR 250)
geronimo-javamail_1.4_spec-1.0-M1.jar (or Sun’s JavaMail jar)
geronimo-servlet_2.5_spec-1.1-M1.jar (or Sun’s Servlet jar)
geronimo-ws-metadata_2.0_spec-1.1.1.jar (JSR 181)
jaxb-api-2.0.jar
jaxb-impl-2.0.5.jar
jaxws-api-2.0.jar
neethi-2.0.jar
saaj-api-1.3.jar
saaj-impl-1.3.jar
stax-api-1.0.1.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.1.jar
XmlSchema-1.2.jar
xml-resolver-1.2.jar
The Spring jars:
aopalliance-1.0.jar
spring-core-2.0.4.jar
spring-beans-2.0.4.jar
spring-context-2.0.4.jar
spring-web-2.0.4.jar
And the CXF jar:
cxf-2.0-incubator.jar
Step 2: Create Following Folder Structure
Step 3: Create Following classes
- Address
- AddressType
- IAddressService
- AddressService
Address.java
package com.sungard.adms.address.ws;
public class Address {
private String name;
private String doorno;
private String road;
private String buildingName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoad() {
return road;
}
public void setRoad(String road) {
this.road = road;
}
public String getBuildingName() {
return buildingName;
}
public void setBuildingName(String buildingName) {
this.buildingName = buildingName;
}
public String getDoorno() {
return doorno;
}
public void setDoorno(String doorno) {
this.doorno = doorno;
}
}
AddressType.java
package com.sungard.adms.address.ws;
public enum AddressType {
HEBBALOFFICE,
ELECTRONIC_CITY,
ESTEEM_TOWERS,
LANGFORD_ROAD
}
IAddressService.java
package com.sungard.adms.address.ws;
/**
* CXF sample interface.
*
*/
@WebService
public interface IAddressService {
public Address getAddress(AddressType adsType);
}
AddressService.java
package com.sungard.adms.address.ws;
import java.util.HashMap;
/**
* This is the Implementation Class for IAddressService. Our Business Logic will
* be present here.
*
* @author PA71448
*
*/
@WebService(endpointInterface = “com.sungard.adms.address.ws.IAddressService”)
public class AddressService implements IAddressService {
private HashMap<AddressType, Address> addressList = new HashMap<AddressType, Address>();
/**
* Default Constructor for this service.
*/
public AddressService() {
Address bhr = new Address();
bhr.setBuildingName(“Kirloskar Business Park”);
bhr.setName(“Sungard”);
bhr.setRoad(“Hyderabad Road”);
bhr.setDoorno(“338”);
addressList.put(AddressType.HEBBALOFFICE, bhr);
Address bsd = new Address();
bsd.setBuildingName(“Electronic City”);
bsd.setName(“Sungard”);
bsd.setRoad(“Hosur Road”);
bsd.setDoorno(“143”);
addressList.put(AddressType.ELECTRONIC_CITY, bsd);
Address bet = new Address();
bet.setBuildingName(“Esteem Towers”);
bet.setName(“Sungard”);
bet.setRoad(“Railway Parallel Road”);
bet.setDoorno(“6”);
addressList.put(AddressType.ESTEEM_TOWERS, bet);
Address bla = new Address();
bla.setBuildingName(“LangFord Avenue”);
bla.setName(“Sungard”);
bla.setRoad(“LangFord Road”);
bla.setDoorno(“653”);
addressList.put(AddressType.LANGFORD_ROAD, bla);
}
@Override
public Address getAddress(AddressType adsType) {
return addressList.get(adsType);
}
}
Step 4: Create beans.xml file in WEB-INF folder
beans.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:jaxws=”http://cxf.apache.org/jaxws”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd”>
<import resource=”classpath:META-INF/cxf/cxf.xml” />
<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />
<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />
<jaxws:endpoint
id=”helloWorld”
implementor=”com.sungard.adms.address.ws.AddressService”
address=”/AddressService” />
</beans>
Step 5: Create web.xml file in WEB-INF folder
web.xml
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!DOCTYPE web-app
PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-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>
Step 6: Copy All class files with folder structure in WEB-INF classes Folder
Step 7:
Create ant directory in project root folder
Create build.xml file
build.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”ws” basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”cxfaddressservice.war” >
<fileset dir=”${basedir}”>
<include name=”**/*.class”/>
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar”/>
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml”/>
<exclude name=”**/*build*”/>
</fileset>
</jar>
</target>
</project>
Step 8: Run ant build
Step 9: Deploy the war file in application server/web server
Step 10: Check application deployed properly or not by using following url. This url will show the wsdl file for this web service application.
http://localhost:8080/cxfaddressservice/AddressService?wsdl
Developing Web Services Client by Using JWSDP
Step 1: Download Following Jar files.
jaxrpc-impl.jar
jaxrpc-spi.jar
activation.jar
mail.jar
dom.jar
sax.jar
xalan.jar
xercesImpl.jar
saaj-impl.jar
FastInfoset.jar
saajImpl.jar
jsr173_api.jar
Step 2: Create a j2EE project AddressWSClient
Step 3: Create folders src, classes, lib ,wsdl under project root folder.
Step 4: Create file config.xml inside the project root as
config.xml
<?xml version=”1.0″ encoding=
“UTF-8″?>
<configuration xmlns=”http://java.sun.com/xml/ns/jax-rpc/ri/config”>
<wsdl location=
“wsdl\AddressService.wsdl”
packageName=
“com.sungard.adms.address.client.gen” />
</configuration>
Step 5: Copy the .wsdl from http://localhost:8080/cxfaddressservice/AddressService?wsdl into AddressWSClient/wsdl
Step 6: Generate client side stubs by executing…
wscompile -verbose -gen -d classes -s src -keep config.xml
Step 7: Copy all jar file into lib (Add them to build path)
Step 8: Create class AddressClient.java as
AddressClient.java
package com.sungard.adms.address.client.gen;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.ServiceFactory;
/**
* @author Peter Arockiaraj
*
* TODO To change the template for this generated type comment go to
* Window – Preferences – Java – Code Style – Code Templates
*/
public class AddressClient {
public static void main(String[] args) throws ServiceException,RemoteException,MalformedURLException{
try{
System.setProperty(“javax.xml.soap.MessageFactory”, “com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl”);
//System.setProperty(“javax.xml.soap.SOAPFactory”,”com.sun.xml.messaging.saaj.soap.ver1_1.SOAPFactory1_1Impl”);
//System.setProperty(“javax.xml.rpc.ServiceFactory”,”com.sun.xml.rpc.client.ServiceFactoryImpl”);
//System.setProperty(“javax.xml.soap.SOAPConnectionFactory”,”javax.xml.soap.SOAPConnectionFactory”);
//System.setProperty(“javax.xml.parsers.DocumentBuilderFactory”,”com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl”);
AddressServiceService_Impl impl =
new AddressServiceService_Impl();
IAddressService ws = impl.getAddressServicePort();
Address result = ws.getAddress(AddressType.HEBBALOFFICE);
System.out.println(“Direct Call Output\n”);
System.out.println(“Company Name:\t”+result.getName());
System.out.println(“Door No:\t”+result.getDoorno());
System.out.println(“Building Name:\t”+result.getBuildingName());
System.out.println(“Road Name:\t”+result.getRoad());
System.out.println(“Dynamic WS call”);
URL url = new URL(“http://localhost:8080/cxfaddressservice/AddressService?wsdl”);
QName qname = new QName(“http://ws.address.adms.sungard.com/”,”AddressServiceService”);
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(url,qname);
IAddressService hello = (IAddressService) service.getPort(IAddressService.class);
Address dynaddress=ws.getAddress(AddressType.ESTEEM_TOWERS);
System.out.println(“\nDynamic Call Output\n”);
System.out.println(“Company Name:\t”+dynaddress.getName());
System.out.println(“Door No:\t”+dynaddress.getDoorno());
System.out.println(“Building Name:\t”+dynaddress.getBuildingName());
System.out.println(“Road Name:\t”+dynaddress.getRoad());
}catch(Exception se){
System.out.println(“ServiceException ” + se.getMessage());
}
}
}
Step 9: Run AddressClient.java as a normal java application.
Developing Simple Web Services Client by Using Flex
Step 1: Create New Flex Project in Flex Builder.
Step 2: Open Main Application MXML.
Step 3: Copy & Paste Following Code.
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” xmlns=”*” layout=”absolute”
creationComplete=”userRequest.returnRecords()” height=”249″ width=”538″>
<mx:Form x=”22″ y=”10″ width=”493″>
<mx:HBox>
<mx:Label text=”Address Code”/>
<mx:TextInputfont-size:10.0pt;font-family:”Courier New”;mso-fareast-font-family:”Times New Roman”; color:#990000″>addresscode”/>
</mx:HBox>
<mx:HBox>
<mx:DataGridfont-size:10.0pt;font-family:”Courier New”; mso-fareast-font-family:”Times New Roman”;color:#990000″>dgUserRequest” x=”22″ y=”128″>
<mx:columns>
<mx:DataGridColumn headerText=”Building Name” dataField=”buildingName”/>
<mx:DataGridColumn headerText=”Door Number” dataField=”doorno”/>
<mx:DataGridColumn headerText=”Name” dataField=”name”/>
<mx:DataGridColumn headerText=”Road Name” dataField=”road”/>
</mx:columns>
</mx:DataGrid>
</mx:HBox>
<mx:Button label=”Submit” click=”clickHandler()”/>
</mx:Form>
<mx:WebService
id=”userRequest”
wsdl=”http://localhost:8080/cxfaddressservice/AddressService?wsdl”>
<mx:operation name=”getAddress” resultFormat=”object” result=”insertCFCHandler(event)”
fault=”mx.controls.Alert.show(event.fault.faultString)”/>
</mx:WebService>
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
private function insertCFCHandler(e:ResultEvent):void
{
dgUserRequest.dataProvider = e.result;
}
private function clickHandler():void
{
userRequest.getAddress(addresscode.text);
}
]]>
</mx:Script>
</mx:Application>
Step 4: Run Application.
Developing Web Services by Using Spring and XFire
Step 1: Download Following Jar files.
Step 2: Create Following Folder Structure
Step 3: Create Following classes
- Address
- AddressType
- IAddressService
- AddressService
Address.java
package com.sungard.adms.address.ws;
public class Address {
private String name;
private String doorno;
private String road;
private String buildingName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoad() {
return road;
}
public void setRoad(String road) {
this.road = road;
}
public String getBuildingName() {
return buildingName;
}
public void setBuildingName(String buildingName) {
this.buildingName = buildingName;
}
public String getDoorno() {
return doorno;
}
public void setDoorno(String doorno) {
this.doorno = doorno;
}
}
AddressType.java
package com.sungard.adms.address.ws;
public enum AddressType {
HEBBALOFFICE,
ELECTRONIC_CITY,
ESTEEM_TOWERS,
LANGFORD_ROAD
}
IAddressService.java
package com.sungard.adms.address.ws;
/** XFire sample interface.
*
*/
public interface IAddressService {
public Address getAddress(AddressType adsType);
}
AddressService.java
package com.sungard.adms.address.ws;
import java.util.HashMap;
/**
* This is the Implementation Class for IAddressService. Our Business Logic will
* be present here.
*
* @author PA71448
*
*/
public class AddressService implements IAddressService {
private HashMap<AddressType, Address> addressList = new HashMap<AddressType, Address>();
/**
* Default Constructor for this service.
*/
public AddressService() {
Address bhr = new Address();
bhr.setBuildingName(“Kirloskar Business Park”);
bhr.setName(“Sungard”);
bhr.setRoad(“Hyderabad Road”);
bhr.setDoorno(“338”);
addressList.put(AddressType.HEBBALOFFICE, bhr);
Address bsd = new Address();
bsd.setBuildingName(“Electronic City”);
bsd.setName(“Sungard”);
bsd.setRoad(“Hosur Road”);
bsd.setDoorno(“143”);
addressList.put(AddressType.ELECTRONIC_CITY, bsd);
Address bet = new Address();
bet.setBuildingName(“Esteem Towers”);
bet.setName(“Sungard”);
bet.setRoad(“Railway Parallel Road”);
bet.setDoorno(“6”);
addressList.put(AddressType.ESTEEM_TOWERS, bet);
Address bla = new Address();
bla.setBuildingName(“LangFord Avenue”);
bla.setName(“Sungard”);
bla.setRoad(“LangFord Road”);
bla.setDoorno(“653”);
addressList.put(AddressType.LANGFORD_ROAD, bla);
}
@Override
public Address getAddress(AddressType adsType) {
return addressList.get(adsType);
}
}
Step 4: Create applicationContext.xml file in WEB-INF folder
applicationContext.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>
<beans>
<bean/>
</beans>
Step 5: Create xfire-servlet.xml file in WEB-INF folder
xfire-servlet.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>
<beans>
<bean class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
<property>
<map>
<entry key=”/AddressService”>
<ref bean=”getAddress”/>
</entry>
</map>
</property>
</bean>
<!– Declare a parent bean with all properties common to both services –>
<bean class=”org.codehaus.xfire.spring.remoting.XFireExporter”>
<property>
<ref bean=”xfire.serviceFactory”/>
</property>
<property>
<ref bean=”xfire”/>
</property>
<property>
<ref bean=”addressService”/>
</property>
<property>
<value>com.sungard.adms.address.ws.IAddressService</value>
</property>
</bean>
</beans>
Step 6: Create web.xml file in WEB-INF folder
web.xml
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!DOCTYPE web-app
PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml
classpath:org/codehaus/xfire/spring/xfire.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>xfire</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xfire</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Step 7: Copy All class files with folder structure in WEB-INF classes Folder
Step 8:
Create ant directory in project root folder
Create build.xml file
build.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”ws” basedir=”../” default=”archive”>
<target name=”archive”>
<jar destfile=”address.war” >
<fileset dir=”${basedir}”>
<include name=”**/*.class”/>
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.jar”/>
</fileset>
<fileset dir=”${basedir}”>
<include name=”**/*.xml”/>
<exclude name=”**/*build*”/>
</fileset>
</jar>
</target>
</project>
Step 9: Run ant build
Step 10: Deploy the war file in application server/web server
Step 11: Check application deployed properly or not by using following url. This url will show the wsdl file for this web service application.
http://localhost:8080/address/AddressService?wsdl
Developing Web Services Client By Using Spring and XFire
Step 1: Download Following Jar files.
Step 2: Create Following Folder Structure
Step 3: Create following classes
- Address
- AddressType
- IAddressService
- WSClient
- MyApplicationClient (This is normal Java Application client. Not a web Client)
WsClient.java
package com.sungard.adms.address.ws.client;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.codehaus.xfire.XFire;
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import com.sungard.adms.address.ws.Address;
import com.sungard.adms.address.ws.AddressType;
import com.sungard.adms.address.ws.IAddressService;
/**
* Servlet working as a Web services client.
*
*/
public class WsClient extends HttpServlet {
private static Logger log = Logger.getLogger(WsClient.class);
/*
* doGet():
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// get request parameters
String addType = req.getParameter(“addressType”);
// use default values wherever needed
AddressType addrType;
if (addType == null)
addrType = AddressType.HEBBALOFFICE;
else
addrType = AddressType.valueOf(addType);
// invoke callWebService()
log.debug(“doGet(): call web service now. “);
Address responseGot = null;
try {
responseGot = callWebService(AddressType.HEBBALOFFICE);
} catch (Exception e) {
e.printStackTrace();
}
// prepare the response page
resp.setContentType(“text/html”);
java.io.PrintWriter out = resp.getWriter();
out.println(“<html>”);
out
.println(“<head><title>Sungard Bangalore – Address Service</title></head><body>”);
out.println(“<h2>Sungard Bangalore – Address Service </h2>”);
out.println(“<B>Service Request</B>” + “<br>” + “Address – ” + addType
+ “<TABLE>” + “<TR><TD>Name: </TD><TD>” + responseGot.getName()
+ “</TD></TR>” + “<TR><TD>Door Number: </TD><TD>”
+ responseGot.getDoorno() + “</TD></TR>”
+ “<TR><TD>Building Name: </TD><TD>”
+ responseGot.getBuildingName() + “<br>” + “</TD></TR>”
+ “<TR><TD>Road: </TD><TD>” + responseGot.getRoad()
+ “</TD></TR>” + “</TABLE>”);
}
/*
* call the web service
*
*/
public static Address callWebService(AddressType addtype)
throws MalformedURLException, Exception {
// create a metadata of the service
Service serviceModel = new ObjectServiceFactory()
.create(IAddressService.class);
System.out.println(“callSoapServiceLocal(): got service model.”);
// create a proxy for the deployed service
XFire xfire = XFireFactory.newInstance().getXFire();
XFireProxyFactory factory = new XFireProxyFactory(xfire);
String serviceUrl = “http://localhost:8080/address/AddressService”;
IAddressService client = null;
try {
client = (IAddressService) factory.create(serviceModel, serviceUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
}
// invoke the service
Address address = null;
try {
address = client.getAddress(addtype);
} catch (Exception e) {
e.printStackTrace();
}
// return the response
return address;
}
/*
* doPost():
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
static String SPACE = “ ”;
}
MyApplicationClient.java
package com.sungard.adms.address.ws.client;
import java.net.MalformedURLException;
import org.codehaus.xfire.XFire;
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import com.sungard.adms.address.ws.Address;
import com.sungard.adms.address.ws.AddressType;
import com.sungard.adms.address.ws.IAddressService;
public class MyApplicationClient {
public static void main(String[] args) {
try{
Address address=MyApplicationClient.callWebService(AddressType.LANGFORD_ROAD);
System.out.println(address.getName());
System.out.println(address.getDoorno());
System.out.println(address.getBuildingName());
System.out.println(address.getRoad());
}catch(Exception e){
e.printStackTrace();
}
}
public static Address callWebService(AddressType addtype)
throws MalformedURLException, Exception{
//create a metadata of the service
Service serviceModel = new ObjectServiceFactory().create(IAddressService.class);
//create a proxy for the deployed service
XFire xfire = XFireFactory.newInstance().getXFire();
XFireProxyFactory factory = new XFireProxyFactory(xfire);
String serviceUrl = “http://localhost:8080/address/AddressService”;
IAddressService client = null;
try {
client = (IAddressService) factory.create(serviceModel, serviceUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
}
//invoke the service
Address address = null;
try {
address = client.getAddress(addtype);
} catch (Exception e){
e.printStackTrace();
}
//return the response
return address;
}
}
Step 4: Copy all the class files in WEB-INF/classes folder with package folder structure.
Step 5: Create web.xml file in WEB-INF folder
web.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE web-app PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN” “http://java.sun.com/dtd/web-app_2_3.dtd”>
<web-app id=”WebApp_ID”>
<display-name>WebServices using XFire</display-name>
<servlet>
<servlet-name>WsClient</servlet-name>
<display-name>WsClientServlet</display-name>
<description></description>
<servlet-class>com.sungard.adms.address.ws.client.WsClient</servlet-class>
</servlet>
<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFire Servlet</display-name>
<servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>WsClient</servlet-name>
<url-pattern>/ws</url-pattern>
</servlet-mapping>
</web-app>
Step 6: Create addressclient.war file by using ant script.
Step 7: deploy the client application in AppServer/WebServer.
Step 8: Run the client by using following url
http://localhost:8080/addressclient/ws?addressType=HEBBALOFFICE
addressType value you can give any one of the Enumerator value(AddressType)
Step 9: Or Run MyApplicationClient as a normal java application.
-
Recent
- Integrating JSF, Spring Security and LDAP
- Developing Web Services by using Mule, CXF, and Spring
- Developing Web Services by Using Metro Webservices Framework
- Developing CXF WS-Security with Spring & Acegi Security
- Developing CXF WS-Security with SAML
- Developing CXF WS-Security with Signature(Certificates)
- Developing CXF Web services with WS-Security
- RESTful web services using the Jersey framework
- Developing Web Services By Using Spring and CXF
- Developing Web Services by Using Spring and XFire
- Developing Web services Using Spring Framework
- Developing Simple Web Services by Using JWSDP
-
Links
-
Archives
- January 2010 (1)
- November 2009 (1)
- October 2009 (1)
- September 2009 (9)
-
Categories
-
RSS
Entries RSS
Comments RSS