jws

JAX-WS Security Example

In this example we shall learn, how to implement JAX-WS security to SOAP web services.

Security is always critical to web services. When talking about web services security here, following security issues are considered:

Wire-level security

  • Assurance between client and web service that they are the only one communicating.
  • Data encryption.
  • Assurance that received message is same as sent message.

User authentication and authorization

  • Authentication is appropriate credentials to gain access.
  • Authorization is users-role security. Users might be restricted to some resources based on their roles.

1. Wire-level security using HTTPS

To make web service more secure, we can use HTTPS instead of HTTP. It addresses three security services
over transport services that HTTP provides; Peer authentication, confidentiality, and integrity.

2. Container managed security for web service

2.1 Deploying web service under tomcat

To understand this let us first create a ‘Dynamic Web Project’ in eclipse.

New Dynamic Web Project
New Dynamic Web Project

Now we shall implement Service Endpoint Interface as follows:

CalculatorI.java

package com.javacodegeeks.jaxws.example;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.RPC)
public interface CalculatorI {
	@WebMethod
	int add(int a, int b);

	@WebMethod
	int subtract(int a, int b);

	@WebMethod
	int multiply(int a, int b);

	@WebMethod
	int divide(int a, int b);
}

After this we shall implement Service Implementation Bean as follows:

CalculatorImpl.java

package com.javacodegeeks.jaxws.example;

import javax.jws.WebService;

@WebService(endpointInterface = "com.javacodegeeks.jaxws.example.CalculatorI")
public class CalculatorImpl implements CalculatorI {

	@Override
	public int add(int a, int b) {
		return a + b;
	}

	@Override
	public int subtract(int a, int b) {
		return a - b;
	}

	@Override
	public int multiply(int a, int b) {
		return a * b;
	}

	@Override
	public int divide(int a, int b) {
		return a / b;
	}

}

To configure a container like tomcat to host a web service, we need to add configuration of JAX-WS’s WSServlet and WSServletContainerListener in web.xml. web.xml on configuration shall be like:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>JaxWSSecurityExample</display-name>
	<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>

	<servlet>
		<servlet-name>CalculatorWS</servlet-name>
		<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>CalculatorWS</servlet-name>
		<url-pattern>/calc</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
	</listener>
</web-app>

Now to add the endpoint that we created to be hosted by tomcat, we will create sun-jaxws.xml in WEB-INF directory as follows:

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="CalcWS"
		implementation="com.javacodegeeks.jaxws.example.CalculatorImpl" />
</endpoints>

2.2 Securing web service under tomcat

Next step is to secure the web service or to enable https. To do this, go to Tomcat’s conf directory and edit server.xml file.
But first things first, we will need to create a digital certificate. We can use Java’s keytool utility to generate the same. The command would be like: keytool -genkey -alias tomcat -keyalg RSA

By default a digital certificate file with name .keystore shall be created in the user’s home directory. Now to configure this file to enable https, we shall edit connector configuration in server.xml as mentioned above. The new configuration shall be like:

server.xml (partial)

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
	maxThreads="150" scheme="https" secure="true" clientAuth="false"
	sslProtocol="TLS" keystoreFile="/home/saurabharora123/.keystore" />

2.3 Implementing authentication and authentication

Next step in securing our web service is to implement authentication and authorization. This can be done at at either application level or container level. We will look at each of these methods.

2.3.1 Authentication at application level

Authentication if done at application level is easy but creates clumsy and un-readable code. The change to web service would be minor.

CalculatorImplAppManagedAuth.java

package com.javacodegeeks.jaxws.example;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.http.HTTPException;

@WebService(endpointInterface = "com.javacodegeeks.jaxws.example.CalculatorI")
public class CalculatorImplAppManagedAuth implements CalculatorI {
	@Resource
	WebServiceContext context;

	@Override
	public int add(int a, int b) {
		if (isAuthenticated())
			return a + b;
		else
			throw new HTTPException(401);
	}

	@Override
	public int subtract(int a, int b) {
		if (isAuthenticated())
			return a - b;
		else
			throw new HTTPException(401);
	}

	@Override
	public int multiply(int a, int b) {
		if (isAuthenticated())
			return a * b;
		else
			throw new HTTPException(401);
	}

	@Override
	public int divide(int a, int b) {
		if (isAuthenticated())
			return a / b;
		else
			throw new HTTPException(401);
	}

	private boolean isAuthenticated() {
		MessageContext messageContext = context.getMessageContext();
		Map httpHeaders = (Map) messageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
		List userNameList = (List) httpHeaders.get("uname");
		List passwordList = (List) httpHeaders.get("pass");

		if (userNameList.contains("saurabh") && passwordList.contains("java"))
			return true;
		else
			return false;
	}
}

In the above program, username and password are expected in http headers which are then authenticated. In case request is not authenticated HTTPException with code 401 shall be thrown which is for unauthorized access. The above program is just a sample, in the real-world scenario this kind of authentication can be done form databases or LDAP or other such repositories. On similar pattern authorization can be implemented.

The downside of the above approach is that the logic is now a mix of application logic and security implementation.

To compliment this web service client shall have to do some additional line of code to put username and password in the HTTP headers.

2.3.2 Authentication and authorization managed by container

Implementing authentication and authorization managed by container like Tomcat is just a matter of some configuration.
First step is to edit the web.xml to implement security constraints.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>JaxWSSecurityExample</display-name>
	<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>

	<servlet>
		<servlet-name>CalculatorWS</servlet-name>
		<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>CalculatorWS</servlet-name>
		<url-pattern>/calc</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
	</listener>

	<security-role>
		<description>Admin role</description>
		<role-name>admin</role-name>
	</security-role>

	<security-constraint>
		<web-resource-collection>
			<web-resource-name>UserRoleSecurity</web-resource-name>
			<url-pattern>/calc</url-pattern>
		</web-resource-collection>
		<auth-constraint>
			<role-name>admin</role-name>
		</auth-constraint>
		<user-data-constraint>
			<transport-guarantee>CONFIDENTIAL</transport-guarantee>
		</user-data-constraint>
	</security-constraint>

	<login-config>
		<auth-method>BASIC</auth-method>
	</login-config>
</web-app>

In this updated web.xml resources to be updated are mentioned in web-resource-collection tag. role-name tag describes the role which authenticated user should have. Here we are using BASIC authentication. Transport is guaranteed to be CONFIDENTIAL which covers services of authentication, encryption and message integrity.

When tomcat receives request, it will know that request needs to be authenticated and authorized. For verification of username, password and role, it shall look into MemoryRealm by default which is configured in file conf/tomcat-users.xml.

tomcat-users.xml

<tomcat-users>
  <role rolename="admin"/>
  <role rolename="normalUser"/>
  <user username="saurabh" password="java" roles="admin"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>

To use digested password auth-method in web.xml shall have to be changed to DIGEST. The digested password can be generated using digest.sh utility in tomcat’s bin directory. And then this digested password shall be replaced in tomcat-users.xml.

3. Directory structure of this example

The directory structure of the above example in eclipse shall look like:

Directory Structure
Directory Structure

4. Download the source code

This was an example of JAX-WS security.

Download
You can download the full source code of this example here: JaxWSSecurityExample

Saurabh Arora

Saurabh graduated with an engineering degree in Information Technology from YMCA Institute of Engineering, India. He is SCJP, OCWCD certified and currently working as Technical Lead with one of the biggest service based firms and is involved in projects extensively using Java and JEE technologies. He has worked in E-Commerce, Banking and Telecom domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jaison Steephen
Jaison Steephen
5 years ago

Could you please provide the client application of the same

Praful Anand
Praful Anand
4 years ago

Hi Saurabh,

Please provide the program at client side for above secure soap web service. Please provide the program to test above secure web services. I generated wsdl file for above web services using Endpoint.publish but still not able to authenticate above web service. It would be great if you provide client program to test above web services with authentication and soap request(xml). and find out proper soap response(xml) like postman and soap ui.

Back to top button