Added support for Vault's 0.10.0+ versioning enabled kv engine. (#1018)

This commit is contained in:
Haroun Pacquée
2018-06-04 23:13:27 +02:00
committed by Ryan Baxter
parent b10135c1ee
commit e6b2d9eec0
9 changed files with 502 additions and 100 deletions

View File

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

View File

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

View File

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