2014-12-31 2 views
29

Я использую springBootVersion 1.2.0.RELEASE. Я пытаюсь настроить хранилище ключей и доверительное хранилище через application.properties.Указание информации о хранилище доверия в весенней загрузке 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 

Однако, если добавить хотя доверенных сертификатов

bootRun { 
    jvmArgs = [ "-Djavax.net.ssl.trustStore=c://foo.jks", "-Djavax.net.ssl.trustStorePassword=password"] 
} 

это работает просто отлично.

Кто-нибудь использовал application.properties для магазинов доверия?

+0

Какой встроенный контейнер вы используете и как вы определили, что это не работает? –

ответ

6

У меня такая же проблема, я попытаюсь объяснить это немного подробнее.

Я использую весеннюю загрузку 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 

работает прекрасно.

Самый простой способ увидеть разницу в рутиме - включить 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 

Надеюсь, что это поможет лучше понять проблему!

+0

Кто-нибудь знает, почему метод 'application.yml' не работает? –

+0

См. [Настройка доверительного хранилища без хранилища ключей] (https://github.com/spring-projects/spring-boot/issues/6493) –

3

У меня также была проблема с 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 DOCS и эти посты: http://vincentdevillers.blogspot.pt/2013/02/configure-best-spring-resttemplate.html http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/

В основном это позволяет для 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 боб за то, что вы хотите.

+0

Я поддержал это, потому что я собрал небольшой фрагмент кода, чтобы продемонстрировать и создать 'server.ssl.trust-store' предназначен для взаимного TLS (имеет какой-либо эффект, если установлен' server.ssl.client-auth'), а не для исходящих соединений. Ответ может быть принят как ответ stackoverflow. Я также хочу отметить, что документация достаточно adaquate: https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html –

-3

В microservice инфраструктуры (не соответствует проблеме, я знаю;)) Вы не должны использовать:

server: 
    ssl: 
    trust-store: path-to-truststore... 
    trust-store-password: my-secret-password... 

Вместо ленты loadbalancer можно configuered:

ribbon: 
    TrustStore: keystore.jks 
    TrustStorePassword : example 
    ReadTimeout: 60000 
    IsSecure: true 
    MaxAutoRetries: 1 

Здесь https://github.com/rajaramkushwaha/https-zuul-proxy-spring-boot-app вас может найти рабочий образец. Об этом шла дискуссия, но я больше этого не нашел.

+0

Downvoted. Даже в инфраструктуре микросервиса есть случаи, когда вы абсолютно * должны * настраивать хранилище доверия. например, если ваша служба попадает в конечную точку HTTPS ниже по потоку, которая подписана внутренним ЦС вашей организации. – sworisbreathing

10

Если вам нужно сделать звонок REST, вы можете использовать следующий способ.

Это будет работать для исходящих звонков через RestTemplate.

Объявление RestTemplate bean like this.

@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 пункта в формате доверенных JKS и пароль для указанных доверенных сертификатов.

Это будет переопределять фасоль RestTemplate, снабженную Spring Boot, и использовать ее в надежном хранилище.

+0

«http.client.ssl.trust-store» - путь к хранилищу? –

+0

В основном это путь к доверительному магазину. Однако может быть, что вы храните доверенные сертификаты в том же файле, где у вас есть собственные сертификаты и закрытые ключи. Если это так, вы можете использовать keystore. Вы можете найти более подробную информацию здесь https://stackoverflow.com/a/6341566/2065796 –

+0

'http.client.ssl.trust-store' и' http.client.ssl.trust-store-password' являются настраиваемыми свойствами, aren они? –

2

Здесь представлена ​​моя расширенная версия Oleksandr Shpota's answer, включая импорт. Пакет 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'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); 
    } 
} 
4

У меня была такая же проблема с загрузкой Spring, Spring Cloud (microservices) и собственный сертификат SSL. Keystore работал из коробки из свойств приложения, а Truststore - нет.

В итоге я сохранил конфигурацию хранилища ключей и доверенность в application.properties и добавил отдельный компонент конфигурации для настройки свойств TrustStore с помощью системы.

@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")); 
} 
1

ява свойства "javax.net.ssl.trustStore" и "javax.net.ssl.trustStorePassword" не соответствуют "server.ssl.trust-магазин" и «server.ssl.trust-магазин «password» («application.yml»)

поэтому вы не можете установить «javax.net.ssl.trustStore» и «javax.net.ssl.trustStorePassword», просто установив " сервер.ssl.trust-store "и" server.ssl.trust-store-password "в" application.properties "(" application.yml ")

альтернатива настройки" javax.net.ssl.trustStore "и" javax.net.ssl.trustStorePassword "является Спринг ботинке Externalized Configuration

ниже выдержки из моей реализации:

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); 
    } 
} 

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». сделанный!

0

Отвечая на этот вопрос, на GITTER странице Spring-ботинка:

Смежные вопросы