Consider prefixes when sanitizing `/configprops`
Update ConfigurationPropertiesReportEndpoint so that property prefixes are also considered when sanitizing values. Fixes gh-4415
This commit is contained in:
parent
4aefe9f856
commit
bd20b5419e
|
|
@ -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
|
||||||
* @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 @@
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue