diff --git a/spring-vault-core/src/main/java/org/springframework/vault/config/AbstractVaultConfiguration.java b/spring-vault-core/src/main/java/org/springframework/vault/config/AbstractVaultConfiguration.java index 44f9769a..0eb27aea 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/config/AbstractVaultConfiguration.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/config/AbstractVaultConfiguration.java @@ -194,12 +194,13 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw } /** - * @return SSL configuration options. Defaults to {@link SslConfiguration#NONE}. + * @return SSL configuration options. Defaults to + * {@link SslConfiguration#unconfigured()}. * @see SslConfiguration - * @see SslConfiguration#NONE + * @see SslConfiguration#unconfigured() */ public SslConfiguration sslConfiguration() { - return SslConfiguration.NONE; + return SslConfiguration.unconfigured(); } /** diff --git a/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpConnectorFactory.java b/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpConnectorFactory.java index 243a3ec0..f2be7b31 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpConnectorFactory.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpConnectorFactory.java @@ -76,12 +76,12 @@ public class ClientHttpConnectorFactory { try { - if (sslConfiguration.getTrustStore() != null) { + if (sslConfiguration.getTrustStoreConfiguration().isPresent()) { sslContextBuilder.trustManager(createTrustManagerFactory(sslConfiguration .getTrustStoreConfiguration())); } - if (sslConfiguration.getKeyStore() != null) { + if (sslConfiguration.getKeyStoreConfiguration().isPresent()) { sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration .getKeyStoreConfiguration())); } diff --git a/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java b/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java index 13f9b78e..5c5b789b 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java @@ -125,13 +125,13 @@ public class ClientHttpRequestFactoryFactory { static SSLContext getSSLContext(SslConfiguration sslConfiguration) throws GeneralSecurityException, IOException { - KeyManager[] keyManagers = sslConfiguration.getKeyStore() != null ? createKeyManagerFactory( - sslConfiguration.getKeyStoreConfiguration()).getKeyManagers() - : null; + KeyManager[] keyManagers = sslConfiguration.getKeyStoreConfiguration() + .isPresent() ? createKeyManagerFactory( + sslConfiguration.getKeyStoreConfiguration()).getKeyManagers() : null; - TrustManager[] trustManagers = sslConfiguration.getTrustStore() != null ? createTrustManagerFactory( - sslConfiguration.getTrustStoreConfiguration()).getTrustManagers() - : null; + TrustManager[] trustManagers = sslConfiguration.getTrustStoreConfiguration() + .isPresent() ? createTrustManagerFactory( + sslConfiguration.getTrustStoreConfiguration()).getTrustManagers() : null; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, trustManagers, null); @@ -192,8 +192,8 @@ public class ClientHttpRequestFactoryFactory { } static boolean hasSslConfiguration(SslConfiguration sslConfiguration) { - return sslConfiguration.getTrustStore() != null - || sslConfiguration.getKeyStore() != null; + return sslConfiguration.getTrustStoreConfiguration().isPresent() + || sslConfiguration.getKeyStoreConfiguration().isPresent(); } /** @@ -281,13 +281,13 @@ public class ClientHttpRequestFactoryFactory { SslContextBuilder sslContextBuilder = SslContextBuilder // .forClient(); - if (sslConfiguration.getTrustStore() != null) { + if (sslConfiguration.getTrustStoreConfiguration().isPresent()) { sslContextBuilder .trustManager(createTrustManagerFactory(sslConfiguration .getTrustStoreConfiguration())); } - if (sslConfiguration.getKeyStore() != null) { + if (sslConfiguration.getKeyStoreConfiguration().isPresent()) { sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration .getKeyStoreConfiguration())); } diff --git a/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java b/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java index c7c87977..c976273c 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java @@ -43,6 +43,7 @@ import org.springframework.vault.authentication.AwsEc2AuthenticationOptions.AwsE import org.springframework.vault.client.VaultEndpoint; import org.springframework.vault.support.SslConfiguration; import org.springframework.vault.support.VaultToken; +import org.springframework.vault.support.SslConfiguration.KeyStoreConfiguration; import org.springframework.web.client.RestOperations; /** @@ -172,14 +173,30 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration im @Override public SslConfiguration sslConfiguration() { - Resource keyStore = getResource("vault.ssl.key-store"); - String keyStorePassword = getProperty("vault.ssl.key-store-password"); - Resource trustStore = getResource("vault.ssl.trust-store"); - String trustStorePassword = getEnvironment().getProperty( - "vault.ssl.trust-store-password"); + KeyStoreConfiguration keyStoreConfiguration = getKeyStoreConfiguration( + "vault.ssl.key-store", "vault.ssl.key-store-password"); - return new SslConfiguration(keyStore, keyStorePassword, trustStore, - trustStorePassword); + KeyStoreConfiguration trustStoreConfiguration = getKeyStoreConfiguration( + "vault.ssl.trust-store", "vault.ssl.trust-store-password"); + + return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration); + } + + private KeyStoreConfiguration getKeyStoreConfiguration(String resourceProperty, + String passwordProperty) { + + Resource keyStore = getResource(resourceProperty); + String keyStorePassword = getProperty(passwordProperty); + + if (keyStore == null) { + return KeyStoreConfiguration.unconfigured(); + } + + if (StringUtils.hasText(keyStorePassword)) { + return KeyStoreConfiguration.of(keyStore, keyStorePassword.toCharArray()); + } + + return KeyStoreConfiguration.of(keyStore); } @Override diff --git a/spring-vault-core/src/main/java/org/springframework/vault/support/SslConfiguration.java b/spring-vault-core/src/main/java/org/springframework/vault/support/SslConfiguration.java index eafffe4f..637fb268 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/support/SslConfiguration.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/support/SslConfiguration.java @@ -15,9 +15,12 @@ */ package org.springframework.vault.support; +import java.io.IOException; +import java.io.InputStream; import java.security.KeyStore; import java.util.Arrays; +import org.springframework.core.io.AbstractResource; import org.springframework.core.io.Resource; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -37,11 +40,7 @@ import org.springframework.util.Assert; */ public class SslConfiguration { - /** - * Default {@link SslConfiguration} without a KeyStore/TrustStore configured. - */ - public static final SslConfiguration NONE = new SslConfiguration( - KeyStoreConfiguration.EMPTY, KeyStoreConfiguration.EMPTY); + private final static String DEFAULT_KEYSTORE_TYPE = KeyStore.getDefaultType(); private final KeyStoreConfiguration keyStoreConfiguration; @@ -50,9 +49,9 @@ public class SslConfiguration { /** * Create a new {@link SslConfiguration} with the default {@link KeyStore} type. * - * @param keyStore the key store resource. + * @param keyStore the key store resource, must not be {@literal null}. * @param keyStorePassword the key store password. - * @param trustStore the trust store resource. + * @param trustStore the trust store resource, must not be {@literal null}. * @param trustStorePassword the trust store password. * @deprecated Since 1.1, use * {@link #SslConfiguration(KeyStoreConfiguration, KeyStoreConfiguration)} to prevent @@ -60,20 +59,21 @@ public class SslConfiguration { * GC than necessary. */ @Deprecated - public SslConfiguration(@Nullable Resource keyStore, - @Nullable String keyStorePassword, @Nullable Resource trustStore, - @Nullable String trustStorePassword) { + public SslConfiguration(Resource keyStore, @Nullable String keyStorePassword, + Resource trustStore, @Nullable String trustStorePassword) { this(new KeyStoreConfiguration(keyStore, charsOrNull(keyStorePassword), - KeyStore.getDefaultType()), new KeyStoreConfiguration(trustStore, - charsOrNull(trustStorePassword), KeyStore.getDefaultType())); + DEFAULT_KEYSTORE_TYPE), new KeyStoreConfiguration(trustStore, + charsOrNull(trustStorePassword), DEFAULT_KEYSTORE_TYPE)); } /** * Create a new {@link SslConfiguration}. * - * @param keyStoreConfiguration the key store configuration. - * @param trustStoreConfiguration the trust store configuration. + * @param keyStoreConfiguration the key store configuration, must not be + * {@literal null}. + * @param trustStoreConfiguration the trust store configuration, must not be + * {@literal null}. * @since 1.1 */ public SslConfiguration(KeyStoreConfiguration keyStoreConfiguration, @@ -121,11 +121,11 @@ public class SslConfiguration { Assert.notNull(trustStore, "TrustStore must not be null"); Assert.isTrue(trustStore.exists(), - String.format("TrustStore %s does not exist", trustStore)); + () -> String.format("TrustStore %s does not exist", trustStore)); - return new SslConfiguration(KeyStoreConfiguration.EMPTY, + return new SslConfiguration(KeyStoreConfiguration.UNCONFIGURED, new KeyStoreConfiguration(trustStore, trustStorePassword, - KeyStore.getDefaultType())); + DEFAULT_KEYSTORE_TYPE)); } /** @@ -162,10 +162,10 @@ public class SslConfiguration { Assert.notNull(keyStore, "KeyStore must not be null"); Assert.isTrue(keyStore.exists(), - String.format("KeyStore %s does not exist", keyStore)); + () -> String.format("KeyStore %s does not exist", keyStore)); return new SslConfiguration(new KeyStoreConfiguration(keyStore, keyStorePassword, - KeyStore.getDefaultType()), KeyStoreConfiguration.EMPTY); + DEFAULT_KEYSTORE_TYPE), KeyStoreConfiguration.UNCONFIGURED); } /** @@ -209,22 +209,32 @@ public class SslConfiguration { Assert.notNull(keyStore, "KeyStore must not be null"); Assert.isTrue(keyStore.exists(), - String.format("KeyStore %s does not exist", trustStore)); + () -> String.format("KeyStore %s does not exist", trustStore)); Assert.notNull(trustStore, "TrustStore must not be null"); Assert.isTrue(trustStore.exists(), String.format("TrustStore %s does not exist", trustStore)); return new SslConfiguration(new KeyStoreConfiguration(keyStore, keyStorePassword, - KeyStore.getDefaultType()), new KeyStoreConfiguration(trustStore, - trustStorePassword, KeyStore.getDefaultType())); + DEFAULT_KEYSTORE_TYPE), new KeyStoreConfiguration(trustStore, + trustStorePassword, DEFAULT_KEYSTORE_TYPE)); + } + + /** + * Factory method returning an unconfigured {@link SslConfiguration} instance. + * + * @return an unconfigured {@link SslConfiguration} instance. + * @since 2.0 + */ + public static SslConfiguration unconfigured() { + return new SslConfiguration(KeyStoreConfiguration.unconfigured(), + KeyStoreConfiguration.unconfigured()); } /** * @return the {@link java.security.KeyStore key store} resource or {@literal null} if * not configured. */ - @Nullable public Resource getKeyStore() { return keyStoreConfiguration.getResource(); } @@ -249,11 +259,22 @@ public class SslConfiguration { return keyStoreConfiguration; } + /** + * Create a new {@link SslConfiguration} with {@link KeyStoreConfiguration} applied + * retaining the {@link #getTrustStoreConfiguration() trust store} configuration. + * + * @param configuration must not be {@literal null}. + * @return a new {@link SslConfiguration} with {@link KeyStoreConfiguration} applied. + * @since 2.0 + */ + public SslConfiguration withKeyStore(KeyStoreConfiguration configuration) { + return new SslConfiguration(configuration, this.trustStoreConfiguration); + } + /** * @return the {@link java.security.KeyStore key store} resource or {@literal null} if * not configured. */ - @Nullable public Resource getTrustStore() { return trustStoreConfiguration.getResource(); } @@ -271,13 +292,27 @@ public class SslConfiguration { } /** - * @return the key store configuration. + * @return the trust store configuration. * @since 1.1 */ public KeyStoreConfiguration getTrustStoreConfiguration() { return trustStoreConfiguration; } + /** + * Create a new {@link SslConfiguration} with {@link KeyStoreConfiguration trust store + * configuration} applied retaining the {@link #getKeyStoreConfiguration()} key store} + * configuration. + * + * @param configuration must not be {@literal null}. + * @return a new {@link SslConfiguration} with {@link KeyStoreConfiguration trust + * store configuration} applied. + * @since 2.0 + */ + public SslConfiguration withTrustStore(KeyStoreConfiguration configuration) { + return new SslConfiguration(this.keyStoreConfiguration, configuration); + } + @Nullable private static String stringOrNull(@Nullable char[] storePassword) { return storePassword != null ? new String(storePassword) : null; @@ -295,13 +330,12 @@ public class SslConfiguration { */ public static class KeyStoreConfiguration { - public static final KeyStoreConfiguration EMPTY = new KeyStoreConfiguration(null, - null, null); + private static final KeyStoreConfiguration UNCONFIGURED = new KeyStoreConfiguration( + AbsentResource.INSTANCE, new char[0], DEFAULT_KEYSTORE_TYPE); /** - * Store that holds certificates, private keys, …. + * Store that holds certificates, private keys. */ - @Nullable private final Resource resource; /** @@ -313,14 +347,18 @@ public class SslConfiguration { /** * Key store/trust store type. */ - @Nullable private final String storeType; /** * Create a new {@link KeyStoreConfiguration}. */ - public KeyStoreConfiguration(@Nullable Resource resource, - @Nullable char[] storePassword, @Nullable String storeType) { + public KeyStoreConfiguration(Resource resource, @Nullable char[] storePassword, + String storeType) { + + Assert.notNull(resource, "Resource must not be null"); + Assert.isTrue(resource instanceof AbsentResource || resource.exists(), + () -> String.format("Resource %s does not exist", resource)); + Assert.notNull(storeType, "Keystore type must not be null"); this.resource = resource; this.storeType = storeType; @@ -333,18 +371,62 @@ public class SslConfiguration { } } + /** + * Create a new {@link KeyStoreConfiguration} given {@link Resource}. + * + * @param resource resource referencing the key store, must not be {@literal null} + * . + * @return the {@link KeyStoreConfiguration} for {@code resource}. + * @since 2.0 + */ + public static KeyStoreConfiguration of(Resource resource) { + return new KeyStoreConfiguration(resource, new char[0], DEFAULT_KEYSTORE_TYPE); + } + + /** + * Create a new {@link KeyStoreConfiguration} given {@link Resource} and + * {@code storePassword} using the default keystore type. + * + * @param resource resource referencing the key store, must not be {@literal null} + * . + * @param storePassword key store password, must not be {@literal null}. + * @return the {@link KeyStoreConfiguration} for {@code resource}. + * @since 2.0 + */ + public static KeyStoreConfiguration of(Resource resource, char[] storePassword) { + return new KeyStoreConfiguration(resource, storePassword, + DEFAULT_KEYSTORE_TYPE); + } + + /** + * Create an unconfigured, empty {@link KeyStoreConfiguration}. + * + * @return unconfigured, empty {@link KeyStoreConfiguration}. + * @since 2.0 + */ + public static KeyStoreConfiguration unconfigured() { + return UNCONFIGURED; + } + + /** + * @return {@literal true} if the resource is present. + * @since 2.0 + */ + public boolean isPresent() { + return !(resource instanceof AbsentResource); + } + /** * @return the {@link java.security.KeyStore key store} resource or * {@literal null} if not configured. */ - @Nullable public Resource getResource() { return resource; } /** - * @return the key store/trust store password or {@literal null} if not - * configured. + * @return the key store/trust store password. Empty {@code char} array if not + * set. */ @Nullable public char[] getStorePassword() { @@ -352,11 +434,28 @@ public class SslConfiguration { } /** - * @return the trust store type or {@literal null} if not configured. + * @return the trust store type. */ - @Nullable public String getStoreType() { return storeType; } } + + static class AbsentResource extends AbstractResource { + + static final AbsentResource INSTANCE = new AbsentResource(); + + private AbsentResource() { + } + + @Override + public String getDescription() { + return getClass().getSimpleName(); + } + + @Override + public InputStream getInputStream() throws IOException { + throw new UnsupportedOperationException("Empty resource"); + } + } } diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationIntegrationTestBase.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationIntegrationTestBase.java index 8d8f844f..ecb322f8 100644 --- a/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationIntegrationTestBase.java +++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationIntegrationTestBase.java @@ -64,8 +64,8 @@ public abstract class ClientCertificateAuthenticationIntegrationTestBase extends SslConfiguration original = createSslConfiguration(); - return new SslConfiguration(new KeyStoreConfiguration(new FileSystemResource( - new File(findWorkDir(), "client-cert.jks")), "changeit".toCharArray(), - null), original.getTrustStoreConfiguration()); + return new SslConfiguration(KeyStoreConfiguration.of(new FileSystemResource( + new File(findWorkDir(), "client-cert.jks")), "changeit".toCharArray()), + original.getTrustStoreConfiguration()); } } diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java index eef1db6b..53b81b07 100644 --- a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java @@ -27,7 +27,6 @@ import org.springframework.context.annotation.Import; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.UrlResource; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.vault.authentication.ClientAuthentication; @@ -77,7 +76,7 @@ public class EnvironmentVaultConfigurationUnitTests { public void shouldConfigureSsl() { Map map = new HashMap(); - map.put("vault.ssl.key-store", "http://foo.bar"); + map.put("vault.ssl.key-store", "classpath:certificate.json"); map.put("vault.ssl.trust-store", "classpath:certificate.json"); MapPropertySource propertySource = new MapPropertySource("shouldConfigureSsl", @@ -86,14 +85,14 @@ public class EnvironmentVaultConfigurationUnitTests { SslConfiguration sslConfiguration = configuration.sslConfiguration(); - assertThat(sslConfiguration.getKeyStore()).isInstanceOf(UrlResource.class); + assertThat(sslConfiguration.getKeyStore()).isInstanceOf(ClassPathResource.class); assertThat(sslConfiguration.getKeyStorePassword()) .isEqualTo("key store password"); assertThat(sslConfiguration.getTrustStore()) .isInstanceOf(ClassPathResource.class); - assertThat(sslConfiguration.getTrustStorePassword()) - .isEqualTo("trust store password"); + assertThat(sslConfiguration.getTrustStorePassword()).isEqualTo( + "trust store password"); configurableEnvironment.getPropertySources().remove(propertySource.getName()); } diff --git a/spring-vault-core/src/test/java/org/springframework/vault/support/SslConfigurationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/support/SslConfigurationUnitTests.java new file mode 100644 index 00000000..36014346 --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/support/SslConfigurationUnitTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.vault.support; + +import org.junit.Test; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.vault.support.SslConfiguration.KeyStoreConfiguration; +import org.springframework.vault.util.Settings; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link SslConfiguration}. + * + * @author Mark Paluch + */ +public class SslConfigurationUnitTests { + + @Test + public void shouldCreateSslConfiguration() { + + SslConfiguration sslConfiguration = Settings.createSslConfiguration(); + + assertThat(sslConfiguration.getKeyStoreConfiguration().isPresent()).isFalse(); + assertThat(sslConfiguration.getTrustStoreConfiguration().isPresent()).isTrue(); + } + + @Test + public void shouldCreateEmptySslConfiguration() { + + SslConfiguration sslConfiguration = SslConfiguration.unconfigured(); + + assertThat(sslConfiguration.getKeyStoreConfiguration().isPresent()).isFalse(); + assertThat(sslConfiguration.getTrustStoreConfiguration().isPresent()).isFalse(); + } + + @Test + public void shouldCreateConfiguration() { + + KeyStoreConfiguration keystore = KeyStoreConfiguration.of(new ClassPathResource( + "certificate.json")); + SslConfiguration ksConfig = SslConfiguration.unconfigured() + .withKeyStore(keystore); + + assertThat(ksConfig.getKeyStoreConfiguration()).isSameAs(keystore); + assertThat(ksConfig.getTrustStoreConfiguration().isPresent()).isFalse(); + + SslConfiguration tsConfig = SslConfiguration.unconfigured().withTrustStore( + keystore); + + assertThat(tsConfig.getTrustStoreConfiguration()).isSameAs(keystore); + assertThat(tsConfig.getKeyStoreConfiguration().isPresent()).isFalse(); + } +}