ssl - Especificación de la información de la tienda de confianza en spring boot application.properties
spring-boot truststore (10)
Aquí mi versión extendida de la respuesta de Oleksandr Shpota , incluidas las importaciones. El paquete org.apache.http.*
Se puede encontrar en org.apache.httpcomponents:httpclient
. He comentado los cambios:
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Value("${http.client.ssl.key-store}")
private Resource keyStore;
@Value("${http.client.ssl.trust-store}")
private Resource trustStore;
// I use the same pw for both keystores:
@Value("${http.client.ssl.trust-store-password}")
private String keyStorePassword;
// wasn''t able to provide this as a @Bean...:
private RestTemplate getRestTemplate() {
try {
SSLContext sslContext = SSLContexts.custom()
// keystore wasn''t within the question''s scope, yet it might be handy:
.loadKeyMaterial(
keyStore.getFile(),
keyStorePassword.toCharArray(),
keyStorePassword.toCharArray())
.loadTrustMaterial(
trustStore.getURL(),
keyStorePassword.toCharArray(),
// use this for self-signed certificates only:
new TrustSelfSignedStrategy())
.build();
HttpClient httpClient = HttpClients.custom()
// use NoopHostnameVerifier with caution, see https://stackoverflow.com/a/22901289/3890673
.setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier()))
.build();
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
Estoy usando springBootVersion 1.2.0.RELEASE. Estoy tratando de configurar mi keystore y truststore a través de application.properties.
Cuando agrego las siguientes configuraciones, puedo hacer funcionar el keystore, pero no el truststore.
server.ssl.key-store=classpath:foo.jks
server.ssl.key-store-password=password
server.ssl.key-password=password
server.ssl.trust-store=classpath:foo.jks
server.ssl.trust-store-password=password
Sin embargo, si agrego el truststore,
bootRun {
jvmArgs = [ "-Djavax.net.ssl.trustStore=c://foo.jks", "-Djavax.net.ssl.trustStorePassword=password"]
}
funciona bien
¿Alguien ha usado la aplicación.propiedades para tiendas de confianza?
En caso de que necesite realizar una llamada REST, puede utilizarla de la siguiente manera.
Esto funcionará para las llamadas salientes a través de RestTemplate
.
Declare RestTemplate
Bean así.
@Configuration
public class SslConfiguration {
@Value("${http.client.ssl.trust-store}")
private Resource keyStore;
@Value("${http.client.ssl.trust-store-password}")
private String keyStorePassword;
@Bean
RestTemplate restTemplate() throws Exception {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(
keyStore.getURL(),
keyStorePassword.toCharArray()
).build();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory).build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
}
Donde http.client.ssl.trust-store
y http.client.ssl.trust-store-password
apuntan a truststore en formato JKS
y la contraseña para el truststore especificado.
Esto anulará el bean RestTemplate
proporcionado con Spring Boot y hará que use el almacén de confianza que necesita.
En una infraestructura de microservicio (no se ajusta al problema, lo sé;)) no debe usar:
server:
ssl:
trust-store: path-to-truststore...
trust-store-password: my-secret-password...
En cambio, el equilibrador de carga de cinta se puede configurar:
ribbon:
TrustStore: keystore.jks
TrustStorePassword : example
ReadTimeout: 60000
IsSecure: true
MaxAutoRetries: 1
Aquí https://github.com/rajaramkushwaha/https-zuul-proxy-spring-boot-app puede encontrar una muestra de trabajo. También hubo una discusión github sobre eso, pero ya no lo encontré.
Las propiedades de Java "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword" no se corresponden con "server.ssl.trust-store" y "server.ssl.trust-store-password" desde Spring boot " application.properties "(" application.yml ")
por lo que no puede establecer "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword" simplemente configurando "server.ssl.trust-store" y "server.ssl.trust-store-password" en " application.properties "(" application.yml ")
una alternativa para configurar "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword" es mediante Spring Externalized Configuration
a continuación se encuentran extractos de mi implementación:
La clase de Params contiene la configuración externa
@Component
@ConfigurationProperties("params")
public class Params{
//default values, can be override by external settings
public static String trustStorePath = "config/client-truststore.jks";
public static String trustStorePassword = "wso2carbon";
public static String keyStorePath = "config/wso2carbon.jks";
public static String keyStorePassword = "wso2carbon";
public static String defaultType = "JKS";
public void setTrustStorePath(String trustStorePath){
Params.trustStorePath = trustStorePath;
}
public void settrustStorePassword(String trustStorePassword){
Params.trustStorePassword=trustStorePassword;
}
public void setKeyStorePath(String keyStorePath){
Params.keyStorePath = keyStorePath;
}
public void setkeyStorePassword(String keyStorePassword){
Params.keyStorePassword = keyStorePassword;
}
public void setDefaultType(String defaultType){
Params.defaultType = defaultType;
}
La clase KeyStoreUtil asume la configuración de "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword"
public class KeyStoreUtil {
public static void setTrustStoreParams() {
File filePath = new File( Params.trustStorePath);
String tsp = filePath.getAbsolutePath();
System.setProperty("javax.net.ssl.trustStore", tsp);
System.setProperty("javax.net.ssl.trustStorePassword", Params.trustStorePassword);
System.setProperty("javax.net.ssl.keyStoreType", Params.defaultType);
}
public static void setKeyStoreParams() {
File filePath = new File(Params.keyStorePath);
String ksp = filePath.getAbsolutePath();
System.setProperty("Security.KeyStore.Location", ksp);
System.setProperty("Security.KeyStore.Password", Params.keyStorePassword);
}
}
obtienes los setters ejecutados dentro de la función de inicio
@SpringBootApplication
@ComponentScan("com.myapp.profiles")
public class ProfilesApplication {
public static void main(String[] args) {
KeyStoreUtil.setKeyStoreParams();
KeyStoreUtil.setTrustStoreParams();
SpringApplication.run(ProfilesApplication.class, args);
}
}
la aplicación.yml
---
params:
trustStorePath: config/client-truststore.jks
trustStorePassword: wso2carbon
keyStorePath: config/wso2carbon.jks
keyStorePassword: wso2carbon
defaultType: JKS
---
finalmente, dentro del entorno en ejecución (servidor de implementación), crea una carpeta llamada "config" en la misma carpeta donde se almacena el archivo jar.
dentro de la carpeta "config", almacena "application.yml", "client-truststore.jks" y "wso2carbon.jks". ¡hecho!
Sé que esto es bastante viejo, pero si alguien se encuentra con esto, lo que hice fue agregar otra propiedad a mi archivo de propiedades.
server.ssl.trust-store=classpath:truststore.jks
server.ssl.trust-store-password=${KEY_STORE_PASS}
server.ssl.client-auth=need
Entonces primero crea el almacén de confianza y establece las propiedades en el archivo de propiedades. Luego, de acuerdo con this , agrega server.ssl.client-auth=need
para forzar a Spring solo a aceptar solicitudes que lleven un certificado aceptado por aquellos en su tienda de confianza.
Este método resolvió mi problema.
Si ejecuta su aplicación Spring Boot como un servicio de Linux (por ejemplo, script init.d o similar), también tiene la siguiente opción: Cree un archivo llamado suAplicación.conf y póngalo junto a su archivo war / jar ejecutable. Su contenido debe ser algo similar:
JAVA_OPTS="
-Djavax.net.ssl.trustStore=path-to-your-trustStore-file
-Djavax.net.ssl.trustStorePassword=yourCrazyPassword
"
También estaba teniendo el mismo problema con Spring Boot y Tomcat integrado.
Por lo que entiendo, estas propiedades solo configuran los parámetros de configuración de Tomcat. Según la documentación de Tomcat, esto solo se usa para la autenticación de Cliente (es decir, para SSL bidireccional) y no para verificar certificados remotos:
truststoreFile - El archivo de almacenamiento de confianza que se utilizará para validar certificados de cliente .
https://tomcat.apache.org/tomcat-8.0-doc/config/http.html
Para configurar el almacén de confianza para HttpClient, depende en gran medida de la implementación de HttpClient que utilice. Por ejemplo, para RestTemplate de forma predeterminada Spring Boot utiliza un SimpleClientHttpRequestFactory basado en clases J2SE estándar como java.net.HttpURLConnection.
He encontrado una solución basada en los documentos de Apache HttpClient y estas publicaciones: http://vincentdevillers.blogspot.pt/2013/02/configure-best-spring-resttemplate.html http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/
Básicamente, esto permite un bean RestTemplate que solo confía en los certificados firmados por la CA raíz en el almacén de confianza configurado.
@Configuration
public class RestClientConfig {
// e.g. Add http.client.ssl.trust-store=classpath:ssl/truststore.jks to application.properties
@Value("${http.client.ssl.trust-store}")
private Resource trustStore;
@Value("${http.client.ssl.trust-store-password}")
private char[] trustStorePassword;
@Value("${http.client.maxPoolSize}")
private Integer maxPoolSize;
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient() {
// Trust own CA and all child certs
Registry<ConnectionSocketFactory> socketFactoryRegistry = null;
try {
SSLContext sslContext = SSLContexts
.custom()
.loadTrustMaterial(trustStore.getFile(),
trustStorePassword)
.build();
// Since only our own certs are trusted, hostname verification is probably safe to bypass
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,
new HostnameVerifier() {
@Override
public boolean verify(final String hostname,
final SSLSession session) {
return true;
}
});
socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build();
} catch (Exception e) {
//TODO: handle exceptions
e.printStackTrace();
}
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connectionManager.setMaxTotal(maxPoolSize);
// This client is for internal connections so only one route is expected
connectionManager.setDefaultMaxPerRoute(maxPoolSize);
return HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.disableCookieManagement()
.disableAuthCaching()
.build();
}
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(httpRequestFactory());
return restTemplate;
}
}
Y luego puede usar este cliente Rest personalizado siempre que lo necesite, por ejemplo:
@Autowired
private RestTemplate restTemplate;
restTemplate.getForEntity(...)
Esto supone que intenta conectarse a un punto final de resto, pero también puede usar el bean HttpClient anterior para lo que desee.
Tengo el mismo problema, trataré de explicarlo un poco más en detalle.
Estoy usando spring-boot 1.2.2-RELEASE y lo probé en Tomcat y Undertow con el mismo resultado.
Definir el trust-store en application.yml como:
server:
ssl:
trust-store: path-to-truststore...
trust-store-password: my-secret-password...
No funciona, mientras:
$ java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=path-to-truststore... -Djavax.net.ssl.trustStorePassword=my-secret-password... -jar build/libs/*.jar
funciona perfectamente bien
La forma más sencilla de ver la diferencia en el momento es habilitar ssl-debug en el cliente. Cuando se trabaja (es decir, usando -D flags) algo similar a lo siguiente se escribe en la consola (durante el procesamiento de la primera solicitud):
trustStore is: path-to-truststore...
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
Subject: C=..., ST=..., O=..., OU=..., CN=...
Issuer: C=..., ST=..., O=..., OU=..., CN=...
Algorithm: RSA; Serial number: 0x4d2
Valid from Wed Oct 16 17:58:35 CEST 2013 until Tue Oct 11 17:58:35 CEST 2033
Sin las banderas -D consigo:
trustStore is: /Library/Java/JavaVirtualMachines/jdk1.8.0_11.jdk/Contents/Home/jre/lib/security/cacerts
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert: ... (one for each CA-cert in the defult truststore)
... y al realizar una solicitud obtengo la excepción:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Espero que ayude a entender mejor el problema.
Tuve el mismo problema con Spring Boot, Spring Cloud (microservicios) y un certificado SSL autofirmado. Keystore funcionó de la caja de propiedades de la aplicación, y Truststore no.
Terminé manteniendo la configuración de almacén de claves y trustore en application.properties y agregando un bean de configuración separado para configurar las propiedades de truststore con el sistema.
@Configuration
public class SSLConfig {
@Autowired
private Environment env;
@PostConstruct
private void configureSSL() {
//set to TLSv1.1 or TLSv1.2
System.setProperty("https.protocols", "TLSv1.1");
//load the ''javax.net.ssl.trustStore'' and
//''javax.net.ssl.trustStorePassword'' from application.properties
System.setProperty("javax.net.ssl.trustStore", env.getProperty("server.ssl.trust-store"));
System.setProperty("javax.net.ssl.trustStorePassword",env.getProperty("server.ssl.trust-store-password"));
}
}