Uses BindHandler if registered in bootstrap.

Spring Cloud Commons now creates a TextEncryptorBindHandler that can decrypt properties when using a Binder. This allows configuration read in ConfigData methods to be decrypted.

Fixes gh-688
This commit is contained in:
spencergibb
2020-12-20 11:49:47 -05:00
parent bc9f8ec39b
commit 70a63018b2
3 changed files with 54 additions and 9 deletions

View File

@@ -34,6 +34,7 @@ import org.springframework.boot.context.config.ConfigDataLocationNotFoundExcepti
import org.springframework.boot.context.config.ConfigDataLocationResolver;
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
import org.springframework.boot.context.config.Profiles;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.consul.ConsulAutoConfiguration;
@@ -89,12 +90,12 @@ public class ConsulConfigDataLocationResolver implements ConfigDataLocationResol
UriComponents locationUri = parseLocation(resolverContext, location);
// create consul client
registerBean(resolverContext, ConsulProperties.class, loadProperties(resolverContext.getBinder(), locationUri));
registerBean(resolverContext, ConsulProperties.class, loadProperties(resolverContext, locationUri));
registerAndPromoteBean(resolverContext, ConsulClient.class, this::createConsulClient);
// create locations
ConsulConfigProperties properties = loadConfigProperties(resolverContext.getBinder());
ConsulConfigProperties properties = loadConfigProperties(resolverContext);
ConsulPropertySources consulPropertySources = new ConsulPropertySources(properties, log);
@@ -111,6 +112,10 @@ public class ConsulConfigDataLocationResolver implements ConfigDataLocationResol
location.isOptional(), properties, consulPropertySources)).collect(Collectors.toList());
}
private BindHandler getBindHandler(ConfigDataLocationResolverContext context) {
return context.getBootstrapContext().getOrElse(BindHandler.class, null);
}
private List<String> getCustomContexts(UriComponents uriComponents, ConsulConfigProperties properties) {
if (StringUtils.isEmpty(uriComponents.getPath())) {
return Collections.emptyList();
@@ -178,9 +183,12 @@ public class ConsulConfigDataLocationResolver implements ConfigDataLocationResol
return ConsulAutoConfiguration.createConsulClient(properties);
}
protected ConsulProperties loadProperties(Binder binder, UriComponents location) {
ConsulProperties consulProperties = binder.bind(ConsulProperties.PREFIX, Bindable.of(ConsulProperties.class))
.orElse(new ConsulProperties());
protected ConsulProperties loadProperties(ConfigDataLocationResolverContext resolverContext,
UriComponents location) {
Binder binder = resolverContext.getBinder();
ConsulProperties consulProperties = binder
.bind(ConsulProperties.PREFIX, Bindable.of(ConsulProperties.class), getBindHandler(resolverContext))
.orElseGet(ConsulProperties::new);
if (location != null) {
if (StringUtils.hasText(location.getHost())) {
@@ -194,10 +202,12 @@ public class ConsulConfigDataLocationResolver implements ConfigDataLocationResol
return consulProperties;
}
protected ConsulConfigProperties loadConfigProperties(Binder binder) {
protected ConsulConfigProperties loadConfigProperties(ConfigDataLocationResolverContext resolverContext) {
Binder binder = resolverContext.getBinder();
BindHandler bindHandler = getBindHandler(resolverContext);
ConsulConfigProperties properties = binder
.bind(ConsulConfigProperties.PREFIX, Bindable.of(ConsulConfigProperties.class))
.orElse(new ConsulConfigProperties());
.bind(ConsulConfigProperties.PREFIX, Bindable.of(ConsulConfigProperties.class), bindHandler)
.orElseGet(ConsulConfigProperties::new);
if (StringUtils.isEmpty(properties.getName())) {
properties.setName(binder.bind("spring.application.name", String.class).orElse("application"));

View File

@@ -23,9 +23,15 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.Bootstrapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.bind.BindContext;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.cloud.consul.ConsulProperties;
import org.springframework.cloud.consul.test.ConsulTestcontainers;
import org.springframework.context.ConfigurableApplicationContext;
@@ -48,12 +54,16 @@ public class ConsulConfigDataCustomizationIntegrationTests {
private static ConfigurableApplicationContext context;
private static BindHandlerBootstrapper bindHandlerBootstrapper;
@BeforeAll
public static void setup() {
ConsulTestcontainers.start();
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
bindHandlerBootstrapper = new BindHandlerBootstrapper();
application.addBootstrapper(bindHandlerBootstrapper);
application.addBootstrapper(ConsulBootstrapper.fromConsulProperties(TestConsulClient::new));
context = application.run("--spring.application.name=" + APP_NAME,
"--spring.config.import=consul:" + ConsulTestcontainers.getHost() + ":"
@@ -73,6 +83,7 @@ public class ConsulConfigDataCustomizationIntegrationTests {
public void consulClientIsCustom() {
ConsulClient client = context.getBean(ConsulClient.class);
assertThat(client).isInstanceOf(TestConsulClient.class);
assertThat(bindHandlerBootstrapper.onSuccessCount).isGreaterThan(0);
}
static class TestConsulClient extends ConsulClient {
@@ -89,4 +100,22 @@ public class ConsulConfigDataCustomizationIntegrationTests {
}
static class BindHandlerBootstrapper implements Bootstrapper {
private int onSuccessCount = 0;
@Override
public void intitialize(BootstrapRegistry registry) {
registry.register(BindHandler.class, context -> new BindHandler() {
@Override
public Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,
Object result) {
onSuccessCount++;
return result;
}
});
}
}
}

View File

@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.BootstrapRegistry.InstanceSupplier;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.context.config.ConfigDataLocation;
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
import org.springframework.boot.context.config.Profiles;
@@ -70,7 +71,11 @@ public class ConsulConfigDataLocationResolverTests {
@Test
public void testLoadProperties() {
ConsulProperties properties = createResolver().loadProperties(Binder.get(new MockEnvironment()),
Binder binder = Binder.get(new MockEnvironment());
ConfigDataLocationResolverContext resolverContext = mock(ConfigDataLocationResolverContext.class);
when(resolverContext.getBinder()).thenReturn(binder);
when(resolverContext.getBootstrapContext()).thenReturn(new DefaultBootstrapContext());
ConsulProperties properties = createResolver().loadProperties(resolverContext,
UriComponentsBuilder.fromUriString("consul://myhost:8502").build());
assertThat(properties.getHost()).isEqualTo("myhost");
assertThat(properties.getPort()).isEqualTo(8502);
@@ -83,6 +88,7 @@ public class ConsulConfigDataLocationResolverTests {
private List<ConsulConfigDataResource> testResolveProfileSpecific(String location) {
ConsulConfigDataLocationResolver resolver = createResolver();
ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class);
when(context.getBootstrapContext()).thenReturn(new DefaultBootstrapContext());
MockEnvironment env = new MockEnvironment();
env.setProperty("spring.application.name", "testapp");
when(context.getBinder()).thenReturn(Binder.get(env));