Allow configuration of PropertySourceLocator behavior.
We now support configuration of PropertySourceLocator behavior of generic and discovered secret backends. We introduced VaultConfigurer as strategy interface to be implemented by customizer beans in the bootstrap context. VaultConfigurer allows configuration of secret backends via SecretBackendConfigurer. Motivation: Customization was only possible by implementing an own PropertySourceLocator by extending VaultPropertySourceLocatorSupport and implementing doCreatePropertySources. Both is non-trivial and does not allow reuse of existing functionality. See gh-116.
This commit is contained in:
@@ -750,6 +750,45 @@ spring.cloud.vault:
|
||||
|
||||
See also: https://www.vaultproject.io/docs/secrets/postgresql/index.html[Vault Documentation: Setting up PostgreSQL with Vault]
|
||||
|
||||
[[vault.config.backends.configurer]]
|
||||
== Configure `PropertySourceLocator` behavior
|
||||
|
||||
Spring Cloud Vault uses property-based configuration to create ``PropertySource``s
|
||||
for generic and discovered secret backends.
|
||||
|
||||
Discovered backends provide `VaultSecretBackendDescriptor` beans to describe the configuration
|
||||
state to use secret backend as `PropertySource`. A `SecretBackendMetadataFactory` is required
|
||||
to create a `SecretBackendMetadata` object which contains path, name and property transformation
|
||||
configuration.
|
||||
|
||||
`SecretBackendMetadata` is used to back a particular `PropertySource`.
|
||||
|
||||
You can register an arbitrary number of beans implementing `VaultConfigurer` for customization.
|
||||
Default generic and discovered backend registration is disabled if Spring Cloud Vault discovers
|
||||
at least one `VaultConfigurer` bean. You can however enable default registration with
|
||||
`SecretBackendConfigurer.registerDefaultGenericSecretBackends()` and `SecretBackendConfigurer.registerDefaultDiscoveredSecretBackends()`.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public class CustomizationBean implements VaultConfigurer {
|
||||
|
||||
@Override
|
||||
public void addSecretBackends(SecretBackendConfigurer configurer) {
|
||||
|
||||
configurer.add("secret/my-application");
|
||||
|
||||
configurer.registerDefaultGenericSecretBackends(false);
|
||||
configurer.registerDefaultDiscoveredSecretBackends(true);
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: All customization is required to happen in the bootstrap context. Add your configuration
|
||||
classes to `META-INF/spring.factories` at `org.springframework.cloud.bootstrap.BootstrapConfiguration`
|
||||
in your application.
|
||||
|
||||
[[vault.config.fail-fast]]
|
||||
== Vault Client Fail Fast
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.cloud.vault.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.core.util.PropertyTransformer;
|
||||
import org.springframework.vault.core.util.PropertyTransformers;
|
||||
|
||||
/**
|
||||
* Default {@link SecretBackendConfigurer} implementation that exposes its configuration
|
||||
* through {@link PropertySourceLocatorConfiguration}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class DefaultSecretBackendConfigurer
|
||||
implements SecretBackendConfigurer, PropertySourceLocatorConfiguration {
|
||||
|
||||
private final Map<String, SecretBackendMetadata> secretBackends = new LinkedHashMap<>();
|
||||
|
||||
private boolean registerDefaultGenericSecretBackends = false;
|
||||
|
||||
private boolean registerDefaultDiscoveredSecretBackends = false;
|
||||
|
||||
@Override
|
||||
public SecretBackendConfigurer add(String path) {
|
||||
|
||||
Assert.hasLength(path, "Path must not be empty");
|
||||
|
||||
return add(path, PropertyTransformers.noop());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretBackendConfigurer add(String path,
|
||||
PropertyTransformer propertyTransformer) {
|
||||
|
||||
Assert.hasLength(path, "Path must not be empty");
|
||||
Assert.notNull(propertyTransformer, "PropertyTransformer must not be null");
|
||||
|
||||
return add(new SimpleSecretBackendMetadata(path, propertyTransformer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretBackendConfigurer add(SecretBackendMetadata metadata) {
|
||||
|
||||
Assert.notNull(metadata, "SecretBackendMetadata must not be null");
|
||||
|
||||
secretBackends.put(metadata.getPath(), metadata);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretBackendConfigurer registerDefaultGenericSecretBackends(
|
||||
boolean registerDefault) {
|
||||
|
||||
this.registerDefaultGenericSecretBackends = registerDefault;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretBackendConfigurer registerDefaultDiscoveredSecretBackends(
|
||||
boolean registerDefault) {
|
||||
|
||||
this.registerDefaultDiscoveredSecretBackends = registerDefault;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isRegisterDefaultGenericSecretBackends() {
|
||||
return registerDefaultGenericSecretBackends;
|
||||
}
|
||||
|
||||
public boolean isRegisterDefaultDiscoveredSecretBackends() {
|
||||
return registerDefaultDiscoveredSecretBackends;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SecretBackendMetadata> getSecretBackends() {
|
||||
return new ArrayList<>(secretBackends.values());
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class SimpleSecretBackendMetadata implements SecretBackendMetadata {
|
||||
|
||||
private final String path;
|
||||
|
||||
private final PropertyTransformer propertyTransformer;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("Context backend: %s", path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyTransformer getPropertyTransformer() {
|
||||
return propertyTransformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
return Collections.singletonMap("path", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,36 +16,29 @@
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.core.util.PropertyTransformer;
|
||||
import org.springframework.vault.core.util.PropertyTransformers;
|
||||
|
||||
/**
|
||||
* {@link SecretBackendMetadata} for the {@code generic} secret backend.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class GenericSecretBackendMetadata implements SecretBackendMetadata {
|
||||
public class GenericSecretBackendMetadata extends SecretBackendMetadataSupport
|
||||
implements SecretBackendMetadata {
|
||||
|
||||
private final String secretBackendPath;
|
||||
private final String path;
|
||||
|
||||
private final String key;
|
||||
private GenericSecretBackendMetadata(String path) {
|
||||
|
||||
private GenericSecretBackendMetadata(String secretBackendPath, String key) {
|
||||
Assert.hasText(path, "Secret backend path must not be empty");
|
||||
|
||||
Assert.hasText(secretBackendPath, "Secret backend path must not be empty");
|
||||
Assert.hasText(key, "Key must not be empty");
|
||||
|
||||
this.key = key;
|
||||
this.secretBackendPath = secretBackendPath;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,33 +52,30 @@ class GenericSecretBackendMetadata implements SecretBackendMetadata {
|
||||
* @return the {@link SecretBackendMetadata}
|
||||
*/
|
||||
public static SecretBackendMetadata create(String secretBackendPath, String key) {
|
||||
return new GenericSecretBackendMetadata(secretBackendPath, key);
|
||||
|
||||
Assert.hasText(secretBackendPath,
|
||||
"Secret backend path must not be null or empty");
|
||||
Assert.hasText(key, "Key must not be null or empty");
|
||||
|
||||
return create(String.format("%s/%s", secretBackendPath, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link SecretBackendMetadata} for the {@code generic} secret backend given
|
||||
* a {@code path}.
|
||||
*
|
||||
* @param path the relative path of the secret. slashes, must not be empty or
|
||||
* {@literal null}.
|
||||
* @return the {@link SecretBackendMetadata}
|
||||
* @since 1.1
|
||||
*/
|
||||
public static SecretBackendMetadata create(String path) {
|
||||
return new GenericSecretBackendMetadata(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return String.format("%s/%s", secretBackendPath, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyTransformer getPropertyTransformer() {
|
||||
return PropertyTransformers.noop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
|
||||
Map<String, String> variables = new HashMap<>();
|
||||
|
||||
variables.put("backend", secretBackendPath);
|
||||
variables.put("key", key);
|
||||
|
||||
return variables;
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,34 +83,51 @@ class GenericSecretBackendMetadata implements SecretBackendMetadata {
|
||||
* Application name and profiles support multiple (comma-separated) values.
|
||||
*
|
||||
* @param genericBackendProperties
|
||||
* @param environment
|
||||
* @return
|
||||
* @param profiles active application profiles.
|
||||
* @return list of context paths.
|
||||
*/
|
||||
public static List<String> buildContexts(
|
||||
VaultGenericBackendProperties genericBackendProperties,
|
||||
Environment environment) {
|
||||
List<String> profiles) {
|
||||
|
||||
String appName = genericBackendProperties.getApplicationName();
|
||||
List<String> profiles = Arrays.asList(environment.getActiveProfiles());
|
||||
List<String> contexts = new ArrayList<>();
|
||||
Set<String> contexts = new LinkedHashSet<>();
|
||||
|
||||
String defaultContext = genericBackendProperties.getDefaultContext();
|
||||
addContext(contexts, defaultContext, profiles, genericBackendProperties);
|
||||
contexts.addAll(buildContexts(defaultContext, profiles,
|
||||
genericBackendProperties.getProfileSeparator()));
|
||||
|
||||
for (String applicationName : StringUtils.commaDelimitedListToSet(appName)) {
|
||||
addContext(contexts, applicationName, profiles, genericBackendProperties);
|
||||
contexts.addAll(buildContexts(applicationName, profiles,
|
||||
genericBackendProperties.getProfileSeparator()));
|
||||
}
|
||||
|
||||
Collections.reverse(contexts);
|
||||
return contexts;
|
||||
List<String> result = new ArrayList<>(contexts);
|
||||
|
||||
Collections.reverse(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void addContext(List<String> contexts, String applicationName,
|
||||
List<String> profiles,
|
||||
VaultGenericBackendProperties genericBackendProperties) {
|
||||
/**
|
||||
* Create a list of context names from a combination of application name and
|
||||
* application name with profile name. Using an empty application name will return an
|
||||
* empty list.
|
||||
*
|
||||
* @param applicationName the application name. May be empty.
|
||||
* @param profiles active application profiles.
|
||||
* @param profileSeparator profile separator character between application name and
|
||||
* profile name.
|
||||
* @return list of context names.
|
||||
* @since 1.1
|
||||
*/
|
||||
public static List<String> buildContexts(String applicationName,
|
||||
List<String> profiles, String profileSeparator) {
|
||||
|
||||
List<String> contexts = new ArrayList<>();
|
||||
|
||||
if (!StringUtils.hasText(applicationName)) {
|
||||
return;
|
||||
return contexts;
|
||||
}
|
||||
|
||||
if (!contexts.contains(applicationName)) {
|
||||
@@ -133,12 +140,13 @@ class GenericSecretBackendMetadata implements SecretBackendMetadata {
|
||||
continue;
|
||||
}
|
||||
|
||||
String contextName = applicationName
|
||||
+ genericBackendProperties.getProfileSeparator() + profile.trim();
|
||||
String contextName = applicationName + profileSeparator + profile.trim();
|
||||
|
||||
if (!contexts.contains(contextName)) {
|
||||
contexts.add(contextName);
|
||||
}
|
||||
}
|
||||
|
||||
return contexts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
@@ -30,8 +28,6 @@ import org.springframework.vault.core.lease.SecretLeaseContainer;
|
||||
import org.springframework.vault.core.lease.domain.RequestedSecret;
|
||||
import org.springframework.vault.core.lease.event.LeaseErrorListener;
|
||||
import org.springframework.vault.core.lease.event.SecretLeaseEvent;
|
||||
import org.springframework.web.util.DefaultUriTemplateHandler;
|
||||
import org.springframework.web.util.UriTemplateHandler;
|
||||
|
||||
/**
|
||||
* Extension to {@link LeasingVaultPropertySourceLocator} that creates
|
||||
@@ -44,25 +40,23 @@ import org.springframework.web.util.UriTemplateHandler;
|
||||
class LeasingVaultPropertySourceLocator extends VaultPropertySourceLocatorSupport
|
||||
implements PriorityOrdered {
|
||||
|
||||
private static final UriTemplateHandler TEMPLATE_HANDLER = new DefaultUriTemplateHandler();
|
||||
|
||||
private final SecretLeaseContainer secretLeaseContainer;
|
||||
|
||||
private final VaultProperties properties;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LeasingVaultPropertySourceLocator}.
|
||||
*
|
||||
* @param properties must not be {@literal null}.
|
||||
* @param genericBackendProperties must not be {@literal null}.
|
||||
* @param backendAccessors must not be {@literal null}.
|
||||
* @param propertySourceLocatorConfiguration must not be {@literal null}.
|
||||
* @param secretLeaseContainer must not be {@literal null}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public LeasingVaultPropertySourceLocator(VaultProperties properties,
|
||||
VaultGenericBackendProperties genericBackendProperties,
|
||||
Collection<SecretBackendMetadata> backendAccessors,
|
||||
PropertySourceLocatorConfiguration propertySourceLocatorConfiguration,
|
||||
SecretLeaseContainer secretLeaseContainer) {
|
||||
|
||||
super("vault", genericBackendProperties, backendAccessors);
|
||||
super("vault", propertySourceLocatorConfiguration);
|
||||
|
||||
Assert.notNull(secretLeaseContainer, "SecretLeaseContainer must not be null");
|
||||
Assert.notNull(properties, "VaultProperties must not be null");
|
||||
@@ -86,9 +80,7 @@ class LeasingVaultPropertySourceLocator extends VaultPropertySourceLocatorSuppor
|
||||
protected PropertySource<?> createVaultPropertySource(
|
||||
SecretBackendMetadata accessor) {
|
||||
|
||||
URI expand = TEMPLATE_HANDLER.expand("{backend}/{key}", accessor.getVariables());
|
||||
|
||||
final RequestedSecret secret = RequestedSecret.renewable(expand.getPath());
|
||||
RequestedSecret secret = RequestedSecret.renewable(accessor.getPath());
|
||||
|
||||
if (properties.isFailFast()) {
|
||||
return createVaultPropertySourceFailFast(secret, accessor);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.cloud.vault.config;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Configuration for a Vault
|
||||
* {@link org.springframework.cloud.bootstrap.config.PropertySourceLocator}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface PropertySourceLocatorConfiguration {
|
||||
|
||||
/**
|
||||
* Return a {@link Collection} of {@link SecretBackendMetadata} to be instantiated as
|
||||
* {@link org.springframework.core.env.PropertySource}.
|
||||
*
|
||||
* @return a {@link Collection} of {@link SecretBackendMetadata}.
|
||||
*/
|
||||
Collection<SecretBackendMetadata> getSecretBackends();
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.cloud.vault.config;
|
||||
|
||||
import org.springframework.vault.core.util.PropertyTransformer;
|
||||
|
||||
/**
|
||||
* Helps to configure {@link SecretBackendMetadata secret backends} with support for
|
||||
* {@link PropertyTransformer property transformers}.
|
||||
*
|
||||
* <p>
|
||||
* Assists configuration with a fluent style. This configurer allows configuration via
|
||||
* context paths and direct registration of {@link SecretBackendMetadata}.
|
||||
* <p>
|
||||
* Use {@link #registerDefaultGenericSecretBackends(boolean)} to register default generic
|
||||
* secret backend property sources and
|
||||
* {@link #registerDefaultDiscoveredSecretBackends(boolean)} to register additional secret
|
||||
* backend property sources such as MySQL and RabbitMQ.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
* @see PropertyTransformer
|
||||
* @see SecretBackendMetadata
|
||||
*/
|
||||
public interface SecretBackendConfigurer {
|
||||
|
||||
/**
|
||||
* Add a {@link SecretBackendMetadata} given its {@code path}.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @return {@code this} {@link SecretBackendConfigurer}.
|
||||
*/
|
||||
SecretBackendConfigurer add(String path);
|
||||
|
||||
/**
|
||||
* Add a {@link SecretBackendMetadata} given its {@code path} and
|
||||
* {@link PropertyTransformer}.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @param propertyTransformer must not be {@literal null}.
|
||||
* @return {@code this} {@link SecretBackendConfigurer}.
|
||||
*/
|
||||
SecretBackendConfigurer add(String path, PropertyTransformer propertyTransformer);
|
||||
|
||||
/**
|
||||
* Add a {@link SecretBackendMetadata}.
|
||||
*
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @return {@code this} {@link SecretBackendConfigurer}.
|
||||
*/
|
||||
SecretBackendConfigurer add(SecretBackendMetadata metadata);
|
||||
|
||||
/**
|
||||
* Register default generic secret backend property sources.
|
||||
*
|
||||
* @param registerDefault {@literal true} to enable default generic secret backend
|
||||
* registration.
|
||||
* @return {@code this} {@link SecretBackendConfigurer}.
|
||||
*/
|
||||
SecretBackendConfigurer registerDefaultGenericSecretBackends(boolean registerDefault);
|
||||
|
||||
/**
|
||||
* Register default discovered secret backend property sources from
|
||||
* {@link SecretBackendMetadata} via {@link VaultSecretBackendDescriptor} beans.
|
||||
*
|
||||
* @param registerDefault {@literal true} to enable default discovered secret backend
|
||||
* registration via {@link VaultSecretBackendDescriptor} beans.
|
||||
* @return {@code this} {@link SecretBackendConfigurer}.
|
||||
*/
|
||||
SecretBackendConfigurer registerDefaultDiscoveredSecretBackends(
|
||||
boolean registerDefault);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.cloud.vault.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.vault.core.util.PropertyTransformer;
|
||||
import org.springframework.vault.core.util.PropertyTransformers;
|
||||
|
||||
/**
|
||||
* Support class for {@link SecretBackendMetadata} implementations. Implementing classes
|
||||
* are required to implement {@link #getPath()} to derive name and variables from the
|
||||
* path.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class SecretBackendMetadataSupport implements SecretBackendMetadata {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyTransformer getPropertyTransformer() {
|
||||
return PropertyTransformers.noop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
return Collections.singletonMap("path", getPath());
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -31,6 +33,8 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
@@ -69,6 +73,8 @@ import org.springframework.vault.support.SslConfiguration;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import static org.springframework.cloud.vault.config.GenericSecretBackendMetadata.create;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Vault support.
|
||||
*
|
||||
@@ -79,6 +85,7 @@ import org.springframework.web.client.RestOperations;
|
||||
@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties({ VaultProperties.class,
|
||||
VaultGenericBackendProperties.class })
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 10)
|
||||
public class VaultBootstrapConfiguration implements InitializingBean {
|
||||
|
||||
private final ConfigurableApplicationContext applicationContext;
|
||||
@@ -134,11 +141,12 @@ public class VaultBootstrapConfiguration implements InitializingBean {
|
||||
VaultGenericBackendProperties vaultGenericBackendProperties,
|
||||
ObjectFactory<SecretLeaseContainer> secretLeaseContainerObjectFactory) {
|
||||
|
||||
Collection<SecretBackendMetadata> backendAccessors = SecretBackendFactories
|
||||
.createSecretBackendMetadata(vaultSecretBackendDescriptors, factories);
|
||||
VaultConfigTemplate vaultConfigTemplate = new VaultConfigTemplate(operations,
|
||||
vaultProperties);
|
||||
|
||||
PropertySourceLocatorConfiguration propertySourceLocatorConfiguration = getPropertySourceConfiguration(
|
||||
vaultGenericBackendProperties);
|
||||
|
||||
if (vaultProperties.getConfig().getLifecycle().isEnabled()) {
|
||||
|
||||
// This is to destroy bootstrap resources
|
||||
@@ -150,12 +158,65 @@ public class VaultBootstrapConfiguration implements InitializingBean {
|
||||
secretLeaseContainer.start();
|
||||
|
||||
return new LeasingVaultPropertySourceLocator(vaultProperties,
|
||||
vaultGenericBackendProperties, backendAccessors,
|
||||
secretLeaseContainer);
|
||||
propertySourceLocatorConfiguration, secretLeaseContainer);
|
||||
}
|
||||
|
||||
return new VaultPropertySourceLocator(vaultConfigTemplate, vaultProperties,
|
||||
vaultGenericBackendProperties, backendAccessors);
|
||||
propertySourceLocatorConfiguration);
|
||||
}
|
||||
|
||||
private PropertySourceLocatorConfiguration getPropertySourceConfiguration(
|
||||
VaultGenericBackendProperties vaultGenericBackendProperties) {
|
||||
|
||||
Collection<VaultConfigurer> configurers = applicationContext
|
||||
.getBeansOfType(VaultConfigurer.class).values();
|
||||
|
||||
DefaultSecretBackendConfigurer secretBackendConfigurer = new DefaultSecretBackendConfigurer();
|
||||
|
||||
if (configurers.isEmpty()) {
|
||||
secretBackendConfigurer.registerDefaultGenericSecretBackends(true)
|
||||
.registerDefaultDiscoveredSecretBackends(true);
|
||||
}
|
||||
else {
|
||||
|
||||
for (VaultConfigurer vaultConfigurer : configurers) {
|
||||
vaultConfigurer.addSecretBackends(secretBackendConfigurer);
|
||||
}
|
||||
}
|
||||
|
||||
if (secretBackendConfigurer.isRegisterDefaultGenericSecretBackends()) {
|
||||
|
||||
if (vaultGenericBackendProperties.isEnabled()) {
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata
|
||||
.buildContexts(vaultGenericBackendProperties, Arrays.asList(
|
||||
applicationContext.getEnvironment().getActiveProfiles()));
|
||||
|
||||
for (String context : contexts) {
|
||||
secretBackendConfigurer.add(
|
||||
create(vaultGenericBackendProperties.getBackend(), context));
|
||||
}
|
||||
}
|
||||
|
||||
Collection<SecretBackendMetadata> backendAccessors = SecretBackendFactories
|
||||
.createSecretBackendMetadata(vaultSecretBackendDescriptors,
|
||||
factories);
|
||||
for (SecretBackendMetadata metadata : backendAccessors) {
|
||||
secretBackendConfigurer.add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
if (secretBackendConfigurer.isRegisterDefaultDiscoveredSecretBackends()) {
|
||||
|
||||
Collection<SecretBackendMetadata> backendAccessors = SecretBackendFactories
|
||||
.createSecretBackendMetadata(vaultSecretBackendDescriptors,
|
||||
factories);
|
||||
for (SecretBackendMetadata metadata : backendAccessors) {
|
||||
secretBackendConfigurer.add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
return secretBackendConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.cloud.vault.config;
|
||||
|
||||
/**
|
||||
* Defines callback methods to customize the configuration for Spring Cloud Vault
|
||||
* applications.
|
||||
*
|
||||
* <p>
|
||||
* Configuration classes may implement this interface to be called back and given a chance
|
||||
* to customize the default configuration. Consider implementing this interface and
|
||||
* overriding the relevant methods for your needs.
|
||||
*
|
||||
* <p>
|
||||
* Registered bean instances of {@link VaultConfigurer} disable default secret backend
|
||||
* registration for the generic and integrative (other discovered
|
||||
* {@link SecretBackendMetadata}) backends. See
|
||||
* {@link SecretBackendConfigurer#registerDefaultGenericSecretBackends(boolean)} and
|
||||
* {@link SecretBackendConfigurer#registerDefaultDiscoveredSecretBackends(boolean)} for
|
||||
* more details.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
* @see SecretBackendConfigurer
|
||||
*/
|
||||
public interface VaultConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the secret backends that are instantiated as
|
||||
* {@link org.springframework.core.env.PropertySource property sources}.
|
||||
*
|
||||
* @param configurer the {@link SecretBackendConfigurer} to configure secret backends,
|
||||
* must not be {@literal null}.
|
||||
*/
|
||||
void addSecretBackends(SecretBackendConfigurer configurer);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
@@ -42,15 +40,14 @@ class VaultPropertySourceLocator extends VaultPropertySourceLocatorSupport
|
||||
*
|
||||
* @param operations must not be {@literal null}.
|
||||
* @param properties must not be {@literal null}.
|
||||
* @param genericBackendProperties must not be {@literal null}.
|
||||
* @param backendAccessors must not be {@literal null}.
|
||||
* @param propertySourceLocatorConfiguration must not be {@literal null}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public VaultPropertySourceLocator(VaultConfigOperations operations,
|
||||
VaultProperties properties,
|
||||
VaultGenericBackendProperties genericBackendProperties,
|
||||
Collection<SecretBackendMetadata> backendAccessors) {
|
||||
PropertySourceLocatorConfiguration propertySourceLocatorConfiguration) {
|
||||
|
||||
super("vault", genericBackendProperties, backendAccessors);
|
||||
super("vault", propertySourceLocatorConfiguration);
|
||||
|
||||
Assert.notNull(operations, "VaultConfigOperations must not be null");
|
||||
Assert.notNull(properties, "VaultProperties must not be null");
|
||||
|
||||
@@ -16,15 +16,20 @@
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.vault.config.GenericSecretBackendMetadata.create;
|
||||
|
||||
@@ -38,9 +43,7 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
|
||||
private final String propertySourceName;
|
||||
|
||||
private final VaultGenericBackendProperties genericBackendProperties;
|
||||
|
||||
private final Collection<SecretBackendMetadata> backendAccessors;
|
||||
private final PropertySourceLocatorConfiguration propertySourceLocatorConfiguration;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultPropertySourceLocatorSupport}.
|
||||
@@ -53,19 +56,63 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
VaultGenericBackendProperties genericBackendProperties,
|
||||
Collection<SecretBackendMetadata> backendAccessors) {
|
||||
|
||||
this(propertySourceName,
|
||||
createConfiguration(genericBackendProperties, backendAccessors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultPropertySourceLocatorSupport} given a
|
||||
* {@link PropertySourceLocatorConfiguration}.
|
||||
*
|
||||
* @param propertySourceName must not be {@literal null} or empty.
|
||||
* @param propertySourceLocatorConfiguration must not be {@literal null}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public VaultPropertySourceLocatorSupport(String propertySourceName,
|
||||
PropertySourceLocatorConfiguration propertySourceLocatorConfiguration) {
|
||||
|
||||
Assert.hasText(propertySourceName, "PropertySource name must not be empty");
|
||||
Assert.notNull(propertySourceLocatorConfiguration,
|
||||
"PropertySourceLocatorConfiguration must not be null");
|
||||
|
||||
this.propertySourceName = propertySourceName;
|
||||
this.propertySourceLocatorConfiguration = propertySourceLocatorConfiguration;
|
||||
}
|
||||
|
||||
static PropertySourceLocatorConfiguration createConfiguration(
|
||||
VaultGenericBackendProperties genericBackendProperties,
|
||||
Collection<SecretBackendMetadata> backendAccessors) {
|
||||
|
||||
Assert.notNull(genericBackendProperties,
|
||||
"VaultGenericBackendProperties must not be null");
|
||||
Assert.notNull(backendAccessors, "BackendAccessors must not be null");
|
||||
|
||||
GenericPropertySourceLocatorConfiguration generic = new GenericPropertySourceLocatorConfiguration(
|
||||
genericBackendProperties);
|
||||
|
||||
WrappedPropertySourceLocatorConfiguration backends = new WrappedPropertySourceLocatorConfiguration(
|
||||
new ArrayList<>(backendAccessors));
|
||||
|
||||
return new CompositePropertySourceConfiguration(generic, backends);
|
||||
}
|
||||
|
||||
static PropertySourceLocatorConfiguration createConfiguration(
|
||||
VaultGenericBackendProperties genericBackendProperties) {
|
||||
|
||||
Assert.notNull(genericBackendProperties,
|
||||
"VaultGenericBackendProperties must not be null");
|
||||
|
||||
this.propertySourceName = propertySourceName;
|
||||
this.backendAccessors = backendAccessors;
|
||||
this.genericBackendProperties = genericBackendProperties;
|
||||
return new GenericPropertySourceLocatorConfiguration(genericBackendProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertySource<?> locate(Environment environment) {
|
||||
|
||||
if (propertySourceLocatorConfiguration instanceof EnvironmentAware) {
|
||||
((EnvironmentAware) propertySourceLocatorConfiguration)
|
||||
.setEnvironment(environment);
|
||||
}
|
||||
|
||||
CompositePropertySource propertySource = createCompositePropertySource(
|
||||
environment);
|
||||
initialize(propertySource);
|
||||
@@ -109,13 +156,16 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
*/
|
||||
protected List<PropertySource<?>> doCreatePropertySources(Environment environment) {
|
||||
|
||||
Collection<SecretBackendMetadata> secretBackends = propertySourceLocatorConfiguration
|
||||
.getSecretBackends();
|
||||
List<SecretBackendMetadata> sorted = new ArrayList<>(secretBackends);
|
||||
List<PropertySource<?>> propertySources = new ArrayList<>();
|
||||
|
||||
if (genericBackendProperties.isEnabled()) {
|
||||
propertySources.addAll(doCreateGenericPropertySources(environment));
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(sorted);
|
||||
|
||||
for (SecretBackendMetadata backendAccessor : backendAccessors) {
|
||||
propertySources.addAll(doCreateGenericPropertySources(environment));
|
||||
|
||||
for (SecretBackendMetadata backendAccessor : sorted) {
|
||||
|
||||
PropertySource<?> vaultPropertySource = createVaultPropertySource(
|
||||
backendAccessor);
|
||||
@@ -135,23 +185,7 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
*/
|
||||
protected List<PropertySource<?>> doCreateGenericPropertySources(
|
||||
Environment environment) {
|
||||
|
||||
List<PropertySource<?>> propertySources = new ArrayList<>();
|
||||
List<String> contexts = GenericSecretBackendMetadata
|
||||
.buildContexts(genericBackendProperties, environment);
|
||||
|
||||
for (String propertySourceContext : contexts) {
|
||||
|
||||
if (StringUtils.hasText(propertySourceContext)) {
|
||||
|
||||
PropertySource<?> vaultPropertySource = createVaultPropertySource(create(
|
||||
genericBackendProperties.getBackend(), propertySourceContext));
|
||||
|
||||
propertySources.add(vaultPropertySource);
|
||||
}
|
||||
}
|
||||
|
||||
return propertySources;
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,4 +219,89 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
protected abstract PropertySource<?> createVaultPropertySource(
|
||||
SecretBackendMetadata accessor);
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class GenericPropertySourceLocatorConfiguration
|
||||
implements EnvironmentAware, PropertySourceLocatorConfiguration {
|
||||
|
||||
private final VaultGenericBackendProperties genericBackendProperties;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SecretBackendMetadata> getSecretBackends() {
|
||||
|
||||
if (genericBackendProperties.isEnabled()) {
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(
|
||||
genericBackendProperties,
|
||||
Arrays.asList(environment.getActiveProfiles()));
|
||||
|
||||
List<SecretBackendMetadata> result = new ArrayList<>(contexts.size());
|
||||
|
||||
for (String context : contexts) {
|
||||
result.add(create(genericBackendProperties.getBackend(), context));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class WrappedPropertySourceLocatorConfiguration
|
||||
implements PropertySourceLocatorConfiguration {
|
||||
|
||||
private final List<SecretBackendMetadata> metadata;
|
||||
|
||||
@Override
|
||||
public Collection<SecretBackendMetadata> getSecretBackends() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompositePropertySourceConfiguration
|
||||
implements PropertySourceLocatorConfiguration, EnvironmentAware {
|
||||
|
||||
private final List<PropertySourceLocatorConfiguration> configurations;
|
||||
|
||||
public CompositePropertySourceConfiguration(
|
||||
PropertySourceLocatorConfiguration... configurations) {
|
||||
|
||||
List<PropertySourceLocatorConfiguration> copy = new ArrayList<>(
|
||||
Arrays.asList(configurations));
|
||||
|
||||
AnnotationAwareOrderComparator.sortIfNecessary(copy);
|
||||
|
||||
this.configurations = copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SecretBackendMetadata> getSecretBackends() {
|
||||
|
||||
List<SecretBackendMetadata> result = new ArrayList<>();
|
||||
|
||||
for (PropertySourceLocatorConfiguration configuration : configurations) {
|
||||
result.addAll(configuration.getSecretBackends());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
|
||||
for (PropertySourceLocatorConfiguration configuration : configurations) {
|
||||
if (configuration instanceof EnvironmentAware) {
|
||||
((EnvironmentAware) configuration).setEnvironment(environment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -30,14 +30,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public class GenericSecretBackendMetadataUnitTests {
|
||||
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
VaultGenericBackendProperties properties = new VaultGenericBackendProperties();
|
||||
|
||||
@Test
|
||||
public void shouldCreateDefaultContexts() {
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(properties,
|
||||
environment);
|
||||
Collections.<String>emptyList());
|
||||
|
||||
assertThat(contexts).hasSize(1).contains("application");
|
||||
}
|
||||
@@ -48,7 +47,7 @@ public class GenericSecretBackendMetadataUnitTests {
|
||||
properties.setApplicationName("my-app");
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(properties,
|
||||
environment);
|
||||
Collections.<String>emptyList());
|
||||
|
||||
assertThat(contexts).hasSize(2).containsSequence("my-app", "application");
|
||||
}
|
||||
@@ -57,11 +56,9 @@ public class GenericSecretBackendMetadataUnitTests {
|
||||
public void shouldCreateDefaultForAppNameAndDefaultContextWithProfiles() {
|
||||
|
||||
properties.setApplicationName("my-app");
|
||||
environment.addActiveProfile("cloud");
|
||||
environment.addActiveProfile("local");
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(properties,
|
||||
environment);
|
||||
Arrays.asList("cloud", "local"));
|
||||
|
||||
assertThat(contexts).hasSize(6).containsSequence("my-app/local", "my-app/cloud",
|
||||
"my-app", "application/local", "application/cloud", "application");
|
||||
@@ -74,7 +71,7 @@ public class GenericSecretBackendMetadataUnitTests {
|
||||
properties.setDefaultContext("");
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(properties,
|
||||
environment);
|
||||
Collections.<String>emptyList());
|
||||
|
||||
assertThat(contexts).hasSize(1).containsSequence("my-app");
|
||||
}
|
||||
@@ -85,7 +82,7 @@ public class GenericSecretBackendMetadataUnitTests {
|
||||
properties.setApplicationName("foo,bar");
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(properties,
|
||||
environment);
|
||||
Collections.<String>emptyList());
|
||||
|
||||
assertThat(contexts).hasSize(3).containsSequence("bar", "foo", "application");
|
||||
}
|
||||
@@ -93,13 +90,10 @@ public class GenericSecretBackendMetadataUnitTests {
|
||||
@Test
|
||||
public void shouldCreateContextsWithProfile() {
|
||||
|
||||
environment.addActiveProfile("cloud");
|
||||
environment.addActiveProfile("local");
|
||||
|
||||
properties.setApplicationName("foo,bar");
|
||||
|
||||
List<String> contexts = GenericSecretBackendMetadata.buildContexts(properties,
|
||||
environment);
|
||||
Arrays.asList("cloud", "local"));
|
||||
|
||||
assertThat(contexts).hasSize(9).containsSequence("bar/local", "bar/cloud", "bar",
|
||||
"foo/local", "foo/cloud", "foo", "application/local", "application/cloud",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -51,8 +49,9 @@ public class LeasingVaultPropertySourceLocatorUnitTests {
|
||||
public void before() {
|
||||
|
||||
propertySourceLocator = new LeasingVaultPropertySourceLocator(
|
||||
new VaultProperties(), new VaultGenericBackendProperties(),
|
||||
Collections.<SecretBackendMetadata>emptyList(), secretLeaseContainer);
|
||||
new VaultProperties(), VaultPropertySourceLocatorSupport
|
||||
.createConfiguration(new VaultGenericBackendProperties()),
|
||||
secretLeaseContainer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -62,8 +61,9 @@ public class LeasingVaultPropertySourceLocatorUnitTests {
|
||||
vaultProperties.getConfig().setOrder(10);
|
||||
|
||||
propertySourceLocator = new LeasingVaultPropertySourceLocator(vaultProperties,
|
||||
new VaultGenericBackendProperties(),
|
||||
Collections.<SecretBackendMetadata>emptyList(), secretLeaseContainer);
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(
|
||||
new VaultGenericBackendProperties()),
|
||||
secretLeaseContainer);
|
||||
|
||||
assertThat(propertySourceLocator.getOrder()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = { BootstrapConfiguration.class,
|
||||
VaultConfigAppIdCustomMechanismTests.TestApplication.class }, properties = {
|
||||
"spring.cloud.vault.authentication=appid", "use.custom.config=true",
|
||||
"spring.cloud.vault.authentication=appid",
|
||||
"VaultConfigAppIdCustomMechanismTests.custom.config=true",
|
||||
"spring.cloud.vault.applicationName=VaultConfigAppIdCustomMechanismTests" })
|
||||
public class VaultConfigAppIdCustomMechanismTests {
|
||||
|
||||
@@ -119,7 +120,7 @@ public class VaultConfigAppIdCustomMechanismTests {
|
||||
@Configuration
|
||||
public static class BootstrapConfiguration {
|
||||
|
||||
@ConditionalOnProperty("use.custom.config")
|
||||
@ConditionalOnProperty("VaultConfigAppIdCustomMechanismTests.custom.config")
|
||||
@Bean
|
||||
ClientAuthentication clientAuthentication() {
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.cloud.vault.config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.vault.util.VaultRule;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration test using config infrastructure with token authentication.
|
||||
* <p>
|
||||
* In case this test should fail because of SSL make sure you run the test within the
|
||||
* spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is
|
||||
* referenced with {@code ../work/keystore.jks}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = VaultConfigWithVaultConfigurerTests.TestApplication.class, properties = "VaultConfigWithVaultConfigurerTests.custom.config=true")
|
||||
public class VaultConfigWithVaultConfigurerTests {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
|
||||
VaultRule vaultRule = new VaultRule();
|
||||
vaultRule.before();
|
||||
|
||||
VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations();
|
||||
|
||||
vaultOperations.write("secret/VaultConfigWithVaultConfigurerTests",
|
||||
Collections.singletonMap("vault.value", "hello"));
|
||||
|
||||
vaultOperations.write("secret/testVaultApp",
|
||||
Collections.singletonMap("vault.value", "world"));
|
||||
}
|
||||
|
||||
@Value("${vault.value}")
|
||||
String configValue;
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
assertThat(configValue).isEqualTo("hello");
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
public static class TestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigurerBootstrapApplication {
|
||||
|
||||
@ConditionalOnProperty("VaultConfigWithVaultConfigurerTests.custom.config")
|
||||
@Bean
|
||||
VaultConfigurer vaultConfigurer() {
|
||||
|
||||
return new VaultConfigurer() {
|
||||
@Override
|
||||
public void addSecretBackends(SecretBackendConfigurer configurer) {
|
||||
configurer.add("secret/VaultConfigWithVaultConfigurerTests");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,13 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
@@ -53,8 +52,8 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
@Before
|
||||
public void before() {
|
||||
propertySourceLocator = new VaultPropertySourceLocator(operations,
|
||||
new VaultProperties(), new VaultGenericBackendProperties(),
|
||||
Collections.<SecretBackendMetadata>emptyList());
|
||||
new VaultProperties(), VaultPropertySourceLocatorSupport
|
||||
.createConfiguration(new VaultGenericBackendProperties()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -64,8 +63,8 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
vaultProperties.getConfig().setOrder(42);
|
||||
|
||||
propertySourceLocator = new VaultPropertySourceLocator(operations,
|
||||
vaultProperties, new VaultGenericBackendProperties(),
|
||||
Collections.<SecretBackendMetadata>emptyList());
|
||||
vaultProperties, VaultPropertySourceLocatorSupport
|
||||
.createConfiguration(new VaultGenericBackendProperties()));
|
||||
|
||||
assertThat(propertySourceLocator.getOrder()).isEqualTo(42);
|
||||
}
|
||||
@@ -102,11 +101,13 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
|
||||
@Test
|
||||
public void shouldLocatePropertySourcesInVaultApplicationContext() {
|
||||
final VaultGenericBackendProperties backendProperties = new VaultGenericBackendProperties();
|
||||
|
||||
VaultGenericBackendProperties backendProperties = new VaultGenericBackendProperties();
|
||||
backendProperties.setApplicationName("wintermute");
|
||||
|
||||
propertySourceLocator = new VaultPropertySourceLocator(operations,
|
||||
new VaultProperties(), backendProperties,
|
||||
Collections.<SecretBackendMetadata>emptyList());
|
||||
new VaultProperties(),
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(backendProperties));
|
||||
|
||||
when(configurableEnvironment.getActiveProfiles())
|
||||
.thenReturn(new String[] { "vermillion", "periwinkle" });
|
||||
@@ -124,11 +125,13 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
|
||||
@Test
|
||||
public void shouldLocatePropertySourcesInEachPathSpecifiedWhenApplicationNameContainsSeveral() {
|
||||
final VaultGenericBackendProperties backendProperties = new VaultGenericBackendProperties();
|
||||
|
||||
VaultGenericBackendProperties backendProperties = new VaultGenericBackendProperties();
|
||||
backendProperties.setApplicationName("wintermute,straylight,icebreaker/armitage");
|
||||
|
||||
propertySourceLocator = new VaultPropertySourceLocator(operations,
|
||||
new VaultProperties(), backendProperties,
|
||||
Collections.<SecretBackendMetadata>emptyList());
|
||||
new VaultProperties(),
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(backendProperties));
|
||||
|
||||
when(configurableEnvironment.getActiveProfiles())
|
||||
.thenReturn(new String[] { "vermillion", "periwinkle" });
|
||||
@@ -146,4 +149,42 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
"secret/icebreaker/armitage/vermillion",
|
||||
"secret/icebreaker/armitage/periwinkle");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreatePropertySourcesInOrder() {
|
||||
|
||||
DefaultSecretBackendConfigurer configurer = new DefaultSecretBackendConfigurer();
|
||||
configurer.add(new MySecondSecretBackendMetadata());
|
||||
configurer.add(new MyFirstSecretBackendMetadata());
|
||||
|
||||
propertySourceLocator = new VaultPropertySourceLocator(operations,
|
||||
new VaultProperties(), configurer);
|
||||
|
||||
PropertySource<?> propertySource = propertySourceLocator
|
||||
.locate(configurableEnvironment);
|
||||
|
||||
assertThat(propertySource).isInstanceOf(CompositePropertySource.class);
|
||||
|
||||
CompositePropertySource composite = (CompositePropertySource) propertySource;
|
||||
assertThat(composite.getPropertySources()).extracting("name")
|
||||
.containsSequence("foo", "bar");
|
||||
}
|
||||
|
||||
@Order(1)
|
||||
static class MyFirstSecretBackendMetadata extends SecretBackendMetadataSupport {
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
@Order(2)
|
||||
static class MySecondSecretBackendMetadata extends SecretBackendMetadataSupport {
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Bootstrap Configuration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.vault.config.VaultConfigAppIdCustomMechanismTests.BootstrapConfiguration
|
||||
org.springframework.cloud.vault.config.VaultConfigAppIdCustomMechanismTests.BootstrapConfiguration,\
|
||||
org.springframework.cloud.vault.config.VaultConfigWithVaultConfigurerTests.ConfigurerBootstrapApplication
|
||||
|
||||
Reference in New Issue
Block a user