Modifica del file jbossws-cxf.xml
Dopo aver analizzato la struttura del nostro progetto possiamo modificare il file jbossws-cxf.xml
come di seguito.
<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'>
<jaxws:endpoint
id='ServizioPresentazione'
address='http://@jboss.bind.address@:8080/Presentazione/PresentazioneService/ServizioPresentazioneIF'
implementor='prova.server.ServizioPresentazione'>
<jaxws:properties>
<entry key="ws-security.callback-handler" value="test.security.KeystorePasswordCallback"/>
</jaxws:properties>
</jaxws:endpoint>
</beans>
Il file risulta decisamente più snello di quelli visti in precedenza in quanto il grosso delle informazioni circa la struttura dell’header di sicurezza sono contenute nel WSDL stesso e non risulta più necessario specificarle.
Quello che troviamo in questo caso è l’associazione della classe destinata ad implementare i controlli di sicurezza con il servizio in questione. Il comportamento relativo può essere esattamente identico a quello della classe KeystorePasswordCallback.java
realizzata in precedenza per il primo esempio relativo a WS-Security, come fatto nel progetto allegato alla guida. Se si sta realizzando un nuovo progetto, ricordarsi quindi di aggiungere ad esso la classe nel relativo package. Gli altri elementi del progetto server non subiranno variazioni rispetto a quelli già descritti.
Lato client, è possibile avviare un nuovo progetto o utilizzare PresentazioneClientCXF
. Prima cosa da dire è che è possibile sostituire il WSDL privo di policies con quello che abbiamo appena modificato, ma l'aspetto positivo è che in realtà non è necessario farlo. Lasciamo dunque invariato questo aspetto mantenendo il vecchio WSDL e concentriamoci sulla classe del client che si occuperà di invocare il servizio. La classe che se ne occuperà è la seguente (file SecureServizioClientWSPolicySeurity.java
):
package wsClient;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
import test.documento.prova.ServizioPresentazioneIF;
import test.security.UsernamePasswordCallback;
public class SecureServizioClientWSPolicySeurity {
public static void main(String[] args) {
String prot = "http";
String host = "localhost";
String port = "8080";
String protHostPort = prot+"://"+host+":"+port;
ClientMETAInf sensorClient = new ClientMETAInf(null);
ServizioPresentazioneIF servicePort = sensorClient.getServicePort(protHostPort);
boolean addSecHeader = true;
if(addSecHeader){
Client client = ClientProxy.getClient(servicePort);
Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, "bob");//ok
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, UsernamePasswordCallback.class.getName());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor());
}
String nome = "Paperino";
String cognome = "Paolino";
System.out.println("Presentazione... ");
String risposta = servicePort.presentazione(nome, cognome);
System.out.println("Risposta ottenuta: "+risposta);
}
}
La classe verifica se va aggiunto un header di sicurezza, nel qual caso introduce un header basato su UsernameToken
in chiaro in modo perfettamente simile a quanto già fatto in precedenza. Anche in questo caso, ad implementare l’associazione tra nome utente e password ci penserà la classe UsernamePasswordCallback.java
, non dissimile da quella realizzata in precedenza.