Migrate VaultEnvironmentRepository from RestTemplate to Spring Vault. (#1522)
Migrates the Spring Cloud Config Server support for Vault from using a RestTemplate directly to using Spring Vault and VaultTemplate. These changes should provide exactly the same features with backward-compatible properties-based auto-configuration and Java configuration, while allowing for more features in the future via Spring Vault's extensive support for Vault integration. The old RestTemplate implementation remains as deprecated. The implementation is chosen based on the existence of VaultTemplate. Fixes gh-1474
This commit is contained in:
committed by
Spencer Gibb
parent
f0bc1af547
commit
5e33794332
@@ -16,6 +16,7 @@
|
||||
<description>Spring Cloud Config Dependencies</description>
|
||||
<properties>
|
||||
<jgit.version>5.1.3.201810200350-r</jgit.version>
|
||||
<spring-vault.version>2.2.0.RELEASE</spring-vault.version>
|
||||
<spring-credhub.version>2.0.0.RELEASE</spring-credhub.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
@@ -40,6 +41,11 @@
|
||||
<artifactId>spring-cloud-config-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.vault</groupId>
|
||||
<artifactId>spring-vault-core</artifactId>
|
||||
<version>${spring-vault.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.credhub</groupId>
|
||||
<artifactId>spring-credhub-core</artifactId>
|
||||
|
||||
@@ -158,6 +158,13 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.vault</groupId>
|
||||
<artifactId>spring-vault-core</artifactId>
|
||||
<version>2.2.0.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.credhub</groupId>
|
||||
<artifactId>spring-credhub-core</artifactId>
|
||||
|
||||
@@ -53,6 +53,11 @@
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-rsa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.vault</groupId>
|
||||
<artifactId>spring-vault-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.credhub</groupId>
|
||||
<artifactId>spring-credhub-core</artifactId>
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -70,6 +71,8 @@ import org.springframework.cloud.config.server.environment.SvnKitEnvironmentRepo
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.environment.vault.SpringVaultEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.vault.SpringVaultEnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.support.GoogleCloudSourceSupport;
|
||||
import org.springframework.cloud.config.server.support.TransportConfigCallbackFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -82,6 +85,7 @@ import org.springframework.core.env.Environment;
|
||||
import org.springframework.credhub.core.CredHubOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -98,11 +102,11 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
RedisEnvironmentProperties.class, AwsS3EnvironmentProperties.class })
|
||||
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class,
|
||||
VaultConfiguration.class, VaultRepositoryConfiguration.class,
|
||||
CredhubConfiguration.class, CredhubRepositoryConfiguration.class,
|
||||
SvnRepositoryConfiguration.class, NativeRepositoryConfiguration.class,
|
||||
GitRepositoryConfiguration.class, RedisRepositoryConfiguration.class,
|
||||
GoogleCloudSourceConfiguration.class, AwsS3RepositoryConfiguration.class,
|
||||
DefaultRepositoryConfiguration.class })
|
||||
SpringVaultRepositoryConfiguration.class, CredhubConfiguration.class,
|
||||
CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class,
|
||||
NativeRepositoryConfiguration.class, GitRepositoryConfiguration.class,
|
||||
RedisRepositoryConfiguration.class, GoogleCloudSourceConfiguration.class,
|
||||
AwsS3RepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
|
||||
public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -208,6 +212,8 @@ public class EnvironmentRepositoryConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingClass("org.springframework.vault.core.VaultTemplate")
|
||||
@SuppressWarnings("deprecation")
|
||||
static class VaultFactoryConfig {
|
||||
|
||||
@Bean
|
||||
@@ -223,6 +229,8 @@ public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(HttpClient.class)
|
||||
@ConditionalOnMissingClass("org.springframework.vault.core.VaultTemplate")
|
||||
@SuppressWarnings("deprecation")
|
||||
static class VaultHttpClientConfig {
|
||||
|
||||
@Bean
|
||||
@@ -232,6 +240,20 @@ public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(VaultTemplate.class)
|
||||
static class SpringVaultFactoryConfig {
|
||||
|
||||
@Bean
|
||||
public SpringVaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory(
|
||||
ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
ConfigTokenProvider tokenProvider) {
|
||||
return new SpringVaultEnvironmentRepositoryFactory(request, watch,
|
||||
tokenProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(JdbcTemplate.class)
|
||||
static class JdbcFactoryConfig {
|
||||
@@ -345,7 +367,9 @@ class SvnRepositoryConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingClass("org.springframework.vault.core.VaultTemplate")
|
||||
@Profile("vault")
|
||||
@SuppressWarnings("deprecation")
|
||||
class VaultRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -357,6 +381,20 @@ class VaultRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(VaultTemplate.class)
|
||||
@Profile("vault")
|
||||
class SpringVaultRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public SpringVaultEnvironmentRepository vaultEnvironmentRepository(
|
||||
SpringVaultEnvironmentRepositoryFactory factory,
|
||||
VaultEnvironmentProperties environmentProperties) {
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Profile("credhub")
|
||||
class CredhubRepositoryConfiguration {
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.config.server.environment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.environment.PropertySource;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.config.client.ConfigClientProperties.STATE_HEADER;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Mark Paluch
|
||||
* @author Haroun Pacquee
|
||||
* @author Haytham Mohamed
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public abstract class AbstractVaultEnvironmentRepository
|
||||
implements EnvironmentRepository, Ordered {
|
||||
|
||||
// TODO: move to watchState:String on findOne?
|
||||
protected final ObjectProvider<HttpServletRequest> request;
|
||||
|
||||
protected final EnvironmentWatch watch;
|
||||
|
||||
/**
|
||||
* The key in vault shared by all applications. Defaults to application. Set to empty
|
||||
* to disable.
|
||||
*/
|
||||
protected String defaultKey;
|
||||
|
||||
/**
|
||||
* Vault profile separator. Defaults to comma.
|
||||
*/
|
||||
@NotEmpty
|
||||
protected String profileSeparator;
|
||||
|
||||
protected int order;
|
||||
|
||||
public AbstractVaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request,
|
||||
EnvironmentWatch watch, VaultEnvironmentProperties properties) {
|
||||
this.defaultKey = properties.getDefaultKey();
|
||||
this.profileSeparator = properties.getProfileSeparator();
|
||||
this.order = properties.getOrder();
|
||||
this.request = request;
|
||||
this.watch = watch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment findOne(String application, String profile, String label) {
|
||||
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
|
||||
List<String> scrubbedProfiles = scrubProfiles(profiles);
|
||||
|
||||
List<String> keys = findKeys(application, scrubbedProfiles);
|
||||
|
||||
Environment environment = new Environment(application, profiles, label, null,
|
||||
getWatchState());
|
||||
|
||||
for (String key : keys) {
|
||||
// read raw 'data' key from vault
|
||||
String data = read(key);
|
||||
if (data != null) {
|
||||
// data is in json format of which, yaml is a superset, so parse
|
||||
final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
|
||||
yaml.setResources(new ByteArrayResource(data.getBytes()));
|
||||
Properties properties = yaml.getObject();
|
||||
|
||||
if (!properties.isEmpty()) {
|
||||
environment.add(new PropertySource("vault:" + key, properties));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return environment;
|
||||
}
|
||||
|
||||
protected abstract String read(String key);
|
||||
|
||||
private String getWatchState() {
|
||||
HttpServletRequest servletRequest = this.request.getIfAvailable();
|
||||
if (servletRequest != null) {
|
||||
String state = servletRequest.getHeader(STATE_HEADER);
|
||||
return this.watch.watch(state);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> findKeys(String application, List<String> profiles) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
|
||||
if (StringUtils.hasText(this.defaultKey)
|
||||
&& !this.defaultKey.equals(application)) {
|
||||
keys.add(this.defaultKey);
|
||||
addProfiles(keys, this.defaultKey, profiles);
|
||||
}
|
||||
|
||||
// application may have comma-separated list of names
|
||||
String[] applications = StringUtils.commaDelimitedListToStringArray(application);
|
||||
for (String app : applications) {
|
||||
keys.add(app);
|
||||
addProfiles(keys, app, profiles);
|
||||
}
|
||||
|
||||
Collections.reverse(keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private List<String> scrubProfiles(String[] profiles) {
|
||||
List<String> scrubbedProfiles = new ArrayList<>(Arrays.asList(profiles));
|
||||
scrubbedProfiles.remove("default");
|
||||
return scrubbedProfiles;
|
||||
}
|
||||
|
||||
private void addProfiles(List<String> contexts, String baseContext,
|
||||
List<String> profiles) {
|
||||
for (String profile : profiles) {
|
||||
contexts.add(baseContext + this.profileSeparator + profile);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultKey(String defaultKey) {
|
||||
this.defaultKey = defaultKey;
|
||||
}
|
||||
|
||||
public void setProfileSeparator(String profileSeparator) {
|
||||
this.profileSeparator = profileSeparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,39 +16,31 @@
|
||||
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.environment.PropertySource;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.springframework.cloud.config.client.ConfigClientProperties.STATE_HEADER;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Mark Paluch
|
||||
* @author Haroun Pacquee
|
||||
* @author Haytham Mohamed
|
||||
* @author Scott Frederick
|
||||
* @deprecated Prefer
|
||||
* {@link org.springframework.cloud.config.server.environment.vault.SpringVaultEnvironmentRepository}
|
||||
* instead of this environment repository implementation. The alternative implementation
|
||||
* supports additional features including more authentication options, support for several
|
||||
* underlying HTTP client libraries, and better SSL configuration.
|
||||
*/
|
||||
@Validated
|
||||
public class VaultEnvironmentRepository implements EnvironmentRepository, Ordered {
|
||||
public class VaultEnvironmentRepository extends AbstractVaultEnvironmentRepository {
|
||||
|
||||
/**
|
||||
* Vault token header name.
|
||||
@@ -76,28 +68,11 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
@NotEmpty
|
||||
private String backend;
|
||||
|
||||
/**
|
||||
* The key in vault shared by all applications. Defaults to application. Set to empty
|
||||
* to disable.
|
||||
*/
|
||||
private String defaultKey;
|
||||
|
||||
/** Vault Namespace header value. */
|
||||
private String namespace;
|
||||
|
||||
/** Vault profile separator. Defaults to comma. */
|
||||
@NotEmpty
|
||||
private String profileSeparator;
|
||||
|
||||
private int order;
|
||||
|
||||
private VaultKvAccessStrategy accessStrategy;
|
||||
|
||||
// TODO: move to watchState:String on findOne?
|
||||
private final ObjectProvider<HttpServletRequest> request;
|
||||
|
||||
private final EnvironmentWatch watch;
|
||||
|
||||
private final ConfigTokenProvider tokenProvider;
|
||||
|
||||
public VaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request,
|
||||
@@ -110,15 +85,11 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
public VaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request,
|
||||
EnvironmentWatch watch, RestTemplate rest,
|
||||
VaultEnvironmentProperties properties, ConfigTokenProvider tokenProvider) {
|
||||
this.request = request;
|
||||
this.watch = watch;
|
||||
super(request, watch, properties);
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.backend = properties.getBackend();
|
||||
this.defaultKey = properties.getDefaultKey();
|
||||
this.host = properties.getHost();
|
||||
this.order = properties.getOrder();
|
||||
this.port = properties.getPort();
|
||||
this.profileSeparator = properties.getProfileSeparator();
|
||||
this.scheme = properties.getScheme();
|
||||
this.namespace = properties.getNamespace();
|
||||
|
||||
@@ -133,78 +104,7 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment findOne(String application, String profile, String label) {
|
||||
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
|
||||
List<String> scrubbedProfiles = scrubProfiles(profiles);
|
||||
|
||||
List<String> keys = findKeys(application, scrubbedProfiles);
|
||||
|
||||
Environment environment = new Environment(application, profiles, label, null,
|
||||
getWatchState());
|
||||
|
||||
for (String key : keys) {
|
||||
// read raw 'data' key from vault
|
||||
String data = read(key);
|
||||
if (data != null) {
|
||||
// data is in json format of which, yaml is a superset, so parse
|
||||
final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
|
||||
yaml.setResources(new ByteArrayResource(data.getBytes()));
|
||||
Properties properties = yaml.getObject();
|
||||
|
||||
if (!properties.isEmpty()) {
|
||||
environment.add(new PropertySource("vault:" + key, properties));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return environment;
|
||||
}
|
||||
|
||||
private String getWatchState() {
|
||||
HttpServletRequest servletRequest = this.request.getIfAvailable();
|
||||
if (servletRequest != null) {
|
||||
String state = servletRequest.getHeader(STATE_HEADER);
|
||||
return this.watch.watch(state);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> findKeys(String application, List<String> profiles) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
|
||||
if (StringUtils.hasText(this.defaultKey)
|
||||
&& !this.defaultKey.equals(application)) {
|
||||
keys.add(this.defaultKey);
|
||||
addProfiles(keys, this.defaultKey, profiles);
|
||||
}
|
||||
|
||||
// application may have comma-separated list of names
|
||||
String[] applications = StringUtils.commaDelimitedListToStringArray(application);
|
||||
for (String app : applications) {
|
||||
keys.add(app);
|
||||
addProfiles(keys, app, profiles);
|
||||
}
|
||||
|
||||
Collections.reverse(keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private List<String> scrubProfiles(String[] profiles) {
|
||||
List<String> scrubbedProfiles = new ArrayList<>(Arrays.asList(profiles));
|
||||
if (scrubbedProfiles.contains("default")) {
|
||||
scrubbedProfiles.remove("default");
|
||||
}
|
||||
return scrubbedProfiles;
|
||||
}
|
||||
|
||||
private void addProfiles(List<String> contexts, String baseContext,
|
||||
List<String> profiles) {
|
||||
for (String profile : profiles) {
|
||||
contexts.add(baseContext + this.profileSeparator + profile);
|
||||
}
|
||||
}
|
||||
|
||||
private String read(String key) {
|
||||
protected String read(String key) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(VAULT_TOKEN, getToken());
|
||||
if (StringUtils.hasText(this.namespace)) {
|
||||
@@ -239,25 +139,8 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
this.backend = backend;
|
||||
}
|
||||
|
||||
public void setDefaultKey(String defaultKey) {
|
||||
this.defaultKey = defaultKey;
|
||||
}
|
||||
|
||||
public void setProfileSeparator(String profileSeparator) {
|
||||
this.profileSeparator = profileSeparator;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ import org.springframework.web.client.RestTemplate;
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
* @author Scott Frederick
|
||||
* @deprecated Prefer
|
||||
* {@link org.springframework.cloud.config.server.environment.vault.SpringVaultEnvironmentRepository}
|
||||
* instead of this environment repository implementation. The alternative implementation
|
||||
* supports additional features including more authentication options, support for several
|
||||
* underlying HTTP client libraries, and better SSL configuration.
|
||||
*/
|
||||
public class VaultEnvironmentRepositoryFactory implements
|
||||
EnvironmentRepositoryFactory<VaultEnvironmentRepository, VaultEnvironmentProperties> {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.config.server.environment.vault;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.config.server.environment.AbstractVaultEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.vault.core.VaultKeyValueOperations;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
|
||||
/**
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Validated
|
||||
public class SpringVaultEnvironmentRepository extends AbstractVaultEnvironmentRepository {
|
||||
|
||||
private VaultKeyValueOperations keyValueTemplate;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public SpringVaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request,
|
||||
EnvironmentWatch watch, VaultEnvironmentProperties properties,
|
||||
VaultKeyValueOperations keyValueTemplate) {
|
||||
super(request, watch, properties);
|
||||
this.keyValueTemplate = keyValueTemplate;
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
protected String read(String key) {
|
||||
VaultResponse response = this.keyValueTemplate.get(key);
|
||||
if (response != null) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(response.getData());
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
throw new RuntimeException("Error creating Vault response", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
VaultKeyValueOperations getKeyValueTemplate() {
|
||||
return this.keyValueTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.config.server.environment.vault;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.config.server.environment.ConfigTokenProvider;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.authentication.ClientAuthentication;
|
||||
import org.springframework.vault.authentication.SimpleSessionManager;
|
||||
import org.springframework.vault.client.RestTemplateBuilder;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.core.VaultKeyValueOperations;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class SpringVaultEnvironmentRepositoryFactory implements
|
||||
EnvironmentRepositoryFactory<SpringVaultEnvironmentRepository, VaultEnvironmentProperties> {
|
||||
|
||||
private final ObjectProvider<HttpServletRequest> request;
|
||||
|
||||
private final EnvironmentWatch watch;
|
||||
|
||||
private final ConfigTokenProvider tokenProvider;
|
||||
|
||||
public SpringVaultEnvironmentRepositoryFactory(
|
||||
ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
ConfigTokenProvider tokenProvider) {
|
||||
this.request = request;
|
||||
this.watch = watch;
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpringVaultEnvironmentRepository build(
|
||||
VaultEnvironmentProperties vaultProperties) {
|
||||
RestTemplateBuilder restTemplateBuilder = buildRestTemplateBuilder(
|
||||
vaultProperties);
|
||||
|
||||
VaultTemplate vaultTemplate = buildVaultTemplate(restTemplateBuilder);
|
||||
|
||||
VaultKeyValueOperations accessStrategy = buildVaultAccessStrategy(vaultProperties,
|
||||
vaultTemplate);
|
||||
|
||||
return new SpringVaultEnvironmentRepository(this.request, this.watch,
|
||||
vaultProperties, accessStrategy);
|
||||
}
|
||||
|
||||
private RestTemplateBuilder buildRestTemplateBuilder(
|
||||
VaultEnvironmentProperties vaultProperties) {
|
||||
URI baseUrl = UriComponentsBuilder.newInstance()
|
||||
.scheme(vaultProperties.getScheme()).host(vaultProperties.getHost())
|
||||
.port(vaultProperties.getPort()).build().toUri();
|
||||
|
||||
RestTemplateBuilder restTemplateBuilder = RestTemplateBuilder.builder()
|
||||
.endpoint(VaultEndpoint.from(baseUrl));
|
||||
|
||||
if (vaultProperties.getNamespace() != null) {
|
||||
restTemplateBuilder.customizers(
|
||||
restTemplate -> restTemplate.getInterceptors().add(VaultClients
|
||||
.createNamespaceInterceptor(vaultProperties.getNamespace())));
|
||||
}
|
||||
|
||||
return restTemplateBuilder;
|
||||
}
|
||||
|
||||
private VaultTemplate buildVaultTemplate(RestTemplateBuilder restTemplateBuilder) {
|
||||
return new VaultTemplate(restTemplateBuilder, new SimpleSessionManager(
|
||||
new ConfigTokenProviderAuthentication(tokenProvider)));
|
||||
}
|
||||
|
||||
private VaultKeyValueOperations buildVaultAccessStrategy(
|
||||
VaultEnvironmentProperties vaultProperties, VaultTemplate vaultTemplate) {
|
||||
String backend = vaultProperties.getBackend();
|
||||
int version = vaultProperties.getKvVersion();
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
return vaultTemplate.opsForKeyValue(backend,
|
||||
VaultKeyValueOperationsSupport.KeyValueBackend.KV_1);
|
||||
case 2:
|
||||
return vaultTemplate.opsForKeyValue(backend,
|
||||
VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"No support for given Vault k/v backend version " + version);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigTokenProviderAuthentication
|
||||
implements ClientAuthentication {
|
||||
|
||||
private final ConfigTokenProvider tokenProvider;
|
||||
|
||||
public ConfigTokenProviderAuthentication(ConfigTokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultToken login() throws VaultException {
|
||||
String token = tokenProvider.getToken();
|
||||
if (!StringUtils.hasLength(token)) {
|
||||
throw new IllegalArgumentException(
|
||||
"A Vault token must be supplied by a token provider");
|
||||
}
|
||||
return VaultToken.of(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.config.server.environment.vault;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.config.server.environment.ConfigTokenProvider;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.vault.core.VaultKeyValueOperations;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class SpringVaultEnvironmentRepositoryFactoryTests {
|
||||
|
||||
@Test
|
||||
public void buildForVersion1() {
|
||||
VaultEnvironmentProperties properties = new VaultEnvironmentProperties();
|
||||
|
||||
SpringVaultEnvironmentRepository environmentRepository = new SpringVaultEnvironmentRepositoryFactory(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(), mockTokenProvider())
|
||||
.build(properties);
|
||||
|
||||
VaultKeyValueOperations keyValueTemplate = environmentRepository
|
||||
.getKeyValueTemplate();
|
||||
assertThat(keyValueTemplate.getApiVersion())
|
||||
.isEqualTo(VaultKeyValueOperationsSupport.KeyValueBackend.KV_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildForVersion2() {
|
||||
VaultEnvironmentProperties properties = new VaultEnvironmentProperties();
|
||||
properties.setKvVersion(2);
|
||||
|
||||
SpringVaultEnvironmentRepository environmentRepository = new SpringVaultEnvironmentRepositoryFactory(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(), mockTokenProvider())
|
||||
.build(properties);
|
||||
|
||||
VaultKeyValueOperations keyValueTemplate = environmentRepository
|
||||
.getKeyValueTemplate();
|
||||
assertThat(keyValueTemplate.getApiVersion())
|
||||
.isEqualTo(VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
|
||||
}
|
||||
|
||||
private ConfigTokenProvider mockTokenProvider() {
|
||||
ConfigTokenProvider tokenProvider = mock(ConfigTokenProvider.class);
|
||||
when(tokenProvider.getToken()).thenReturn("token");
|
||||
return tokenProvider;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ObjectProvider<HttpServletRequest> mockHttpRequest() {
|
||||
ObjectProvider<HttpServletRequest> objectProvider = mock(ObjectProvider.class);
|
||||
when(objectProvider.getIfAvailable()).thenReturn(null);
|
||||
return objectProvider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.config.server.environment.vault;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.vault.core.VaultKeyValueOperations;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Ryan Baxter
|
||||
* @author Haroun Pacquee
|
||||
* @author Mark Paluch
|
||||
* @author Haytham Mohamed
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class SpringVaultEnvironmentRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void testFindOneNoDefaultKey() {
|
||||
VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
|
||||
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
|
||||
when(keyValueTemplate.get("application"))
|
||||
.thenReturn(withVaultResponse("def-foo", "def-bar"));
|
||||
|
||||
SpringVaultEnvironmentRepository repo = new SpringVaultEnvironmentRepository(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(),
|
||||
new VaultEnvironmentProperties(), keyValueTemplate);
|
||||
|
||||
Environment e = repo.findOne("myapp", null, null);
|
||||
assertThat(e.getName()).as("Name should be the same as the application argument")
|
||||
.isEqualTo("myapp");
|
||||
assertThat(e.getPropertySources()).as(
|
||||
"Properties for specified application and default application with key 'application' should be returned")
|
||||
.hasSize(2);
|
||||
|
||||
assertThat(e.getPropertySources().get(0).getSource()).as(
|
||||
"Properties for specified application should be returned in priority position")
|
||||
.containsOnly((Map.Entry) entry("foo", "bar"));
|
||||
assertThat(e.getPropertySources().get(1).getSource()).as(
|
||||
"Properties for default application with key 'application' should be returned in second position")
|
||||
.containsOnly((Map.Entry) entry("def-foo", "def-bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackendWithSlashes() {
|
||||
VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
|
||||
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
|
||||
when(keyValueTemplate.get("application"))
|
||||
.thenReturn(withVaultResponse("def-foo", "def-bar"));
|
||||
|
||||
VaultEnvironmentProperties properties = new VaultEnvironmentProperties();
|
||||
properties.setBackend("foo/bar/secret");
|
||||
|
||||
SpringVaultEnvironmentRepository repo = new SpringVaultEnvironmentRepository(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(), properties,
|
||||
keyValueTemplate);
|
||||
|
||||
Environment e = repo.findOne("myapp", null, null);
|
||||
assertThat(e.getName()).as("Name should be the same as the application argument")
|
||||
.isEqualTo("myapp");
|
||||
assertThat(e.getPropertySources()).as(
|
||||
"Properties for specified application and default application with key 'application' should be returned")
|
||||
.hasSize(2);
|
||||
|
||||
assertThat(e.getPropertySources().get(0).getSource()).as(
|
||||
"Properties for specified application should be returned in priority position")
|
||||
.containsOnly((Map.Entry) entry("foo", "bar"));
|
||||
assertThat(e.getPropertySources().get(1).getSource()).as(
|
||||
"Properties for default application with key 'application' should be returned in second position")
|
||||
.containsOnly((Map.Entry) entry("def-foo", "def-bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindOneDefaultKeySetAndDifferentToApplication() {
|
||||
VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
|
||||
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
|
||||
when(keyValueTemplate.get("mydefaultkey"))
|
||||
.thenReturn(withVaultResponse("def-foo", "def-bar"));
|
||||
|
||||
SpringVaultEnvironmentRepository repo = new SpringVaultEnvironmentRepository(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(),
|
||||
new VaultEnvironmentProperties(), keyValueTemplate);
|
||||
repo.setDefaultKey("mydefaultkey");
|
||||
|
||||
Environment e = repo.findOne("myapp", null, null);
|
||||
assertThat(e.getName()).as("Name should be the same as the application argument")
|
||||
.isEqualTo("myapp");
|
||||
assertThat(e.getPropertySources()).as(
|
||||
"Properties for specified application and default application with key 'mydefaultkey' should be returned")
|
||||
.hasSize(2);
|
||||
|
||||
assertThat(e.getPropertySources().get(0).getSource()).as(
|
||||
"Properties for specified application should be returned in priority position")
|
||||
.containsOnly((Map.Entry) entry("foo", "bar"));
|
||||
assertThat(e.getPropertySources().get(1).getSource()).as(
|
||||
"Properties for default application with key 'mydefaultkey' should be returned in second position")
|
||||
.containsOnly((Map.Entry) entry("def-foo", "def-bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindOneDefaultKeySetAndDifferentToMultipleApplications() {
|
||||
VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
|
||||
when(keyValueTemplate.get("myapp"))
|
||||
.thenReturn(withVaultResponse("myapp-foo", "myapp-bar"));
|
||||
when(keyValueTemplate.get("yourapp"))
|
||||
.thenReturn(withVaultResponse("yourapp-foo", "yourapp-bar"));
|
||||
when(keyValueTemplate.get("mydefaultkey"))
|
||||
.thenReturn(withVaultResponse("def-foo", "def-bar"));
|
||||
|
||||
SpringVaultEnvironmentRepository repo = new SpringVaultEnvironmentRepository(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(),
|
||||
new VaultEnvironmentProperties(), keyValueTemplate);
|
||||
repo.setDefaultKey("mydefaultkey");
|
||||
|
||||
Environment e = repo.findOne("myapp,yourapp", null, null);
|
||||
assertThat(e.getName()).as("Name should be the same as the application argument")
|
||||
.isEqualTo("myapp,yourapp");
|
||||
assertThat(e.getPropertySources()).as(
|
||||
"Properties for specified applications and default application with key 'mydefaultkey' should be returned")
|
||||
.hasSize(3);
|
||||
|
||||
assertThat(e.getPropertySources().get(0).getSource()).as(
|
||||
"Properties for first specified application should be returned in priority position")
|
||||
.containsOnly((Map.Entry) entry("yourapp-foo", "yourapp-bar"));
|
||||
|
||||
assertThat(e.getPropertySources().get(1).getSource()).as(
|
||||
"Properties for second specified application should be returned in priority position")
|
||||
.containsOnly((Map.Entry) entry("myapp-foo", "myapp-bar"));
|
||||
|
||||
assertThat(e.getPropertySources().get(2).getSource()).as(
|
||||
"Properties for default application with key 'mydefaultkey' should be returned in second position")
|
||||
.containsOnly((Map.Entry) entry("def-foo", "def-bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindOneDefaultKeySetAndEqualToApplication() {
|
||||
VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
|
||||
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
|
||||
when(keyValueTemplate.get("application"))
|
||||
.thenReturn(withVaultResponse("def-foo", "def-bar"));
|
||||
|
||||
SpringVaultEnvironmentRepository repo = new SpringVaultEnvironmentRepository(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(),
|
||||
new VaultEnvironmentProperties(), keyValueTemplate);
|
||||
repo.setDefaultKey("myapp");
|
||||
|
||||
Environment e = repo.findOne("myapp", null, null);
|
||||
assertThat(e.getName()).as("Name should be the same as the application argument")
|
||||
.isEqualTo("myapp");
|
||||
assertThat(e.getPropertySources())
|
||||
.as("Only properties for specified application should be returned")
|
||||
.hasSize(1);
|
||||
|
||||
assertThat(e.getPropertySources().get(0).getSource())
|
||||
.as("Properties should be returned for specified application")
|
||||
.containsOnly((Map.Entry) entry("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVaultVersioning() {
|
||||
VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
|
||||
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
|
||||
when(keyValueTemplate.get("application"))
|
||||
.thenReturn(withVaultResponse("def-foo", "def-bar"));
|
||||
|
||||
final VaultEnvironmentProperties vaultEnvironmentProperties = new VaultEnvironmentProperties();
|
||||
vaultEnvironmentProperties.setKvVersion(2);
|
||||
SpringVaultEnvironmentRepository repo = new SpringVaultEnvironmentRepository(
|
||||
mockHttpRequest(), new EnvironmentWatch.Default(),
|
||||
vaultEnvironmentProperties, keyValueTemplate);
|
||||
|
||||
Environment e = repo.findOne("myapp", null, null);
|
||||
assertThat(e.getName()).as("Name should be the same as the application argument")
|
||||
.isEqualTo("myapp");
|
||||
assertThat(e.getPropertySources()).as(
|
||||
"Properties for specified application and default application with key 'application' should be returned")
|
||||
.hasSize(2);
|
||||
|
||||
assertThat(e.getPropertySources().get(0).getSource()).as(
|
||||
"Properties for specified application should be returned in priority position")
|
||||
.containsOnly((Map.Entry) entry("foo", "bar"));
|
||||
}
|
||||
|
||||
private VaultResponse withVaultResponse(String key, Object value) {
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
responseData.put(key, value);
|
||||
|
||||
VaultResponse response = new VaultResponse();
|
||||
response.setData(responseData);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ObjectProvider<HttpServletRequest> mockHttpRequest() {
|
||||
ObjectProvider<HttpServletRequest> objectProvider = mock(ObjectProvider.class);
|
||||
when(objectProvider.getIfAvailable()).thenReturn(null);
|
||||
return objectProvider;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user