Me ha pasado recientemente que tenía que hacer llamadas SOAP a través de un cliente basado en Axis2 y utilizar un certificado de confianza concreto. El problema venía por la manera de indicar el certificado de confianza y como estábamos invocando a nuestro programa.
La primera solución ha sido la ampliamente conocida de setear dicho certificado en el sistema. De la siguiente forma:
System.setProperty("javax.net.ssl.trustStore", trustStorePath); System.setProperty("javax.net.ssl.trustStorePassword", trstStorePass); System.setProperty("javax.net.ssl.trustStoreType", trustStoreType);
Esta solución funciona correctamente por sí sola. El problema en nuestro caso lo teníamos al lanzar la ejecución a través de Maven. Y esto es debido a que Maven hace sus propias llamadas a determinados repositorios para comprobar el estado de las librerías del proyecto. Y al hacer esto Axis2 cachea el certificado utilizado previamente por Maven, es decir el certificado de la máquina virtual Java. Por tanto el seteo posterior de nuestro certificado no sirve para nada.
¿Como he llegado a esta conclusión? Si ejecutaba el programa con el comando offline de Maven, funcionaba correctamente. Y si lo ejecutaba sin dicho comando, al intentar realizar la llamada, indicaba que no encontraba un certificado válido.
unable to find valid certification path to requested target
La solución puede ser simplemente descargarnos el certificado del host al que vayamos a llamar y añadirlo al certificado de confianza de la máquina virtual.
sudo keytool -import -trustcacerts -file /path/to/ca/ca.pem \
-alias mydomain -keystore $JAVA_HOME/jre/lib/security/cacerts
Pero como estamos en una Web sobre Java nosotros vamos a ver como hacerlo con Java. Y para ellos vamos ha hacer uso de la librería commons-io y su clase Protocol. Esta nos permitirá indicar nuestra propia autorización a utilizar en las llamadas con el protocolo indicado, en nuestro caso SSL.
En nuestro caso lo realizaremos a través de la clase AuthSSLProtocolSocketFactory la cual nos permite validar la identidad de servidores HTTPS dentro de una lista de certificados de confianza. El servidor será el endpoint al cual llamaremos y el certificado de confianza será el de dicho servidor que se encuentra almacenado en el keystore que le pasaremos.
URL url = new File(trustStorePath).toURI().toURL(); ProtocolSocketFactory factory = new AuthSSLProtocolSocketFactory(url, trstStorePass, url, trstStorePass); Protocol httpsProtocol = new Protocol("https", factory, 443); Protocol.registerProtocol("https", httpsProtocol);
No hay comentarios:
Publicar un comentario