Instaurare sicurezza a livello trasporto ha impatto sul protocollo utilizzato per il trasporto e in maniera indiretta sull’applicazione. Essendo SSL/TLS ben supportato nativamente in Java, il tutto si traduce nell’utilizzo di determinate configurazioni al posto di altre. Detto altrimenti, Il WSDL descritto in precedenza non richiede modifiche mentre per utilizzare HTTPS con JBoss occorre agire sui parametri di configurazione dell’application server. Più in dettaglio, occorre definire un connector HTTPS e collegarlo al keystore che si vorrà utilizzare. La definizione del nuovo connector consisterà nella modifica di un file di configurazione.
In primo luogo, assicuriamoci di avere a disposizione (o generare) un keystore in formato JKS, il certificato associato e il truststore relativo:
- password della chiave e del keystore devono essere uguali, viceversa si solleverà l’eccezione Cannot Recover Key;
- il nome assegnato per generare il certificato vincola l’host cui si connetterà il client (avviene una verifica del nome), per cui per eseguire un test occorre assegnare l’host attualmente in uso dalla macchina o il nome della macchina stessa (per ragioni di portabilità andrebbe assegnato il nome di dominio). Viceversa, si otterrà lato client un’eccezione del tipo No subject alternative names present. Questo meccanismo serve a evitare che il traffico diretto al server venga reindirizzato verso altri soggetti.
Nel proseguo della lezione vedremo come configurare un server per abilitare il traffico su HTTPS con autenticazione a una via e le modifiche minimali da apportare al client per eseguire gli esempi.
Configurazione server
In precedenza abbiamo lanciato l’esempio di base utilizzando un server di tipo default. Ora possiamo modificare la configurazione del medesimo server o crearne un duplicato e modificarlo senza impattare sulla configurazione di base, in modo da mantenere il server originale pronto per ulteriori esempi o impattare su un ambiente di deploy in uso. Nell'esempio creeremo un duplicato del server default. In pratica una copia della cartella JBoss[version]/server/default
all’interno della stessa cartella server di JBoss.
Ipotizziamo di chiamare la cartella copiata defaultSec
. Creato il nuovo server (privo di cartelle, librerie etc. che non siano quegli originali), possiamo definire un nuovo punto di accesso da Eclipse creando una nuova configurazione server che punti a questa cartella: nella vista "JavaEE" accedere a "servers" e aggiungere un nuovo server, dare poi un nuovo nome al server (es. JBoss 6.x Secure RS) e aggiungere ("Add") un nuovo Server runtime environment che punti a defaultSec.
Dalla scheda del server, alla voce "Overview/Open launch" configuration sarà possibile --configuration=defaultSec
, che indica che il server lanciato sarà quello di cui stiamo per andare a modificare le impostazioni. Se si preferisce lanciare il server da riga di comando, occorre aggiungere al comando l’opzione -c defaultSec
. Prima di proseguire è consigliabile lanciare una volta il server e verificare l’assenza di messaggi di errore. Ricordare inoltre di modificare l’host se si vuole rendere il server accessibile dall’esterno (0.0.0.0
o l’host relativo alla scheda di rete, al posto di localhost
).
A questo punto copiamo il keystore server.jks
nella cartella defaultSec/conf/
e andiamo a modificare il file server.xml
contenuto nella cartella defaultSec/deploy/jbossWeb.sar/server
. Nel file troveremo un connector HTTP/1.1 su porto 8080
, per il momento possiamo limitarci ad aggiungere subito dopo un secondo connector su porto 8443
e limitarci a impostare la seguente configurazione.
<Connector protocol="HTTP/1.1" SSLEnabled="true"
port="8443" address="${jboss.bind.address}"
scheme="https" secure="true" clientAuth="false"
keystoreFile="${jboss.server.home.dir}/conf/server.jks"
keystorePass="password" sslProtocol = "TLS" />
In estrema sintesi, stiamo indicando dove trovare il keystore (fornendo la relativa password), quale protocollo di sicurezza da abilitare (TLS) e su quale porto si accetteranno le relative richieste. A questo punto, si dovrà provvedere al deploy del progetto PresentazioneServer
e al lancio del server defaultSec
.
Verifichiamo subito che effettuando una ricerca sull’host http://localhost:8080
verremo rimandati normalmente sulla console di amministrazione di JBoss. Questo perché non abbiamo disabilitato il connector base sul porto 8080
. Provando ad accedere invece su https://localhost:8443
verremo accolti da una schermata che indica che è presente un certificato di origine non riconosciuta. Per il momento limitiamoci ad acconsentire e continuare verso il sito, potremo accedere in modalità protetta alla console di amministrazione dell’application server.
Sarà possibile anche eseguire un accesso diretto in modalità sicura al WSDL mediante il seguente indirizzo (eventualmente adeguare l’host a quello in uso): https://127.0.0.1:8443/Presentazione/PresentazioneService/ServizioPresentazioneIF?wsdl
. E’ possibile vedere che il WSDL è raggiungibile sia su https://127.0.0.1:8443
che su http://127:0.0.1:8080
, pertanto ancora raggiungibile con il client del progetto creato in precedenza. E’ possibile fare un'altra prova arrestando il server, accedendo nuovamente al file di configurazione defaultSec/deploy/jbossWeb.sar/server
e commentando il connector relativo al lancio standard su http (HTTP 1.1 su 8080
) per poi rilanciare il server.
Questa volta troveremo il WSDL (e console JBoss) solo su HTTPS, conseguentemente non sarà possibile raggiungere il Web service con il precedente client. A questo punto si potrà scegliere se ripristinare il connector su 8080
.
Modifiche al client
Per connettersi al server utilizzando con una connessione sicura il client dovrà avere a disposizione il truststore generato a partire dal certificato del server, in quanto è previsto che in seguito all’invio del certificato questo venga verificato confrontandolo con quello a disposizione del client. E’ possibile copiarlo nella cartella META-INF
del progetto PresentazioneClient
.
Per quanto riguarda la classe contenente il main, potremo modificare la classe creata in precedenza, o crearne una nuova (ServizioClientTransportSec.java
).
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=false;
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");
}
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);
}
}
Rispetto al precedente esempio è stata aggiunta una variabile booleana che abilita l’accesso sicuro permettendo di modificare i parametri dell’indirizzo, settare alcune proprietà per la libreria JSSE, in particolare indicare posizione, password e tipo del trustore. Ricordarsi di modificare l’host (nel codice esempio settato su Nome
con host corretto coincidente con quello inserito nel certificato del server).
Non serve altro, eseguendo un accesso con la variabile su false
, se il server mantiene avviati entrambi i connectors (HTTP e HTTPS), potremo accedere al Web service senza problemi. Viceversa, qualora fosse abilitato solo il connector su HTTPS, lasciando la variabile booleana su false otterremo un errore.
Esecuzione del test
Impostiamo ora la variabile secTransport
su true
e proviamo a lanciare. Se tutto è configurato secondo indicazioni, otterremo la risposta corretta dal Web service. Provando a sniffare il traffico con Wireshark questa volta non riusciremo a vedere cosa sta viaggiando.
L’instaurazione di un canale sicuro oltre alla configurazione dell’application server e all’individuazione nel client del truststore, non ha richiesto altro. Il progetto del server non ha avuto bisogno di modifiche, né vi sono stati impatti sul WSDL.
Finora abbiamo visto che provando ad accedere all’host su HTTPS ci veniva segnalata la presenza di un certificato di origine non riconosciuta (Il certificato di sicurezza presentato dal sito Web non è stato emesso da un'Autorità di certificazione disponibile nell'elenco locale). E’ possibile evitare questo inconveniente aggiungendo il certificato a quelli presenti nel browser nella lista delle autorità di certificazioni attendibili. Accedendo a (a seconda delle versioni può cambiare il path):
È possibile importare il certificato precedentemente generato fornendo il path e lasciando su valori di default le altre opzioni. A questo punto uscire dal browser e riavviarlo. Provando ad accedere all’indirizzo in questione (avendo cura di inserire nell’host il nome contenuto nel certificato), potremo accedere al WSDL senza incappare in warnings.
E' comunque possibile ridurre le modifiche da apportare impostando le properties tramite gli argomenti della JVM. Sarà così possibile utilizzare il client ServizioClient.java
senza aggiungere codice (ma riconfigurando i parametri di connessione protocollo, host e porto, ad esempio "https", "Nome", 8443
, presi da file di configurazione o passati come argomenti del programma) semplicemente lanciandolo con i seguenti argomenti per la JVM:
-Djavax.net.ssl.trustStore="src/META-INF/truststore.jks"
-Djavax.net.ssl.trustStorePassword="password" -Djavax.net.ssl.trustStoreType="JKS"
Connector: parametri di configurazione
In precedenza abbiamo impostato un connector per stabilire una comunicazione protetta SSL sorvolando sulle voci contenute. Ecco i principali parametri legati alla comunicazione mediante SSL.
Protocol |
Definizione |
---|---|
redirectPort |
Se il connector supporta richieste non SSL e viene ricevuta una richiesta che necessita di SSL, Catalina effettua il redirect della richiesta al porto specificato. |
SSLEnabled |
se Settato su true (default false ), abilita il traffico SSL. Se abilitato, si setteranno gli attributi scheme e secure . |
port |
Porto TCP sul quale il connector crearà una server socket e si porrà in attesa per connessioni. |
address |
Per server con più indirizzi IP, specifica su quale indirizzo il connector si porrà in ascolto. |
scheme |
Nome del protocollo (default http ) che ritornerà in seguito ad una chiamata request.getScheme() . Nel nostro caso su https . |
secure |
Settato su true (default false ) per far ritornare true l’invocazione del metodo request.isSecure() . |
clientAutd |
true se è richiesta l’autorizzazione da parte del client; In un’autenticazione a una via non è richiesta, pertanto nel nostro caso è impostato su false ; impostando su want , verrà richiesto ma se un client non lo fornirà non verrà sollevato un errore. |
keystoreFile |
Il patd al file keystore. |
keystorePass |
La password per il keystore. |
keystoreProvider |
Nome del provider del keystore da usare con il certificato; se non specificato, viene scorsa la lista dei providers registrati e usato il primo provider che supporta il tipo di keystore. |
keystoreType |
Tipo di keystore (default JKS). |
sslProtocol |
Versione del protocollo (default TLS). |
keyAlias |
Alias per il certificato del server nel keystore, se non specificato viene usata la prima chiave letta. |
truststoreFile |
Patd al file trustore per validare i client (usato solo in modalità autenticazione a due vie). |
truststorePass |
Password per il trustore. |
truststoreProvider |
Nome del provider del trustore da usare con il certificato del server; se non specificato viene scorsa la lista dei providers registrati e usato il primo provider che supporta il tipo di trustore fornito. |
truststoreType |
Si utilizza tale attributo se il tipo di formato del trustore è differente da quello del keystore. |
Algoritdm |
Codifica (default SunX509). |