Um módulo que estou adicionando ao nosso grande aplicativo Java precisa conversar com o site protegido por SSL de outra empresa. O problema é que o site usa um certificado autoassinado. Eu tenho uma cópia do certificado para verificar se não estou encontrando um ataque intermediário e preciso incorporar esse certificado ao nosso código de forma que a conexão com o servidor seja bem-sucedida.
Aqui está o 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();
}
Sem qualquer manipulação adicional em vigor para o certificado autoassinado, ele morre em conn.getOutputStream () com a seguinte exceção:
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, meu código precisa ensinar Java a aceitar este certificado autoassinado, para este ponto no aplicativo e em nenhum outro lugar.
Eu sei que posso importar o certificado para o armazenamento da autoridade de certificação do JRE e isso permitirá que o Java aceite. Essa não é uma abordagem que quero adotar se puder ajudar; parece muito invasivo em todas as máquinas de nossos clientes para um módulo que eles não podem usar; isso afetaria todos os outros aplicativos Java que usam o mesmo JRE, e eu não gosto disso, embora as chances de qualquer outro aplicativo Java acessar este site sejam nulas. Também não é uma operação trivial: no UNIX, tenho que obter direitos de acesso para modificar o JRE dessa maneira.
Também vi que posso criar uma instância do TrustManager que faz alguma verificação personalizada. Parece que eu posso até criar um TrustManager que delega para o TrustManager real em todas as instâncias, exceto neste certificado. Mas parece que o TrustManager é instalado globalmente, e presumo que isso afetaria todas as outras conexões do nosso aplicativo, e isso também não parece muito bom para mim.
Qual é a maneira preferida, padrão ou melhor de configurar um aplicativo Java para aceitar um certificado autoassinado? Posso cumprir todos os objetivos que tenho em mente acima ou terei que me comprometer? Existe uma opção envolvendo arquivos e diretórios e definições de configuração, e pouco ou nenhum código?