Nella scorsa lezione era il solo server ad esporre un certificato, conseguentemente qualsiasi client in possesso del certificato del server poteva invocarne i servizi. L’autenticazione a due vie richiede invece che i client debbano a loro volta disporre di un certificato, esposto conseguentemente con il proprio keystore, certificato che deve essere condiviso con il server che pertanto avrà a sua volta un trustore contenente i certificati dei clients autorizzati ad accedere ai servizi esposti.
Per svolgere questo esempio occorrerà pertanto generare un nuovo keystore per il client (clientKeystore), utilizzato per generare un certificato (clientCer), importato dal server nel trustore generato allo scopo (clientTruststore). I passaggi richiesti sono quelli già indicati nella lezione sul keytool e si riportano di seguito come esempio.
keytool -genkey -alias clientkey -keyalg RSA -storepass password -keystore clientKeystore.jks -keypass password -dname “CN=NomeC, OU=IT, O=CNO, L=loc, S=reg, C=IT"
keytool -export -alias clientkey -keypass password -file clientCer.crt -keystore clientKeystore.jks -storepass password
keytool -import -alias clientcert -keypass password -file clientCer.crt -keystore serverTruststore.jks -storepass password
Configurazione del server
Generati gli archivi possiamo passare alla configurazione del server. E’ possibile creare un nuovo server appositamente per questo esempio o modificare il server precedentemente creato. Ipotizzando di voler semplicemente modificare il server precedente, aggiorniamo il file di configurazione (defaultSec/deploy/jbossweb.sar/server
) e impostiamo il seguente connector (magari commentando il precedente per evitare di perderlo):
<Connector protocol="HTTP/1.1" SSLEnabled="true"
port="8443" address="${jboss.bind.address}"
scheme="https" secure="true" clientAuth="true"
keystoreFile="${jboss.server.home.dir}/conf/server.jks"
keystorePass="password" sslProtocol = "TLS"
truststoreFile="${jboss.server.home.dir}/conf/serverTrustore.jks"
truststorePass="password" />
Rispetto al caso precedente, richiediamo l’autenticazione da parte del client (clientAuth) e forniamo il truststore utilizzato per la relativa validazione. Copiamo quindi il serverTrustostore nella cartella conf
del server. Andiamo anche a fornire il trustore ai parametri di lancio dell’application server agendo sulla scheda di Eclipse ("Open launch configuration") o semplicemente aggiungendo il parametro al lancio da console:
-Djavax.net.ssl.trustStore="[path]/server/defaultSec/conf/server.jks"
Non serve altro. Ci sarà però una piccola differenza nel momento in cui vorremo provare a raggiungere l’host su http/8443
. Se proveremo a raggiungerlo il server rifiuterà di mostrare il WSDL così come la console di amministrazione di JBoss. Questo perché l’application server richiede che il client, in questo caso il browser, debba esporre un certificato valido (già aggiunto al truststore del server) per poter essere servito.
Modifiche da apportare al client ed esecuzione del test
Per il client, possiamo modificare leggermente la classe creata in precedenza. Per prima cosa aggiungiamo alla cartella META-INF
il file clientKeystore.jks
. Quindi Modifichiamo (o creiamo ex novo) una classe come di seguito
package wsClient;
import test.documento.prova.ServizioPresentazioneIF;
public class ServizioClientTransportSec {
public static void main(String[] args) {
String prot = "http";
String host = "localhost";
String port = "8080";
boolean secTransport=true;
if(secTransport){
prot = "https";
host = "Nome";
port = "8443";
System.setProperty("javax.net.ssl.trustStore","src/META-INF/truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword","password");
System.setProperty("javax.net.ssl.trustStoreType","JKS");
boolean mutuaAutentic=true;
if(mutuaAutentic){
System.setProperty("javax.net.ssl.keyStore","src/META-"+
"INF/clientKeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword","password");
}
}
String protHostPort = prot+"://"+host+":"+port;
ClientMETAInf sensorClientSDM = new ClientMETAInf(null);
ServizioPresentazioneIF servicePort=sensorClientSDM.getServicePort(protHostPort);
String nome = "Micky";
String cognome = "Mouse";
System.out.println(nome+" "+cognome+" effettua la presentazione. ");
String risposta=servicePort.presentazione(nome, cognome);
System.out.println("Risposta ottenuta: "+risposta);
}
}
Abbiamo introdotto una nuova sezione che viene attivata nel momento in cui la variabile booleana mutuaAutentic
è vera. Avviato il server e lanciato il client, il server risponderà alla nostra richiesta, verificando che il certificato del client sia contenuto tra le voci a disposizione. Provando a eseguire richieste senza fornire il certificato (variabile su false
) otterremo un rifiuto da parte del server.
Nello stesso modo, provando ad effettuare richieste con client il cui certificato non è stato aggiunto al truststore del server egualmente otterremo in risposta un messaggio di errore. Questo è un meccanismo di sicurezza più avanzato rispetto al precedente perché richiede che il client sia noto, o eventualmente sia affidabile, ossia garantito da un certificato di un’autorità terza riconosciuta dal server.
Ciò da un lato aumenta la sicurezza, dall’altro implica un maggior dispendio di risorse (è possibile notare i maggiori tempi di esecuzione richiesti), e una maggiore complessità di gestione dei certificati, sia da parte del client che del server che deve poter discriminare a chi fornire il servizio. Questi aspetti verranno poi affrontati con un maggior dettaglio nel capitolo destinato alle infrastrutture di sicurezza.