Un módulo que estoy agregando a nuestra gran aplicación Java tiene que conversar con el sitio web con seguridad SSL de otra compañía. El problema es que el sitio usa un certificado autofirmado. Tengo una copia del certificado para verificar que no encuentro un ataque de intermediario y necesito incorporar este certificado a nuestro código de tal manera que la conexión al servidor sea exitosa.
Aquí está el código básico:
void sendRequest(String dataPacket) {
String urlStr = "https://host.example.com/";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setMethod("POST");
conn.setRequestProperty("Content-Length", data.length());
conn.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
o.write(data);
o.flush();
}
Sin ningún manejo adicional para el certificado autofirmado, esto muere en conn.getOutputStream () con la siguiente excepción:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Idealmente, mi código debe enseñarle a Java a aceptar este certificado autofirmado, para este punto en la aplicación y en ningún otro lugar.
Sé que puedo importar el certificado en el almacén de autoridad de certificación de JRE, y eso permitirá que Java lo acepte. Ese no es un enfoque que quiero adoptar si puedo ayudar; parece muy invasivo hacer en todas las máquinas de nuestros clientes un módulo que no pueden usar; afectaría a todas las demás aplicaciones Java que usan el mismo JRE, y eso no me gusta a pesar de que las posibilidades de que cualquier otra aplicación Java acceda a este sitio son nulas. Tampoco es una operación trivial: en UNIX tengo que obtener derechos de acceso para modificar el JRE de esta manera.
También he visto que puedo crear una instancia de TrustManager que realiza algunas comprobaciones personalizadas. Parece que incluso podría crear un TrustManager que delegue al TrustManager real en todas las instancias, excepto en este certificado. Pero parece que TrustManager se instala globalmente, y supongo que afectaría a todas las demás conexiones de nuestra aplicación, y eso tampoco me huele bien.
¿Cuál es la forma preferida, estándar o mejor para configurar una aplicación Java para aceptar un certificado autofirmado? ¿Puedo lograr todas las metas que tengo en mente arriba, o voy a tener que comprometerme? ¿Existe una opción que involucre archivos y directorios y configuraciones de configuración, y código de poco a nada?