Nella lezione precedente abbiamo analizzato un esempio in cui si è aggiunto al messaggio in uscita dal client un header in chiaro contenente un nome utente e una password. Tramite Wireshark abbiamo potuto osservare che il messaggio di richiesta aveva sì un header di sicurezza, ma a parte questo il contenuto era del tutto leggibile; è quindi ovvio aspettarsi di più come misura di sicurezza. Sappiamo che è possibile utilizzare HTTPS a livello trasporto e criptare quanto transita, ma è anche possibile aumentare il livello di sicurezza tramite WS-Security. In questa lezione vedremo un esempio di messaggio con timestamp, criptato e firmato nei due versi.
Keystore server e utente
Ipotizzeremo di avere un utente "bob" che si mette in contatto con il server serverwssec. La criptografia e la firma avvengono mediante due keystore, bob.jks
e serverwssec.jks
contenenti sia le proprie credenziali da esporre che quelle da validare. Conterranno pertanto entrambi una voce (PrivateEntryKey
) chiave segreta con associato il proprio certificato e una voce utile per la validazione dell’altro lato (trustedCertEntry
). Seguono i comandi utilizzabili per generare i keystores descritti.
keytool -genkey -alias bob -keyalg RSA -storepass password -keystore bob.jks -keypass password -dname "CN=bob, OU=IT, O=CNO, L=loc, S=reg, C=IT"
keytool -genkey -alias serverwssec -keyalg RSA -storepass password -keystore serverwssec.jks -keypass password -dname “CN=Name, OU=IT, O=CNO, L=loc, S=reg, C=IT"
keytool -export -alias bob -file bob.crt -keystore bob.jks
keytool -export -alias serverwssec -file serverWSSec.crt -keystore serverwssec.jks
keytool -import -trustcacerts -alias bob -file bob.crt -keystore serverwssec.jks
keytool -import -trustcacerts -alias serverwssec -file serverwssec.crt -keystore bob.jks
keytool -list -keystore bob.jks
keytool -list -keystore serverwssec.jks
Da notare che questa volta il nome inserito nel certificato non sarà vincolante per connettersi al server.
Files di configurazione e files di properties
Di seguito la nuova versione del file jbossws-cxf.xml
, è possibile sovrascrivere o rinominare la vecchia per non perderla o anche commentare le sezioni non utilizzate come nel progetto d’esempio.
<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="Sign_Request" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature Encrypt"/>
<entry key="signaturePropFile" value="serverwssec.properties"/>
<entry key="decryptionPropFile" value="serverwssec.properties"/>
<entry key="passwordCallbackClass" value="test.security.KeystorePasswordCallbackComplete"/>
</map>
</constructor-arg>
</bean>
<bean id="Sign_Response" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature Encrypt"/>
<entry key="user" value="serverwssec"/>
<entry key="signaturePropFile" value="serverwssec.properties"/>
<entry key="encryptionPropFile" value="serverwssec.properties"/>
<entry key="encryptionUser" value="bob"/>
<entry key="signatureKeyIdentifier" value="DirectReference"/>
<entry key="passwordCallbackClass" value="test.security.KeystorePasswordCallbackComplete"/>
<entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<entry key="encryptionParts" value="{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<entry key="encryptionKeyTransportAlgorithm" value="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<entry key="encryptionSymAlgorithm" value="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
</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:outInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
<ref bean="Sign_Response"/>
</jaxws:outInterceptors>
<jaxws:inInterceptors>
<ref bean="Sign_Request"/>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
Nell’elemento endpoint troviamo associati al Web service due interceptors, uno in uscita e uno in ingresso. In entrambi i casi l’azione è di tipo Timestamp Signature Encrypt, ossia ci si accinge a prevedere un timestamp, firmare e criptare il messaggio.
Nel bean che gestisce la richiesta troviamo sia per la decriptazione che per la gestione della firma un riferimento a un file di properties, serverwssec.propertiesy
. Vi è inoltre il riferimento a una classe, test.security.KeystorePasswordCallbackComplete
, contenente alcune properties per accedere al keystore, decriptare e verificare la firma utilizzando le properties ivi contenute. Essa consente di gestire l’associazione tra user/alias del keystore e password per accedere alla voce del keystore.
Il bean che gestisce la risposta presenta diversi campi. Oltre alle informazioni di base per individuare e accedere al keystore per mezzo delle properties contenute nel file di properties, il bean informa della presenza di un user rispetto al quale processare le richieste di criptazione e firma. Vengono inoltre fornite alcune informazioni accessorie come elementi e namespace destinati ad accogliere le sezioni relative a firma e informazioni di criptazione, oltre che agli algoritmi per criptare e firmare, nell'esempio rispettivamente RSA e TripleDES. Anche in questo caso la classe test.security.KeystorePasswordCallbackComplete
fornirà informazioni utili ad eseguire il mapping tra user e password.
Seguono i due files di properties da associare ai progetti lato server (serverwssec.properties
) e lato client (bob.properties
).
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.alias=serverwssec
org.apache.ws.security.crypto.merlin.file=serverwssec.jks
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.alias=bob
org.apache.ws.security.crypto.merlin.file=META-INF/bob.jks
I files sono destinati ad accogliere le informazioni di base per configurare WSS4J e accedere ai keystores: password, posizione, tipo e nome, oltre che alla classe (org.apache.ws.security.components.crypto.Merlin
) destinata a gestire il processo.