diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializer.java b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializer.java index 2048bc5f..7691c51d 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializer.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializer.java @@ -15,7 +15,9 @@ */ package org.springframework.cloud.bootstrap.encrypt; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; @@ -38,7 +40,7 @@ import org.springframework.security.crypto.encrypt.TextEncryptor; /** * Decrypt properties from the environment and insert them with high priority so they * override the encrypted values. - * + * * @author Dave Syer * */ @@ -58,7 +60,7 @@ public class EnvironmentDecryptApplicationInitializer implements /** * Strategy to determine how to handle exceptions during decryption. - * + * * @param failOnError the flag value (default true) */ public void setFailOnError(boolean failOnError) { @@ -71,14 +73,15 @@ public class EnvironmentDecryptApplicationInitializer implements @Override public int getOrder() { - return order; + return this.order; } @Override public void initialize(ConfigurableApplicationContext applicationContext) { ConfigurableEnvironment environment = applicationContext.getEnvironment(); MapPropertySource decrypted = new MapPropertySource( - DECRYPTED_PROPERTY_SOURCE_NAME, decrypt(environment.getPropertySources())); + DECRYPTED_PROPERTY_SOURCE_NAME, + decrypt(environment.getPropertySources())); if (!decrypted.getSource().isEmpty()) { // We have some decrypted properties insert(environment.getPropertySources(), decrypted); @@ -91,8 +94,8 @@ public class EnvironmentDecryptApplicationInitializer implements // initialized, so we can fire an EnvironmentChangeEvent there to rebind // @ConfigurationProperties, in case they were encrypted. insert(mutable.getPropertySources(), decrypted); - parent.publishEvent(new EnvironmentChangeEvent(decrypted.getSource() - .keySet())); + parent.publishEvent( + new EnvironmentChangeEvent(decrypted.getSource().keySet())); } } } @@ -112,7 +115,11 @@ public class EnvironmentDecryptApplicationInitializer implements public Map decrypt(PropertySources propertySources) { Map overrides = new LinkedHashMap(); + List> sources = new ArrayList>(); for (PropertySource source : propertySources) { + sources.add(0, source); + } + for (PropertySource source : sources) { decrypt(source, overrides); } return overrides; @@ -128,14 +135,14 @@ public class EnvironmentDecryptApplicationInitializer implements if (value.startsWith("{cipher}")) { value = value.substring("{cipher}".length()); try { - value = encryptor.decrypt(value); + value = this.encryptor.decrypt(value); if (logger.isDebugEnabled()) { logger.debug("Decrypted: key=" + key); } } catch (Exception e) { String message = "Cannot decrypt: key=" + key; - if (failOnError) { + if (this.failOnError) { throw new IllegalStateException(message, e); } if (logger.isDebugEnabled()) { @@ -163,5 +170,5 @@ public class EnvironmentDecryptApplicationInitializer implements } } - + } diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationListenerTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationListenerTests.java index d9fb86ab..4e6ef446 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationListenerTests.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationListenerTests.java @@ -15,46 +15,63 @@ */ package org.springframework.cloud.bootstrap.encrypt; -import static org.junit.Assert.assertEquals; +import java.util.Collections; 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.security.crypto.encrypt.Encryptors; +import static org.junit.Assert.assertEquals; + /** * @author Dave Syer * */ public class EnvironmentDecryptApplicationListenerTests { - - private EnvironmentDecryptApplicationInitializer listener = new EnvironmentDecryptApplicationInitializer(Encryptors.noOpText()); + + private EnvironmentDecryptApplicationInitializer listener = new EnvironmentDecryptApplicationInitializer( + Encryptors.noOpText()); @Test public void decryptCipherKey() { ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar"); - listener.initialize(context); + this.listener.initialize(context); assertEquals("bar", context.getEnvironment().getProperty("foo")); } - @Test(expected=IllegalStateException.class) + @Test + public void propertySourcesOrderedCorrectly() { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar"); + context.getEnvironment().getPropertySources().addFirst(new MapPropertySource( + "test_override", + Collections. singletonMap("foo", "{cipher}spam"))); + this.listener.initialize(context); + assertEquals("spam", context.getEnvironment().getProperty("foo")); + } + + @Test(expected = IllegalStateException.class) public void errorOnDecrypt() { - listener = new EnvironmentDecryptApplicationInitializer(Encryptors.text("deadbeef", "AFFE37")); + this.listener = new EnvironmentDecryptApplicationInitializer( + Encryptors.text("deadbeef", "AFFE37")); ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar"); - listener.initialize(context); + this.listener.initialize(context); assertEquals("bar", context.getEnvironment().getProperty("foo")); } @Test public void errorOnDecryptWithEmpty() { - listener = new EnvironmentDecryptApplicationInitializer(Encryptors.text("deadbeef", "AFFE37")); - listener.setFailOnError(false); + this.listener = new EnvironmentDecryptApplicationInitializer( + Encryptors.text("deadbeef", "AFFE37")); + this.listener.setFailOnError(false); ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar"); - listener.initialize(context); + this.listener.initialize(context); // Empty is safest fallback for undecryptable cipher assertEquals("", context.getEnvironment().getProperty("foo")); }