Commit bd20b541 authored by Phillip Webb's avatar Phillip Webb

Consider prefixes when sanitizing `/configprops`

Update ConfigurationPropertiesReportEndpoint so that property prefixes
are also considered when sanitizing values.

Fixes gh-4415
parent 4aefe9f8
...@@ -111,7 +111,7 @@ public class ConfigurationPropertiesReportEndpoint ...@@ -111,7 +111,7 @@ public class ConfigurationPropertiesReportEndpoint
Map<String, Object> root = new HashMap<String, Object>(); Map<String, Object> root = new HashMap<String, Object>();
String prefix = extractPrefix(context, beanFactoryMetaData, beanName, bean); String prefix = extractPrefix(context, beanFactoryMetaData, beanName, bean);
root.put("prefix", prefix); root.put("prefix", prefix);
root.put("properties", sanitize(safeSerialize(mapper, bean, prefix))); root.put("properties", sanitize(prefix, safeSerialize(mapper, bean, prefix)));
result.put(beanName, root); result.put(beanName, root);
} }
if (context.getParent() != null) { if (context.getParent() != null) {
...@@ -231,15 +231,18 @@ public class ConfigurationPropertiesReportEndpoint ...@@ -231,15 +231,18 @@ public class ConfigurationPropertiesReportEndpoint
* @return the sanitized map * @return the sanitized map
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Map<String, Object> sanitize(Map<String, Object> map) { private Map<String, Object> sanitize(String prefix, Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) { for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
String qualifiedKey = (prefix.length() == 0 ? prefix : prefix + ".") + key;
Object value = entry.getValue(); Object value = entry.getValue();
if (value instanceof Map) { if (value instanceof Map) {
map.put(key, sanitize((Map<String, Object>) value)); map.put(key, sanitize(qualifiedKey, (Map<String, Object>) value));
} }
else { else {
map.put(key, this.sanitizer.sanitize(key, value)); value = this.sanitizer.sanitize(key, value);
value = this.sanitizer.sanitize(qualifiedKey, value);
map.put(key, value);
} }
} }
return map; return map;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
...@@ -135,8 +136,8 @@ public class ConfigurationPropertiesReportEndpointTests ...@@ -135,8 +136,8 @@ public class ConfigurationPropertiesReportEndpointTests
assertEquals("654321", nestedProperties.get("myTestProperty")); assertEquals("654321", nestedProperties.get("myTestProperty"));
} }
@SuppressWarnings("unchecked")
@Test @Test
@SuppressWarnings("unchecked")
public void testKeySanitizationWithCustomPatternAndKeyByEnvironment() public void testKeySanitizationWithCustomPatternAndKeyByEnvironment()
throws Exception { throws Exception {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
...@@ -153,6 +154,29 @@ public class ConfigurationPropertiesReportEndpointTests ...@@ -153,6 +154,29 @@ public class ConfigurationPropertiesReportEndpointTests
assertEquals("******", nestedProperties.get("myTestProperty")); assertEquals("******", nestedProperties.get("myTestProperty"));
} }
@Test
@SuppressWarnings("unchecked")
public void testKeySanitizationWithCustomPatternUsingCompositeKeys()
throws Exception {
// gh-4415
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"endpoints.configprops.keys-to-sanitize: .*\\.secrets\\..*, .*\\.hidden\\..*");
this.context.register(Config.class);
this.context.refresh();
ConfigurationPropertiesReportEndpoint report = getEndpointBean();
Map<String, Object> properties = report.invoke();
Map<String, Object> nestedProperties = (Map<String, Object>) ((Map<String, Object>) properties
.get("testProperties")).get("properties");
assertNotNull(nestedProperties);
Map<String, Object> secrets = (Map<String, Object>) nestedProperties
.get("secrets");
Map<String, Object> hidden = (Map<String, Object>) nestedProperties.get("hidden");
assertEquals("******", secrets.get("mine"));
assertEquals("******", secrets.get("yours"));
assertEquals("******", hidden.get("mine"));
}
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void mixedBoolean() throws Exception { public void mixedBoolean() throws Exception {
...@@ -197,6 +221,15 @@ public class ConfigurationPropertiesReportEndpointTests ...@@ -197,6 +221,15 @@ public class ConfigurationPropertiesReportEndpointTests
private Boolean mixedBoolean = true; private Boolean mixedBoolean = true;
private Map<String, Object> secrets = new HashMap<String, Object>();
private Hidden hidden = new Hidden();
public TestProperties() {
this.secrets.put("mine", "myPrivateThing");
this.secrets.put("yours", "yourPrivateThing");
}
public String getDbPassword() { public String getDbPassword() {
return this.dbPassword; return this.dbPassword;
} }
...@@ -221,5 +254,35 @@ public class ConfigurationPropertiesReportEndpointTests ...@@ -221,5 +254,35 @@ public class ConfigurationPropertiesReportEndpointTests
this.mixedBoolean = mixedBoolean; this.mixedBoolean = mixedBoolean;
} }
public Map<String, Object> getSecrets() {
return this.secrets;
}
public void setSecrets(Map<String, Object> secrets) {
this.secrets = secrets;
}
public Hidden getHidden() {
return this.hidden;
}
public void setHidden(Hidden hidden) {
this.hidden = hidden;
}
public static class Hidden {
private String mine = "mySecret";
public String getMine() {
return this.mine;
}
public void setMine(String mine) {
this.mine = mine;
}
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment