Java SOAP Web Service e WS-Security

Andrea Scanzani
Architetture Digitali
7 min readApr 23, 2021
Photo by Kevin Ku on Unsplash

In questo articolo andiamo a realizzare un Web Service SOAP con la specifica WS-Security per applicare dei profili di sicurezza ai nostri WS.

Le tecnologie utilizzate in questo articolo sono le seguenti:

  • Spring Boot 2.4.2
  • Apache CXF 3.2.4

Tutto il sorgente Java presente nell’articolo è disponibile al seguente Git repos:

Cosa è WS-Security?

Web Services Security (WS-Security o WSS) è una estensione di SOAP per implementare la sicurezza ai Web Service garantendo autenticazione, integrità e confidenzialità a livello messaggio. La specifica è redata dall’ente OASIS. Il protocollo specifica come può essere rafforzata l’integrità e la confidenzialità e permette la comunicazione di vari token di sicurezza, come SAML, Kerberos e X. 509.

WS-Security fornisce un meccanismo generico per l’associazione di token di sicurezza ai messaggi. Nessun tipo specifico di token di sicurezza è richiesto da WS-Security. È progettato per essere estendibile, ad esempio, per supportare più formati di token di sicurezza.

Lo standard WS-Security affronta tre principali problemi di sicurezza:

  • Autenticazione (identità)
  • Riservatezza (crittografia e decrittografia)
  • Integrità (firma XML)

Nell’immagine seguente vediamo tutto i vari layer previsti dalla specifica WS-Security:

WS-Security layer block

WS-Security viene trasmesso attraverso il protocollo SOAP con la seguente modalità:

WS-Security in SOAP Protocol

Questo articolo affronterà l’aspetto dell’autenticazione di WS-Security.

WS-Security Authentication

Lo standard WS-Security offre tre metodi di autenticazione. Questi metodi sono:

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

In questo tutorial andremo ad applicare lo “UsernameToken Profile”.

UsernameToken Profile

UsernameToken rappresenta delle credenziali (nome utente e password) nello standard WS-Security. È incluso nell’intestazione SOAP della richiesta del servizio web.

La password scambiata tra client e server può essere di due tipologie:

  • Password Text → Password scambiata in chiaro
  • Password Digest → Il tipo è il digest della password per il nome utente. Il valore è un hash SHA1 con codifica Base64 della password con codifica UTF-8. Questa è la formula con la quale viene calcolata:
Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )

Apache CXF e JAX-WS

Java API for XML Web Services (JAX-WS) semplifica la creazione e l’utilizzo dei Web Service in ambiente Java, in particolare JAX-WS viene utilizzato per la messaggistica basata su SOAP. Si basa ampiamente su Java API for XML Binding (JAXB) per il marshalling e l’unmarshalling di oggetti Java in documenti XML e viceversa.

Tra le varie implementazione della specifica JAX-WS troviamo Apache CXF, che implementa molti degli standard sui Web Service, tra cui WS-Security.

Cosa è un WSDL?

E’ un linguaggio di descrizione dell’interfaccia basato su XML utilizzato per descrivere le funzionalità offerte da un Web Service. Fornisce una descrizione di come il servizio può essere chiamato, quali parametri si aspetta e quali strutture dati restituisce . Pertanto, il suo scopo è più o meno simile a quello di un contratto tra le parti.

L’esposizione e l’interrogazione di un Web Service si basa sempre su un file WSDL che contiene il dettaglio.

WSDL (Web Services Description Language)

All’interno dei paragrafi successivi andremo a creare un WebService, per farlo è necessario scrivere prima un WSDL (può anche essere generato a partire dal codice sorgente).

Questo è il WSDL che andremo ad utilizzare più avanti:

Il nostro WSDL referenzia un XSD, che contiene le strutture dati di Input/Output utilizzata dal WebService.

Il nostro Servizio prevede una sola operation GetSum”.

Spring Boot + Apache CXF (Server)

Creiamo il nostro progetto Maven, di seguito il file pom.xml utilizzato nel nostro esempio.

Le librerie che andiamo ad includere sono le seguenti:

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

Come vedete dal file pom.xml abbiamo configurato il plugin Apache CXF (cxf-codegen-plugin) per la generazione automatica, a partire da un WSDL, del codice (lato server) per l’esposizione e l’implementazione della logica del nostro Web Service. All’interno del plugin quindi andiamo a specificare dove si trova il file WSDL, il Service Name ed il package di destinazione del codice generato.

Alla prossima build del progetto il plugin di cxf ha bisogno del WSDL, pertanto andiamo ad includerlo nel nostro progetto:

Project Structure

Una volta che abbiamo il codice generato, possiamo andare ad implementare la logica del Servizio.

Come prima cosa creiamo la classe principale per Spring Boot:

Successivamente creiamo la configurazione d’esposizione del nostro WSDL tramite configurazione Spring:

Con questa configurazione il WSDL sarà visionabile tramite seguente url:

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

Andiamo ad implementare la nostra logica del WebService:

Nella classe sopra andiamo ad implementare l’interfaccia “SumServicePort”, che è stata generata da Apache CXF a partire dal WSDL, che espone le operation definite dal contratto WSDL.

In questo esempio il nostro WebService ha solamente una operation getSum” e andiamo ad implementarlo con una semplice somma dei due addendi.

Come vedrete è presente un’annotazione Spring:

@InInterceptors(classes = WSSecurityInterceptor.class)

Questa annotazione applica un Interceptor al WebService, nel nostro caso è l’interceptor per il meccanismo WS Security mostrato di seguito:

Con questa configurazione diamo la direttiva al framework Apache CXF di applicare il meccanismo di sicurezza con profilo UsernameToken (WSHandlerConstants.USERNAME_TOKEN) di tipo PasswordDiget (WSConstants.PW_DIGEST), come ultima cosa definiamo la classe di callback per il recupero e la validazione delle credenziali arrivate dalla request SOAP.

N.B.: Qualora volessimo usare il tipo PasswordText, invece del PasswordDigest, è sufficiente cambiare il valore della costante.

Di seguito è presente la classe di Callback richiamata e utilizzta sopra:

Per semplificare l’esempio abbiamo settato a codice le credenziali utente che vogliamo validare.

In questo caso le nostre credenziali sono le seguenti:

  • Username →admin
  • Password → pwd123

La nostra applicazione ora è pronta, espone il WSDL ed il relativo WebService con WS Security di tipo UsernameToken con PasswordDigest.

Lanciando l’applicazione con il seguente comando:

mvn clean spring-boot:run

Possiamo vedere il WSDL esposto al seguente URL:

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

Test con SoapUI

Per testare la nostra applicazione creata nel paragrafo precedente utilizzeremo SoapUI (link).

Creiamo un nuovo progetto di tipo SOAP, e indichiamo al programma dove può recuperare il WSDL per generarci il client:

New SOAP Project

Creato il progetto “SumService”, destra troveremo tutte le operation esposte dal WebService nel nostro caso è presente solo l’operation “GetSum”.

Aprendo la request ed effettuando una richiesta, avremo come risposta un errore di mancata autenticazione al Servizio, come da immagine che segue:

SOAP Request — Fail

Ora andiamo a creare sul nostro progetto SoapUI la configurazione relativa a WS Security. Facendo doppio click sul nome del Servizio (SumService) si apre una finestra modale dove troviamo un tab denominato “WS-Security Configurations”.

Da questo tab possiamo creare la nostra configurazione, in questo caso d’esempio sarà nominata “WSS”.

Creating WS-Security Configurations

Creata la configurazione andiamo a settare il tipo, in questo caso Username:

Type of configurations

Ed impostiamo le nostre specifiche credenziali, quindi:

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

Tornando alla nostra SOAP Request, nel sotto-tab “Authorization” andiamo ad impostare una nuova autorizzazione di tipo “Basic”, specificando nel campo “Outgoing WSS” la nostra configurazione creata sopra, quindi WSS.

Chiamando il Servizio ora, riceveremmo correttamente la risposta dal nostro Web Service:

SOAP Request — OK

Cosi facendo abbiamo verificato la corretta esposizione del Web Service e la corretta implementazione del meccanismo di sicurezza tramite WS-Security.

Spring Boot + Apache CXF (Client)

In questo paragrafo viene mostrato come richiamare il WebService che utilizza WS-Security.

Creiamo il nostro progetto Maven, con il seguente pom.xml:

Come visto sopra, nel progetto lato Server, andiamo ad utilizzare le dipendenze:

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

Ed impostiamo allo stesso modo il plugin cxf-codegen-plugin, per la generezione del codice per il client. Come sopra andiamo ad inserire sempre il file WSDL per permettere ad Apache CXF di generare le classi Java.

Andiamo a creare la classe principale:

Nel codice sopra possiamo vedere come inizializziamo ol Client per il WebService e il settaggio dell’endpoint per richiamare il Servizio, e la creazione di un Interceptor, in questo caso OutInterceptor, per fornire indicazioni al framework Apache CXF:

  • Profilo di autenticazione → UsernameToken
  • Password Type → PasswordDigest
  • Password Calback Class → Per l’invio della password
  • Username

Di seguito riportiamo la classe di Callback utilizzata sopra:

L’applicazione lato Client è ora completa e pronta per l’invocazione del Web Service.

Eseguendo l’applicazione con il comando:

mvn clean spring-boot:run

Vedremo sulla console la risposta del WebService.

--

--

Andrea Scanzani
Architetture Digitali

IT Solution Architect and Project Leader (PMI-ACP®, PRINCE2®, TOGAF®, PSM®, ITIL®, IBM® ACE).