Re-order initializers so bootstrap properties can be decrypted

The Environment only picks up the "bootstrap" property source when
the parent context is set, and that was happening at order=0. Moving
it to a higher order than the decryption initializer makes it possible
to decrypt properties in bootstrap.

Fixes gh-84
This commit is contained in:
Dave Syer
2015-02-13 09:52:58 +00:00
parent e28b137fb0
commit 32bc35b915
9 changed files with 75 additions and 25 deletions

View File

@@ -72,8 +72,8 @@ public class BootstrapApplicationListener implements
if (environment.getPropertySources().contains("bootstrapInProgress")) {
return;
}
ConfigurableApplicationContext context = bootstrapServiceContext(
environment, event.getSpringApplication());
ConfigurableApplicationContext context = bootstrapServiceContext(environment,
event.getSpringApplication());
apply(context, event.getSpringApplication(), environment);
}
@@ -189,8 +189,9 @@ public class BootstrapApplicationListener implements
public int getOrder() {
// Need to run not too late (so not unordered), so that, for instance, the
// ContextIdApplicationContextInitializer runs later and picks up the merged
// Environment
return 0;
// Environment. Also not too early so that other initializers can pick up the
// parent (especially the Environment).
return Ordered.HIGHEST_PRECEDENCE + 10;
}
@Override

View File

@@ -90,11 +90,11 @@ public class EncryptionBootstrapConfiguration {
}
@Bean
public EnvironmentDecryptApplicationListener environmentDecryptApplicationListener() {
public EnvironmentDecryptApplicationInitializer environmentDecryptApplicationListener() {
if (encryptor == null) {
encryptor = new FailsafeTextEncryptor();
}
EnvironmentDecryptApplicationListener listener = new EnvironmentDecryptApplicationListener(encryptor);
EnvironmentDecryptApplicationInitializer listener = new EnvironmentDecryptApplicationInitializer(encryptor);
listener.setFailOnError(key.isFailOnError());
return listener;
}

View File

@@ -20,7 +20,6 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
@@ -35,19 +34,19 @@ import org.springframework.security.crypto.encrypt.TextEncryptor;
* @author Dave Syer
*
*/
public class EnvironmentDecryptApplicationListener implements
public class EnvironmentDecryptApplicationInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private static Log logger = LogFactory
.getLog(EnvironmentDecryptApplicationListener.class);
.getLog(EnvironmentDecryptApplicationInitializer.class);
private int order = ConfigFileApplicationListener.DEFAULT_ORDER + 1;
private int order = Ordered.HIGHEST_PRECEDENCE + 15;
private TextEncryptor encryptor;
private boolean failOnError = true;
public EnvironmentDecryptApplicationListener(TextEncryptor encryptor) {
public EnvironmentDecryptApplicationInitializer(TextEncryptor encryptor) {
this.encryptor = encryptor;
}

View File

@@ -1,29 +1,29 @@
package org.springframework.cloud.bootstrap;
import static org.junit.Assert.assertFalse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.bootstrap.BootstrapDisabledAutoConfigurationIntegrationTests.Application;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest({ "server.port:0", "spring.cloud.bootstrap.enabled:false" })
@WebAppConfiguration
@ActiveProfiles("test")
@IntegrationTest("spring.cloud.bootstrap.enabled:false")
public class BootstrapDisabledAutoConfigurationIntegrationTests {
@Value("${local.server.port}")
private int port;
@Autowired
private ConfigurableEnvironment environment;
@Test
public void contextLoads() {
public void noBootstrapProperties() {
assertFalse(environment.getPropertySources().contains("bootstrap"));
}
@EnableAutoConfiguration

View File

@@ -0,0 +1,48 @@
package org.springframework.cloud.bootstrap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.bootstrap.BootstrapOrderingAutoConfigurationIntegrationTests.Application;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest("encrypt.key:deadbeef")
@ActiveProfiles("encrypt")
public class BootstrapOrderingAutoConfigurationIntegrationTests {
@Autowired
private ConfigurableEnvironment environment;
@Test
public void bootstrapPropertiesExist() {
assertTrue(environment.getPropertySources().contains("bootstrap"));
}
@Test
public void normalPropertiesDecrypted() {
assertEquals("foo", environment.resolvePlaceholders("${foo}"));
}
@Test
public void bootstrapPropertiesDecrypted() {
assertEquals("bar", environment.resolvePlaceholders("${bar}"));
}
@EnableAutoConfiguration
@Configuration
protected static class Application {
}
}

View File

@@ -29,7 +29,7 @@ import org.springframework.security.crypto.encrypt.Encryptors;
*/
public class EnvironmentDecryptApplicationListenerTests {
private EnvironmentDecryptApplicationListener listener = new EnvironmentDecryptApplicationListener(Encryptors.noOpText());
private EnvironmentDecryptApplicationInitializer listener = new EnvironmentDecryptApplicationInitializer(Encryptors.noOpText());
@Test
public void decryptCipherKey() {
@@ -41,7 +41,7 @@ public class EnvironmentDecryptApplicationListenerTests {
@Test(expected=IllegalStateException.class)
public void errorOnDecrypt() {
listener = new EnvironmentDecryptApplicationListener(Encryptors.text("deadbeef", "AFFE37"));
listener = new EnvironmentDecryptApplicationInitializer(Encryptors.text("deadbeef", "AFFE37"));
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");
listener.initialize(context);
@@ -50,7 +50,7 @@ public class EnvironmentDecryptApplicationListenerTests {
@Test
public void errorOnDecryptWithEmpty() {
listener = new EnvironmentDecryptApplicationListener(Encryptors.text("deadbeef", "AFFE37"));
listener = new EnvironmentDecryptApplicationInitializer(Encryptors.text("deadbeef", "AFFE37"));
listener.setFailOnError(false);
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "foo: {cipher}bar");

View File

@@ -0,0 +1 @@
foo: {cipher}e4e061f9fe39ba5b14d8012d2f17d39775606039409b71ed4be0fdd033d5324a

View File

@@ -0,0 +1 @@
bar: {cipher}6154ca04d4bb6144d672c4e3d750b5147116dd381946d51fa44f8bc25dc256f4

View File

@@ -1,2 +1,2 @@
spring.main.sources: org.springframework.cloud.bootstrap.config.BootstrapConfigurationTests.PropertySourceConfiguration
info.name: child
info.name: child