Improve output of `/application/env/{propertyName}`
This commit changes the output of a single property to mention the actual value in the environment as well as the property source that contributed to the value. Closes gh-10178
This commit is contained in:
parent
5d05347e61
commit
c2c6f49cbc
|
|
@ -22,8 +22,8 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceDescriptor;
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertyValueDescriptor;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,15 @@ import java.util.function.Predicate;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.Sanitizer;
|
import org.springframework.boot.actuate.endpoint.Sanitizer;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
|
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
|
|
||||||
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
|
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
|
||||||
import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;
|
import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;
|
||||||
|
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||||
import org.springframework.boot.origin.OriginLookup;
|
import org.springframework.boot.origin.OriginLookup;
|
||||||
import org.springframework.core.env.CompositePropertySource;
|
import org.springframework.core.env.CompositePropertySource;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
|
@ -54,6 +55,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
|
* @author Stephane Nicoll
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Endpoint(id = "env")
|
@Endpoint(id = "env")
|
||||||
|
|
@ -80,8 +82,8 @@ public class EnvironmentEndpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReadOperation
|
@ReadOperation
|
||||||
public EnvironmentDescriptor environmentEntry(@Selector String toMatch) {
|
public EnvironmentEntryDescriptor environmentEntry(@Selector String toMatch) {
|
||||||
return getEnvironmentDescriptor(toMatch::equals);
|
return getEnvironmentEntryDescriptor(toMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EnvironmentDescriptor getEnvironmentDescriptor(
|
private EnvironmentDescriptor getEnvironmentDescriptor(
|
||||||
|
|
@ -99,6 +101,46 @@ public class EnvironmentEndpoint {
|
||||||
Arrays.asList(this.environment.getActiveProfiles()), propertySources);
|
Arrays.asList(this.environment.getActiveProfiles()), propertySources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EnvironmentEntryDescriptor getEnvironmentEntryDescriptor(
|
||||||
|
String propertyName) {
|
||||||
|
Map<String, PropertyValueDescriptor> descriptors = getPropertySourceDescriptors(
|
||||||
|
propertyName);
|
||||||
|
PropertySummaryDescriptor summary = getPropertySummaryDescriptor(descriptors);
|
||||||
|
return new EnvironmentEntryDescriptor(summary,
|
||||||
|
Arrays.asList(this.environment.getActiveProfiles()),
|
||||||
|
toPropertySourceDescriptors(descriptors));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PropertySourceEntryDescriptor> toPropertySourceDescriptors(
|
||||||
|
Map<String, PropertyValueDescriptor> descriptors) {
|
||||||
|
List<PropertySourceEntryDescriptor> result = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, PropertyValueDescriptor> entry : descriptors.entrySet()) {
|
||||||
|
result.add(new PropertySourceEntryDescriptor(entry.getKey(), entry.getValue()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertySummaryDescriptor getPropertySummaryDescriptor(
|
||||||
|
Map<String, PropertyValueDescriptor> descriptors) {
|
||||||
|
for (Map.Entry<String, PropertyValueDescriptor> entry : descriptors.entrySet()) {
|
||||||
|
if (entry.getValue() != null) {
|
||||||
|
return new PropertySummaryDescriptor(entry.getKey(),
|
||||||
|
entry.getValue().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, PropertyValueDescriptor> getPropertySourceDescriptors(
|
||||||
|
String propertyName) {
|
||||||
|
Map<String, PropertyValueDescriptor> propertySources = new LinkedHashMap<>();
|
||||||
|
PlaceholdersResolver resolver = getResolver();
|
||||||
|
getPropertySourcesAsMap().forEach((sourceName, source) ->
|
||||||
|
propertySources.put(sourceName, source.containsProperty(propertyName) ?
|
||||||
|
describeValueOf(propertyName, source, resolver) : null));
|
||||||
|
return propertySources;
|
||||||
|
}
|
||||||
|
|
||||||
private PropertySourceDescriptor describeSource(String sourceName,
|
private PropertySourceDescriptor describeSource(String sourceName,
|
||||||
EnumerablePropertySource<?> source, PlaceholdersResolver resolver,
|
EnumerablePropertySource<?> source, PlaceholdersResolver resolver,
|
||||||
Predicate<String> namePredicate) {
|
Predicate<String> namePredicate) {
|
||||||
|
|
@ -109,7 +151,7 @@ public class EnvironmentEndpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertyValueDescriptor describeValueOf(String name,
|
private PropertyValueDescriptor describeValueOf(String name,
|
||||||
EnumerablePropertySource<?> source, PlaceholdersResolver resolver) {
|
PropertySource<?> source, PlaceholdersResolver resolver) {
|
||||||
Object resolved = resolver.resolvePlaceholders(source.getProperty(name));
|
Object resolved = resolver.resolvePlaceholders(source.getProperty(name));
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
String origin = (source instanceof OriginLookup)
|
String origin = (source instanceof OriginLookup)
|
||||||
|
|
@ -125,8 +167,10 @@ public class EnvironmentEndpoint {
|
||||||
private Map<String, PropertySource<?>> getPropertySourcesAsMap() {
|
private Map<String, PropertySource<?>> getPropertySourcesAsMap() {
|
||||||
Map<String, PropertySource<?>> map = new LinkedHashMap<>();
|
Map<String, PropertySource<?>> map = new LinkedHashMap<>();
|
||||||
for (PropertySource<?> source : getPropertySources()) {
|
for (PropertySource<?> source : getPropertySources()) {
|
||||||
|
if (!ConfigurationPropertySources.isMainConfigurationPropertySource(source)) {
|
||||||
extract("", map, source);
|
extract("", map, source);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,6 +252,93 @@ public class EnvironmentEndpoint {
|
||||||
return this.propertySources;
|
return this.propertySources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of an entry of the {@link Environment}.
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static final class EnvironmentEntryDescriptor {
|
||||||
|
|
||||||
|
private final PropertySummaryDescriptor property;
|
||||||
|
|
||||||
|
private final List<String> activeProfiles;
|
||||||
|
|
||||||
|
private final List<PropertySourceEntryDescriptor> propertySources;
|
||||||
|
|
||||||
|
private EnvironmentEntryDescriptor(PropertySummaryDescriptor property,
|
||||||
|
List<String> activeProfiles,
|
||||||
|
List<PropertySourceEntryDescriptor> propertySources) {
|
||||||
|
this.property = property;
|
||||||
|
this.activeProfiles = activeProfiles;
|
||||||
|
this.propertySources = propertySources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertySummaryDescriptor getProperty() {
|
||||||
|
return this.property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getActiveProfiles() {
|
||||||
|
return this.activeProfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PropertySourceEntryDescriptor> getPropertySources() {
|
||||||
|
return this.propertySources;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary of a particular entry of the {@link Environment}.
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static final class PropertySummaryDescriptor {
|
||||||
|
|
||||||
|
private final String source;
|
||||||
|
|
||||||
|
private final Object value;
|
||||||
|
|
||||||
|
public PropertySummaryDescriptor(String source, Object value) {
|
||||||
|
this.source = source;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return this.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of a particular entry of {@link PropertySource}.
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static final class PropertySourceEntryDescriptor {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final PropertyValueDescriptor property;
|
||||||
|
|
||||||
|
private PropertySourceEntryDescriptor(String name,
|
||||||
|
PropertyValueDescriptor property) {
|
||||||
|
this.name = name;
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyValueDescriptor getProperty() {
|
||||||
|
return this.property;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A description of a {@link PropertySource}.
|
* A description of a {@link PropertySource}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -231,9 +362,12 @@ public class EnvironmentEndpoint {
|
||||||
return this.properties;
|
return this.properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A description of a property's value, including its origin if available.
|
* A description of a property's value, including its origin if available.
|
||||||
*/
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
public static final class PropertyValueDescriptor {
|
public static final class PropertyValueDescriptor {
|
||||||
|
|
||||||
private final Object value;
|
private final Object value;
|
||||||
|
|
@ -255,9 +389,6 @@ public class EnvironmentEndpoint {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when the specified property cannot be found.
|
* Exception thrown when the specified property cannot be found.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -17,23 +17,25 @@
|
||||||
package org.springframework.boot.actuate.env;
|
package org.springframework.boot.actuate.env;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentEntryDescriptor;
|
||||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceDescriptor;
|
||||||
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceEntryDescriptor;
|
||||||
|
import org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertyValueDescriptor;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.test.util.TestPropertyValues;
|
import org.springframework.boot.test.util.TestPropertyValues;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.env.CompositePropertySource;
|
import org.springframework.core.env.CompositePropertySource;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.env.MapPropertySource;
|
import org.springframework.core.env.MapPropertySource;
|
||||||
import org.springframework.core.env.MutablePropertySources;
|
|
||||||
import org.springframework.core.env.StandardEnvironment;
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
@ -57,59 +59,67 @@ public class EnvironmentEndpointTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void basicResponse() {
|
public void basicResponse() {
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(new StandardEnvironment())
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
|
environment.getPropertySources().addLast(
|
||||||
|
singleKeyPropertySource("one", "my.key", "first"));
|
||||||
|
environment.getPropertySources().addLast(
|
||||||
|
singleKeyPropertySource("two", "my.key", "second"));
|
||||||
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environment(null);
|
.environment(null);
|
||||||
assertThat(env.getActiveProfiles()).isEmpty();
|
assertThat(descriptor.getActiveProfiles()).isEmpty();
|
||||||
assertThat(env.getPropertySources()).hasSize(2);
|
Map<String, PropertySourceDescriptor> sources = propertySources(descriptor);
|
||||||
|
assertThat(sources.keySet()).containsExactly("one", "two");
|
||||||
|
assertThat(sources.get("one").getProperties()).containsOnlyKeys("my.key");
|
||||||
|
assertThat(sources.get("two").getProperties()).containsOnlyKeys("my.key");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compositeSourceIsHandledCorrectly() {
|
public void compositeSourceIsHandledCorrectly() {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
CompositePropertySource source = new CompositePropertySource("composite");
|
CompositePropertySource source = new CompositePropertySource("composite");
|
||||||
source.addPropertySource(
|
source.addPropertySource(
|
||||||
new MapPropertySource("one", Collections.singletonMap("foo", "bar")));
|
new MapPropertySource("one", Collections.singletonMap("foo", "bar")));
|
||||||
source.addPropertySource(
|
source.addPropertySource(
|
||||||
new MapPropertySource("two", Collections.singletonMap("foo", "spam")));
|
new MapPropertySource("two", Collections.singletonMap("foo", "spam")));
|
||||||
environment.getPropertySources().addFirst(source);
|
environment.getPropertySources().addFirst(source);
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environment(null);
|
.environment(null);
|
||||||
assertThat(getSource("composite:one", env).getProperties().get("foo").getValue())
|
Map<String, PropertySourceDescriptor> sources = propertySources(descriptor);
|
||||||
|
assertThat(sources.keySet()).containsExactly("composite:one", "composite:two");
|
||||||
|
assertThat(sources.get("composite:one").getProperties().get("foo").getValue())
|
||||||
.isEqualTo("bar");
|
.isEqualTo("bar");
|
||||||
assertThat(getSource("composite:two", env).getProperties().get("foo").getValue())
|
assertThat(sources.get("composite:two").getProperties().get("foo").getValue())
|
||||||
.isEqualTo("spam");
|
.isEqualTo("spam");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sensitiveKeysHaveTheirValuesSanitized() {
|
public void sensitiveKeysHaveTheirValuesSanitized() {
|
||||||
System.setProperty("dbPassword", "123456");
|
TestPropertyValues.of("dbPassword=123456", "apiKey=123456", "mySecret=123456",
|
||||||
System.setProperty("apiKey", "123456");
|
"myCredentials=123456", "VCAP_SERVICES=123456"
|
||||||
System.setProperty("mySecret", "123456");
|
).applyToSystemProperties(() -> {
|
||||||
System.setProperty("myCredentials", "123456");
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(
|
||||||
System.setProperty("VCAP_SERVICES", "123456");
|
new StandardEnvironment()).environment(null);
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(new StandardEnvironment())
|
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||||
.environment(null);
|
descriptor).get("systemProperties").getProperties();
|
||||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
|
||||||
"systemProperties", env).getProperties();
|
|
||||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
||||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
||||||
assertThat(systemProperties.get("mySecret").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("mySecret").getValue()).isEqualTo("******");
|
||||||
assertThat(systemProperties.get("myCredentials").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("myCredentials").getValue()).isEqualTo("******");
|
||||||
assertThat(systemProperties.get("VCAP_SERVICES").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("VCAP_SERVICES").getValue()).isEqualTo("******");
|
||||||
clearSystemProperties("dbPassword", "apiKey", "mySecret", "myCredentials",
|
return null;
|
||||||
"VCAP_SERVICES");
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sensitiveKeysMatchingCredentialsPatternHaveTheirValuesSanitized() {
|
public void sensitiveKeysMatchingCredentialsPatternHaveTheirValuesSanitized() {
|
||||||
System.setProperty("my.services.amqp-free.credentials.uri", "123456");
|
TestPropertyValues.of("my.services.amqp-free.credentials.uri=123456",
|
||||||
System.setProperty("credentials.http_api_uri", "123456");
|
"credentials.http_api_uri=123456",
|
||||||
System.setProperty("my.services.cleardb-free.credentials", "123456");
|
"my.services.cleardb-free.credentials=123456",
|
||||||
System.setProperty("foo.mycredentials.uri", "123456");
|
"foo.mycredentials.uri=123456").applyToSystemProperties(() -> {
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(new StandardEnvironment())
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(
|
||||||
.environment(null);
|
new StandardEnvironment()).environment(null);
|
||||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||||
"systemProperties", env).getProperties();
|
descriptor).get("systemProperties").getProperties();
|
||||||
assertThat(
|
assertThat(
|
||||||
systemProperties.get("my.services.amqp-free.credentials.uri").getValue())
|
systemProperties.get("my.services.amqp-free.credentials.uri").getValue())
|
||||||
.isEqualTo("******");
|
.isEqualTo("******");
|
||||||
|
|
@ -120,121 +130,172 @@ public class EnvironmentEndpointTests {
|
||||||
.isEqualTo("******");
|
.isEqualTo("******");
|
||||||
assertThat(systemProperties.get("foo.mycredentials.uri").getValue())
|
assertThat(systemProperties.get("foo.mycredentials.uri").getValue())
|
||||||
.isEqualTo("******");
|
.isEqualTo("******");
|
||||||
clearSystemProperties("my.services.amqp-free.credentials.uri",
|
return null;
|
||||||
"credentials.http_api_uri", "my.services.cleardb-free.credentials",
|
});
|
||||||
"foo.mycredentials.uri");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sensitiveKeysMatchingCustomNameHaveTheirValuesSanitized() {
|
public void sensitiveKeysMatchingCustomNameHaveTheirValuesSanitized() {
|
||||||
System.setProperty("dbPassword", "123456");
|
TestPropertyValues.of("dbPassword=123456",
|
||||||
System.setProperty("apiKey", "123456");
|
"apiKey=123456").applyToSystemProperties(() -> {
|
||||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
||||||
endpoint.setKeysToSanitize("key");
|
endpoint.setKeysToSanitize("key");
|
||||||
EnvironmentDescriptor env = endpoint.environment(null);
|
EnvironmentDescriptor descriptor = endpoint.environment(null);
|
||||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||||
"systemProperties", env).getProperties();
|
descriptor).get("systemProperties").getProperties();
|
||||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("123456");
|
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("123456");
|
||||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
||||||
clearSystemProperties("dbPassword", "apiKey");
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sensitiveKeysMatchingCustomPatternHaveTheirValuesSanitized() {
|
public void sensitiveKeysMatchingCustomPatternHaveTheirValuesSanitized() {
|
||||||
System.setProperty("dbPassword", "123456");
|
TestPropertyValues.of("dbPassword=123456",
|
||||||
System.setProperty("apiKey", "123456");
|
"apiKey=123456").applyToSystemProperties(() -> {
|
||||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
||||||
endpoint.setKeysToSanitize(".*pass.*");
|
endpoint.setKeysToSanitize(".*pass.*");
|
||||||
EnvironmentDescriptor env = endpoint.environment(null);
|
EnvironmentDescriptor descriptor = endpoint.environment(null);
|
||||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||||
"systemProperties", env).getProperties();
|
descriptor).get("systemProperties").getProperties();
|
||||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
||||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("123456");
|
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("123456");
|
||||||
clearSystemProperties("dbPassword", "apiKey");
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyWithPlaceholderResolved() {
|
public void propertyWithPlaceholderResolved() {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
TestPropertyValues.of("my.foo: ${bar.blah}", "bar.blah: hello")
|
TestPropertyValues.of("my.foo: ${bar.blah}", "bar.blah: hello")
|
||||||
.applyTo(environment);
|
.applyTo(environment);
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environment(null);
|
.environment(null);
|
||||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||||
.isEqualTo("hello");
|
.getValue()).isEqualTo("hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyWithPlaceholderNotResolved() {
|
public void propertyWithPlaceholderNotResolved() {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
TestPropertyValues.of("my.foo: ${bar.blah}").applyTo(environment);
|
TestPropertyValues.of("my.foo: ${bar.blah}").applyTo(environment);
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environment(null);
|
.environment(null);
|
||||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||||
.isEqualTo("${bar.blah}");
|
.getValue()).isEqualTo("${bar.blah}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyWithSensitivePlaceholderResolved() {
|
public void propertyWithSensitivePlaceholderResolved() {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
TestPropertyValues
|
TestPropertyValues
|
||||||
.of("my.foo: http://${bar.password}://hello", "bar.password: hello")
|
.of("my.foo: http://${bar.password}://hello", "bar.password: hello")
|
||||||
.applyTo(environment);
|
.applyTo(environment);
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environment(null);
|
.environment(null);
|
||||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||||
.isEqualTo("http://******://hello");
|
.getValue()).isEqualTo("http://******://hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyWithSensitivePlaceholderNotResolved() {
|
public void propertyWithSensitivePlaceholderNotResolved() {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
TestPropertyValues.of("my.foo: http://${bar.password}://hello")
|
TestPropertyValues.of("my.foo: http://${bar.password}://hello")
|
||||||
.applyTo(environment);
|
.applyTo(environment);
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environment(null);
|
.environment(null);
|
||||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||||
.isEqualTo("http://${bar.password}://hello");
|
.getValue()).isEqualTo("http://${bar.password}://hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void propertyWithTypeOtherThanStringShouldNotFail() {
|
public void propertyWithTypeOtherThanStringShouldNotFail() {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
MutablePropertySources propertySources = environment.getPropertySources();
|
environment.getPropertySources().addFirst(singleKeyPropertySource("test", "foo",
|
||||||
Map<String, Object> source = new HashMap<>();
|
Collections.singletonMap("bar", "baz")));
|
||||||
source.put("foo", Collections.singletonMap("bar", "baz"));
|
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
propertySources.addFirst(new MapPropertySource("test", source));
|
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
|
||||||
.environment(null);
|
.environment(null);
|
||||||
Map<String, PropertyValueDescriptor> testProperties = getSource("test", env)
|
Map<String, String> foo = (Map<String, String>) propertySources(descriptor)
|
||||||
.getProperties();
|
.get("test").getProperties().get("foo").getValue();
|
||||||
Map<String, String> foo = (Map<String, String>) testProperties.get("foo")
|
|
||||||
.getValue();
|
|
||||||
assertThat(foo.get("bar")).isEqualTo("baz");
|
assertThat(foo.get("bar")).isEqualTo("baz");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyEntry() {
|
public void propertyEntry() {
|
||||||
|
TestPropertyValues.of("my.foo=another").applyToSystemProperties(() -> {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
StandardEnvironment environment = new StandardEnvironment();
|
||||||
TestPropertyValues.of("my.foo=bar", "my.foo2=bar2").applyTo(environment);
|
TestPropertyValues.of("my.foo=bar", "my.foo2=bar2").applyTo(environment,
|
||||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
TestPropertyValues.Type.MAP, "test");
|
||||||
|
EnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
.environmentEntry("my.foo");
|
.environmentEntry("my.foo");
|
||||||
assertThat(env).isNotNull();
|
assertThat(descriptor).isNotNull();
|
||||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
assertThat(descriptor.getProperty()).isNotNull();
|
||||||
.isEqualTo("bar");
|
assertThat(descriptor.getProperty().getSource()).isEqualTo("test");
|
||||||
|
assertThat(descriptor.getProperty().getValue()).isEqualTo("bar");
|
||||||
|
Map<String, PropertySourceEntryDescriptor> sources = propertySources(descriptor);
|
||||||
|
assertThat(sources.keySet()).containsExactly(
|
||||||
|
"test", "systemProperties", "systemEnvironment");
|
||||||
|
assertPropertySourceEntryDescriptor(sources.get("test"), "bar", null);
|
||||||
|
assertPropertySourceEntryDescriptor(sources.get("systemProperties"), "another", null);
|
||||||
|
assertPropertySourceEntryDescriptor(sources.get("systemEnvironment"), null, null);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearSystemProperties(String... properties) {
|
@Test
|
||||||
for (String property : properties) {
|
public void propertyEntryNotFound() {
|
||||||
System.clearProperty(property);
|
ConfigurableEnvironment environment = emptyEnvironment();
|
||||||
}
|
environment.getPropertySources().addFirst(
|
||||||
|
singleKeyPropertySource("test", "foo", "bar"));
|
||||||
|
EnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||||
|
.environmentEntry("does.not.exist");
|
||||||
|
assertThat(descriptor).isNotNull();
|
||||||
|
assertThat(descriptor.getProperty()).isNull();
|
||||||
|
Map<String, PropertySourceEntryDescriptor> sources = propertySources(descriptor);
|
||||||
|
assertThat(sources.keySet()).containsExactly(
|
||||||
|
"test");
|
||||||
|
assertPropertySourceEntryDescriptor(sources.get("test"), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertySourceDescriptor getSource(String name,
|
private static ConfigurableEnvironment emptyEnvironment() {
|
||||||
|
StandardEnvironment environment = new StandardEnvironment();
|
||||||
|
environment.getPropertySources().remove(
|
||||||
|
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
|
||||||
|
environment.getPropertySources().remove(
|
||||||
|
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapPropertySource singleKeyPropertySource(String name, String key, Object value) {
|
||||||
|
return new MapPropertySource(name, Collections.singletonMap(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, PropertySourceDescriptor> propertySources(
|
||||||
EnvironmentDescriptor descriptor) {
|
EnvironmentDescriptor descriptor) {
|
||||||
return descriptor.getPropertySources().stream()
|
Map<String, PropertySourceDescriptor> sources = new LinkedHashMap<>();
|
||||||
.filter((source) -> name.equals(source.getName())).findFirst().get();
|
descriptor.getPropertySources().forEach(d -> sources.put(d.getName(), d));
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, PropertySourceEntryDescriptor> propertySources(
|
||||||
|
EnvironmentEntryDescriptor descriptor) {
|
||||||
|
Map<String, PropertySourceEntryDescriptor> sources = new LinkedHashMap<>();
|
||||||
|
descriptor.getPropertySources().forEach(d -> sources.put(d.getName(), d));
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertPropertySourceEntryDescriptor(PropertySourceEntryDescriptor actual,
|
||||||
|
Object value, String origin) {
|
||||||
|
assertThat(actual).isNotNull();
|
||||||
|
if (value != null) {
|
||||||
|
assertThat(actual.getProperty().getValue()).isEqualTo(value);
|
||||||
|
assertThat(actual.getProperty().getOrigin()).isEqualTo(origin);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat(actual.getProperty()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,9 @@ public class EnvironmentEndpointWebIntegrationTests {
|
||||||
@Test
|
@Test
|
||||||
public void sub() throws Exception {
|
public void sub() throws Exception {
|
||||||
client.get().uri("/application/env/foo").exchange().expectStatus().isOk()
|
client.get().uri("/application/env/foo").exchange().expectStatus().isOk()
|
||||||
.expectBody().jsonPath(forProperty("test", "foo")).isEqualTo("bar");
|
.expectBody()
|
||||||
|
.jsonPath("property.source").isEqualTo("test")
|
||||||
|
.jsonPath("property.value").isEqualTo("bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -75,8 +77,10 @@ public class EnvironmentEndpointWebIntegrationTests {
|
||||||
context.getEnvironment().getPropertySources()
|
context.getEnvironment().getPropertySources()
|
||||||
.addFirst(new MapPropertySource("unresolved-placeholder", map));
|
.addFirst(new MapPropertySource("unresolved-placeholder", map));
|
||||||
client.get().uri("/application/env/my.foo").exchange().expectStatus().isOk()
|
client.get().uri("/application/env/my.foo").exchange().expectStatus().isOk()
|
||||||
.expectBody().jsonPath(forProperty("unresolved-placeholder", "my.foo"))
|
.expectBody()
|
||||||
.isEqualTo("${my.bar}");
|
.jsonPath("property.value").isEqualTo("${my.bar}")
|
||||||
|
.jsonPath(forPropertyEntry(
|
||||||
|
"unresolved-placeholder")).isEqualTo("${my.bar}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -87,8 +91,9 @@ public class EnvironmentEndpointWebIntegrationTests {
|
||||||
context.getEnvironment().getPropertySources()
|
context.getEnvironment().getPropertySources()
|
||||||
.addFirst(new MapPropertySource("placeholder", map));
|
.addFirst(new MapPropertySource("placeholder", map));
|
||||||
client.get().uri("/application/env/my.foo").exchange().expectStatus().isOk()
|
client.get().uri("/application/env/my.foo").exchange().expectStatus().isOk()
|
||||||
.expectBody().jsonPath(forProperty("placeholder", "my.foo"))
|
.expectBody()
|
||||||
.isEqualTo("******");
|
.jsonPath("property.value").isEqualTo("******")
|
||||||
|
.jsonPath(forPropertyEntry("placeholder")).isEqualTo("******");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -123,6 +128,10 @@ public class EnvironmentEndpointWebIntegrationTests {
|
||||||
+ "'].value";
|
+ "'].value";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String forPropertyEntry(String source) {
|
||||||
|
return "propertySources[?(@.name=='" + source + "')].property.value";
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class TestConfiguration {
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,18 @@ public final class ConfigurationPropertySources {
|
||||||
private ConfigurationPropertySources() {
|
private ConfigurationPropertySources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the specific {@link PropertySource} is the
|
||||||
|
* {@link ConfigurationPropertySource} that was {@link #attach(Environment) attached}
|
||||||
|
* to the {@link Environment}.
|
||||||
|
* @param propertySource the property source to test
|
||||||
|
* @return {@code true} if this is the attached {@link ConfigurationPropertySource}
|
||||||
|
*/
|
||||||
|
public static boolean isMainConfigurationPropertySource(
|
||||||
|
PropertySource<?> propertySource) {
|
||||||
|
return ATTACHED_PROPERTY_SOURCE_NAME.equals(propertySource.getName());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach a {@link ConfigurationPropertySource} support to the specified
|
* Attach a {@link ConfigurationPropertySource} support to the specified
|
||||||
* {@link Environment}. Adapts each {@link PropertySource} managed by the environment
|
* {@link Environment}. Adapts each {@link PropertySource} managed by the environment
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue