diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizer.java index e42111c75db..1a3b4d3789a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizer.java @@ -111,9 +111,19 @@ class SslConnectorCustomizer implements TomcatConnectorCustomizer { .getInstance(); instance.addUserFactory( new SslStoreProviderUrlStreamHandlerFactory(sslStoreProvider)); - protocol.setKeystoreFile(SslStoreProviderUrlStreamHandlerFactory.KEY_STORE_URL); - protocol.setTruststoreFile( - SslStoreProviderUrlStreamHandlerFactory.TRUST_STORE_URL); + try { + if (sslStoreProvider.getKeyStore() != null) { + protocol.setKeystoreFile(SslStoreProviderUrlStreamHandlerFactory.KEY_STORE_URL); + } + if (sslStoreProvider.getTrustStore() != null) { + protocol.setTruststoreFile( + SslStoreProviderUrlStreamHandlerFactory.TRUST_STORE_URL); + } + } + catch (Exception ex) { + throw new WebServerException("Could not load store: " + ex.getMessage(), + ex); + } } private void configureSslKeyStore(AbstractHttp11JsseProtocol protocol, Ssl ssl) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java index 744cacba44c..59d1449b2df 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java @@ -16,6 +16,13 @@ package org.springframework.boot.web.embedded.tomcat; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.util.net.SSLHostConfig; @@ -24,8 +31,13 @@ import org.junit.Before; import org.junit.Test; import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.SslStoreProvider; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; /** * Tests for {@link SslConnectorCustomizer} @@ -101,4 +113,50 @@ public class SslConnectorCustomizerTests { assertThat(sslHostConfig.getEnabledProtocols()).containsExactly("TLSv1.2"); } + @Test + public void customizeWhenSslStoreProviderProvidesOnlyKeyStoreShouldUseDefaultTruststore() throws Exception { + Ssl ssl = new Ssl(); + ssl.setKeyPassword("password"); + ssl.setTrustStore("src/test/resources/test.jks"); + SslStoreProvider sslStoreProvider = mock(SslStoreProvider.class); + given(sslStoreProvider.getKeyStore()).willReturn(loadStore()); + SslConnectorCustomizer customizer = new SslConnectorCustomizer(ssl, sslStoreProvider); + Connector connector = this.tomcat.getConnector(); + customizer.customize(connector); + this.tomcat.start(); + SSLHostConfig sslHostConfig = connector.getProtocolHandler() + .findSslHostConfigs()[0]; + SSLHostConfig sslHostConfigWithDefaults = new SSLHostConfig(); + assertThat(sslHostConfig.getTruststoreFile()).isEqualTo(sslHostConfigWithDefaults.getTruststoreFile()); + assertThat(sslHostConfig.getCertificateKeystoreFile()).isEqualTo(SslStoreProviderUrlStreamHandlerFactory.KEY_STORE_URL); + } + + @Test + public void customizeWhenSslStoreProviderProvidesOnlyTrustStoreShouldUseDefaultKeystore() throws Exception { + Ssl ssl = new Ssl(); + ssl.setKeyPassword("password"); + ssl.setKeyStore("src/test/resources/test.jks"); + SslStoreProvider sslStoreProvider = mock(SslStoreProvider.class); + given(sslStoreProvider.getTrustStore()).willReturn(loadStore()); + SslConnectorCustomizer customizer = new SslConnectorCustomizer(ssl, sslStoreProvider); + Connector connector = this.tomcat.getConnector(); + customizer.customize(connector); + this.tomcat.start(); + SSLHostConfig sslHostConfig = connector.getProtocolHandler() + .findSslHostConfigs()[0]; + SSLHostConfig sslHostConfigWithDefaults = new SSLHostConfig(); + assertThat(sslHostConfig.getTruststoreFile()).isEqualTo(SslStoreProviderUrlStreamHandlerFactory.TRUST_STORE_URL); + assertThat(sslHostConfig.getCertificateKeystoreFile()).contains(sslHostConfigWithDefaults.getCertificateKeystoreFile()); + } + + private KeyStore loadStore() throws KeyStoreException, IOException, + NoSuchAlgorithmException, CertificateException { + KeyStore keyStore = KeyStore.getInstance("JKS"); + Resource resource = new ClassPathResource("test.jks"); + try (InputStream inputStream = resource.getInputStream()) { + keyStore.load(inputStream, "secret".toCharArray()); + return keyStore; + } + } + }