diff --git a/docs/pom.xml b/docs/pom.xml
index ff6fb294..a03d8a2b 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -6,7 +6,7 @@
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
pom
Spring Cloud Config Docs
diff --git a/pom.xml b/pom.xml
index 70351dea..86b1f176 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
pom
Spring Cloud Config
Spring Cloud Config
@@ -11,7 +11,7 @@
org.springframework.cloud
spring-cloud-build
- 1.2.2.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
diff --git a/spring-cloud-config-client/pom.xml b/spring-cloud-config-client/pom.xml
index f27b03be..5817b46b 100644
--- a/spring-cloud-config-client/pom.xml
+++ b/spring-cloud-config-client/pom.xml
@@ -10,7 +10,7 @@
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
..
diff --git a/spring-cloud-config-dependencies/pom.xml b/spring-cloud-config-dependencies/pom.xml
index b479ae7b..6e038a8f 100644
--- a/spring-cloud-config-dependencies/pom.xml
+++ b/spring-cloud-config-dependencies/pom.xml
@@ -5,11 +5,11 @@
spring-cloud-dependencies-parent
org.springframework.cloud
- 1.2.2.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
spring-cloud-config-dependencies
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
pom
spring-cloud-config-dependencies
Spring Cloud Config Dependencies
@@ -35,6 +35,11 @@
spring-cloud-config-monitor
${project.version}
+
+ org.springframework.vault
+ spring-vault-core
+ 1.0.0.M1
+
org.eclipse.jgit
org.eclipse.jgit
diff --git a/spring-cloud-config-monitor/pom.xml b/spring-cloud-config-monitor/pom.xml
index e9b6dc67..e154b441 100644
--- a/spring-cloud-config-monitor/pom.xml
+++ b/spring-cloud-config-monitor/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
..
spring-cloud-config-monitor
diff --git a/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/FileMonitorConfiguration.java b/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/FileMonitorConfiguration.java
index 33afb6a2..20fb5393 100644
--- a/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/FileMonitorConfiguration.java
+++ b/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/FileMonitorConfiguration.java
@@ -39,6 +39,7 @@ import org.springframework.cloud.config.server.environment.NativeEnvironmentRepo
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpHeaders;
@@ -182,11 +183,13 @@ public class FileMonitorConfiguration implements SmartLifecycle, ResourceLoaderA
}
private Set getFileRepo() {
- if (this.scmRepository != null
- && this.scmRepository.getUri().startsWith("file:")) {
+ if (this.scmRepository != null) {
try {
- return Collections.singleton(Paths.get(this.resourceLoader
- .getResource(this.scmRepository.getUri()).getURI()));
+
+ Resource resource = this.resourceLoader.getResource(this.scmRepository.getUri());
+ if (resource instanceof FileSystemResource) {
+ return Collections.singleton(Paths.get(resource.getURI()));
+ }
}
catch (IOException e) {
log.error("Cannot resolve URI for path: " + this.scmRepository.getUri());
diff --git a/spring-cloud-config-sample/pom.xml b/spring-cloud-config-sample/pom.xml
index 5514e1bc..113c6933 100644
--- a/spring-cloud-config-sample/pom.xml
+++ b/spring-cloud-config-sample/pom.xml
@@ -12,7 +12,7 @@
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
..
diff --git a/spring-cloud-config-sample/src/test/java/sample/ApplicationTests.java b/spring-cloud-config-sample/src/test/java/sample/ApplicationTests.java
index 90cc3eec..91aeb8af 100644
--- a/spring-cloud-config-sample/src/test/java/sample/ApplicationTests.java
+++ b/spring-cloud-config-sample/src/test/java/sample/ApplicationTests.java
@@ -9,8 +9,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.LocalServerPort;
-import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -22,7 +22,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
@SpringBootTest(classes = Application.class,
// Normally spring.cloud.config.enabled:true is the default but since we have the config
// server on the classpath we need to set it explicitly
- properties = { "spring.cloud.config.enabled:true" }, webEnvironment = RANDOM_PORT)
+ properties = { "spring.cloud.config.enabled:true",
+ "management.security.enabled=false" }, webEnvironment = RANDOM_PORT)
public class ApplicationTests {
private static int configPort = 0;
diff --git a/spring-cloud-config-server/pom.xml b/spring-cloud-config-server/pom.xml
index 5b8752ed..311e1bb7 100644
--- a/spring-cloud-config-server/pom.xml
+++ b/spring-cloud-config-server/pom.xml
@@ -12,7 +12,7 @@
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
..
@@ -42,6 +42,11 @@
org.springframework.security
spring-security-rsa
+
+ org.springframework.vault
+ spring-vault-core
+ true
+
org.eclipse.jgit
org.eclipse.jgit
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepository.java
index e68b26a7..1fd69ecd 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepository.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepository.java
@@ -1,41 +1,62 @@
+/*
+ * Copyright 2013-2016 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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
-import com.fasterxml.jackson.annotation.JsonRawValue;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.JsonNode;
import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
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.web.client.HttpStatusCodeException;
+import org.springframework.vault.client.VaultClient;
+import org.springframework.vault.client.VaultEndpoint;
+import org.springframework.vault.client.VaultException;
+import org.springframework.vault.client.VaultResponseEntity;
+import org.springframework.vault.support.VaultResponseSupport;
+import org.springframework.vault.support.VaultToken;
import org.springframework.web.client.RestTemplate;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import static org.springframework.cloud.config.client.ConfigClientProperties.STATE_HEADER;
import static org.springframework.cloud.config.client.ConfigClientProperties.TOKEN_HEADER;
/**
* @author Spencer Gibb
+ * @author Mark Paluch
*/
@ConfigurationProperties("spring.cloud.config.server.vault")
-public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentRepository {
+public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentRepository
+ implements InitializingBean{
public static final String VAULT_TOKEN = "X-Vault-Token";
@@ -67,6 +88,7 @@ public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentReposi
private HttpServletRequest request;
private EnvironmentWatch watch;
+ private VaultClient client;
public VaultEnvironmentRepository(HttpServletRequest request, EnvironmentWatch watch, RestTemplate rest) {
this.request = request;
@@ -74,6 +96,11 @@ public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentReposi
this.rest = rest;
}
+ @Override
+ public void afterPropertiesSet() {
+ this.client = new VaultClient(rest, getVaultEndpoint());
+ }
+
@Override
public Environment findOne(String application, String profile, String label) {
@@ -136,34 +163,47 @@ public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentReposi
}
String read(String key) {
- String url = String.format("%s://%s:%s/v1/{backend}/{key}", this.scheme,
- this.host, this.port);
-
- HttpHeaders headers = new HttpHeaders();
String token = request.getHeader(TOKEN_HEADER);
if (!StringUtils.hasLength(token)) {
- throw new IllegalArgumentException("Missing required header: "+TOKEN_HEADER);
- }
- headers.add(VAULT_TOKEN, token);
- try {
- ResponseEntity 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;
+ throw new IllegalArgumentException("Missing required header: " + TOKEN_HEADER);
}
- return null;
+ VaultToken vaultToken = VaultToken.of(token);
+ VaultResponseEntity response = client.exchange("{backend}/{key}", HttpMethod.GET,
+ new HttpEntity<>(VaultClient.createHeaders(vaultToken)), VaultResponse.class, getUriVariables(key));
+
+ HttpStatus status = response.getStatusCode();
+
+ if (status == HttpStatus.OK) {
+
+ JsonNode data = response.getBody().getData();
+ return data != null ? data.toString() : null;
+ }
+
+ if (status == HttpStatus.NOT_FOUND) {
+ return null;
+ }
+
+ throw new VaultException(response.getMessage());
+ }
+
+ private Map getUriVariables(String key) {
+ Map uriVariables = new HashMap<>(2, 1);
+ uriVariables.put("backend", backend);
+ uriVariables.put("key", key);
+ return uriVariables;
+ }
+
+ private VaultEndpoint getVaultEndpoint() {
+
+ VaultEndpoint vaultEndpoint = new VaultEndpoint();
+
+ vaultEndpoint.setScheme(scheme);
+ vaultEndpoint.setHost(host);
+ vaultEndpoint.setPort(port);
+
+ return vaultEndpoint;
}
public void setHost(String host) {
@@ -195,61 +235,7 @@ public class VaultEnvironmentRepository extends AbstractOrderedEnvironmentReposi
super.setOrder(order);
}
- 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;
- }
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ static class VaultResponse extends VaultResponseSupport {
}
}
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/NativeConfigServerIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/NativeConfigServerIntegrationTests.java
index 084fdee0..0dadce1a 100644
--- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/NativeConfigServerIntegrationTests.java
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/NativeConfigServerIntegrationTests.java
@@ -7,8 +7,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.LocalServerPort;
-import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.http.HttpStatus;
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SubversionConfigServerIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SubversionConfigServerIntegrationTests.java
index 2e557aee..608fbe26 100644
--- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SubversionConfigServerIntegrationTests.java
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/SubversionConfigServerIntegrationTests.java
@@ -22,8 +22,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.LocalServerPort;
-import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.environment.SvnKitEnvironmentRepository;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepositoryTests.java
index a3962d85..9db71148 100644
--- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepositoryTests.java
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/VaultEnvironmentRepositoryTests.java
@@ -3,9 +3,12 @@ package org.springframework.cloud.config.server.environment;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
+import java.net.URI;
import java.util.HashMap;
import java.util.Map;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
@@ -16,13 +19,16 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriTemplateHandler;
/**
* @author Spencer Gibb
* @author Ryan Baxter
+ * @author Mark Paluch
*/
public class VaultEnvironmentRepositoryTests {
+ private ObjectMapper objectMapper = new ObjectMapper();
@Before
public void init() {}
@@ -33,22 +39,22 @@ public class VaultEnvironmentRepositoryTests {
configRequest.addHeader("X-CONFIG-TOKEN", "mytoken");
RestTemplate rest = Mockito.mock(RestTemplate.class);
ResponseEntity myAppResp = Mockito.mock(ResponseEntity.class);
+ Mockito.when(rest.getUriTemplateHandler()).thenReturn(new DefaultUriTemplateHandler());
Mockito.when(myAppResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse myAppVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
- Mockito.when(myAppVaultResp.getData()).thenReturn("{\"foo\":\"bar\"}");
+ Mockito.when(myAppVaultResp.getData()).thenReturn(asJsonNode("{\"foo\":\"bar\"}"));
Mockito.when(myAppResp.getBody()).thenReturn(myAppVaultResp);
- Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
- Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
- Mockito.eq("secret"), Mockito.eq("myapp"))).thenReturn(myAppResp);
+ Mockito.when(rest.exchange(Mockito.eq(URI.create("http://127.0.0.1:8200/v1/secret/myapp")),
+ Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class))).thenReturn(myAppResp);
ResponseEntity appResp = Mockito.mock(ResponseEntity.class);
Mockito.when(appResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse appVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
Mockito.when(appVaultResp.getData()).thenReturn(null);
Mockito.when(appResp.getBody()).thenReturn(appVaultResp);
- Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
- Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
- Mockito.eq("secret"), Mockito.eq("application"))).thenReturn(appResp);
+ Mockito.when(rest.exchange(Mockito.eq(URI.create("http://127.0.0.1:8200/v1/secret/application")),
+ Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class))).thenReturn(appResp);
VaultEnvironmentRepository repo = new VaultEnvironmentRepository(configRequest, new EnvironmentWatch.Default(), rest);
+ repo.afterPropertiesSet();
Environment e = repo.findOne("myapp", null, null);
assertEquals("myapp", e.getName());
Map result = new HashMap();
@@ -61,14 +67,24 @@ public class VaultEnvironmentRepositoryTests {
MockHttpServletRequest configRequest = new MockHttpServletRequest();
RestTemplate rest = Mockito.mock(RestTemplate.class);
ResponseEntity myAppResp = Mockito.mock(ResponseEntity.class);
+ Mockito.when(rest.getUriTemplateHandler()).thenReturn(new DefaultUriTemplateHandler());
Mockito.when(myAppResp.getStatusCode()).thenReturn(HttpStatus.OK);
VaultEnvironmentRepository.VaultResponse myAppVaultResp = Mockito.mock(VaultEnvironmentRepository.VaultResponse.class);
- Mockito.when(myAppVaultResp.getData()).thenReturn("{\"foo\":\"bar\"}");
+ Mockito.when(myAppVaultResp.getData()).thenReturn(asJsonNode("{\"foo\":\"bar\"}"));
Mockito.when(myAppResp.getBody()).thenReturn(myAppVaultResp);
Mockito.when(rest.exchange(Mockito.eq("http://127.0.0.1:8200/v1/{backend}/{key}"),
Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(VaultEnvironmentRepository.VaultResponse.class),
Mockito.eq("secret"), Mockito.eq("myapp"))).thenReturn(myAppResp);
VaultEnvironmentRepository repo = new VaultEnvironmentRepository(configRequest, new EnvironmentWatch.Default(), rest);
+ repo.afterPropertiesSet();
repo.findOne("myapp", null, null);
}
+
+ private JsonNode asJsonNode(String content) {
+ try {
+ return objectMapper.readTree(content);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
}
diff --git a/spring-cloud-starter-config/pom.xml b/spring-cloud-starter-config/pom.xml
index 9760a1c1..1a379652 100644
--- a/spring-cloud-starter-config/pom.xml
+++ b/spring-cloud-starter-config/pom.xml
@@ -5,10 +5,10 @@
org.springframework.cloud
spring-cloud-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
spring-cloud-starter-config
- 1.2.3.BUILD-SNAPSHOT
+ 1.3.0.BUILD-SNAPSHOT
spring-cloud-starter-config
Spring Cloud Starter
https://projects.spring.io/spring-cloud