JBoss si basa su Apache CXF e WSS4J per fornire le funzionalità di WS-Security. WSS4J basa il suo funzionamento su degli interceptors che possono essere aggiunti programmaticamente o tramite il framework Spring. Seguiremo quest’ultimo approccio che è quello descritto nella documentazione ufficiale di JBoss.
Integrare Spring Framework in JBoss
Spring fa sempre più riferimento a Maven per la risoluzione delle dipendenze e il successivo deployment, ma in questa guida eviteremo di utilizzarlo. Tutto quello che occorre fare per integrarlo in JBoss è scaricare un opportuno insieme di librerie di Spring e decidere una modalità di utilizzo.
E’ possibile scaricare le librerie da Internet (ad esempio dal repository Maven che oltre a consentire di aggiungere le librerie come dipendenze ne permette anche il semplice download), o prelevarle dall’archivio allegato a questa guida (cartella LibrerieSpring
).
Segue la lista delle librerie Spring utili al nostro scopo:
- spring-aop
- spring-asm
- spring-beans
- spring-context
- spring-core
- spring-expression
In particolare, risultano certificate in JBoss le seguenti versioni di Spring: 2.5.6.SEC02 e 3.0.3.RELEASE
Nell’archivio allegato e nei progetti che verranno descritti vengono utilizzate la librerie della versione 3.0.3.RELEASE.
Per quanto riguarda la modalità di utilizzo, è possibile aggiungere l’insieme di librerie alla cartella delle librerie comuni di JBoss ([JBOSS_HOME]/common/lib
), rendendo il set di librerie disponibile per qualsiasi server lanciato, o aggiungerle al set di librerie di un server specifico (JBOSS_HOME/[NomeProfiloServer]/lib
) in modo da non modificare l’insieme di librerie caricate dagli altri server.
E’ infine possibile decidere di lasciare le librerie a livello applicazione e farle caricare solo per un’applicazione specifica, evitando così che i relativi tempi di caricamento delle librerie Spring divengano parte integrante del server.
In generale si preferisce caricare le librerie direttamente nella common/lib
o nel server specifico in modo da ridurre le dimensioni del package da deployare e permettere un semplice upgrade delle librerie senza impatto diretto sul package. In definitiva è consigliabile scegliere di caso in caso. Nei nostri esempi ipotizzeremo di caricare le librerie nel profilo server in uso. Una volta avviato il server, sarà possibile notare sul log il caricamento delle classi Spring:
Refreshing org.jboss.wsf.stack.cxf.client.configuration.JBossWSBusApplicationContext
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory
Non occorre altro, Spring è integrato in JBoss. Nello specifico, nei prossimi esempi assumeremo di lavorare con un nuovo server, defaultSpring
, replica del server default con integrate nella cartella lib
le librerie Spring precedentemente indicate. Come in precedenza, sarà possibile creare un nuovo profilo server nell’apposita sezione Eclipse (scheda "Servers", nel nostro esempio chiameremo il nuovo server JBoss 6.x Spring RS) da cui fare riferimento al server defaultSpring
.
Server, implementazione e struttura del progetto
WS-Security agisce tramite un’estensione del messaggio SOAP. Le librerie sulle quali si appoggia JBoss per gestire questa estensione utilizzano degli interceptors, registrati e gestiti da Spring mediante un file di configurazione.
Per prima cosa, possiamo creare un nuovo progetto, replica del precedente PresentazioneServer
, ad esempio lo chiameremo PresentazioneServerWSSecurity
(come il progetto allegato alla guida), e commentiamo l’annotazione @Stateless
nella classe prova.server.ServizioPresentazione
in quanto esporremo il Web service come servlet.
Aggiungiamo quindi il file di configurazione web.xml
alla cartella META-INF
per il mapping della servlet con il Web service.
File web.xml
:
<?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>PresentazioneService</servlet-name>
<servlet-class>prova.server.ServizioPresentazione</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PresentazioneService</servlet-name>
<url-pattern>/PresentazioneService/ServizioPresentazioneIF</url-pattern>
</servlet-mapping>
</web-app>
Passo successivo è la creazione e configurazione del file jbossws-cxf.xml
, nel quale andremo a dichiarare gli interceptors che dovranno gestire l’accesso al Web service previa verifica dell’header di sicurezza.
File jbossws-cxf.xml
:
<beans
xmlns='http://www.springframework.org/schema/beans'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:beans='http://www.springframework.org/schema/beans'
xmlns:jaxws='http://cxf.apache.org/jaxws'
xsi:schemaLocation='http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd'>
<bean id="inRequest" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordCallbackClass" value="test.security.KeystorePasswordCallback"/>
</map>
</constructor-arg>
</bean>
<jaxws:endpoint
id='ServizioPresentazione'
address='http://@jboss.bind.address@:8080/Presentazione/PresentazioneService/ServizioPresentazioneIF'
implementor='prova.server.ServizioPresentazione'>
<jaxws:invoker>
<bean class='org.jboss.wsf.stack.cxf.InvokerJSE'/>
</jaxws:invoker>
<jaxws:inInterceptors>
<ref bean="inRequest"/>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
In primo luogo osserviamo nel namespace gli schemi XML referenziati, tra i quali troviamo le estensioni cxf di jaxws e il framework Spring. Passiamo quindi a notare che all’endpoint ServizioPresentazione
viene associato un interceptor per la fase di input, e un bean che riassume l’azione, o meglio dire il tipo di livello di sicurezza atteso, e la classe che andrà ad implementare il meccanismo di sicurezza.
Nel dettaglio, la voce action
ci indica che è atteso un UsernameToken
e che la gestione del contenuto di tale token viene demandata alla classe test.security.KeystorePasswordCallback
.