Cliente de Web Service CXF con certificado de cliente sobre https

De ChuWiki

Es posible que el web service al que queremos acceder esté sobre un https que requiera certificado de cliente (two ways ssl). Con CXF la forma de conseguir acceder es la siguiente.

// HelloService y HelloPortType son las clases de cliente generadas por
// wsdl2java de CXF a partir del fichero wsdl correspondiente.
HelloService hello = new HelloService();
HelloPortType helloPort = cliente.getHelloPort();

org.apache.cxf.endpoint.Client client = ClientProxy.getClient(helloPort);

HTTPConduit http = (HTTPConduit) client.getConduit();
TLSClientParameters tlsParams = new TLSClientParameters();
...
http.setTlsClientParameters(tlsParams);

Y lo verdaderamente importante, rellenar estos tlsParams. El código para ello, extraído de http://caffiendfrog.blogspot.com/2011/06/setting-up-apache-cxf-with-ssl-for.html y con algunos arreglos es el siguiente

// set up the keystore and password

KeyStore keyStore = KeyStore.getInstance("PKCS12");
// -- provide your password
String trustpass = "una password";
// -- provide your truststore
File truststore = new File("C:/path/client.p12");

keyStore.load(new FileInputStream(truststore),trustpass.toCharArray());

// should JSEE omit checking if the host name specified in the
// URL matches that of the Common Name (CN) on the server's
// certificate.
tlsParams.setDisableCNCheck(true);

// set the SSL protocol
tlsParams.setSecureSocketProtocol("SSL");

// set the trust store
// (decides whether credentials presented by a peer should be
// accepted)
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keyStore2 = KeyStore.getInstance("JKS");
// -- provide your password
String trustpass2 = "un password";
// -- provide your truststore
File truststore2 = new File("C:/Users/usuario/.keystore");

keyStore2.load(new FileInputStream(truststore2),trustpass2.toCharArray());

trustFactory.init(keyStore2);
TrustManager[] tm = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(tm);

// set our key store
// (used to authenticate the local SSLSocket to its peer)
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, trustpass.toCharArray());
KeyManager[] km = keyFactory.getKeyManagers();
tlsParams.setKeyManagers(km);

// set all the needed include & exclude cipher filters
FiltersType filter = new FiltersType();
// filter.getInclude().add(".*_WITH_3DES_.*"); // XXX needed?
filter.getInclude().add(".*_EXPORT_.*");
filter.getInclude().add(".*_EXPORT1024_.*");
filter.getInclude().add(".*_WITH_DES_.*");
filter.getInclude().add(".*_WITH_NULL_.*");
filter.getExclude().add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
 

Veamos sólo un par de detalles, que son los que tendremos que configurar en nuestro caso concreto. En el siguiente grupo de líneas

KeyStore keyStore = KeyStore.getInstance("PKCS12");
// -- provide your password
String trustpass = "una password";
// -- provide your truststore
File truststore = new File("C:/path/client.p12");

debemos poner el fichero con nuestro certificado de cliente (client.p12) y la password para desencriptarlo. Si el fichero está en formato PKCS#12 como en este caso, a KeyStore.getInstance() debemos pasarle "PKCS12". Otra opción es que el certificado esté en el formato porpio de la herramienta keytool que viene con java, en ese caso el parámetro a pasar sería "JKS".

En las siguientes líneas

// set the trust store
// (decides whether credentials presented by a peer should be
// accepted)
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keyStore2 = KeyStore.getInstance("JKS");
// -- provide your password
String trustpass2 = "un password";
// -- provide your truststore
File truststore2 = new File("C:/Users/usuario/.keystore");

debemos indicar en qué certificados de servidor confiamos. Estos certificados, como en el ejemplo, pueden estar guardaos en un fichero .keystore generado con la herramienta keytool de java. Esta herramienta por defecto deja ese fichero en el HOME del usuario con el nombre .keystore. Debemos pasar también la password para desencriptar dicho fichero. Al ser el fichero generado por keytool de java, a KeyStore.getInstance() le pasamos como parámetro "JKS".

Para crear/añadir certificados a este fichero usamos keytool que viene con java

keytool -import -trustcacerts -file /path/to/ca/ca.crt -alias un_nombre -keystore c:\users\usuario\.keystore

donde ca.crt es el certificado que queremos incluir en el fichero, un_nombre es cualquier nombre que queramos darle y que nos sirva para identificarlo y -keystore apunta al fichero donde queramos guardar el certificado, por defecto en HOME\.keystore.