Added support for Vault's 0.10.0+ versioning enabled kv engine. (#1018)
This commit is contained in:
committed by
Ryan Baxter
parent
b10135c1ee
commit
e6b2d9eec0
@@ -546,12 +546,17 @@ The following table describes configurable Vault properties:
|
||||
|profileSeparator
|
||||
|,
|
||||
|
||||
|kvVersion
|
||||
|1
|
||||
|
||||
|===
|
||||
|
||||
IMPORTANT: All of the properties in the preceding table must be prefixed with `spring.cloud.config.server.vault`.
|
||||
|
||||
All configurable properties can be found in `org.springframework.cloud.config.server.environment.VaultEnvironmentRepository`.
|
||||
|
||||
Vault 0.10.0 introduced a versioned key-value backend (k/v backend version 2) that exposes a different API than earlier versions, it now requires a `data/` between the mount path and the actual context path and wraps secrets in a `data` object. Setting `kvVersion=2` will take this into account.
|
||||
|
||||
With your config server running, you can make HTTP requests to the server to retrieve
|
||||
values from the Vault backend.
|
||||
To do so, you need a token for your Vault server.
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
* @author Haroun Pacquee
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.vault")
|
||||
public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProperties {
|
||||
@@ -52,6 +53,10 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp
|
||||
private Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxy = new HashMap<>();
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
/**
|
||||
* Value to indicate which version of Vault kv backend is used. Defaults to 1.
|
||||
*/
|
||||
private int kvVersion = 1;
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
@@ -127,4 +132,12 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getKvVersion() {
|
||||
return kvVersion;
|
||||
}
|
||||
|
||||
public void setKvVersion(int kvVersion) {
|
||||
this.kvVersion = kvVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,25 +26,15 @@ import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonRawValue;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
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.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.springframework.cloud.config.client.ConfigClientProperties.STATE_HEADER;
|
||||
@@ -53,6 +43,7 @@ import static org.springframework.cloud.config.client.ConfigClientProperties.TOK
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Mark Paluch
|
||||
* @author Haroun Pacquee
|
||||
*/
|
||||
@Validated
|
||||
public class VaultEnvironmentRepository implements EnvironmentRepository, Ordered {
|
||||
@@ -84,18 +75,18 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
|
||||
private int order;
|
||||
|
||||
private RestTemplate rest;
|
||||
private VaultKvAccessStrategy accessStrategy;
|
||||
|
||||
// TODO: move to watchState:String on findOne?
|
||||
private ObjectProvider<HttpServletRequest> request;
|
||||
|
||||
private EnvironmentWatch watch;
|
||||
|
||||
public VaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch, RestTemplate rest,
|
||||
VaultEnvironmentProperties properties) {
|
||||
public VaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request,
|
||||
EnvironmentWatch watch, RestTemplate rest,
|
||||
VaultEnvironmentProperties properties) {
|
||||
this.request = request;
|
||||
this.watch = watch;
|
||||
this.rest = rest;
|
||||
this.backend = properties.getBackend();
|
||||
this.defaultKey = properties.getDefaultKey();
|
||||
this.host = properties.getHost();
|
||||
@@ -103,6 +94,11 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
this.port = properties.getPort();
|
||||
this.profileSeparator = properties.getProfileSeparator();
|
||||
this.scheme = properties.getScheme();
|
||||
|
||||
String baseUrl = String.format("%s://%s:%s", this.scheme, this.host, this.port);
|
||||
|
||||
this.accessStrategy = VaultKvAccessStrategyFactory.forVersion(rest, baseUrl,
|
||||
properties.getKvVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,7 +168,6 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
}
|
||||
|
||||
String read(HttpServletRequest servletRequest, String key) {
|
||||
String url = String.format("%s://%s:%s/v1/{backend}/{key}", this.scheme, this.host, this.port);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
@@ -181,22 +176,7 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
throw new IllegalArgumentException("Missing required header: " + TOKEN_HEADER);
|
||||
}
|
||||
headers.add(VAULT_TOKEN, token);
|
||||
try {
|
||||
ResponseEntity<VaultResponse> response = this.rest.exchange(url, HttpMethod.GET, new HttpEntity<>(headers),
|
||||
VaultResponse.class, this.backend, key);
|
||||
|
||||
HttpStatus status = response.getStatusCode();
|
||||
if (status == HttpStatus.OK) {
|
||||
return response.getBody().getData();
|
||||
}
|
||||
} catch (HttpStatusCodeException e) {
|
||||
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return null;
|
||||
return accessStrategy.getData(headers, backend, key);
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
@@ -231,64 +211,4 @@ public class VaultEnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
static class VaultResponse {
|
||||
|
||||
private String auth;
|
||||
|
||||
private Object data;
|
||||
|
||||
@JsonProperty("lease_duration")
|
||||
private long leaseDuration;
|
||||
|
||||
@JsonProperty("lease_id")
|
||||
private String leaseId;
|
||||
|
||||
private boolean renewable;
|
||||
|
||||
public VaultResponse() {
|
||||
}
|
||||
|
||||
public String getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
public void setAuth(String auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
@JsonRawValue
|
||||
public String getData() {
|
||||
return data == null ? null : data.toString();
|
||||
}
|
||||
|
||||
public void setData(JsonNode data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public long getLeaseDuration() {
|
||||
return leaseDuration;
|
||||
}
|
||||
|
||||
public void setLeaseDuration(long leaseDuration) {
|
||||
this.leaseDuration = leaseDuration;
|
||||
}
|
||||
|
||||
public String getLeaseId() {
|
||||
return leaseId;
|
||||
}
|
||||
|
||||
public void setLeaseId(String leaseId) {
|
||||
this.leaseId = leaseId;
|
||||
}
|
||||
|
||||
public boolean isRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
|
||||
public void setRenewable(boolean renewable) {
|
||||
this.renewable = renewable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
/**
|
||||
* Strategy interface to obtain secrets from Vault's key-value secret backend.
|
||||
* @author Haroun Pacquee
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface VaultKvAccessStrategy {
|
||||
|
||||
/**
|
||||
* Return secrets from Vault. The response is represented as JSON object marshaled to
|
||||
* {@link String}.
|
||||
* @param headers must not be {@literal null}.
|
||||
* @param backend secret backend mount path, must not be {@literal null}.
|
||||
* @param key key within the key-value secret backend, must not be {@literal null}.
|
||||
* @return the marshaled JSON object or {@literal null} if the key was not found.
|
||||
* @throws RestClientException in case of a transport/access failure.
|
||||
* @see com.fasterxml.jackson.annotation.JsonRawValue
|
||||
*/
|
||||
String getData(HttpHeaders headers, String backend, String key)
|
||||
throws RestClientException;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class VaultResponse {
|
||||
|
||||
private String auth;
|
||||
|
||||
private Object data;
|
||||
|
||||
@JsonProperty("lease_duration")
|
||||
private long leaseDuration;
|
||||
|
||||
@JsonProperty("lease_id")
|
||||
private String leaseId;
|
||||
|
||||
private boolean renewable;
|
||||
|
||||
public VaultResponse() {
|
||||
}
|
||||
|
||||
public String getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
public void setAuth(String auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(JsonNode data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public long getLeaseDuration() {
|
||||
return leaseDuration;
|
||||
}
|
||||
|
||||
public void setLeaseDuration(long leaseDuration) {
|
||||
this.leaseDuration = leaseDuration;
|
||||
}
|
||||
|
||||
public String getLeaseId() {
|
||||
return leaseId;
|
||||
}
|
||||
|
||||
public void setLeaseId(String leaseId) {
|
||||
this.leaseId = leaseId;
|
||||
}
|
||||
|
||||
public boolean isRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
|
||||
public void setRenewable(boolean renewable) {
|
||||
this.renewable = renewable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Factory for {@link VaultKvAccessStrategy}.
|
||||
* @author Haroun Pacquee
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class VaultKvAccessStrategyFactory {
|
||||
|
||||
/**
|
||||
* Create a new {@link VaultKvAccessStrategy} given {@link RestOperations},
|
||||
* {@code baseUrl}, and {@code version}.
|
||||
* @param rest must not be {@literal null}.
|
||||
* @param baseUrl the Vault base URL.
|
||||
* @param version version of the Vault key-value backend.
|
||||
* @return the access strategy.
|
||||
*/
|
||||
public static VaultKvAccessStrategy forVersion(RestOperations rest, String baseUrl,
|
||||
int version) {
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
return new V1VaultKvAccessStrategy(baseUrl, rest);
|
||||
case 2:
|
||||
return new V2VaultKvAccessStrategy(baseUrl, rest);
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"No support for given Vault k/v backend version " + version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy for the key-value backend API version 1.
|
||||
*/
|
||||
static class V1VaultKvAccessStrategy extends VaultKvAccessStrategySupport {
|
||||
|
||||
V1VaultKvAccessStrategy(String baseUrl, RestOperations rest) {
|
||||
super(baseUrl, rest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "/v1/{backend}/{key}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extractDataFromBody(VaultResponse body) {
|
||||
return body.getData() == null ? null : body.getData().toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy for the key-value backend API version 2.
|
||||
*/
|
||||
static class V2VaultKvAccessStrategy extends VaultKvAccessStrategySupport {
|
||||
|
||||
V2VaultKvAccessStrategy(String baseUrl, RestOperations rest) {
|
||||
super(baseUrl, rest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "/v1/{backend}/data/{key}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extractDataFromBody(VaultResponse body) {
|
||||
JsonNode nestedDataNode = body.getData() == null ? null
|
||||
: ((JsonNode) body.getData()).get("data");
|
||||
return nestedDataNode == null ? null : nestedDataNode.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Base class for {@link VaultKvAccessStrategy} implementors.
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class VaultKvAccessStrategySupport implements VaultKvAccessStrategy {
|
||||
|
||||
private final String baseUrl;
|
||||
private final RestOperations rest;
|
||||
|
||||
VaultKvAccessStrategySupport(String baseUrl, RestOperations rest) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.rest = rest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the context path to append to the {@code baseUrl}.
|
||||
*/
|
||||
abstract String getPath();
|
||||
|
||||
/**
|
||||
* Extract the raw JSON from the
|
||||
* {@link org.springframework.cloud.config.server.environment.VaultKvAccessStrategy.VaultResponse}.
|
||||
* @param body
|
||||
* @return
|
||||
*/
|
||||
abstract String extractDataFromBody(VaultResponse body);
|
||||
|
||||
/**
|
||||
* @param headers must not be {@literal null}.
|
||||
* @param backend secret backend mount path, must not be {@literal null}.
|
||||
* @param key key within the key-value secret backend, must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getData(HttpHeaders headers, String backend, String key) {
|
||||
try {
|
||||
ResponseEntity<VaultResponse> response = rest.exchange(baseUrl + getPath(),
|
||||
HttpMethod.GET, new HttpEntity<>(headers), VaultResponse.class,
|
||||
backend, key);
|
||||
HttpStatus status = response.getStatusCode();
|
||||
if (status == HttpStatus.OK) {
|
||||
return extractDataFromBody(response.getBody());
|
||||
}
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,26 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepository.VaultResponse;
|
||||
import org.springframework.cloud.config.server.environment.VaultKvAccessStrategy.VaultResponse;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -18,7 +28,12 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -27,11 +42,16 @@ import static org.mockito.Mockito.when;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Ryan Baxter
|
||||
* @author Haroun Pacquee
|
||||
*/
|
||||
public class VaultEnvironmentRepositoryTests {
|
||||
|
||||
@Before
|
||||
public void init() {}
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ObjectProvider<HttpServletRequest> mockProvide(HttpServletRequest request) {
|
||||
@@ -199,4 +219,52 @@ public class VaultEnvironmentRepositoryTests {
|
||||
new EnvironmentWatch.Default(), rest, new VaultEnvironmentProperties());
|
||||
repo.findOne("myapp", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testVaultVersioning() {
|
||||
MockHttpServletRequest configRequest = new MockHttpServletRequest();
|
||||
configRequest.addHeader("X-CONFIG-TOKEN", "mytoken");
|
||||
|
||||
RestTemplate rest = mock(RestTemplate.class);
|
||||
|
||||
ResponseEntity<VaultResponse> myAppResp = mock(ResponseEntity.class);
|
||||
when(myAppResp.getStatusCode()).thenReturn(HttpStatus.OK);
|
||||
VaultResponse myAppVaultResp = getVaultResponse("{\"data\": {\"data\": {\"foo\": \"bar\"}}}");
|
||||
when(myAppResp.getBody()).thenReturn(myAppVaultResp);
|
||||
when(rest.exchange(eq("http://127.0.0.1:8200/v1/{backend}/data/{key}"),
|
||||
eq(HttpMethod.GET), any(HttpEntity.class), eq(VaultResponse.class),
|
||||
eq("secret"), eq("myapp"))).thenReturn(myAppResp);
|
||||
|
||||
ResponseEntity<VaultResponse> appResp = mock(ResponseEntity.class);
|
||||
when(appResp.getStatusCode()).thenReturn(HttpStatus.OK);
|
||||
VaultResponse appVaultResp = getVaultResponse("{\"data\": {\"data\": {\"def-foo\":\"def-bar\"}}}");
|
||||
when(appResp.getBody()).thenReturn(appVaultResp);
|
||||
when(rest.exchange(eq("http://127.0.0.1:8200/v1/{backend}/data/{key}"),
|
||||
eq(HttpMethod.GET), any(HttpEntity.class), eq(VaultResponse.class),
|
||||
eq("secret"), eq("application"))).thenReturn(appResp);
|
||||
|
||||
final VaultEnvironmentProperties vaultEnvironmentProperties = new VaultEnvironmentProperties();
|
||||
vaultEnvironmentProperties.setKvVersion(2);
|
||||
VaultEnvironmentRepository repo = new VaultEnvironmentRepository(mockProvide(configRequest),
|
||||
new EnvironmentWatch.Default(), rest, vaultEnvironmentProperties);
|
||||
|
||||
Environment e = repo.findOne("myapp", null, null);
|
||||
assertEquals("Name should be the same as the application argument", "myapp", e.getName());
|
||||
assertEquals("Properties for specified application and default application with key 'application' should be returned",
|
||||
2, e.getPropertySources().size());
|
||||
Map<String, String> firstResult = new HashMap<String, String>();
|
||||
firstResult.put("foo", "bar");
|
||||
assertEquals("Properties for specified application should be returned in priority position",
|
||||
firstResult, e.getPropertySources().get(0).getSource());
|
||||
}
|
||||
|
||||
private VaultResponse getVaultResponse(String json) {
|
||||
try {
|
||||
return objectMapper.readValue(json, VaultResponse.class);
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cloud.config.server.environment.VaultKvAccessStrategyFactory.V1VaultKvAccessStrategy;
|
||||
import org.springframework.cloud.config.server.environment.VaultKvAccessStrategyFactory.V2VaultKvAccessStrategy;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Haroun Pacquee
|
||||
*/
|
||||
public class VaultKvAccessStrategyFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testGetV1Strategy() {
|
||||
VaultKvAccessStrategy vaultKvAccessStrategy = VaultKvAccessStrategyFactory
|
||||
.forVersion(null, "foo", 1);
|
||||
assertTrue(vaultKvAccessStrategy instanceof V1VaultKvAccessStrategy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetV2Strategy() {
|
||||
VaultKvAccessStrategy vaultKvAccessStrategy = VaultKvAccessStrategyFactory
|
||||
.forVersion(null, "foo", 2);
|
||||
assertTrue(vaultKvAccessStrategy instanceof V2VaultKvAccessStrategy);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetUnsupportedStrategy() {
|
||||
VaultKvAccessStrategyFactory.forVersion(null, "foo", 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cloud.config.server.environment.VaultKvAccessStrategy.VaultResponse;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Haroun Pacquee
|
||||
*/
|
||||
public class VaultKvAccessStrategyTest {
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static final String FOO_BAR = "{\"foo\":\"bar\"}";
|
||||
|
||||
@Test
|
||||
public void testV1ExtractFromBody() {
|
||||
String json = "{\"data\": {\"foo\": \"bar\"}}";
|
||||
String s = getStrategy(1).extractDataFromBody(getVaultResponse(json));
|
||||
assertThat(s, is(FOO_BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV1ExtractFromBodyNoData() {
|
||||
String json = "{}";
|
||||
String s = getStrategy(1).extractDataFromBody(getVaultResponse(json));
|
||||
assertNull(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2ExtractFromBody() {
|
||||
String json = "{\"data\": {\"data\": {\"foo\": \"bar\"}}}";
|
||||
String s = getStrategy(2).extractDataFromBody(getVaultResponse(json));
|
||||
assertThat(s, is(FOO_BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2ExtractFromBodyEmptyNestedData() {
|
||||
String json = "{\"data\": {}}";
|
||||
String s = getStrategy(2).extractDataFromBody(getVaultResponse(json));
|
||||
assertNull(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2ExtractFromBodyNoData() {
|
||||
String json = "{}";
|
||||
String s = getStrategy(2).extractDataFromBody(getVaultResponse(json));
|
||||
assertNull(s);
|
||||
}
|
||||
|
||||
private VaultResponse getVaultResponse(String json) {
|
||||
try {
|
||||
return objectMapper.readValue(json, VaultResponse.class);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static VaultKvAccessStrategySupport getStrategy(int version) {
|
||||
return (VaultKvAccessStrategySupport) VaultKvAccessStrategyFactory
|
||||
.forVersion(null, "foo", version);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user