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.EnvironmentDescriptor;
|
||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
|
||||
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.PropertyValueDescriptor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
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.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Sanitizer;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
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.PropertySourcesPlaceholdersResolver;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||
import org.springframework.boot.origin.OriginLookup;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
@ -54,6 +55,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
|||
* @author Phillip Webb
|
||||
* @author Christian Dupuis
|
||||
* @author Madhura Bhave
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "env")
|
||||
|
@ -80,8 +82,8 @@ public class EnvironmentEndpoint {
|
|||
}
|
||||
|
||||
@ReadOperation
|
||||
public EnvironmentDescriptor environmentEntry(@Selector String toMatch) {
|
||||
return getEnvironmentDescriptor(toMatch::equals);
|
||||
public EnvironmentEntryDescriptor environmentEntry(@Selector String toMatch) {
|
||||
return getEnvironmentEntryDescriptor(toMatch);
|
||||
}
|
||||
|
||||
private EnvironmentDescriptor getEnvironmentDescriptor(
|
||||
|
@ -99,6 +101,46 @@ public class EnvironmentEndpoint {
|
|||
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,
|
||||
EnumerablePropertySource<?> source, PlaceholdersResolver resolver,
|
||||
Predicate<String> namePredicate) {
|
||||
|
@ -109,7 +151,7 @@ public class EnvironmentEndpoint {
|
|||
}
|
||||
|
||||
private PropertyValueDescriptor describeValueOf(String name,
|
||||
EnumerablePropertySource<?> source, PlaceholdersResolver resolver) {
|
||||
PropertySource<?> source, PlaceholdersResolver resolver) {
|
||||
Object resolved = resolver.resolvePlaceholders(source.getProperty(name));
|
||||
@SuppressWarnings("unchecked")
|
||||
String origin = (source instanceof OriginLookup)
|
||||
|
@ -125,7 +167,9 @@ public class EnvironmentEndpoint {
|
|||
private Map<String, PropertySource<?>> getPropertySourcesAsMap() {
|
||||
Map<String, PropertySource<?>> map = new LinkedHashMap<>();
|
||||
for (PropertySource<?> source : getPropertySources()) {
|
||||
extract("", map, source);
|
||||
if (!ConfigurationPropertySources.isMainConfigurationPropertySource(source)) {
|
||||
extract("", map, source);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -208,54 +252,141 @@ public class EnvironmentEndpoint {
|
|||
return this.propertySources;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of a {@link PropertySource}.
|
||||
*/
|
||||
public static final class PropertySourceDescriptor {
|
||||
}
|
||||
|
||||
private final String name;
|
||||
/**
|
||||
* A description of an entry of the {@link Environment}.
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static final class EnvironmentEntryDescriptor {
|
||||
|
||||
private final Map<String, PropertyValueDescriptor> properties;
|
||||
private final PropertySummaryDescriptor property;
|
||||
|
||||
private PropertySourceDescriptor(String name,
|
||||
Map<String, PropertyValueDescriptor> properties) {
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
}
|
||||
private final List<String> activeProfiles;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Map<String, PropertyValueDescriptor> getProperties() {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of a property's value, including its origin if available.
|
||||
*/
|
||||
public static final class PropertyValueDescriptor {
|
||||
|
||||
private final Object value;
|
||||
|
||||
private final String origin;
|
||||
|
||||
private PropertyValueDescriptor(Object value, String origin) {
|
||||
this.value = value;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
}
|
||||
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}.
|
||||
*/
|
||||
public static final class PropertySourceDescriptor {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Map<String, PropertyValueDescriptor> properties;
|
||||
|
||||
private PropertySourceDescriptor(String name,
|
||||
Map<String, PropertyValueDescriptor> properties) {
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Map<String, PropertyValueDescriptor> getProperties() {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of a property's value, including its origin if available.
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static final class PropertyValueDescriptor {
|
||||
|
||||
private final Object value;
|
||||
|
||||
private final String origin;
|
||||
|
||||
private PropertyValueDescriptor(Object value, String origin) {
|
||||
this.value = value;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,23 +17,25 @@
|
|||
package org.springframework.boot.actuate.env;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;
|
||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
|
||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
|
||||
import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentEntryDescriptor;
|
||||
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.test.util.TestPropertyValues;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -57,184 +59,243 @@ public class EnvironmentEndpointTests {
|
|||
|
||||
@Test
|
||||
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);
|
||||
assertThat(env.getActiveProfiles()).isEmpty();
|
||||
assertThat(env.getPropertySources()).hasSize(2);
|
||||
assertThat(descriptor.getActiveProfiles()).isEmpty();
|
||||
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
|
||||
public void compositeSourceIsHandledCorrectly() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
CompositePropertySource source = new CompositePropertySource("composite");
|
||||
source.addPropertySource(
|
||||
new MapPropertySource("one", Collections.singletonMap("foo", "bar")));
|
||||
source.addPropertySource(
|
||||
new MapPropertySource("two", Collections.singletonMap("foo", "spam")));
|
||||
environment.getPropertySources().addFirst(source);
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.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");
|
||||
assertThat(getSource("composite:two", env).getProperties().get("foo").getValue())
|
||||
assertThat(sources.get("composite:two").getProperties().get("foo").getValue())
|
||||
.isEqualTo("spam");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensitiveKeysHaveTheirValuesSanitized() {
|
||||
System.setProperty("dbPassword", "123456");
|
||||
System.setProperty("apiKey", "123456");
|
||||
System.setProperty("mySecret", "123456");
|
||||
System.setProperty("myCredentials", "123456");
|
||||
System.setProperty("VCAP_SERVICES", "123456");
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(new StandardEnvironment())
|
||||
.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
||||
"systemProperties", env).getProperties();
|
||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("mySecret").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("myCredentials").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("VCAP_SERVICES").getValue()).isEqualTo("******");
|
||||
clearSystemProperties("dbPassword", "apiKey", "mySecret", "myCredentials",
|
||||
"VCAP_SERVICES");
|
||||
TestPropertyValues.of("dbPassword=123456", "apiKey=123456", "mySecret=123456",
|
||||
"myCredentials=123456", "VCAP_SERVICES=123456"
|
||||
).applyToSystemProperties(() -> {
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(
|
||||
new StandardEnvironment()).environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||
descriptor).get("systemProperties").getProperties();
|
||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("mySecret").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("myCredentials").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("VCAP_SERVICES").getValue()).isEqualTo("******");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensitiveKeysMatchingCredentialsPatternHaveTheirValuesSanitized() {
|
||||
System.setProperty("my.services.amqp-free.credentials.uri", "123456");
|
||||
System.setProperty("credentials.http_api_uri", "123456");
|
||||
System.setProperty("my.services.cleardb-free.credentials", "123456");
|
||||
System.setProperty("foo.mycredentials.uri", "123456");
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(new StandardEnvironment())
|
||||
.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
||||
"systemProperties", env).getProperties();
|
||||
assertThat(
|
||||
systemProperties.get("my.services.amqp-free.credentials.uri").getValue())
|
||||
.isEqualTo("******");
|
||||
assertThat(systemProperties.get("credentials.http_api_uri").getValue())
|
||||
.isEqualTo("******");
|
||||
assertThat(
|
||||
systemProperties.get("my.services.cleardb-free.credentials").getValue())
|
||||
.isEqualTo("******");
|
||||
assertThat(systemProperties.get("foo.mycredentials.uri").getValue())
|
||||
.isEqualTo("******");
|
||||
clearSystemProperties("my.services.amqp-free.credentials.uri",
|
||||
"credentials.http_api_uri", "my.services.cleardb-free.credentials",
|
||||
"foo.mycredentials.uri");
|
||||
TestPropertyValues.of("my.services.amqp-free.credentials.uri=123456",
|
||||
"credentials.http_api_uri=123456",
|
||||
"my.services.cleardb-free.credentials=123456",
|
||||
"foo.mycredentials.uri=123456").applyToSystemProperties(() -> {
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(
|
||||
new StandardEnvironment()).environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||
descriptor).get("systemProperties").getProperties();
|
||||
assertThat(
|
||||
systemProperties.get("my.services.amqp-free.credentials.uri").getValue())
|
||||
.isEqualTo("******");
|
||||
assertThat(systemProperties.get("credentials.http_api_uri").getValue())
|
||||
.isEqualTo("******");
|
||||
assertThat(
|
||||
systemProperties.get("my.services.cleardb-free.credentials").getValue())
|
||||
.isEqualTo("******");
|
||||
assertThat(systemProperties.get("foo.mycredentials.uri").getValue())
|
||||
.isEqualTo("******");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensitiveKeysMatchingCustomNameHaveTheirValuesSanitized() {
|
||||
System.setProperty("dbPassword", "123456");
|
||||
System.setProperty("apiKey", "123456");
|
||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
||||
endpoint.setKeysToSanitize("key");
|
||||
EnvironmentDescriptor env = endpoint.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
||||
"systemProperties", env).getProperties();
|
||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("123456");
|
||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
||||
clearSystemProperties("dbPassword", "apiKey");
|
||||
TestPropertyValues.of("dbPassword=123456",
|
||||
"apiKey=123456").applyToSystemProperties(() -> {
|
||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
||||
endpoint.setKeysToSanitize("key");
|
||||
EnvironmentDescriptor descriptor = endpoint.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||
descriptor).get("systemProperties").getProperties();
|
||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("123456");
|
||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("******");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensitiveKeysMatchingCustomPatternHaveTheirValuesSanitized() {
|
||||
System.setProperty("dbPassword", "123456");
|
||||
System.setProperty("apiKey", "123456");
|
||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
||||
endpoint.setKeysToSanitize(".*pass.*");
|
||||
EnvironmentDescriptor env = endpoint.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = getSource(
|
||||
"systemProperties", env).getProperties();
|
||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("123456");
|
||||
clearSystemProperties("dbPassword", "apiKey");
|
||||
TestPropertyValues.of("dbPassword=123456",
|
||||
"apiKey=123456").applyToSystemProperties(() -> {
|
||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(new StandardEnvironment());
|
||||
endpoint.setKeysToSanitize(".*pass.*");
|
||||
EnvironmentDescriptor descriptor = endpoint.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = propertySources(
|
||||
descriptor).get("systemProperties").getProperties();
|
||||
assertThat(systemProperties.get("dbPassword").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("apiKey").getValue()).isEqualTo("123456");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyWithPlaceholderResolved() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
TestPropertyValues.of("my.foo: ${bar.blah}", "bar.blah: hello")
|
||||
.applyTo(environment);
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.environment(null);
|
||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
||||
.isEqualTo("hello");
|
||||
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||
.getValue()).isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyWithPlaceholderNotResolved() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
TestPropertyValues.of("my.foo: ${bar.blah}").applyTo(environment);
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.environment(null);
|
||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
||||
.isEqualTo("${bar.blah}");
|
||||
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||
.getValue()).isEqualTo("${bar.blah}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyWithSensitivePlaceholderResolved() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
TestPropertyValues
|
||||
.of("my.foo: http://${bar.password}://hello", "bar.password: hello")
|
||||
.applyTo(environment);
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.environment(null);
|
||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
||||
.isEqualTo("http://******://hello");
|
||||
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||
.getValue()).isEqualTo("http://******://hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyWithSensitivePlaceholderNotResolved() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
TestPropertyValues.of("my.foo: http://${bar.password}://hello")
|
||||
.applyTo(environment);
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.environment(null);
|
||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
||||
.isEqualTo("http://${bar.password}://hello");
|
||||
assertThat(propertySources(descriptor).get("test").getProperties().get("my.foo")
|
||||
.getValue()).isEqualTo("http://${bar.password}://hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void propertyWithTypeOtherThanStringShouldNotFail() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
Map<String, Object> source = new HashMap<>();
|
||||
source.put("foo", Collections.singletonMap("bar", "baz"));
|
||||
propertySources.addFirst(new MapPropertySource("test", source));
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
environment.getPropertySources().addFirst(singleKeyPropertySource("test", "foo",
|
||||
Collections.singletonMap("bar", "baz")));
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.environment(null);
|
||||
Map<String, PropertyValueDescriptor> testProperties = getSource("test", env)
|
||||
.getProperties();
|
||||
Map<String, String> foo = (Map<String, String>) testProperties.get("foo")
|
||||
.getValue();
|
||||
Map<String, String> foo = (Map<String, String>) propertySources(descriptor)
|
||||
.get("test").getProperties().get("foo").getValue();
|
||||
assertThat(foo.get("bar")).isEqualTo("baz");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyEntry() {
|
||||
TestPropertyValues.of("my.foo=another").applyToSystemProperties(() -> {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
TestPropertyValues.of("my.foo=bar", "my.foo2=bar2").applyTo(environment,
|
||||
TestPropertyValues.Type.MAP, "test");
|
||||
EnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment)
|
||||
.environmentEntry("my.foo");
|
||||
assertThat(descriptor).isNotNull();
|
||||
assertThat(descriptor.getProperty()).isNotNull();
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyEntryNotFound() {
|
||||
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 static ConfigurableEnvironment emptyEnvironment() {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
TestPropertyValues.of("my.foo=bar", "my.foo2=bar2").applyTo(environment);
|
||||
EnvironmentDescriptor env = new EnvironmentEndpoint(environment)
|
||||
.environmentEntry("my.foo");
|
||||
assertThat(env).isNotNull();
|
||||
assertThat(getSource("test", env).getProperties().get("my.foo").getValue())
|
||||
.isEqualTo("bar");
|
||||
environment.getPropertySources().remove(
|
||||
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
|
||||
environment.getPropertySources().remove(
|
||||
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
|
||||
return environment;
|
||||
}
|
||||
|
||||
private void clearSystemProperties(String... properties) {
|
||||
for (String property : properties) {
|
||||
System.clearProperty(property);
|
||||
}
|
||||
private MapPropertySource singleKeyPropertySource(String name, String key, Object value) {
|
||||
return new MapPropertySource(name, Collections.singletonMap(key, value));
|
||||
}
|
||||
|
||||
private PropertySourceDescriptor getSource(String name,
|
||||
private Map<String, PropertySourceDescriptor> propertySources(
|
||||
EnvironmentDescriptor descriptor) {
|
||||
return descriptor.getPropertySources().stream()
|
||||
.filter((source) -> name.equals(source.getName())).findFirst().get();
|
||||
Map<String, PropertySourceDescriptor> sources = new LinkedHashMap<>();
|
||||
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
|
||||
|
|
|
@ -53,7 +53,9 @@ public class EnvironmentEndpointWebIntegrationTests {
|
|||
@Test
|
||||
public void sub() throws Exception {
|
||||
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
|
||||
|
@ -75,8 +77,10 @@ public class EnvironmentEndpointWebIntegrationTests {
|
|||
context.getEnvironment().getPropertySources()
|
||||
.addFirst(new MapPropertySource("unresolved-placeholder", map));
|
||||
client.get().uri("/application/env/my.foo").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath(forProperty("unresolved-placeholder", "my.foo"))
|
||||
.isEqualTo("${my.bar}");
|
||||
.expectBody()
|
||||
.jsonPath("property.value").isEqualTo("${my.bar}")
|
||||
.jsonPath(forPropertyEntry(
|
||||
"unresolved-placeholder")).isEqualTo("${my.bar}");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -87,8 +91,9 @@ public class EnvironmentEndpointWebIntegrationTests {
|
|||
context.getEnvironment().getPropertySources()
|
||||
.addFirst(new MapPropertySource("placeholder", map));
|
||||
client.get().uri("/application/env/my.foo").exchange().expectStatus().isOk()
|
||||
.expectBody().jsonPath(forProperty("placeholder", "my.foo"))
|
||||
.isEqualTo("******");
|
||||
.expectBody()
|
||||
.jsonPath("property.value").isEqualTo("******")
|
||||
.jsonPath(forPropertyEntry("placeholder")).isEqualTo("******");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -123,6 +128,10 @@ public class EnvironmentEndpointWebIntegrationTests {
|
|||
+ "'].value";
|
||||
}
|
||||
|
||||
private String forPropertyEntry(String source) {
|
||||
return "propertySources[?(@.name=='" + source + "')].property.value";
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
|
||||
|
|
|
@ -45,6 +45,18 @@ public final class 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
|
||||
* {@link Environment}. Adapts each {@link PropertySource} managed by the environment
|
||||
|
|
Loading…
Reference in New Issue