Указание информации хранилища доверия в spring boot application.properties
Я использую springBootVersion 1.2.0.RELEASE. Я пытаюсь настроить хранилище ключей и доверенных сертификатов через application.properties
.
Когда я добавляю следующие настройки, я могу заставить работать хранилище ключей, но не хранилище доверенных сертификатов.
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
Однако, если я добавлю хранилище доверенных сертификатов через gradle:
bootRun {
jvmArgs = [ "-Djavax.net.ssl.trustStore=c://foo.jks", "-Djavax.net.ssl.trustStorePassword=password"]
}
это работает просто отлично.
Кто-нибудь использовал application.properties
для трастовых магазинов?
Ответы
Ответ 1
В случае, если вам нужно сделать вызов REST, вы можете использовать следующий способ.
Это будет работать для исходящих звонков через RestTemplate
.
RestTemplate
bean-компонент RestTemplate
следующим образом.
@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);
}
}
Где http.client.ssl.trust-store
и http.client.ssl.trust-store-password
указывают на http.client.ssl.trust-store-password
доверенных сертификатов в формате JKS
и пароль для указанного хранилища доверенных сертификатов.
Это переопределит RestTemplate
компонент RestTemplate
предоставляемый Spring Boot, и заставит его использовать RestTemplate
.
Ответ 2
У меня такая же проблема, я попытаюсь объяснить ее немного подробнее.
Я использую spring -boot 1.2.2-RELEASE и пробовал его как для Tomcat, так и для Undertow с тем же результатом.
Определение хранилища доверия в application.yml, например:
server:
ssl:
trust-store: path-to-truststore...
trust-store-password: my-secret-password...
Не работает, а:
$ java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=path-to-truststore... -Djavax.net.ssl.trustStorePassword=my-secret-password... -jar build/libs/*.jar
работает отлично.
Самый простой способ увидеть разницу в rutime - включить ssl-debug в клиенте. При работе (например, с использованием флагов -D) на консоль записывается что-то вроде следующего: (при обработке первого запроса):
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
Без флагов -D я получаю:
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)
... и при выполнении запроса я получаю исключение:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Надеюсь, что это поможет лучше понять проблему!
Ответ 3
У меня была такая же проблема с Spring Boot, Spring Cloud (микросервисы) и самозаверяющим SSL-сертификатом. Keystore работал из коробки из свойств приложения, а Truststore - нет.
В итоге я сохранил конфигурацию хранилища ключей и доверенных сертификатов в application.properties и добавил отдельный компонент конфигурации для настройки свойств хранилища доверенных сертификатов в Системе.
@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"));
}
}
Ответ 4
У меня также была та же проблема с Spring Boot и встроенным Tomcat.
Из того, что я понимаю эти свойства только установить параметры конфигурации Tomcat. Согласно документации Tomcat, это используется только для аутентификации клиента (т.е. для двустороннего SSL), а не для проверки удаленных сертификатов:
truststoreFile - файл хранилища доверенных сертификатов, используемый для проверки клиентских сертификатов.
https://tomcat.apache.org/tomcat-8.0-doc/config/http.html
Чтобы настроить хранилище доверия для HttpClient, оно в значительной степени зависит от используемой вами реализации HttpClient. Например, для RestTemplate по умолчанию Spring Boot использует SimpleClientHttpRequestFactory, основанный на стандартных классах J2SE, таких как java.net.HttpURLConnection.
Я придумала решение на основе документов Apache HttpClient и этих постов: http://vincentdevillers.blogspot.pt/2013/02/configure-best-spring-resttemplate.html http://literatejava.com/networks/игнорирующая-SSL-сертификат-ошибка-апаш-HttpClient-4-4/
По сути это позволяет использовать bean-компонент RestTemplate, который доверяет только сертификатам, подписанным корневым ЦС в настроенном хранилище доверенных сертификатов.
@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;
}
}
И тогда вы можете использовать этот собственный клиент Rest, когда вам нужно, например:
@Autowired
private RestTemplate restTemplate;
restTemplate.getForEntity(...)
Это предполагает, что вы пытаетесь подключиться к конечной точке Rest, но вы также можете использовать вышеупомянутый компонент HttpClient для чего угодно.
Ответ 5
Свойства java "javax.net.ssl.trustStore" и "javax.net.ssl.trustStorePassword" не соответствуют "server.ssl.trust-store" и "server.ssl.trust-store-password" из весенней загрузки " application.properties "(" application.yml ")
поэтому вы не можете установить "javax.net.ssl.trustStore" и "javax.net.ssl.trustStorePassword", просто установив "server.ssl.trust-store" и "server.ssl.trust-store-password" в " application.properties "(" application.yml ")
Альтернативой настройки "javax.net.ssl.trustStore" и "javax.net.ssl.trustStorePassword" является внешняя конфигурация загрузки Spring.
ниже приведены выдержки из моей реализации:
Класс Params содержит внешние настройки
@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;
}
Класс KeyStoreUtil выполняет настройки "javax.net.ssl.trustStore" и "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);
}
}
вы получаете сеттеры, выполняемые в функции запуска
@SpringBootApplication
@ComponentScan("com.myapp.profiles")
public class ProfilesApplication {
public static void main(String[] args) {
KeyStoreUtil.setKeyStoreParams();
KeyStoreUtil.setTrustStoreParams();
SpringApplication.run(ProfilesApplication.class, args);
}
}
Отредактировано 2018-10-03
Вы также можете принять аннотацию "PostConstruct" в качестве альтернативы для выполнения установщиков
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);
}
}
application.yml
---
params:
trustStorePath: config/client-truststore.jks
trustStorePassword: wso2carbon
keyStorePath: config/wso2carbon.jks
keyStorePassword: wso2carbon
defaultType: JKS
---
наконец, в рабочей среде (сервер развертывания) вы создаете папку с именем "config" в той же папке, где хранится архив JAR.
в папке "config" вы храните "application.yml", "client-truststore.jks" и "wso2carbon.jks". сделанный!
Обновление 2018-11-27 о Spring boot 2.xx
начиная с весенней загрузки 2.xx, статические свойства больше не поддерживаются, смотрите здесь. Лично я не считаю это хорошим шагом, потому что в цепочке ссылок должны быть сделаны сложные изменения...
в любом случае, выдержка из имплементации может выглядеть так
класс "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";
}
"класс приложения Springboot" (с "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);
}
}
Ответ 6
Вот моя расширенная версия ответ Александра Шпота, включая импорт. Пакет org.apache.http.*
можно найти в org.apache.httpcomponents:httpclient
. Я прокомментировал изменения:
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 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);
}
}
Ответ 7
Если вы выполняете приложение Spring Boot как службу linux (например, скрипт init.d или аналогичный), то у вас также есть следующий вариант: создайте файл yourApplication.conf и поместите его рядом с исполняемым файлом war/jar. По содержанию должно быть что-то похожее:
JAVA_OPTS="
-Djavax.net.ssl.trustStore=path-to-your-trustStore-file
-Djavax.net.ssl.trustStorePassword=yourCrazyPassword
"
Ответ 8
Хотя я комментирую поздно. Но я использовал этот метод, чтобы сделать работу. Здесь, когда я запускаю свое весеннее приложение, я предоставляю файл приложения yaml через -Dspring.config.location=file:/location-to-file/config-server-vault-application.yml
, который содержит все мои свойства
config-server-vault-application.yml
***********************************
server:
port: 8888
ssl:
trust-store: /trust-store/config-server-trust-store.jks
trust-store-password: config-server
trust-store-type: pkcs12
************************************
Java Code
************************************
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) throws IOException {
setUpTrustStoreForApplication();
SpringApplication.run(ConfigServerApplication.class, args);
}
private static void setUpTrustStoreForApplication() throws IOException {
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
List<PropertySource<?>> applicationYamlPropertySource = loader.load(
"config-application-properties", new UrlResource(System.getProperty("spring.config.location")));
Map<String, Object> source = ((MapPropertySource) applicationYamlPropertySource.get(0)).getSource();
System.setProperty("javax.net.ssl.trustStore", source.get("server.ssl.trust-store").toString());
System.setProperty("javax.net.ssl.trustStorePassword", source.get("server.ssl.trust-store-password").toString());
}
}
Ответ 9
Когда все звучало так сложно, эта команда работала для меня:
keytool -genkey -alias foo -keystore cacerts -dname cn=test -storepass changeit -keypass changeit
Когда у разработчика возникают проблемы, я считаю, что простого фрагмента рабочего решения для него более чем достаточно. Позже он мог диагностировать основную причину и общее понимание, связанное с проблемой.
Ответ 10
Если вы находитесь в Spring, попробуйте просто добавить для него свойства (используйте необходимые свойства), и он должен работать для всей JVM
javax:
net:
ssl:
key-store-password: ${KEYSTORE_SECRET}
key-store-type: PKCS12
trust-store-password: ${TRUSTSTORE_SECRET}
trust-store-type: PKCS12
Ответ 11
В инфраструктуре микросервиса (не соответствует этой проблеме, я знаю;)), вы не должны использовать:
server:
ssl:
trust-store: path-to-truststore...
trust-store-password: my-secret-password...
Вместо этого можно настроить балансировщик ленты:
ribbon:
TrustStore: keystore.jks
TrustStorePassword : example
ReadTimeout: 60000
IsSecure: true
MaxAutoRetries: 1
Здесь https://github.com/rajaramkushwaha/https-zuul-proxy-spring-boot-app вы можете найти рабочий образец. Об этом шла дискуссия по github, но я больше этого не нашел.