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 b4e7d94e..3933abfd 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 @@ -163,31 +163,34 @@ public class EnvironmentDecryptApplicationInitializer implements sources.add(0, source); } for (PropertySource source : sources) { - decrypt(source, overrides); + collectEncryptedProperties(source, overrides); } + + doDecrypt(overrides); return overrides; } private Map decrypt(PropertySource source) { Map overrides = new LinkedHashMap<>(); - decrypt(source, overrides); + collectEncryptedProperties(source, overrides); + doDecrypt(overrides); return overrides; } private static final Pattern COLLECTION_PROPERTY = Pattern .compile("(\\S+)?\\[(\\d+)\\](\\.\\S+)?"); - private void decrypt(PropertySource source, Map overrides) { + private void collectEncryptedProperties(PropertySource source, + Map overrides) { if (source instanceof CompositePropertySource) { for (PropertySource nested : ((CompositePropertySource) source) .getPropertySources()) { - decrypt(nested, overrides); + collectEncryptedProperties(nested, overrides); } - } - else if (source instanceof EnumerablePropertySource) { + } else if (source instanceof EnumerablePropertySource) { Map otherCollectionProperties = new LinkedHashMap<>(); boolean sourceHasDecryptedCollection = false; @@ -197,37 +200,16 @@ public class EnvironmentDecryptApplicationInitializer implements if (property != null) { String value = property.toString(); if (value.startsWith("{cipher}")) { - value = value.substring("{cipher}".length()); - try { - value = this.encryptor.decrypt(value); - if (logger.isDebugEnabled()) { - logger.debug("Decrypted: key=" + key); - } - } - catch (Exception e) { - String message = "Cannot decrypt: key=" + key; - if (this.failOnError) { - throw new IllegalStateException(message, e); - } - if (logger.isDebugEnabled()) { - logger.warn(message, e); - } - else { - logger.warn(message); - } - // Set value to empty to avoid making a password out of the - // cipher text - value = ""; - } overrides.put(key, value); if (COLLECTION_PROPERTY.matcher(key).matches()) { sourceHasDecryptedCollection = true; } - } - else if (COLLECTION_PROPERTY.matcher(key).matches()) { - // put non-ecrypted properties so merging of index properties + } else if (COLLECTION_PROPERTY.matcher(key).matches()) { + // put non-encrypted properties so merging of index properties // happens correctly otherCollectionProperties.put(key, value); + } else { + overrides.remove(key); } } } @@ -239,4 +221,35 @@ public class EnvironmentDecryptApplicationInitializer implements } } + private void doDecrypt(Map overrides) { + for (String key : overrides.keySet()) { + String value = overrides.get(key).toString(); + if (value.startsWith("{cipher}")) { + value = value.substring("{cipher}".length()); + try { + value = this.encryptor.decrypt(value); + if (logger.isDebugEnabled()) { + logger.debug("Decrypted: key=" + key); + } + } + catch (Exception e) { + String message = "Cannot decrypt: key=" + key; + if (this.failOnError) { + throw new IllegalStateException(message, e); + } + if (logger.isDebugEnabled()) { + logger.warn(message, e); + } + else { + logger.warn(message); + } + // Set value to empty to avoid making a password out of the + // cipher text + value = ""; + } + overrides.put(key, value); + } + } + } + } diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializerTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializerTests.java index b7ef9d68..54ac03a4 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializerTests.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializerTests.java @@ -38,6 +38,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.springframework.cloud.bootstrap.encrypt.EnvironmentDecryptApplicationInitializer.DECRYPTED_PROPERTY_SOURCE_NAME; @@ -78,6 +80,17 @@ public class EnvironmentDecryptApplicationInitializerTests { assertEquals("spam", context.getEnvironment().getProperty("foo")); } + @Test + public void propertySourcesOrderedCorrectlyWithUnencryptedOverrides() { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); + TestPropertyValues.of("foo: {cipher}bar").applyTo(context); + context.getEnvironment().getPropertySources() + .addFirst(new MapPropertySource("test_override", + Collections.singletonMap("foo", "spam"))); + this.listener.initialize(context); + assertEquals("spam", context.getEnvironment().getProperty("foo")); + } + @Test(expected = IllegalStateException.class) public void errorOnDecrypt() { this.listener = new EnvironmentDecryptApplicationInitializer( @@ -173,4 +186,22 @@ public class EnvironmentDecryptApplicationInitializerTests { initializer.initialize(ctx); assertEquals(expected, ctx.getEnvironment().getProperty("key")); } + + @Test + public void testOnlyDecryptIfNotOverridden() { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); + TextEncryptor encryptor = mock(TextEncryptor.class); + when(encryptor.decrypt("bar2")).thenReturn("bar2"); + EnvironmentDecryptApplicationInitializer initializer = new EnvironmentDecryptApplicationInitializer( + encryptor); + TestPropertyValues.of("foo: {cipher}bar", "foo2: {cipher}bar2").applyTo(context); + context.getEnvironment().getPropertySources() + .addFirst(new MapPropertySource("test_override", + Collections.singletonMap("foo", "spam"))); + initializer.initialize(context); + assertEquals("spam", context.getEnvironment().getProperty("foo")); + assertEquals("bar2", context.getEnvironment().getProperty("foo2")); + verify(encryptor).decrypt("bar2"); + verifyNoMoreInteractions(encryptor); + } }