Java SOAP Web Service and WS-Security

Andrea Scanzani
Apr 23 · 7 min read
Photo by Kevin Ku on Unsplash

In this article we are going to create a SOAP Web Service with the WS-Security specification to apply security profiles to our WS.

The technologies used in this article are as follows:

  • Spring Boot 2.4.2
  • Apache CXF 3.2.4

All the Java source present in the article is available at the following Git repos:

Web Services Security (WS-Security or WSS) is a SOAP extension to implement security for Web Services by guaranteeing authentication, integrity and confidentiality at the message level. The specification is drawn up by the OASIS body. The protocol specifies how integrity and confidentiality can be enforced and allows the communication of various security tokens, such as SAML, Kerberos, and X.509.

WS-Security provides a generic mechanism for binding security tokens to messages. No specific type of security token is required by WS-Security. It is designed to be extensible, for example, to support multiple security token formats.

The WS-Security standard addresses three main security issues:

  • Authentication (identity)
  • Confidentiality (encryption and decryption)
  • Integrity (XML signature)

In the following image we see all the various layers provided by the WS-Security specification:

WS-Security layer block

WS-Security is transmitted through the SOAP protocol in the following way:

WS-Security in SOAP Protocol

This article will address the authentication aspect of WS-Security.

The WS-Security standard offers three authentication methods.

These methods are:

  • UsernameToken Profile
  • X 508 Certificates Token Profile
  • SAML Token Profile

In this tutorial we are going to apply the “UsernameToken Profile”.

UsernameToken represents credentials (username and password) in the WS-Security standard. It is included in the SOAP header of the web service request.

The password exchanged between client and server can be of two types:

  • Password Text → Password exchanged in clear text
  • Password Digest → The type is the password digest for the username. The value is a Base64-encoded SHA1 hash of the UTF-8 encoded password. This is the formula with which it is calculated:
Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )

Java API for XML Web Services (JAX-WS) simplifies the creation and use of Web Services in the Java environment, in particular JAX-WS is used for SOAP-based messaging. It relies heavily on the Java API for XML Binding (JAXB) for marshaling and unmarshaling of Java objects into XML documents and vice versa.

Among the various implementations of the JAX-WS specification is Apache CXF, which implements many of the standards on Web Services, including WS-Security.

What is a WSDL?

It is an XML-based interface description language used to describe the functions offered by a Web Service. It provides a description of how the service can be called, what parameters it expects, and what data structures it returns. Therefore, its purpose is more or less similar to that of a contract between the parties.

The exposure and query of a Web Service is always based on a WSDL file that contains the detail.

WSDL (Web Services Description Language)

Within the following paragraphs we will create a WebService, to do this it is necessary to first write a WSDL (it can also be generated from the source code).

This is the WSDL we are going to use later:

Our WSDL references an XSD, which contains the Input/Output data structures used by the WebService.

This Web Service provides only one “GetSumoperation.

Spring Boot + Apache CXF (Server)

Let’s create our Maven project, below the pom.xml file used in our example.

The libraries we are going to include are the following:

  • Spring Boot Web
  • Apache CXF — Spring Boot Starter JAXWS
  • Apache CXF — WS Security

As you can see from the pom.xml file we have configured the Apache CXF plugin (cxf-codegen-plugin) for the automatic generation, starting from a WSDL, of the code (server side) for the exposure and implementation of the logic of our Web Service.

Inside the plugin then we are going to specify where the WSDL file is, the Service Name and the destination package of the generated code.

At the next build of the project the cxf plugin needs the WSDL, so let’s include it in our project:

Project Structure

Once we have the generated code, we can go on to implement the logic of the Service.

First we create the main class for Spring Boot:

Next we create the exposure configuration of our WSDL via Spring configuration:

With this configuration the WSDL will be on the following url:

http://localhost:8080/services/soap/SumService?wsdl

Let’s implement our WebService logic:

In the class above we are going to implement the “SumServicePort” interface, which was generated by Apache CXF starting from the WSDL, which exposes the operations defined by the WSDL contract.

In this example our WebService has only one “getSumoperation and we are going to implement it with a simple sum of the two addends.

As you will see there is a Spring annotation:

@InInterceptors(classes = WSSecurityInterceptor.class)

This annotation applies an Interceptor to the WebService, in our case it is the interceptor for the WS Security mechanism shown below:

With this configuration we give the directive to the Apache CXF framework to apply the security mechanism with UsernameToken profile (WSHandlerConstants.USERNAME_TOKEN) of type PasswordDiget (WSConstants.PW_DIGEST), lastly we define the callback class for retrieving and validating the arrived credentials from the SOAP request.

N.B.: If we want to use the PasswordText type, instead of the PasswordDigest, it is sufficient to change the value of the constant.

Here is the Callback class called and used above:

To simplify the example we have set the user credentials that we want to validate.

In this case our credentials are as follows:

  • Username →admin
  • Password → pwd123

Our application is now ready, it exposes the WSDL and the relative WebService with WS Security of type UsernameToken with PasswordDigest.

Launching the application with the following command:

mvn clean spring-boot:run

We can see the WSDL exposed at the following URL:

http://localhost:8080/services/soap/SumService?wsdl

Test withSoapUI

To test our application created in the previous paragraph we will use SoapUI (link).

We create a new SOAP type project, and we indicate to the program where it can retrieve the WSDL to generate the client:

New SOAP Project

Once the “SumService” project has been created, on the right we will find all the operations exposed by the WebService in our case only the “GetSum” operation is present.

By opening the request and making a request, we will have as a response an error of non-authentication to the Service, as shown in the following image:

SOAP Request — Fail

Now let’s create the WS Security configuration on our SoapUI project. Double clicking on the name of the Service (SumService) opens a modal window where we find a tab called “WS-Security Configurations”.

From this tab we can create our configuration, in this example case it will be named “WSS”.

Creating WS-Security Configurations

Once the configuration has been created, let’s set the type, in this case Username:

Type of configurations

And we set our specific credentials, then:

  • Username → admin
  • Password → pwd123
  • PasswordType → PasswordDigest
Setting credential info

Returning to our SOAP Request, in the “Authorization” sub-tab we set a new “Basic” authorization, specifying in the “Outgoing WSS” field our configuration created above, then WSS.

By calling the Service now, we would correctly receive the response from our Web Service:

SOAP Request — OK

So we have verified the correct exposure of the Web Service and the correct implementation of the security mechanism through WS-Security.

Spring Boot + Apache CXF (Client)

This section shows how to invoke the WebService using WS-Security.

Let’s create our Maven project, with the following pom.xml:

As seen above, in the Server side project, let’s use the dependencies:

  • Spring Boot Web
  • Apache CXF — Spring Boot Starter JAXWS
  • Apache CXF — WS Security

And we set up the cxf-codegen-plugin in the same way, to generate the code for the client. As above we are going to always insert the WSDL file to allow Apache CXF to generate the Java classes.

Let’s create the main class:

In the above code we can see how we initialize the Client for the WebService and the setting of the endpoint to call the Service, and the creation of an Interceptor, in this case OutInterceptor, to provide indications to the Apache CXF framework:

  • Authentication Profile → UsernameToken
  • Password Type → PasswordDigest
  • Password Calback Class → Per l’invio della password
  • Username

Below is the Callback class used above:

The Client side application is now complete and ready for the invocation of the Web Service.

By running the application with the command:

mvn clean spring-boot:run

We will see the response from the WebService on the console.

Digital Software Architecture

Digital Software Architecture