Introduce factory methods for SslConfiguration and KeyStoreConfiguration to improve null handling.

See gh-112.
This commit is contained in:
Mark Paluch
2017-07-14 22:07:44 +02:00
parent 55eab1b6b9
commit 14bbb44199
8 changed files with 251 additions and 67 deletions

View File

@@ -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();
}
/**

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

@@ -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<String, Object> map = new HashMap<String, Object>();
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());
}

View File

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