Подтвердить что ты не робот

Указание информации хранилища доверия в 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 для трастовых магазинов?

4b9b3361

Ответ 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, но я больше этого не нашел.