J'utilisespringBootVersion 1.2.0.RELEASE. J'essaie de configurer mon magasin de clés et mon magasin de clés de confiance via application.properties
.
Lorsque j'ajoute les paramètres suivants, le fichier de clés peut fonctionner, mais pas le fichier de clés certifiées.
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
Toutefois, si j'ajoute le fichier de clés de confiance via gradle:
bootRun {
jvmArgs = [ "-Djavax.net.ssl.trustStore=c://foo.jks", "-Djavax.net.ssl.trustStorePassword=password"]
}
cela fonctionne très bien.
Quelqu'un at-il utilisé le application.properties
pour les magasins de confiance?
Si vous devez passer un appel REST, vous pouvez utiliser la méthode suivante.
Ceci fonctionnera pour les appels sortants via RestTemplate
.
Déclarez RestTemplate
bean comme ceci.
@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);
}
}
Où http.client.ssl.trust-store
et http.client.ssl.trust-store-password
désignent le fichier de clés certifiées au format JKS
et le mot de passe du magasin de clés spécifié.
Cela remplacera le bean RestTemplate
fourni avec Spring Boot et lui fera utiliser le magasin de données de confiance dont vous avez besoin.
J'ai le même problème, je vais essayer de l'expliquer un peu plus en détail.
J'utilise spring-boot 1.2.2-RELEASE et l'ai essayé sur Tomcat et Undertow avec le même résultat.
Définir le magasin de confiance dans application.yml comme suit:
server:
ssl:
trust-store: path-to-truststore...
trust-store-password: my-secret-password...
Ne fonctionne pas, alors que:
$ Java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=path-to-truststore... -Djavax.net.ssl.trustStorePassword=my-secret-password... -jar build/libs/*.jar
fonctionne parfaitement bien.
Le moyen le plus simple de voir la différence à l’arrivée est d’activer ssl-debug dans le client. Lorsque vous travaillez (c'est-à-dire en utilisant les indicateurs -D), le texte suivant est écrit sur la console (lors du traitement de la première demande):
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
Sans les drapeaux -D, je reçois:
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)
... et lors de l'exécution d'une requête, j'obtiens l'exception:
Sun.security.validator.ValidatorException: PKIX path building failed: Sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
J'espère que cela aide à mieux comprendre le problème!
J'ai eu le même problème avec Spring Boot, Spring Cloud (microservices) et un certificat SSL auto-signé. Keystore a fonctionné directement à partir des propriétés de l'application, contrairement à Truststore.
J'ai fini par conserver la configuration du fichier de clés et du fichier de relations de confiance dans application.properties, puis d'ajouter un bean de configuration distinct pour la configuration des propriétés du magasin de clés de confiance avec le système.
@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"));
}
}
J'avais également le même problème avec Spring Boot et Tomcat intégré.
D'après ce que j'ai compris, ces propriétés définissent uniquement les paramètres de configuration de Tomcat. Selon la documentation de Tomcat, cela n’est utilisé que pour l’authentification du client (c'est-à-dire pour le protocole SSL bidirectionnel) et non pour la vérification des certificats distants:
truststoreFile - Le fichier de magasin de confiance à utiliser pour valider client certificats.
(https://Tomcat.Apache.org/Tomcat-8.0-doc/config/http.html } _
Afin de configurer le magasin de données de confiance pour HttpClient, celui-ci dépend en grande partie de l'implémentation de HttpClient que vous utilisez. Par exemple, pour RestTemplate par défaut, Spring Boot utilise une classe SimpleClientHttpRequestFactory basée sur les classes J2SE standard telles que Java.net.HttpURLConnection.
J'ai mis au point une solution basée sur la documentation Apache HttpClient et sur ses publications: http://vincentdevillers.blogspot.pt/2013/02/configure-best-spring-resttemplate.htmlhttp://literatejava.com/networks/ignore-ssl-certificate-errors-Apache-httpclient-4-4/
En gros, cela permet de créer un bean RestTemplate qui approuve uniquement les certificats signés par l'autorité de certification racine dans le magasin de clés de confiance configuré.
@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;
}
}
Et ensuite, vous pouvez utiliser ce client Rest personnalisé à tout moment, par exemple:
@Autowired
private RestTemplate restTemplate;
restTemplate.getForEntity(...)
Cela suppose que vous tentiez de vous connecter à un point de terminaison Rest, mais vous pouvez également utiliser le bean HttpClient ci-dessus pour tout ce que vous voulez.
Les propriétés Java "javax.net.ssl.trustStore" et "javax.net.ssl.trustStorePassword" ne correspondent pas à "server.ssl.trust-store" et "server.ssl.trust-store-password" à partir de Spring Boot " application.properties "(" application.yml ")
vous ne pouvez donc pas définir "javax.net.ssl.trustStore" et "javax.net.ssl.trustStorePassword" simplement en définissant "server.ssl.trust-store" et "server.ssl.trust-store-password" dans " application.properties "(" application.yml ")
une alternative consistant à définir "javax.net.ssl.trustStore" et "javax.net.ssl.trustStorePassword" est définie par Spring boot configuration externalisée
voici des extraits de ma mise en œuvre:
La classe Params contient les paramètres externes
@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 classe KeyStoreUtil gère les paramètres "javax.net.ssl.trustStore" et "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);
}
}
vous obtenez les setters exécutés dans la fonction de démarrage
@SpringBootApplication
@ComponentScan("com.myapp.profiles")
public class ProfilesApplication {
public static void main(String[] args) {
KeyStoreUtil.setKeyStoreParams();
KeyStoreUtil.setTrustStoreParams();
SpringApplication.run(ProfilesApplication.class, args);
}
}
Modifié le 2018-10-03
vous voudrez peut-être aussi adopter l'annotation "PostConstruct" comme alternative à l'exécution des setters
import javax.annotation.PostConstruct;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages={"com.xxx"})
public class GateApplication {
public static void main(String[] args) {
SpringApplication.run(GateApplication.class, args);
}
@PostConstruct
void postConstruct(){
setTrustStoreParams();
setKeyStoreParams();
}
private 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);
}
private 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);
}
}
l'application.yml
---
params:
trustStorePath: config/client-truststore.jks
trustStorePassword: wso2carbon
keyStorePath: config/wso2carbon.jks
keyStorePassword: wso2carbon
defaultType: JKS
---
enfin, dans l'environnement en cours d'exécution (serveur de déploiement), vous créez un dossier nommé "config" dans le même dossier que l'archive jar.
dans le dossier "config", vous stockez "application.yml", "client-truststore.jks" et "wso2carbon.jks". terminé!
Mise à jour du 2018-11-27 sur Spring Boot 2.x.x
à partir de spring boot 2.x.x, les propriétés statiques ne sont plus supportées, veuillez voir ici . Personnellement, je ne pense pas que ce soit un bon geste, car des changements complexes doivent être apportés tout au long de la chaîne de référence ...
de toute façon, un extrait d’impelmation pourrait ressembler à ceci
la classe 'Params'
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
/**
* Params class represent all config parameters that can
* be external set by spring xml file
*/
@Component
@ConfigurationProperties("params")
@Data
public class Params{
//default values, can be override by external settings
public String trustStorePath = "config/client-truststore.jks";
public String trustStorePassword = "wso2carbon";
public String keyStorePath = "config/wso2carbon.jks";
public String keyStorePassword = "wso2carbon";
public String defaultType = "JKS";
}
la 'classe d'application Springboot' (avec 'PostConstruct')
import Java.io.File;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages={"com.xx.xx"})
public class BillingApplication {
@Autowired
Params params;
public static void main(String[] args) {
SpringApplication.run(BillingApplication.class, args);
}
@PostConstruct
void postConstruct() {
// set TrustStoreParams
File trustStoreFilePath = new File(params.trustStorePath);
String tsp = trustStoreFilePath.getAbsolutePath();
System.setProperty("javax.net.ssl.trustStore", tsp);
System.setProperty("javax.net.ssl.trustStorePassword", params.trustStorePassword);
System.setProperty("javax.net.ssl.keyStoreType", params.defaultType);
// set KeyStoreParams
File keyStoreFilePath = new File(params.keyStorePath);
String ksp = keyStoreFilePath.getAbsolutePath();
System.setProperty("Security.KeyStore.Location", ksp);
System.setProperty("Security.KeyStore.Password", params.keyStorePassword);
}
}
Voici ma version étendue de la réponse d'Oleksandr Shpota , y compris les importations. Le package org.Apache.http.*
se trouve dans org.Apache.httpcomponents:httpclient
. J'ai commenté les changements:
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);
}
}
Si vous exécutez votre application Spring Boot en tant que service Linux (par exemple, un script init.d ou similaire), vous disposez également de l'option suivante: fichier. Son contenu devrait être quelque chose de similaire:
Java_OPTS="
-Djavax.net.ssl.trustStore=path-to-your-trustStore-file
-Djavax.net.ssl.trustStorePassword=yourCrazyPassword
"