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
をトラストストアに使用しましたか?
REST呼び出しを行う必要がある場合は、次の方法を使用できます。
これはRestTemplate
を介した発信呼び出しで機能します。
このようにRestTemplate
Beanを宣言します。
@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
形式のトラストストアと、指定されたトラストストアのパスワードを指します。
これにより、Spring Bootで提供されるRestTemplate
Beanがオーバーライドされ、必要なトラストストアが使用されるようになります。
私は同じ問題を抱えています。もう少し詳しく説明しようと思います。
私は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
問題をよりよく理解するのに役立つことを願っています!
Spring Boot、Spring Cloud(マイクロサービス)、および自己署名SSL証明書でも同じ問題が発生しました。キーストアはアプリケーションのプロパティからそのまま使用できましたが、トラストストアは使用できませんでした。
最終的に、application.propertiesにキーストアとトラストアーの両方の構成を保持し、システムでトラストストアのプロパティーを構成するための別個の構成Beanを追加しました。
@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"));
}
}
Spring Bootと組み込みTomcatでも同じ問題が発生していました。
私が理解していることから、これらのプロパティはTomcat構成パラメータのみを設定します。 Tomcatのドキュメントによると、これはクライアント認証(つまり、双方向SSL)にのみ使用され、リモート証明書の検証には使用されません。
truststoreFile-検証に使用するトラストストアファイル クライアント 証明書。
https://Tomcat.Apache.org/Tomcat-8.0-doc/config/http.html
HttpClientのトラストストアを設定するには、使用するHttpClient実装に大きく依存します。たとえば、デフォルトでRestTemplateの場合、Spring BootはJava.net.HttpURLConnectionなどの標準J2SEクラスに基づいたSimpleClientHttpRequestFactoryを使用します。
Apache HttpClientのドキュメントとこれらの投稿に基づいたソリューションを考え出しました: http://vincentdevillers.blogspot.pt/2013/02/configure-best-spring-resttemplate.html - http://literatejava.com/networks/ignore-ssl-certificate-errors-Apache-httpclient-4-4/
基本的に、これにより、構成されたトラストストア内のルートCAによって署名された証明書のみを信頼するRestTemplate Beanが許可されます。
@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 Beanも使用できます。
Javaプロパティ「javax.net.ssl.trustStore」と「javax.net.ssl.trustStorePassword」は、Springブートの「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 boot 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);
}
}
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
---
最後に、実行中の環境(展開サーバー)内で、jarアーカイブが保存されているフォルダーと同じフォルダーの下に「config」という名前のフォルダーを作成します。
「config」フォルダー内に、「application.yml」、「client-truststore.jks」、および「wso2carbon.jks」を保存します。できた!
2018-11-27にSpring boot 2.x.xについての更新
スプリングブート2.x.x以降、静的プロパティはサポートされなくなりました。 こちらをご覧ください をご覧ください。私は個人的にはそれが良い動きだとは思わない、なぜなら複雑な変更が参照チェーンに沿ってなされなければならないからだ...
とにかく、強制排除の抜粋は次のようになります
「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);
}
}
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);
}
}
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
"