Add support for the AWS Systems Manager Parameter Store

Fixes gh-1598
Fixes gh-850
This commit is contained in:
Iulian Antohe
2021-07-27 17:01:38 -04:00
committed by spencergibb
parent 64a28c476d
commit 39cb1a2104
16 changed files with 1506 additions and 135 deletions

View File

@@ -337,7 +337,7 @@ To correct the above error the RSA key must be converted to PEM format. An examp
Spring Cloud Config Server also supports https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html[AWS CodeCommit] authentication.
AWS CodeCommit uses an authentication helper when using Git from the command line.
This helper is not used with the JGit library, so a JGit CredentialProvider for AWS CodeCommit is created if the Git URI matches the AWS CodeCommit pattern.
AWS CodeCommit URIs follow this pattern:
AWS CodeCommit URIs follow this pattern:
```bash
https//git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${repo}.
@@ -834,6 +834,18 @@ secret value =
----
===== AWS Parameter Store
When using AWS Parameter Store as a backend, you can share configuration with all applications by placing properties within the `/application` hierarchy.
For example, if you add parameters with the following names, all applications using the config server will have the properties `foo.bar` and `fred.baz` available to them:
[source]
----
/config/application/foo.bar
/config/application-default/fred.baz
----
==== JDBC Backend
Spring Cloud Config Server supports JDBC (relational database) as a backend for configuration properties.
@@ -932,6 +944,99 @@ Configuration files are stored in your bucket as `{application}-{profile}.proper
NOTE: When no profile is specified `default` will be used.
==== AWS Parameter Store Backend
Spring Cloud Config Server supports AWS Parameter Store as a backend for configuration properties. You can enable this feature by adding a dependency to the link:https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-ssm[AWS Java SDK for SSM].
[source,xml,indent=0]
.pom.xml
----
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-ssm</artifactId>
</dependency>
----
The following configuration uses the AWS SSM client to access parameters.
[source,yaml]
----
spring:
profiles:
active: awsparamstore
cloud:
config:
server:
awsparamstore:
region: eu-west-2
endpoint: https://ssm.eu-west-2.amazonaws.com
origin: aws:parameter:
prefix: /config/service
profileSeparator: _
recursive: true
decryptValues: true
maxResults: 5
----
The following table describes the AWS Parameter Store configuration properties.
.AWS Parameter Store Configuration Properties
|===
|Property Name |Required |Default Value |Remarks
|*region*
|no
|
|The region to be used by the AWS Parameter Store client. If it's not explicitly set, the SDK tries to determine the region to use by using the link:https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html#default-region-provider-chain[Default Region Provider Chain].
|*endpoint*
|no
|
|The URL of the entry point for the AWS SSM client. This can be used to specify an alternate endpoint for the API requests.
|*origin*
|no
|`aws:ssm:parameter:`
|The prefix that is added to the property source's name to show their provenance.
|*prefix*
|no
|`/config`
|Prefix indicating L1 level in the parameter hierarchy for every property loaded from the AWS Parameter Store.
|*profileSeparator*
|no
|`-`
|String that separates an appended profile from the context name.
|*recursive*
|no
|`true`
|Flag to indicate the retrieval of all AWS parameters within a hierarchy.
|*decryptValues*
|no
|`true`
|Flag to indicate the retrieval of all AWS parameters with their value decrypted.
|*maxResults*
|no
|`10`
|The maximum number of items to return for an AWS Parameter Store API call.
|===
AWS Parameter Store API credentials are determined using the link:https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default[Default Credential Provider Chain].
Versioned parameters are already supported with the default behaviour of returning the latest version.
[NOTE]
====
- When no application is specified `application` is the default, and when no profile is specified `default` is used.
- Valid values for `awsparamstore.prefix` must start with a forward slash followed by one or more valid path segments or be empty.
- Valid values for `awsparamstore.profileSeparator` can only contain dots, dashes and underscores.
- Valid values for `awsparamstore.maxResults` must be within the *[1, 10]* range.
====
==== AWS Secrets Manager Backend
Spring Cloud Config Server supports link:https://aws.amazon.com/secrets-manager/[AWS Secrets Manager] as a backend for configuration properties.

View File

@@ -28,7 +28,7 @@
<properties>
<bintray.package>config</bintray.package>
<spring-cloud-commons.version>3.1.0-SNAPSHOT</spring-cloud-commons.version>
<aws-java-sdk.version>1.11.903</aws-java-sdk.version>
<aws-java-sdk.version>1.11.911</aws-java-sdk.version>
<google-api-services-iam.version>v1-rev20201112-1.30.10</google-api-services-iam.version>
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError>
<maven-checkstyle-plugin.failsOnViolation>true
@@ -83,6 +83,11 @@
<artifactId>aws-java-sdk-secretsmanager</artifactId>
<version>${aws-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-ssm</artifactId>
<version>${aws-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-iam</artifactId>

View File

@@ -104,6 +104,11 @@
<artifactId>aws-java-sdk-secretsmanager</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-ssm</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>

View File

@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import org.apache.http.client.HttpClient;
import org.eclipse.jgit.api.TransportConfigCallback;
@@ -40,6 +41,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.config.server.composite.CompositeEnvironmentBeanFactoryPostProcessor;
import org.springframework.cloud.config.server.composite.ConditionalOnMissingSearchPathLocator;
import org.springframework.cloud.config.server.composite.ConditionalOnSearchPathLocator;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentProperties;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentRepository;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentProperties;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentRepository;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentRepositoryFactory;
@@ -106,18 +110,20 @@ import org.springframework.vault.core.VaultTemplate;
* @author Alberto C. Ríos
* @author Scott Frederick
* @author Tejas Pandilwar
* @author Iulian Antohe
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ SvnKitEnvironmentProperties.class, CredhubEnvironmentProperties.class,
JdbcEnvironmentProperties.class, NativeEnvironmentProperties.class, VaultEnvironmentProperties.class,
RedisEnvironmentProperties.class, AwsS3EnvironmentProperties.class,
AwsSecretsManagerEnvironmentProperties.class, GoogleSecretManagerEnvironmentProperties.class })
AwsSecretsManagerEnvironmentProperties.class, AwsParameterStoreEnvironmentProperties.class, GoogleSecretManagerEnvironmentProperties.class })
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class, VaultConfiguration.class,
VaultRepositoryConfiguration.class, SpringVaultRepositoryConfiguration.class, CredhubConfiguration.class,
CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class, NativeRepositoryConfiguration.class,
GitRepositoryConfiguration.class, RedisRepositoryConfiguration.class, GoogleCloudSourceConfiguration.class,
AwsS3RepositoryConfiguration.class, AwsSecretsManagerRepositoryConfiguration.class,
GoogleSecretManagerRepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
AwsParameterStoreRepositoryConfiguration.class,,
GoogleSecretManagerRepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
public class EnvironmentRepositoryConfiguration {
@Bean
@@ -225,6 +231,18 @@ public class EnvironmentRepositoryConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AWSSimpleSystemsManagement.class)
static class AwsParameterStoreFactoryConfig {
@Bean
public AwsParameterStoreEnvironmentRepositoryFactory awsParameterStoreEnvironmentRepositoryFactory(
ConfigServerProperties server) {
return new AwsParameterStoreEnvironmentRepositoryFactory(server);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SVNException.class)
static class SvnFactoryConfig {
@@ -385,6 +403,20 @@ class AwsS3RepositoryConfiguration {
}
@Configuration(proxyBeanMethods = false)
@Profile("awsparamstore")
class AwsParameterStoreRepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(AwsParameterStoreEnvironmentRepository.class)
public AwsParameterStoreEnvironmentRepository awsParameterStoreEnvironmentRepository(
AwsParameterStoreEnvironmentRepositoryFactory factory,
AwsParameterStoreEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("awssecretsmanager")
class AwsSecretsManagerRepositoryConfiguration {
@@ -516,8 +548,7 @@ class GoogleSecretManagerRepositoryConfiguration {
@Bean
public GoogleSecretManagerEnvironmentRepository googleSecretManagerEnvironmentRepository(
GoogleSecretManagerEnvironmentRepositoryFactory factory,
GoogleSecretManagerEnvironmentProperties environmentProperties)
throws Exception {
GoogleSecretManagerEnvironmentProperties environmentProperties) throws Exception {
return factory.build(environmentProperties);
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright 2018-2020 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 javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.config.server.support.EnvironmentRepositoryProperties;
import org.springframework.core.Ordered;
import org.springframework.validation.annotation.Validated;
/**
* @author Iulian Antohe
*/
@Validated
@ConfigurationProperties("spring.cloud.config.server.awsparamstore")
public class AwsParameterStoreEnvironmentProperties
implements EnvironmentRepositoryProperties {
static final String DEFAULT_PATH_SEPARATOR = "/";
private static final String DEFAULT_ORIGIN = "aws:ssm:parameter:";
private static final String DEFAULT_PREFIX = DEFAULT_PATH_SEPARATOR + "config";
private static final String DEFAULT_PROFILE_SEPARATOR = "-";
/**
* The order of the environment repository.
*/
private int order = Ordered.LOWEST_PRECEDENCE;
/**
* The region to be used by the AWS Parameter Store client.
*/
private String region;
/**
* The service endpoint to be used by the AWS Parameter Store client.
*/
private String endpoint;
/**
* Prefix indicating the property's origin. Defaults to "aws:ssm:parameter:".
*/
@NotNull
private String origin = DEFAULT_ORIGIN;
/**
* Prefix indicating first level for every property loaded from the AWS Parameter
* Store. Value must start with a forward slash followed by one or more valid path
* segments or be empty. Defaults to "/config".
*/
@NotNull
@Pattern(regexp = "(/[a-zA-Z0-9.\\-_]+)*")
private String prefix = DEFAULT_PREFIX;
/**
* String that separates an appended profile from the context name. Note that an AWS
* parameter name can only contain dots, dashes and underscores next to alphanumeric
* characters. Defaults to "-".
*/
@NotBlank
@Pattern(regexp = "[a-zA-Z0-9.\\-_/]+")
private String profileSeparator = DEFAULT_PROFILE_SEPARATOR;
/**
* Flag to indicate the retrieval of all AWS parameters within a hierarchy. Defaults
* to "true".
*/
private boolean recursive = true;
/**
* Flag to indicate the retrieval of all AWS parameters in a hierarchy with their
* value decrypted. Defaults to "true".
*/
private boolean decryptValues = true;
/**
* The maximum number of items to return for an AWS Parameter Store API call. Defaults
* to "10".
*/
@Min(1)
@Max(10)
private int maxResults = 10;
public int getOrder() {
return order;
}
@Override
public void setOrder(int order) {
this.order = order;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getProfileSeparator() {
return profileSeparator;
}
public void setProfileSeparator(String profileSeparator) {
this.profileSeparator = profileSeparator;
}
public boolean isRecursive() {
return recursive;
}
public void setRecursive(boolean recursive) {
this.recursive = recursive;
}
public boolean isDecryptValues() {
return decryptValues;
}
public void setDecryptValues(boolean decryptValues) {
this.decryptValues = decryptValues;
}
public int getMaxResults() {
return maxResults;
}
public void setMaxResults(int maxResults) {
this.maxResults = maxResults;
}
}

View File

@@ -0,0 +1,174 @@
/*
* Copyright 2013-2020 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.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersByPathRequest;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersByPathResult;
import com.amazonaws.services.simplesystemsmanagement.model.Parameter;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.config.ConfigServerProperties;
import org.springframework.util.StringUtils;
import static org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentProperties.DEFAULT_PATH_SEPARATOR;
/**
* @author Iulian Antohe
*/
public class AwsParameterStoreEnvironmentRepository implements EnvironmentRepository {
private final AWSSimpleSystemsManagement awsSsmClient;
private final ConfigServerProperties configServerProperties;
private final AwsParameterStoreEnvironmentProperties environmentProperties;
public AwsParameterStoreEnvironmentRepository(AWSSimpleSystemsManagement awsSsmClient,
ConfigServerProperties configServerProperties,
AwsParameterStoreEnvironmentProperties environmentProperties) {
this.awsSsmClient = awsSsmClient;
this.configServerProperties = configServerProperties;
this.environmentProperties = environmentProperties;
}
@Override
public Environment findOne(String application, String profile, String label) {
if (!StringUtils.hasLength(application)) {
application = configServerProperties.getDefaultApplicationName();
}
if (!StringUtils.hasLength(profile)) {
profile = configServerProperties.getDefaultProfile();
}
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
Environment result = new Environment(application, profiles, label, null, null);
Set<String> paths = buildParameterPaths(application, profiles);
List<PropertySource> propertySources = getPropertySources(paths);
result.addAll(propertySources);
return result;
}
private Set<String> buildParameterPaths(String application, String[] profiles) {
Set<String> result = new LinkedHashSet<>();
String prefix = environmentProperties.getPrefix();
String defaultApplication = configServerProperties.getDefaultApplicationName();
String profileSeparator = environmentProperties.getProfileSeparator();
String defaultProfile = configServerProperties.getDefaultProfile();
List<String> orderedProfiles = Stream
.concat(Arrays.stream(profiles).filter(p -> !p.equals(defaultProfile)),
Arrays.stream(new String[] { defaultProfile }))
.collect(Collectors.toList());
if (application.equals(defaultApplication)) {
for (String profile : orderedProfiles) {
result.add(prefix + DEFAULT_PATH_SEPARATOR + defaultApplication
+ profileSeparator + profile + DEFAULT_PATH_SEPARATOR);
}
}
else {
for (String profile : orderedProfiles) {
result.add(prefix + DEFAULT_PATH_SEPARATOR + application
+ profileSeparator + profile + DEFAULT_PATH_SEPARATOR);
result.add(prefix + DEFAULT_PATH_SEPARATOR + defaultApplication
+ profileSeparator + profile + DEFAULT_PATH_SEPARATOR);
}
result.add(prefix + DEFAULT_PATH_SEPARATOR + application
+ DEFAULT_PATH_SEPARATOR);
}
result.add(prefix + DEFAULT_PATH_SEPARATOR + defaultApplication
+ DEFAULT_PATH_SEPARATOR);
return result;
}
private List<PropertySource> getPropertySources(Set<String> parameterPaths) {
List<PropertySource> result = new ArrayList<>();
for (String path : parameterPaths) {
String name = environmentProperties.getOrigin() + path;
Map<String, String> source = getPropertiesByParameterPath(path);
if (!source.isEmpty()) {
result.add(new PropertySource(name, source));
}
}
Map<String, String> overrides = configServerProperties.getOverrides();
if (!overrides.isEmpty()) {
result.add(0, new PropertySource("overrides", overrides));
}
return result;
}
private Map<String, String> getPropertiesByParameterPath(String path) {
Map<String, String> result = new HashMap<>();
GetParametersByPathRequest request = new GetParametersByPathRequest()
.withPath(path).withRecursive(environmentProperties.isRecursive())
.withWithDecryption(environmentProperties.isDecryptValues())
.withMaxResults(environmentProperties.getMaxResults());
GetParametersByPathResult response = awsSsmClient.getParametersByPath(request);
if (response != null) {
addParametersToProperties(path, response.getParameters(), result);
while (StringUtils.hasLength(response.getNextToken())) {
response = awsSsmClient.getParametersByPath(request.withNextToken(response.getNextToken()));
addParametersToProperties(path, response.getParameters(), result);
}
}
return result;
}
private void addParametersToProperties(String path, List<Parameter> parameters,
Map<String, String> properties) {
for (Parameter parameter : parameters) {
String name = StringUtils.delete(parameter.getName(), path)
.replace(DEFAULT_PATH_SEPARATOR, ".");
properties.put(name, parameter.getValue());
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2018-2020 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 com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClientBuilder;
import org.springframework.cloud.config.server.config.ConfigServerProperties;
import org.springframework.util.StringUtils;
/**
* @author Iulian Antohe
*/
public class AwsParameterStoreEnvironmentRepositoryFactory implements
EnvironmentRepositoryFactory<AwsParameterStoreEnvironmentRepository, AwsParameterStoreEnvironmentProperties> {
private final ConfigServerProperties configServerProperties;
public AwsParameterStoreEnvironmentRepositoryFactory(
ConfigServerProperties configServerProperties) {
this.configServerProperties = configServerProperties;
}
@Override
public AwsParameterStoreEnvironmentRepository build(
AwsParameterStoreEnvironmentProperties environmentProperties) {
AWSSimpleSystemsManagementClientBuilder clientBuilder = AWSSimpleSystemsManagementClientBuilder
.standard();
String region = environmentProperties.getRegion();
if (StringUtils.hasLength(region)) {
Regions awsRegion = Regions.fromName(region);
clientBuilder.withRegion(awsRegion);
String endpoint = environmentProperties.getEndpoint();
if (StringUtils.hasLength(endpoint)) {
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
endpoint, awsRegion.getName());
clientBuilder.withEndpointConfiguration(endpointConfiguration);
}
}
AWSSimpleSystemsManagement client = clientBuilder.build();
return new AwsParameterStoreEnvironmentRepository(client, configServerProperties,
environmentProperties);
}
}

View File

@@ -24,8 +24,7 @@ import org.springframework.core.Ordered;
* @author Jose Maria Alvarez
*/
@ConfigurationProperties("spring.cloud.config.server.gcp-secret-manager")
public class GoogleSecretManagerEnvironmentProperties
implements EnvironmentRepositoryProperties {
public class GoogleSecretManagerEnvironmentProperties implements EnvironmentRepositoryProperties {
private int order = Ordered.LOWEST_PRECEDENCE;

View File

@@ -49,14 +49,12 @@ public class GoogleSecretManagerEnvironmentRepository implements EnvironmentRepo
private GoogleConfigProvider configProvider;
public GoogleSecretManagerEnvironmentRepository(
ObjectProvider<HttpServletRequest> request, RestTemplate rest,
GoogleSecretManagerEnvironmentProperties properties) {
public GoogleSecretManagerEnvironmentRepository(ObjectProvider<HttpServletRequest> request, RestTemplate rest,
GoogleSecretManagerEnvironmentProperties properties) {
this.applicationLabel = properties.getApplicationLabel();
this.profileLabel = properties.getProfileLabel();
this.configProvider = new HttpHeaderGoogleConfigProvider(request);
this.accessStrategy = GoogleSecretManagerAccessStrategyFactory.forVersion(rest,
configProvider, properties);
this.accessStrategy = GoogleSecretManagerAccessStrategyFactory.forVersion(rest, configProvider, properties);
this.tokenMandatory = properties.getTokenMandatory();
}
@@ -72,7 +70,7 @@ public class GoogleSecretManagerEnvironmentRepository implements EnvironmentRepo
profile = "default," + profile;
}
String[] profiles = org.springframework.util.StringUtils
.trimArrayElements(org.springframework.util.StringUtils.commaDelimitedListToStringArray(profile));
.trimArrayElements(org.springframework.util.StringUtils.commaDelimitedListToStringArray(profile));
Environment result = new Environment(application, profile, label, null, null);
if (tokenMandatory) {
if (accessStrategy.checkRemotePermissions()) {
@@ -85,13 +83,11 @@ public class GoogleSecretManagerEnvironmentRepository implements EnvironmentRepo
return result;
}
private void addPropertySource(String application, String[] profiles,
Environment result) {
private void addPropertySource(String application, String[] profiles, Environment result) {
for (String profileUnit : profiles) {
Map<?, ?> secrets = getSecrets(application, profileUnit);
if (!secrets.isEmpty()) {
result.add(new PropertySource("gsm:" + application + "-" + profileUnit,
secrets));
result.add(new PropertySource("gsm:" + application + "-" + profileUnit, secrets));
}
}
}
@@ -103,23 +99,16 @@ public class GoogleSecretManagerEnvironmentRepository implements EnvironmentRepo
*/
private Map<?, ?> getSecrets(String application, String profile) {
Map<String, String> result = new HashMap<>();
String prefix = configProvider
.getValue(HttpHeaderGoogleConfigProvider.PREFIX_HEADER, false);
String prefix = configProvider.getValue(HttpHeaderGoogleConfigProvider.PREFIX_HEADER, false);
for (Secret secret : accessStrategy.getSecrets()) {
if (secret.getLabelsOrDefault(applicationLabel, "application")
.equalsIgnoreCase(application)
&& secret.getLabelsOrDefault(profileLabel, "profile")
.equalsIgnoreCase(profile)) {
result.put(accessStrategy.getSecretName(secret), accessStrategy
.getSecretValue(secret, new GoogleSecretComparatorByVersion()));
if (secret.getLabelsOrDefault(applicationLabel, "application").equalsIgnoreCase(application)
&& secret.getLabelsOrDefault(profileLabel, "profile").equalsIgnoreCase(profile)) {
result.put(accessStrategy.getSecretName(secret),
accessStrategy.getSecretValue(secret, new GoogleSecretComparatorByVersion()));
}
else if (StringUtils.isNotBlank(prefix)
&& accessStrategy.getSecretName(secret).startsWith(prefix)) {
result.put(
StringUtils.removeStart(accessStrategy.getSecretName(secret),
prefix),
accessStrategy.getSecretValue(secret,
new GoogleSecretComparatorByVersion()));
else if (StringUtils.isNotBlank(prefix) && accessStrategy.getSecretName(secret).startsWith(prefix)) {
result.put(StringUtils.removeStart(accessStrategy.getSecretName(secret), prefix),
accessStrategy.getSecretValue(secret, new GoogleSecretComparatorByVersion()));
}
}
return result;

View File

@@ -29,17 +29,14 @@ public class GoogleSecretManagerEnvironmentRepositoryFactory implements
private final ObjectProvider<HttpServletRequest> request;
public GoogleSecretManagerEnvironmentRepositoryFactory(
ObjectProvider<HttpServletRequest> request) {
public GoogleSecretManagerEnvironmentRepositoryFactory(ObjectProvider<HttpServletRequest> request) {
this.request = request;
}
@Override
public GoogleSecretManagerEnvironmentRepository build(
GoogleSecretManagerEnvironmentProperties environmentProperties)
throws Exception {
return new GoogleSecretManagerEnvironmentRepository(request, new RestTemplate(),
environmentProperties);
GoogleSecretManagerEnvironmentProperties environmentProperties) throws Exception {
return new GoogleSecretManagerEnvironmentRepository(request, new RestTemplate(), environmentProperties);
}
}

View File

@@ -28,40 +28,33 @@ public final class GoogleSecretManagerAccessStrategyFactory {
throw new IllegalStateException("Can't instantiate an utility class");
}
public static GoogleSecretManagerAccessStrategy forVersion(RestTemplate rest,
GoogleConfigProvider configProvider,
GoogleSecretManagerEnvironmentProperties properties) {
public static GoogleSecretManagerAccessStrategy forVersion(RestTemplate rest, GoogleConfigProvider configProvider,
GoogleSecretManagerEnvironmentProperties properties) {
switch (properties.getVersion()) {
case 1:
try {
return new GoogleSecretManagerV1AccessStrategy(rest, configProvider,
properties.getServiceAccount());
return new GoogleSecretManagerV1AccessStrategy(rest, configProvider, properties.getServiceAccount());
}
catch (Exception e) {
throw new RepositoryException("Cannot create service client", e);
}
default:
throw new IllegalArgumentException(
"No support for given Google Secret manager backend version "
+ properties.getVersion());
"No support for given Google Secret manager backend version " + properties.getVersion());
}
}
public static GoogleSecretManagerAccessStrategy forVersion(RestTemplate rest,
GoogleConfigProvider configProvider,
GoogleSecretManagerEnvironmentProperties properties,
SecretManagerServiceClient client) {
public static GoogleSecretManagerAccessStrategy forVersion(RestTemplate rest, GoogleConfigProvider configProvider,
GoogleSecretManagerEnvironmentProperties properties, SecretManagerServiceClient client) {
switch (properties.getVersion()) {
case 1:
return new GoogleSecretManagerV1AccessStrategy(rest, configProvider,
client);
return new GoogleSecretManagerV1AccessStrategy(rest, configProvider, client);
default:
throw new IllegalArgumentException(
"No support for given Google Secret manager backend version "
+ properties.getVersion());
"No support for given Google Secret manager backend version " + properties.getVersion());
}
}

View File

@@ -55,8 +55,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
public class GoogleSecretManagerV1AccessStrategy
implements GoogleSecretManagerAccessStrategy {
public class GoogleSecretManagerV1AccessStrategy implements GoogleSecretManagerAccessStrategy {
private final SecretManagerServiceClient client;
@@ -68,19 +67,14 @@ public class GoogleSecretManagerV1AccessStrategy
private static final String ACCESS_SECRET_PERMISSION = "secretmanager.versions.access";
private static Log logger = LogFactory
.getLog(GoogleSecretManagerV1AccessStrategy.class);
private static Log logger = LogFactory.getLog(GoogleSecretManagerV1AccessStrategy.class);
public GoogleSecretManagerV1AccessStrategy(RestTemplate rest,
GoogleConfigProvider configProvider, String serviceAccountFile)
throws IOException {
public GoogleSecretManagerV1AccessStrategy(RestTemplate rest, GoogleConfigProvider configProvider,
String serviceAccountFile) throws IOException {
if (StringUtils.isNotEmpty(serviceAccountFile)) {
GoogleCredentials creds = GoogleCredentials
.fromStream(new FileInputStream(new File(serviceAccountFile)));
this.client = SecretManagerServiceClient.create(SecretManagerServiceSettings
.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(creds))
.build());
GoogleCredentials creds = GoogleCredentials.fromStream(new FileInputStream(new File(serviceAccountFile)));
this.client = SecretManagerServiceClient.create(SecretManagerServiceSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(creds)).build());
}
else {
this.client = SecretManagerServiceClient.create();
@@ -89,8 +83,8 @@ public class GoogleSecretManagerV1AccessStrategy
this.configProvider = configProvider;
}
public GoogleSecretManagerV1AccessStrategy(RestTemplate rest,
GoogleConfigProvider configProvider, SecretManagerServiceClient client) {
public GoogleSecretManagerV1AccessStrategy(RestTemplate rest, GoogleConfigProvider configProvider,
SecretManagerServiceClient client) {
this.client = client;
this.rest = rest;
this.configProvider = configProvider;
@@ -102,12 +96,11 @@ public class GoogleSecretManagerV1AccessStrategy
ProjectName project = ProjectName.of(getProjectId());
// Create the request.
ListSecretsRequest listSecretRequest = ListSecretsRequest.newBuilder()
.setParent(project.toString()).build();
ListSecretsRequest listSecretRequest = ListSecretsRequest.newBuilder().setParent(project.toString()).build();
// Get all secrets.
SecretManagerServiceClient.ListSecretsPagedResponse pagedListSecretResponse = client
.listSecrets(listSecretRequest);
.listSecrets(listSecretRequest);
List<Secret> result = new ArrayList<Secret>();
pagedListSecretResponse.iterateAll().forEach(result::add);
@@ -120,12 +113,12 @@ public class GoogleSecretManagerV1AccessStrategy
SecretName parent = SecretName.parse(secret.getName());
// Create the request.
ListSecretVersionsRequest listVersionRequest = ListSecretVersionsRequest
.newBuilder().setParent(parent.toString()).build();
ListSecretVersionsRequest listVersionRequest = ListSecretVersionsRequest.newBuilder()
.setParent(parent.toString()).build();
// Get all versions.
SecretManagerServiceClient.ListSecretVersionsPagedResponse pagedListVersionResponse = client
.listSecretVersions(listVersionRequest);
.listSecretVersions(listVersionRequest);
List<SecretVersion> result = new ArrayList<SecretVersion>();
pagedListVersionResponse.iterateAll().forEach(result::add);
return result;
@@ -137,17 +130,16 @@ public class GoogleSecretManagerV1AccessStrategy
List<SecretVersion> versions = getSecretVersions(secret);
SecretVersion winner = null;
for (SecretVersion secretVersion : versions) {
if ((secretVersion.getState()
.getNumber() == SecretVersion.State.ENABLED_VALUE)
&& comparator.compare(secretVersion, winner) > 0) {
if ((secretVersion.getState().getNumber() == SecretVersion.State.ENABLED_VALUE)
&& comparator.compare(secretVersion, winner) > 0) {
winner = secretVersion;
}
}
if (winner != null) {
SecretVersionName name = SecretVersionName.parse(winner.getName());
// Access the secret version.
AccessSecretVersionRequest request = AccessSecretVersionRequest.newBuilder()
.setName(name.toString()).build();
AccessSecretVersionRequest request = AccessSecretVersionRequest.newBuilder().setName(name.toString())
.build();
AccessSecretVersionResponse response = client.accessSecretVersion(request);
result = response.getPayload().getData().toStringUtf8();
}
@@ -166,27 +158,22 @@ public class GoogleSecretManagerV1AccessStrategy
try {
AccessToken accessToken = new AccessToken(getAccessToken(), null);
GoogleCredentials credential = new GoogleCredentials(accessToken);
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
credential);
service = new CloudResourceManager.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
JacksonFactory.getDefaultInstance(), requestInitializer)
.setApplicationName(APPLICATION_NAME).build();
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credential);
service = new CloudResourceManager.Builder(GoogleNetHttpTransport.newTrustedTransport(),
JacksonFactory.getDefaultInstance(), requestInitializer).setApplicationName(APPLICATION_NAME)
.build();
List<String> permissionsList = Arrays.asList(ACCESS_SECRET_PERMISSION);
TestIamPermissionsRequest requestBody = new TestIamPermissionsRequest()
.setPermissions(permissionsList);
TestIamPermissionsRequest requestBody = new TestIamPermissionsRequest().setPermissions(permissionsList);
TestIamPermissionsResponse testIamPermissionsResponse = service.projects()
.testIamPermissions(getProjectId(), requestBody).execute();
.testIamPermissions(getProjectId(), requestBody).execute();
if (testIamPermissionsResponse.getPermissions() != null
&& testIamPermissionsResponse.size() >= 1) {
if (testIamPermissionsResponse.getPermissions() != null && testIamPermissionsResponse.size() >= 1) {
return Boolean.TRUE;
}
else {
logger.warn(
"Access token has no permissions to access secrets in project");
logger.warn("Access token has no permissions to access secrets in project");
return Boolean.FALSE;
}
}
@@ -197,26 +184,22 @@ public class GoogleSecretManagerV1AccessStrategy
}
private String getAccessToken() {
return configProvider.getValue(HttpHeaderGoogleConfigProvider.ACCESS_TOKEN_HEADER,
true);
return configProvider.getValue(HttpHeaderGoogleConfigProvider.ACCESS_TOKEN_HEADER, true);
}
/**
* @return
* @return the Project Id.
*/
private String getProjectId() {
String result = null;
try {
result = configProvider
.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true);
result = configProvider.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true);
}
catch (Exception e) {
// not in GCP
HttpEntity<String> entity = new HttpEntity<String>("parameters",
getMetadataHttpHeaders());
result = rest.exchange(
GoogleSecretManagerEnvironmentProperties.GOOGLE_METADATA_PROJECT_URL,
HttpMethod.GET, entity, String.class).getBody();
HttpEntity<String> entity = new HttpEntity<String>("parameters", getMetadataHttpHeaders());
result = rest.exchange(GoogleSecretManagerEnvironmentProperties.GOOGLE_METADATA_PROJECT_URL, HttpMethod.GET,
entity, String.class).getBody();
}
return result;
}

View File

@@ -53,8 +53,7 @@ public class HttpHeaderGoogleConfigProvider implements GoogleConfigProvider {
}
String value = request.getHeader(key);
if (!StringUtils.hasLength(value) && mandatory) {
throw new IllegalArgumentException(
"Missing required header in HttpServletRequest: " + key);
throw new IllegalArgumentException("Missing required header in HttpServletRequest: " + key);
}
return value;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2020 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.
@@ -32,6 +32,7 @@ import org.springframework.cloud.config.server.encryption.EncryptionControllerTe
import org.springframework.cloud.config.server.encryption.EncryptionIntegrationTests;
import org.springframework.cloud.config.server.encryption.EnvironmentPrefixHelperTests;
import org.springframework.cloud.config.server.encryption.KeyStoreTextEncryptorLocatorTests;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentRepositoryTests;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentRepositoryTests;
import org.springframework.cloud.config.server.environment.CompositeEnvironmentRepositoryTests;
import org.springframework.cloud.config.server.environment.EnvironmentControllerIntegrationTests;
@@ -86,7 +87,7 @@ import org.springframework.cloud.config.server.ssh.SshUriPropertyProcessorTest;
SshPropertyValidatorTest.class, CompositeIntegrationTests.class, SubversionConfigServerIntegrationTests.class,
ConfigServerHealthIndicatorTests.class, CustomCompositeEnvironmentRepositoryTests.class,
CustomEnvironmentRepositoryTests.class, BootstrapConfigServerIntegrationTests.class,
AwsS3EnvironmentRepositoryTests.class })
AwsS3EnvironmentRepositoryTests.class, AwsParameterStoreEnvironmentRepositoryTests.class })
@Ignore
public class AdhocTestSuite {

View File

@@ -0,0 +1,856 @@
/*
* Copyright 2013-2020 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.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersByPathRequest;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersByPathResult;
import com.amazonaws.services.simplesystemsmanagement.model.Parameter;
import com.amazonaws.services.simplesystemsmanagement.model.ParameterType;
import org.apache.commons.lang3.RandomUtils;
import org.junit.Test;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.config.ConfigServerProperties;
import org.springframework.util.StringUtils;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentProperties.DEFAULT_PATH_SEPARATOR;
/**
* @author Iulian Antohe
*/
public class AwsParameterStoreEnvironmentRepositoryTests {
private static final Map<String, String> SHARED_PROPERTIES = new HashMap<String, String>() {
{
put("logging.level.root", "warn");
put("spring.cache.redis.time-to-live", "0");
}
};
private static final Map<String, String> SHARED_DEFAULT_PROPERTIES = new HashMap<String, String>() {
{
put("logging.level.root", "error");
put("spring.cache.redis.time-to-live", "1000");
}
};
private static final Map<String, String> SHARED_PRODUCTION_PROPERTIES = new HashMap<String, String>() {
{
put("logging.level.root", "fatal");
put("spring.cache.redis.time-to-live", "5000");
}
};
private static final Map<String, String> APPLICATION_SPECIFIC_PROPERTIES = new HashMap<String, String>() {
{
put("logging.level.com.example.service", "trace");
put("spring.cache.redis.time-to-live", "30000");
}
};
private static final Map<String, String> APPLICATION_SPECIFIC_DEFAULT_PROPERTIES = new HashMap<String, String>() {
{
put("logging.level.com.example.service", "debug");
put("spring.cache.redis.time-to-live", "60000");
}
};
private static final Map<String, String> APPLICATION_SPECIFIC_PRODUCTION_PROPERTIES = new HashMap<String, String>() {
{
put("logging.level.com.example.service", "info");
put("spring.cache.redis.time-to-live", "300000");
}
};
private final AWSSimpleSystemsManagement awsSsmClientMock = mock(
AWSSimpleSystemsManagement.class, "aws-ssm-client-mock");
private final ConfigServerProperties configServerProperties = new ConfigServerProperties();
private final AwsParameterStoreEnvironmentProperties environmentProperties = new AwsParameterStoreEnvironmentProperties();
private final AwsParameterStoreEnvironmentRepository repository = new AwsParameterStoreEnvironmentRepository(
awsSsmClientMock, configServerProperties, environmentProperties);
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithNullApplicationAndNullProfile() {
// Arrange
String application = null;
String profile = null;
String defaultApp = configServerProperties.getDefaultApplicationName();
String defaultProfile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(defaultProfile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(defaultApp, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithNullApplicationAndDefaultProfile() {
// Arrange
String application = null;
String profile = configServerProperties.getDefaultProfile();
String defaultApp = configServerProperties.getDefaultApplicationName();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(defaultApp, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithNullApplicationAndNonExistentProfile() {
// Arrange
String application = null;
String profile = randomAlphabetic(RandomUtils.nextInt(3, 33));
String defaultApp = configServerProperties.getDefaultApplicationName();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String name = "aws:ssm:parameter:/config/application/";
PropertySource ps = new PropertySource(name, SHARED_PROPERTIES);
Environment expected = new Environment(defaultApp, profiles, null, null, null);
expected.add(ps);
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithNullApplicationAndExistentProfile() {
// Arrange
String application = null;
String profile = "production";
String defaultApp = configServerProperties.getDefaultApplicationName();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedProdParamsPsName = "aws:ssm:parameter:/config/application-production/";
PropertySource sharedProdParamsPs = new PropertySource(sharedProdParamsPsName,
SHARED_PRODUCTION_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(defaultApp, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedProdParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithDefaultApplicationAndNullProfile() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = null;
String defaultProfile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(defaultProfile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithDefaultApplicationAndDefaultProfile() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithDefaultApplicationAndNonExistentProfile() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = randomAlphabetic(RandomUtils.nextInt(3, 33));
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String name = "aws:ssm:parameter:/config/application/";
PropertySource ps = new PropertySource(name, SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.add(ps);
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithDefaultApplicationAndExistentProfile() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = "production";
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedProdParamsPsName = "aws:ssm:parameter:/config/application-production/";
PropertySource sharedProdParamsPs = new PropertySource(sharedProdParamsPsName,
SHARED_PRODUCTION_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedProdParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithNonExistentApplicationAndNullProfile() {
// Arrange
String application = randomAlphabetic(RandomUtils.nextInt(3, 33));
String profile = null;
String defaultProfile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(defaultProfile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithNonExistentApplicationAndDefaultProfile() {
// Arrange
String application = randomAlphabetic(RandomUtils.nextInt(3, 33));
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithNonExistentApplicationAndNonExistentProfile() {
// Arrange
String application = randomAlphabetic(RandomUtils.nextInt(3, 33));
String profile = randomAlphabetic(RandomUtils.nextInt(3, 33));
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String name = "aws:ssm:parameter:/config/application/";
PropertySource ps = new PropertySource(name, SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.add(ps);
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithNonExistentApplicationAndExistentProfile() {
// Arrange
String application = randomAlphabetic(RandomUtils.nextInt(3, 33));
String profile = "production";
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedProdParamsPsName = "aws:ssm:parameter:/config/application-production/";
PropertySource sharedProdParamsPs = new PropertySource(sharedProdParamsPsName,
SHARED_PRODUCTION_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedProdParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
@SuppressWarnings("ConstantConditions")
public void testFindOneWithExistentApplicationAndNullProfile() {
// Arrange
String application = "service";
String profile = null;
String defaultProfile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(defaultProfile);
String appSpecificDefaultParamsPsName = "aws:ssm:parameter:/config/service-default/";
PropertySource appSpecificDefaultParamsPs = new PropertySource(
appSpecificDefaultParamsPsName, APPLICATION_SPECIFIC_DEFAULT_PROPERTIES);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String appSpecificParamsPsName = "aws:ssm:parameter:/config/service/";
PropertySource appSpecificParamsPs = new PropertySource(appSpecificParamsPsName,
APPLICATION_SPECIFIC_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(appSpecificDefaultParamsPs, sharedDefaultParamsPs,
appSpecificParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithExistentApplicationAndDefaultProfile() {
// Arrange
String application = "service";
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String appSpecificDefaultParamsPsName = "aws:ssm:parameter:/config/service-default/";
PropertySource appSpecificDefaultParamsPs = new PropertySource(
appSpecificDefaultParamsPsName, APPLICATION_SPECIFIC_DEFAULT_PROPERTIES);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String appSpecificParamsPsName = "aws:ssm:parameter:/config/service/";
PropertySource appSpecificParamsPs = new PropertySource(appSpecificParamsPsName,
APPLICATION_SPECIFIC_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(appSpecificDefaultParamsPs, sharedDefaultParamsPs,
appSpecificParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithExistentApplicationAndNonExistentProfile() {
// Arrange
String application = "service";
String profile = randomAlphabetic(RandomUtils.nextInt(3, 33));
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String appSpecificParamsPsName = "aws:ssm:parameter:/config/service/";
PropertySource appSpecificParamsPs = new PropertySource(appSpecificParamsPsName,
APPLICATION_SPECIFIC_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(appSpecificParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithExistentApplicationAndExistentProfile() {
// Arrange
String application = "service";
String profile = "production";
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String appSpecificProdParamsPsName = "aws:ssm:parameter:/config/service-production/";
PropertySource appSpecificProdParamsPs = new PropertySource(
appSpecificProdParamsPsName, APPLICATION_SPECIFIC_PRODUCTION_PROPERTIES);
String sharedProdParamsPsName = "aws:ssm:parameter:/config/application-production/";
PropertySource sharedProdParamsPs = new PropertySource(sharedProdParamsPsName,
SHARED_PRODUCTION_PROPERTIES);
String appSpecificParamsPsName = "aws:ssm:parameter:/config/service/";
PropertySource appSpecificParamsPs = new PropertySource(appSpecificParamsPsName,
APPLICATION_SPECIFIC_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(appSpecificProdParamsPs, sharedProdParamsPs,
appSpecificParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithExistentApplicationAndMultipleExistentProfiles() {
// Arrange
String application = "service";
String profile = configServerProperties.getDefaultProfile() + ",production";
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String appSpecificProdParamsPsName = "aws:ssm:parameter:/config/service-production/";
PropertySource appSpecificProdParamsPs = new PropertySource(
appSpecificProdParamsPsName, APPLICATION_SPECIFIC_PRODUCTION_PROPERTIES);
String sharedProdParamsPsName = "aws:ssm:parameter:/config/application-production/";
PropertySource sharedProdParamsPs = new PropertySource(sharedProdParamsPsName,
SHARED_PRODUCTION_PROPERTIES);
String appSpecificDefaultParamsPsName = "aws:ssm:parameter:/config/service-default/";
PropertySource appSpecificDefaultParamsPs = new PropertySource(
appSpecificDefaultParamsPsName, APPLICATION_SPECIFIC_DEFAULT_PROPERTIES);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String appSpecificParamsPsName = "aws:ssm:parameter:/config/service/";
PropertySource appSpecificParamsPs = new PropertySource(appSpecificParamsPsName,
APPLICATION_SPECIFIC_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(appSpecificProdParamsPs, sharedProdParamsPs,
appSpecificDefaultParamsPs, sharedDefaultParamsPs, appSpecificParamsPs,
sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithOverrides() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
Map<String, String> overrides = new HashMap<String, String>(4) {
{
put("logging.level.root", "boom");
put("logging.level.com.example.service", "boom");
put("spring.cache.redis.time-to-live", "-1");
}
};
configServerProperties.setOverrides(overrides);
PropertySource overridesPs = new PropertySource("overrides", overrides);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(
Arrays.asList(overridesPs, sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithSlashesInTheParameterKeyPath() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected, true, false);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithPaginatedAwsSsmClientResponse() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
environmentProperties.setMaxResults(1);
String sharedDefaultParamsPsName = "aws:ssm:parameter:/config/application-default/";
PropertySource sharedDefaultParamsPs = new PropertySource(
sharedDefaultParamsPsName, SHARED_DEFAULT_PROPERTIES);
String sharedParamsPsName = "aws:ssm:parameter:/config/application/";
PropertySource sharedParamsPs = new PropertySource(sharedParamsPsName,
SHARED_PROPERTIES);
Environment expected = new Environment(application, profiles, null, null, null);
expected.addAll(Arrays.asList(sharedDefaultParamsPs, sharedParamsPs));
setupAwsSsmClientMocks(expected, false, true);
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
@Test
public void testFindOneWithNoParametersInThePaths() {
// Arrange
String application = configServerProperties.getDefaultApplicationName();
String profile = configServerProperties.getDefaultProfile();
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
Environment expected = new Environment(application, profiles, null, null, null);
when(awsSsmClientMock.getParametersByPath(any(GetParametersByPathRequest.class)))
.thenReturn(new GetParametersByPathResult());
// Act
Environment result = repository.findOne(application, profile, null);
// Assert
assertThat(result).usingRecursiveComparison().withStrictTypeChecking()
.isEqualTo(expected);
}
private void setupAwsSsmClientMocks(Environment environment) {
setupAwsSsmClientMocks(environment, false, false);
}
private void setupAwsSsmClientMocks(Environment environment,
boolean withSlashesForPropertyName, boolean paginatedResponse) {
for (PropertySource ps : environment.getPropertySources()) {
String path = StringUtils.delete(ps.getName(),
environmentProperties.getOrigin());
GetParametersByPathRequest request = new GetParametersByPathRequest()
.withPath(path).withRecursive(environmentProperties.isRecursive())
.withWithDecryption(environmentProperties.isDecryptValues())
.withMaxResults(environmentProperties.getMaxResults());
Set<Parameter> parameters = getParameters(ps, path,
withSlashesForPropertyName);
GetParametersByPathResult response = new GetParametersByPathResult()
.withParameters(parameters);
if (paginatedResponse
&& environmentProperties.getMaxResults() < parameters.size()) {
List<Set<Parameter>> chunks = splitParametersIntoChunks(parameters);
String nextToken = null;
for (int i = 0; i < chunks.size(); i++) {
Set<Parameter> chunk = chunks.get(i);
if (i == 0) {
nextToken = generateNextToken();
GetParametersByPathResult responseClone = response.clone()
.withParameters(chunk).withNextToken(nextToken);
when(awsSsmClientMock.getParametersByPath(eq(request)))
.thenReturn(responseClone);
}
else if (i == chunks.size() - 1) {
GetParametersByPathRequest requestClone = request.clone().withNextToken(nextToken);
GetParametersByPathResult responseClone = response.clone().withParameters(chunk);
when(awsSsmClientMock.getParametersByPath(eq(requestClone)))
.thenReturn(responseClone);
}
else {
String newNextToken = generateNextToken();
GetParametersByPathRequest requestClone = request.clone()
.withNextToken(nextToken);
GetParametersByPathResult responseClone = response.clone()
.withParameters(chunk).withNextToken(newNextToken);
when(awsSsmClientMock.getParametersByPath(eq(requestClone)))
.thenReturn(responseClone);
nextToken = newNextToken;
}
}
}
else {
when(awsSsmClientMock.getParametersByPath(eq(request)))
.thenReturn(response);
}
}
}
private Set<Parameter> getParameters(PropertySource propertySource, String path,
boolean withSlashesForPropertyName) {
Function<Map.Entry<?, ?>, Parameter> mapper = p -> new Parameter()
.withName(path + (withSlashesForPropertyName
? ((String) p.getKey()).replace(".", DEFAULT_PATH_SEPARATOR)
: p.getKey()))
.withType(ParameterType.String).withValue((String) p.getValue())
.withVersion(1L);
return propertySource.getSource().entrySet().stream().map(mapper)
.collect(Collectors.toSet());
}
private List<Set<Parameter>> splitParametersIntoChunks(Set<Parameter> parameters) {
AtomicInteger counter = new AtomicInteger();
Collector<Parameter, ?, Map<Integer, Set<Parameter>>> collector = Collectors
.groupingBy(
p -> counter.getAndIncrement()
/ environmentProperties.getMaxResults(),
Collectors.toSet());
return new ArrayList<>(parameters.stream().collect(collector).values());
}
private String generateNextToken() {
String random = randomAlphabetic(RandomUtils.nextInt(3, 33));
return Base64.getEncoder()
.encodeToString(random.getBytes(StandardCharsets.UTF_8));
}
}

View File

@@ -53,8 +53,8 @@ public class GoogleSecretManagerEnvironmentRepositoryTests {
GoogleSecretManagerEnvironmentProperties properties = new GoogleSecretManagerEnvironmentProperties();
SecretManagerServiceClient mock = mock(SecretManagerServiceClient.class);
properties.setVersion(1);
assertThat(GoogleSecretManagerAccessStrategyFactory.forVersion(null, null,
properties, mock) instanceof GoogleSecretManagerV1AccessStrategy).isTrue();
assertThat(GoogleSecretManagerAccessStrategyFactory.forVersion(null, null, properties,
mock) instanceof GoogleSecretManagerV1AccessStrategy).isTrue();
}
@Test(expected = IllegalArgumentException.class)
@@ -70,19 +70,16 @@ public class GoogleSecretManagerEnvironmentRepositoryTests {
public void testGetSecrets() throws IOException {
RestTemplate rest = mock(RestTemplate.class);
GoogleConfigProvider provider = mock(HttpHeaderGoogleConfigProvider.class);
when(provider.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true))
.thenReturn("test-project");
when(provider.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true)).thenReturn("test-project");
SecretManagerServiceClient mock = mock(SecretManagerServiceClient.class);
SecretManagerServiceClient.ListSecretsPagedResponse response = mock(
SecretManagerServiceClient.ListSecretsPagedResponse.class);
Secret secret = Secret.newBuilder().setName("projects/test-project/secrets/test")
.build();
Secret secret = Secret.newBuilder().setName("projects/test-project/secrets/test").build();
List<Secret> secrets = new ArrayList<Secret>();
secrets.add(secret);
when(response.iterateAll()).thenReturn(secrets);
Mockito.doReturn(response).when(mock).listSecrets(any(ListSecretsRequest.class));
GoogleSecretManagerV1AccessStrategy strategy = new GoogleSecretManagerV1AccessStrategy(
rest, provider, mock);
GoogleSecretManagerV1AccessStrategy strategy = new GoogleSecretManagerV1AccessStrategy(rest, provider, mock);
assertThat(strategy.getSecrets().size()).isEqualTo(1);
}
@@ -91,27 +88,21 @@ public class GoogleSecretManagerEnvironmentRepositoryTests {
public void testGetSecretValues() throws IOException {
RestTemplate rest = mock(RestTemplate.class);
GoogleConfigProvider provider = mock(HttpHeaderGoogleConfigProvider.class);
when(provider.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true))
.thenReturn("test-project");
when(provider.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true)).thenReturn("test-project");
SecretManagerServiceClient mock = mock(SecretManagerServiceClient.class);
SecretManagerServiceClient.ListSecretVersionsPagedResponse response = mock(
SecretManagerServiceClient.ListSecretVersionsPagedResponse.class);
SecretVersion secret1 = SecretVersion.newBuilder()
.setName("projects/test-project/secrets/test/versions/1")
SecretVersion secret1 = SecretVersion.newBuilder().setName("projects/test-project/secrets/test/versions/1")
.setState(SecretVersion.State.ENABLED).build();
SecretVersion secret2 = SecretVersion.newBuilder()
.setName("projects/test-project/secrets/test/versions/2")
SecretVersion secret2 = SecretVersion.newBuilder().setName("projects/test-project/secrets/test/versions/2")
.setState(SecretVersion.State.DISABLED).build();
List<SecretVersion> secrets = new ArrayList<SecretVersion>();
secrets.add(secret1);
secrets.add(secret2);
when(response.iterateAll()).thenReturn(secrets);
Mockito.doReturn(response).when(mock)
.listSecretVersions(any(ListSecretVersionsRequest.class));
GoogleSecretManagerV1AccessStrategy strategy = new GoogleSecretManagerV1AccessStrategy(
rest, provider, mock);
AccessSecretVersionResponse accessSecretVersionResponse = mock(
AccessSecretVersionResponse.class);
Mockito.doReturn(response).when(mock).listSecretVersions(any(ListSecretVersionsRequest.class));
GoogleSecretManagerV1AccessStrategy strategy = new GoogleSecretManagerV1AccessStrategy(rest, provider, mock);
AccessSecretVersionResponse accessSecretVersionResponse = mock(AccessSecretVersionResponse.class);
SecretPayload payload = mock(SecretPayload.class);
ByteString data = mock(ByteString.class);
when(accessSecretVersionResponse.getPayload()).thenReturn(payload);
@@ -119,19 +110,15 @@ public class GoogleSecretManagerEnvironmentRepositoryTests {
when(data.toStringUtf8()).thenReturn("test-value");
ArgumentMatcher<AccessSecretVersionRequest> matcher = new ArgumentMatcher<AccessSecretVersionRequest>() {
@Override
public boolean matches(
AccessSecretVersionRequest accessSecretVersionRequest) {
if (accessSecretVersionRequest.getName()
.equals("projects/test-project/secrets/test/versions/1")) {
public boolean matches(AccessSecretVersionRequest accessSecretVersionRequest) {
if (accessSecretVersionRequest.getName().equals("projects/test-project/secrets/test/versions/1")) {
return true;
}
return false;
}
};
Mockito.doReturn(accessSecretVersionResponse).when(mock)
.accessSecretVersion(ArgumentMatchers.argThat(matcher));
assertThat(strategy.getSecretValue(
Secret.newBuilder().setName("projects/test-project/secrets/test").build(),
Mockito.doReturn(accessSecretVersionResponse).when(mock).accessSecretVersion(ArgumentMatchers.argThat(matcher));
assertThat(strategy.getSecretValue(Secret.newBuilder().setName("projects/test-project/secrets/test").build(),
new GoogleSecretComparatorByVersion())).isEqualTo("test-value");
}