Fixes indexed properties merging problem.

Given the following in one property source
```
mine[0].someValue=Foo
mine[0].someKey={cipher}XXXX
mine[1].someValue=Bar
mine[1].someKey={cipher}XXXX
yours[0].anotherKey=Baz
```
only `mine[*].someKey` were added to "decrypted" property source. Due to house spring boot manages indexed properties, they can not be merged across property source. This change includes all indexed properties in the "decrypted" property source if any one of them is encrypted.

In the above example, `yours[*].*` is included even though unrelated.

fixes gh-466
This commit is contained in:
Spencer Gibb
2016-09-09 14:23:19 -06:00
parent 23d3a2ec3d
commit e13764db66
2 changed files with 61 additions and 9 deletions

View File

@@ -16,15 +16,21 @@
package org.springframework.cloud.bootstrap.encrypt;
import java.util.Collections;
import java.util.Map;
import org.junit.Test;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.security.crypto.encrypt.Encryptors;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.springframework.boot.test.EnvironmentTestUtils.addEnvironment;
import static org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.DECRYPTED_PROPERTY_SOURCE_NAME;
/**
* @author Dave Syer
@@ -38,7 +44,7 @@ public class EnvironmentDecryptApplicationInitializerTests {
@Test
public void decryptCipherKey() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
addEnvironment(context, "foo: {cipher}bar");
this.listener.initialize(context);
assertEquals("bar", context.getEnvironment().getProperty("foo"));
}
@@ -46,7 +52,7 @@ public class EnvironmentDecryptApplicationInitializerTests {
@Test
public void relaxedBinding() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "FOO_TEXT: {cipher}bar");
addEnvironment(context, "FOO_TEXT: {cipher}bar");
this.listener.initialize(context);
assertEquals("bar", context.getEnvironment().getProperty("foo.text"));
}
@@ -54,7 +60,7 @@ public class EnvironmentDecryptApplicationInitializerTests {
@Test
public void propertySourcesOrderedCorrectly() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
addEnvironment(context, "foo: {cipher}bar");
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
"test_override",
Collections.<String, Object> singletonMap("foo", "{cipher}spam")));
@@ -67,7 +73,7 @@ public class EnvironmentDecryptApplicationInitializerTests {
this.listener = new EnvironmentDecryptApplicationInitializer(
Encryptors.text("deadbeef", "AFFE37"));
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
addEnvironment(context, "foo: {cipher}bar");
this.listener.initialize(context);
assertEquals("bar", context.getEnvironment().getProperty("foo"));
}
@@ -78,10 +84,35 @@ public class EnvironmentDecryptApplicationInitializerTests {
Encryptors.text("deadbeef", "AFFE37"));
this.listener.setFailOnError(false);
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
addEnvironment(context, "foo: {cipher}bar");
this.listener.initialize(context);
// Empty is safest fallback for undecryptable cipher
assertEquals("", context.getEnvironment().getProperty("foo"));
}
@Test
@SuppressWarnings("unchecked")
public void indexedPropertiesCopied() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
// tests that collections in another property source don't get copied into "decrypted" property source
addEnvironment(context, "yours[0].someValue: yourFoo", "yours[1].someValue: yourBar");
// collection with some encrypted keys and some not encrypted
addEnvironment("combinedTest", context.getEnvironment(), "mine[0].someValue: Foo",
"mine[0].someKey: {cipher}Foo0", "mine[1].someValue: Bar",
"mine[1].someKey: {cipher}Bar1", "nonindexed: nonindexval");
this.listener.initialize(context);
assertEquals("Foo", context.getEnvironment().getProperty("mine[0].someValue"));
assertEquals("Foo0", context.getEnvironment().getProperty("mine[0].someKey"));
assertEquals("Bar", context.getEnvironment().getProperty("mine[1].someValue"));
assertEquals("Bar1", context.getEnvironment().getProperty("mine[1].someKey"));
assertEquals("yourFoo", context.getEnvironment().getProperty("yours[0].someValue"));
assertEquals("yourBar", context.getEnvironment().getProperty("yours[1].someValue"));
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
PropertySource<Map> decrypted = (PropertySource<Map>) propertySources.get(DECRYPTED_PROPERTY_SOURCE_NAME);
assertThat("decrypted property source had wrong size", decrypted.getSource().size(), is(4));
}
}