Authentication example in JAX-WS webservice

Introduction

Authentication example in JAX-WS webservice will show you how to authenticate a user before the user is able to see the response from the SOAP based JAX-WS webservice. You may also like to read JAX-WS webservice example.

In this example I will show you basic authentication example because I am going to pass credentials (username/password) into the headers of the request.

Related Posts:

Prerequisites

Java at least 1.8, Gradle 5.4.1 – 6.7.1, JAX-WS 2.3.1, Maven 3.6.3

The build.gradle script is given below with the required dependencies:

plugins {
    id 'java-library'
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
	maven {
		url 'http://maven.java.net/content/repositories/staging/'
	}
}

dependencies {
    implementation 'javax.xml.ws:jaxws-api:2.3.1'
    implementation 'com.sun.xml.ws:jaxws-rt:2.3.1'
    implementation 'org.glassfish.jaxb:txw2:2.4.0-b180608.0325'
}

If you are creating maven based project then you can use the following pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>jax-ws-authentication</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>12</maven.compiler.source>
		<maven.compiler.target>12</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>javax.xml.ws</groupId>
			<artifactId>jaxws-api</artifactId>
			<version>2.3.1</version>
		</dependency>

		<dependency>
			<groupId>com.sun.xml.ws</groupId>
			<artifactId>jaxws-rt</artifactId>
			<version>2.3.1</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
			</plugin>
		</plugins>
	</build>

</project>

How Authentication Works

I am going to give an example on how to implement a simple application level authentication in JAX-WS.

In this tutorial I am going to authenticate a client to the endpoint server.

The idea is straight forward. The client who wants to consume the Service, will have to authenticate using sending the credentials like username and password in the HTTP Request Header.

Then server retrieves these username and password from header information and validates the client’s identity.

In reality password should be encrypted to achieve an acceptable level of security. But in this tutorial I am going to keep things as simple as possible, but keep in mind that authentication along with session management are hard and crucial issues when developing a secure Web application.

Service Endpoint

First you need to create a Web Service Endpoint Interface. This interface will contain the declarations of all the methods for the Web Service.
Then we have to create a class that actually implements the above interface, which will be your Endpoint implementation.

package com.roytuts.jax.ws.authentication.service;
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 Hello {
	@WebMethod
	public String sayHello(String name);
}

Endpoint Implementation

As discussed previously, the server would have to read the HTTP request header information which the client put, and validate its identity.

Service Endpoint Implementation obtains a MessageContext object through a WebServiceContext for accessing the objects of the message.

The WebServiceContext interface enables a web service endpoint implementation class to access message contexts and security information of the requester.

The service runtime will inject the WebServiceContext on any field marked with @Resource annotation. We will call the WebServiceContext‘s getMessageContext() method to get MessageContext instance.

The HTTP Request Header will be retrieved using MessageContext‘s get method with MessageContext.HTTP_REQUEST_HEADERS as a parameter which nominates the kind of context we need from the message.

The Header will be retrieved as a Map which is very convenient because you can specify (key,value) pairs directly. Thus, we retrieve the coresspoding credentials.

package com.roytuts.jax.ws.authentication.service.impl;
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 com.roytuts.jax.ws.authentication.service.Hello;
@WebService(endpointInterface = "com.roytuts.jax.ws.authentication.service.Hello")
public class HelloImpl implements Hello {
	@Resource
	WebServiceContext context;
	@Override
	public String sayHello(String name) {
		MessageContext messageContext = context.getMessageContext();
		/**
		 * get http header information
		 */
		Map<?, ?> httpHeaders = (Map<?, ?>) messageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
		List<?> users = (List<?>) httpHeaders.get("username");
		List<?> passwords = (List<?>) httpHeaders.get("password");
		/**
		 * retrieve username and password information from http headers
		 */
		String username = "";
		String password = "";
		if (users != null && !users.isEmpty()) {
			username = users.get(0).toString();
		}
		if (passwords != null && !passwords.isEmpty()) {
			password = passwords.get(0).toString();
		}
		/**
		 * verify the user and return response
		 */
		if (username.equalsIgnoreCase("user") && password.equals("pass")) {
			return "Hello " + name;
		} else {
			return "Authentication faild! Please provide correct credentials";
		}
	}
}

Webservice Publisher

I will create webservice publisher to publish our webservice on a particular port on localhost.

package com.roytuts.jax.ws.authentication.service.publisher;
import javax.xml.ws.Endpoint;
import com.roytuts.jax.ws.authentication.service.impl.HelloImpl;
public class HelloPublisher {
	public static void main(String[] args) {
		Endpoint.publish("http://localhost:8888/jax-ws-auth/hello", new HelloImpl());
	}
}

Once you run the above publisher class the Web Service will be available to the clients, deployed in the URL: http://localhost:8888/jax-ws-auth/hello.

WSDL File

And this is the wsdl file that automatically created and
published at: http://localhost:8888/jax-ws-auth/hello?WSDL.

<!--
 Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.3.1 svn-revision#6ef5f7eb9a938dbc4562f25f8fa0b67cc4ff2dbb.
-->
<!--
 Generated by JAX-WS RI (http://javaee.github.io/metro-jax-ws). RI's version is JAX-WS RI 2.3.1 svn-revision#6ef5f7eb9a938dbc4562f25f8fa0b67cc4ff2dbb.
-->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://impl.service.authentication.ws.jax.roytuts.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://impl.service.authentication.ws.jax.roytuts.com/" name="HelloImplService">
	<import namespace="http://service.authentication.ws.jax.roytuts.com/" location="http://localhost:8888/jax-ws-auth/hello?wsdl=1"/>
	<binding xmlns:ns1="http://service.authentication.ws.jax.roytuts.com/" name="HelloImplPortBinding" type="ns1:Hello">
	<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
		<operation name="sayHello">
			<soap:operation soapAction=""/>
			<input>
				<soap:body use="literal" namespace="http://service.authentication.ws.jax.roytuts.com/"/>
			</input>
			<output>
				<soap:body use="literal" namespace="http://service.authentication.ws.jax.roytuts.com/"/>
			</output>
		</operation>
	</binding>
	<service name="HelloImplService">
		<port name="HelloImplPort" binding="tns:HelloImplPortBinding">
			<soap:address location="http://localhost:8888/jax-ws-auth/hello"/>
		</port>
	</service>
</definitions>

Webservice Consumer

The client will consume the web service so the client has to make a new HTTP Request Header containing its username and password.

To access and manipulate the request contexts of the message the client has to get a BindingProvider from the service port using getRequestContext() method.

The BindingProvider interface enables the client to access and manipulate the associated context objects for request and response messages. The Request Context is retrieved as a Map object.

MessageContext.ENDPOINT_ADDRESS_PROPERTY is used to nominate the target service endpoint address. Now we need to add two properties username and password to the Map object. Then we put this Map object in MessageContext.HTTP_REQUEST_HEADERS.

package com.roytuts.jax.ws.authentication.service.consumer;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.handler.MessageContext;
import com.roytuts.jax.ws.authentication.service.Hello;
public class HelloConsumer {
	public static void main(String[] args) throws MalformedURLException {
		URL url = new URL("http://localhost:8888/jax-ws-auth/hello?wsdl");
		QName qname = new QName("http://impl.service.authentication.ws.jax.roytuts.com/", "HelloImplService");
		Service service = Service.create(url, qname);
		Hello hello = service.getPort(Hello.class);
		/******************* Username & Password ******************************/
		Map<String, Object> reqContext = ((BindingProvider) hello).getRequestContext();
		reqContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8888/jax-ws-auth/hello?wsdl");
		Map<String, List<String>> headers = new HashMap<String, List<String>>();
		headers.put("username", Collections.singletonList("user"));
		headers.put("password", Collections.singletonList("pass"));
		reqContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
		/**********************************************************************/
		System.out.println(hello.sayHello("Soumitra"));
	}
}

Testing the Application

Run the HelloConsumer class, you will see below response in the console when you pass username/password as user/pass.

Hello Soumitra

If you do not pass any credentials or wrong credentials then you will see below output:

Authentication faild! Please provide correct credentials

That’s all about authenticating JAX WS webservice.

Source Code

Download

Leave a Reply

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