Factor out encryption into a repository (not controller)

This commit is contained in:
Dave Syer
2015-10-01 10:02:38 +01:00
parent 309d1fbfbc
commit b024788be9
11 changed files with 217 additions and 96 deletions

View File

@@ -19,7 +19,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -32,7 +31,6 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.bind.PropertiesConfigurationFactory;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.encryption.EnvironmentEncryptor;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.http.HttpHeaders;
@@ -66,23 +64,10 @@ public class EnvironmentController {
private EnvironmentRepository repository;
private EnvironmentEncryptor environmentEncryptor;
private String defaultLabel;
private Map<String, String> overrides = new LinkedHashMap<>();
private boolean stripDocument = true;
public EnvironmentController(EnvironmentRepository repository) {
this(repository, null);
}
public EnvironmentController(EnvironmentRepository repository,
EnvironmentEncryptor environmentEncryptor) {
this.repository = repository;
this.defaultLabel = repository.getDefaultLabel();
this.environmentEncryptor = environmentEncryptor;
}
/**
@@ -98,14 +83,14 @@ public class EnvironmentController {
@RequestMapping("/{name}/{profiles:.*[^-].*}")
public Environment defaultLabel(@PathVariable String name,
@PathVariable String profiles) {
return labelled(name, profiles, this.defaultLabel);
return labelled(name, profiles, this.repository.getDefaultLabel());
}
@RequestMapping("/{name}/{profiles}/{label:.*}")
public Environment labelled(@PathVariable String name, @PathVariable String profiles,
@PathVariable String label) {
if (label == null) {
label = this.defaultLabel;
label = this.repository.getDefaultLabel();
}
if (label != null && label.contains("(_)")) {
// "(_)" is uncommon in a git branch name, but "/" cannot be matched
@@ -113,19 +98,13 @@ public class EnvironmentController {
label = label.replace("(_)", "/");
}
Environment environment = this.repository.findOne(name, profiles, label);
if (this.environmentEncryptor != null) {
environment = this.environmentEncryptor.decrypt(environment);
}
if (!this.overrides.isEmpty()) {
environment.addFirst(new PropertySource("overrides", this.overrides));
}
return environment;
}
@RequestMapping("/{name}-{profiles}.properties")
public ResponseEntity<String> properties(@PathVariable String name,
@PathVariable String profiles) throws IOException {
return labelledProperties(name, profiles, this.defaultLabel);
return labelledProperties(name, profiles, this.repository.getDefaultLabel());
}
@RequestMapping("/{label}/{name}-{profiles}.properties")
@@ -141,7 +120,7 @@ public class EnvironmentController {
@RequestMapping("{name}-{profiles}.json")
public ResponseEntity<Map<String, Object>> jsonProperties(@PathVariable String name,
@PathVariable String profiles) throws Exception {
return labelledJsonProperties(name, profiles, this.defaultLabel);
return labelledJsonProperties(name, profiles, this.repository.getDefaultLabel());
}
@RequestMapping("/{label}/{name}-{profiles}.json")
@@ -168,7 +147,7 @@ public class EnvironmentController {
@RequestMapping({ "/{name}-{profiles}.yml", "/{name}-{profiles}.yaml" })
public ResponseEntity<String> yaml(@PathVariable String name,
@PathVariable String profiles) throws Exception {
return labelledYaml(name, profiles, this.defaultLabel);
return labelledYaml(name, profiles, this.repository.getDefaultLabel());
}
@RequestMapping({ "/{label}/{name}-{profiles}.yml",
@@ -314,23 +293,4 @@ public class EnvironmentController {
}
}
/**
* @param defaultLabel
*/
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
}
/**
* @param overrides the overrides to set
*/
public void setOverrides(Map<String, String> overrides) {
this.overrides = new HashMap<String, String>(overrides);
for (String key : overrides.keySet()) {
if (overrides.get(key).contains("$\\{")) {
this.overrides.put(key, overrides.get(key).replace("$\\{", "${"));
}
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2015 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;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.encryption.EnvironmentEncryptor;
/**
* A delegating {@link EnvironmentRepository} that can decrypt the properties if an
* {@link EnvironmentEncryptor} is provided.
*
* @author Dave Syer
*
*/
public class EnvironmentEncryptorEnvironmentRepository implements EnvironmentRepository {
private EnvironmentRepository delegate;
private EnvironmentEncryptor environmentEncryptor;
private Map<String, String> overrides = new LinkedHashMap<>();
public EnvironmentEncryptorEnvironmentRepository(EnvironmentRepository delegate) {
this(delegate, null);
}
public EnvironmentEncryptorEnvironmentRepository(EnvironmentRepository delegate,
EnvironmentEncryptor environmentEncryptor) {
this.delegate = delegate;
this.environmentEncryptor = environmentEncryptor;
}
@Override
public String getDefaultLabel() {
return this.delegate.getDefaultLabel();
}
@Override
public Environment findOne(String name, String profiles, String label) {
if (label == null) {
label = getDefaultLabel();
}
Environment environment = this.delegate.findOne(name, profiles, label);
if (this.environmentEncryptor != null) {
environment = this.environmentEncryptor.decrypt(environment);
}
if (!this.overrides.isEmpty()) {
environment.addFirst(new PropertySource("overrides", this.overrides));
}
return environment;
}
/**
* @param overrides the overrides to set
*/
public void setOverrides(Map<String, String> overrides) {
this.overrides = new HashMap<String, String>(overrides);
for (String key : overrides.keySet()) {
if (overrides.get(key).contains("$\\{")) {
this.overrides.put(key, overrides.get(key).replace("$\\{", "${"));
}
}
}
}

View File

@@ -74,6 +74,8 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
private JGitEnvironmentRepository.JGitFactory gitFactory = new JGitEnvironmentRepository.JGitFactory();
private String defaultLabel = DEFAULT_LABEL;
public JGitEnvironmentRepository(ConfigurableEnvironment environment) {
super(environment);
}
@@ -104,7 +106,11 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
@Override
public String getDefaultLabel() {
return DEFAULT_LABEL;
return this.defaultLabel;
}
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
}
@Override

View File

@@ -50,12 +50,12 @@ public class ResourceController {
private ResourceRepository resourceRepository;
private EnvironmentController environmentController;
private EnvironmentRepository environmentRepository;
public ResourceController(ResourceRepository resourceRepository,
EnvironmentController environmentController) {
EnvironmentRepository environmentRepository) {
this.resourceRepository = resourceRepository;
this.environmentController = environmentController;
this.environmentRepository = environmentRepository;
}
@RequestMapping("/{name}/{profile}/{label}/{path:.*}")
@@ -66,7 +66,7 @@ public class ResourceController {
environment.getPropertySources().addAfter(
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
new EnvironmentPropertySource(
this.environmentController.labelled(name, profile, label)));
this.environmentRepository.findOne(name, profile, label)));
String text = StreamUtils.copyToString(
this.resourceRepository.findOne(name, profile, label, path).getInputStream(),
Charset.forName("UTF-8"));

View File

@@ -48,9 +48,15 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
private static final String DEFAULT_LABEL = "trunk";
private String defaultLabel = DEFAULT_LABEL;
@Override
public String getDefaultLabel() {
return DEFAULT_LABEL;
return this.defaultLabel ;
}
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
}
@Override

View File

@@ -19,13 +19,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.cloud.config.server.ConfigServerProperties;
import org.springframework.cloud.config.server.EnvironmentController;
import org.springframework.cloud.config.server.EnvironmentEncryptorEnvironmentRepository;
import org.springframework.cloud.config.server.EnvironmentRepository;
import org.springframework.cloud.config.server.ResourceController;
import org.springframework.cloud.config.server.ResourceRepository;
import org.springframework.cloud.config.server.encryption.EnvironmentEncryptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
/**
* @author Dave Syer
@@ -48,25 +48,20 @@ public class ConfigServerMvcConfiguration {
@Bean
public EnvironmentController environmentController() {
EnvironmentController controller = new EnvironmentController(this.repository, this.environmentEncryptor);
controller.setDefaultLabel(getDefaultLabel());
controller.setOverrides(this.server.getOverrides());
EnvironmentController controller = new EnvironmentController(encrypted());
controller.setStripDocumentFromYaml(this.server.isStripDocumentFromYaml());
return controller;
}
@Bean
public ResourceController resourceController() {
ResourceController controller = new ResourceController(this.resources, environmentController());
ResourceController controller = new ResourceController(this.resources, encrypted());
return controller;
}
private String getDefaultLabel() {
if (StringUtils.hasText(this.server.getDefaultLabel())) {
return this.server.getDefaultLabel();
}
else {
return this.repository.getDefaultLabel();
}
private EnvironmentEncryptorEnvironmentRepository encrypted() {
EnvironmentEncryptorEnvironmentRepository encrypted = new EnvironmentEncryptorEnvironmentRepository(this.repository, this.environmentEncryptor);
encrypted.setOverrides(this.server.getOverrides());
return encrypted;
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.StringUtils;
/**
* @author Dave Syer
@@ -45,6 +46,22 @@ public class EnvironmentRepositoryConfiguration {
return new ConfigServerHealthIndicator(repository);
}
protected static class BaseRepositoryConfiguration {
@Autowired
private ConfigServerProperties server;
protected String getDefaultLabel(EnvironmentRepository repository) {
if (StringUtils.hasText(this.server.getDefaultLabel())) {
return this.server.getDefaultLabel();
}
else {
return repository.getDefaultLabel();
}
}
}
@Configuration
@Profile("native")
protected static class NativeRepositoryConfiguration {
@@ -61,26 +78,30 @@ public class EnvironmentRepositoryConfiguration {
@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
protected static class GitRepositoryConfiguration {
protected static class GitRepositoryConfiguration extends BaseRepositoryConfiguration {
@Autowired
private ConfigurableEnvironment environment;
@Bean
public EnvironmentRepository environmentRepository() {
return new MultipleJGitEnvironmentRepository(this.environment);
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment);
repository.setDefaultLabel(getDefaultLabel(repository));
return repository;
}
}
@Configuration
@Profile("subversion")
protected static class SvnRepositoryConfiguration {
protected static class SvnRepositoryConfiguration extends BaseRepositoryConfiguration {
@Autowired
private ConfigurableEnvironment environment;
@Bean
public EnvironmentRepository environmentRepository() {
return new SvnKitEnvironmentRepository(this.environment);
SvnKitEnvironmentRepository repository = new SvnKitEnvironmentRepository(this.environment);
repository.setDefaultLabel(getDefaultLabel(repository));
return repository;
}
}

View File

@@ -26,7 +26,6 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.EnvironmentControllerIntegrationTests.ControllerConfiguration;
import org.springframework.cloud.config.server.encryption.CipherEnvironmentEncryptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -57,6 +56,7 @@ public class EnvironmentControllerIntegrationTests {
@Before
public void init() {
Mockito.reset(this.repository);
Mockito.when(this.repository.getDefaultLabel()).thenReturn("master");
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@@ -135,8 +135,7 @@ public class EnvironmentControllerIntegrationTests {
@Bean
public EnvironmentController controller() {
return new EnvironmentController(environmentRepository(),
new CipherEnvironmentEncryptor(null));
return new EnvironmentController(environmentRepository());
}
}

View File

@@ -30,7 +30,6 @@ import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.encryption.CipherEnvironmentEncryptor;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@@ -55,8 +54,7 @@ public class EnvironmentControllerTests {
@Before
public void init() {
Mockito.when(this.repository.getDefaultLabel()).thenReturn("master");
this.controller = new EnvironmentController(this.repository,
new CipherEnvironmentEncryptor(null));
this.controller = new EnvironmentController(this.repository);
}
@Test
@@ -256,26 +254,4 @@ public class EnvironmentControllerTests {
MockMvcResultMatchers.status().isBadRequest());
}
@Test
public void allowOverrideFalse() throws Exception {
this.controller.setOverrides(Collections.singletonMap("foo", "bar"));
Map<String, Object> map = new HashMap<String, Object>();
map.put("a.b.c", "d");
this.environment.add(new PropertySource("one", map));
Mockito.when(this.repository.findOne("foo", "bar", "master")).thenReturn(this.environment);
assertEquals("{foo=bar}", this.controller.defaultLabel("foo", "bar")
.getPropertySources().get(0).getSource().toString());
}
@Test
public void overrideWithEscapedPlaceholders() throws Exception {
this.controller.setOverrides(Collections.singletonMap("foo", "$\\{bar}"));
Map<String, Object> map = new HashMap<String, Object>();
map.put("bar", "foo");
this.environment.add(new PropertySource("one", map));
Mockito.when(this.repository.findOne("foo", "bar", "master")).thenReturn(this.environment);
assertEquals("{foo=${bar}}", this.controller.defaultLabel("foo", "bar")
.getPropertySources().get(0).getSource().toString());
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2013-2015 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;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
/**
* @author Dave Syer
* @author Roy Clarkson
*/
public class EnvironmentEncryptorEnvironmentRepositoryTests {
@Rule
public ExpectedException expected = ExpectedException.none();
private EnvironmentRepository repository = Mockito.mock(EnvironmentRepository.class);
private EnvironmentEncryptorEnvironmentRepository controller;
private Environment environment = new Environment("foo", "master");
@Before
public void init() {
Mockito.when(this.repository.getDefaultLabel()).thenReturn("master");
this.controller = new EnvironmentEncryptorEnvironmentRepository(this.repository);
}
@Test
public void allowOverrideFalse() throws Exception {
this.controller.setOverrides(Collections.singletonMap("foo", "bar"));
Map<String, Object> map = new HashMap<String, Object>();
map.put("a.b.c", "d");
this.environment.add(new PropertySource("one", map));
Mockito.when(this.repository.findOne("foo", "bar", "master")).thenReturn(this.environment);
assertEquals("{foo=bar}", this.controller.findOne("foo", "bar", "master")
.getPropertySources().get(0).getSource().toString());
}
@Test
public void overrideWithEscapedPlaceholders() throws Exception {
this.controller.setOverrides(Collections.singletonMap("foo", "$\\{bar}"));
Map<String, Object> map = new HashMap<String, Object>();
map.put("bar", "foo");
this.environment.add(new PropertySource("one", map));
Mockito.when(this.repository.findOne("foo", "bar", "master")).thenReturn(this.environment);
assertEquals("{foo=${bar}}", this.controller.findOne("foo", "bar", "master")
.getPropertySources().get(0).getSource().toString());
}
}

View File

@@ -51,7 +51,7 @@ public class ResourceControllerTests {
this.repository = new GenericResourceRepository(this.environmentRepository);
this.repository.setResourceLoader(this.context);
this.controller = new ResourceController(this.repository,
new EnvironmentController(this.environmentRepository));
this.environmentRepository);
this.context.close();
}