Solución:
Descargo de responsabilidad
En realidad, no debería hacer esto por varias muy buenas razones. La forma más fácil de solucionar los problemas de SSL es seguir las mejores prácticas de SSL y utilizar certificados válidos. Hay excelentes proyectos en línea como https://letsencrypt.org/ que incluso le permitirán obtener una gran seguridad de forma gratuita si el host es de acceso público (si tiene un nombre de host real que se pueda verificar).
ÚSELO BAJO SU PROPIO RIESGO. ASEGÚRESE DE COMPRENDER QUE ESTÁ VIOLANDO MUCHAS MEJORES PRÁCTICAS Y UTILICE ESTO SOLO SI ENTIENDE ESO.
Si causa algún tipo de problema importante con este código de ejemplo, usted es responsable.
Charla honesta
Tuve el mismo problema al tratar con servicios internos (no accesibles públicamente) a los que quería llamar desde una aplicación de arranque de primavera y lo resolví usando el siguiente código.
Breve descripción
Mucha gente le dirá que puede aceptar todos los certificados, codificar su certificado particular en él o algo más. De hecho, puede permitir solo ciertos hosts confiables a través de la ruta de código, que es lo que estoy intentando aquí para una capa adicional de seguridad.
En este código de ejemplo, puede pasar varios hosts a las clases y debería permitir que las solicitudes solo a esos hosts se emitan con certificados no válidos, y todo lo demás pasará por la cadena de mando normal.
Este no es realmente un código de grado de producción, pero es de esperar que pueda aprovecharlo.
Basta de conferencias, lo que sigue puede que te interese más.
El código
Esto se usa para Java 8 y spring-boot.
Configuración
@Configuration
public class FeignClientConfiguration {
@Bean
public Client client() throws NoSuchAlgorithmException,
KeyManagementException {
return new Client.Default(
new NaiveSSLSocketFactory("your.host.here"),
new NaiveHostnameVerifier("your.host.here"));
}
}
NaiveHostnameVerifier
public class NaiveHostnameVerifier implements HostnameVerifier {
private final Set<String> naivelyTrustedHostnames;
private final HostnameVerifier hostnameVerifier =
HttpsURLConnection.getDefaultHostnameVerifier();
public NaiveHostnameVerifier(String ... naivelyTrustedHostnames) {
this.naivelyTrustedHostnames =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(naivelyTrustedHostnames)));
}
@Override
public boolean verify(String hostname, SSLSession session) {
return naivelyTrustedHostnames.contains(hostname) ||
hostnameVerifier.verify(hostname, session);
}
}
NaiveSSLSocketFactory
public class NaiveSSLSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory sslSocketFactory =
(SSLSocketFactory) SSLSocketFactory.getDefault();
private final SSLContext alwaysAllowSslContext;
private final Set<String> naivelyTrustedHostnames;
public NaiveSSLSocketFactory(String ... naivelyTrustedHostnames)
throws NoSuchAlgorithmException, KeyManagementException {
this.naivelyTrustedHostnames =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(naivelyTrustedHostnames)));
alwaysAllowSslContext = SSLContext.getInstance("TLS");
TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
alwaysAllowSslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public String[] getDefaultCipherSuites() {
return sslSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return sslSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
return (naivelyTrustedHostnames.contains(host))
? alwaysAllowSslContext.getSocketFactory().createSocket(socket, host, port, autoClose)
: sslSocketFactory.createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return (naivelyTrustedHostnames.contains(host))
? alwaysAllowSslContext.getSocketFactory().createSocket(host, port)
: sslSocketFactory.createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException, UnknownHostException {
return (naivelyTrustedHostnames.contains(host))
? alwaysAllowSslContext.getSocketFactory().createSocket(host, port, localAddress, localPort)
: sslSocketFactory.createSocket(host, port, localAddress, localPort);
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return (naivelyTrustedHostnames.contains(host.getHostName()))
? alwaysAllowSslContext.getSocketFactory().createSocket(host, port)
: sslSocketFactory.createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException {
return (naivelyTrustedHostnames.contains(host.getHostName()))
? alwaysAllowSslContext.getSocketFactory().createSocket(host, port, localHost, localPort)
: sslSocketFactory.createSocket(host, port, localHost, localPort);
}
}
Referencias
Tomé prestado mucho de esta respuesta:
Confiar en todos los certificados usando HttpClient sobre HTTPS
Cuando usas Spring Cloud Netflix> = 1.4.4. también puede hacer lo siguiente:
Agregar okhttp dependencia de maven del cliente:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
Y agregue las siguientes propiedades:
feign.httpclient.disableSslValidation=true
feign.httpclient.enabled=false
feign.okhttp.enabled=true
Referencia: https://github.com/spring-cloud/spring-cloud-netflix/issues/2729
feign.httpclient.disableSslValidation = true no me funcionó.
Se trabaja Crear bean de cliente en Configuración mediante el siguiente código:
import feign.Client;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContexts;
import org.springframework.context.annotation.Bean;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
public class ClientConfiguration {
@Bean
public Client feignClient() {
return new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
}
private SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
return sslContext.getSocketFactory();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
pom.xml podría necesitar agregar dependencias:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.8</version>
</dependency>