Commit 54f4e440 authored by Madhura Bhave's avatar Madhura Bhave

Merge pull request #17939 from htztomic

* pr/17939:
  Polish "Sanitize password in URI properties"
  Sanitize password in URI properties

Closes gh-17939
parents 0fee0ca7 78295937
......@@ -16,9 +16,11 @@
package org.springframework.boot.actuate.endpoint;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Strategy that should be used by endpoint implementations to sanitize potentially
......@@ -29,16 +31,19 @@ import org.springframework.util.Assert;
* @author Phillip Webb
* @author Nicolas Lejeune
* @author Stephane Nicoll
* @author HaiTao Zhang
* @since 2.0.0
*/
public class Sanitizer {
private static final String[] REGEX_PARTS = { "*", "$", "^", "+" };
private static final Pattern URI_USERINFO_PATTERN = Pattern.compile("[A-Za-z]+://.+:(.*)@.+$");
private Pattern[] keysToSanitize;
public Sanitizer() {
this("password", "secret", "key", "token", ".*credentials.*", "vcap_services", "sun.java.command");
this("password", "secret", "key", "token", ".*credentials.*", "vcap_services", "sun.java.command", "uri");
}
public Sanitizer(String... keysToSanitize) {
......@@ -86,10 +91,22 @@ public class Sanitizer {
}
for (Pattern pattern : this.keysToSanitize) {
if (pattern.matcher(key).matches()) {
if (pattern.matcher("uri").matches()) {
return sanitizeUri(value);
}
return "******";
}
}
return value;
}
private Object sanitizeUri(Object value) {
Matcher matcher = URI_USERINFO_PATTERN.matcher(value.toString());
String password = matcher.matches() ? matcher.group(1) : null;
if (password != null) {
return StringUtils.replace(value.toString(), ":" + password + "@", ":******@");
}
return value;
}
}
......@@ -16,6 +16,7 @@
package org.springframework.boot.actuate.context.properties;
import java.net.URI;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -46,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author HaiTao Zhang
*/
class ConfigurationPropertiesReportEndpointTests {
......@@ -174,6 +176,22 @@ class ConfigurationPropertiesReportEndpointTests {
});
}
@Test
void sanitizedUriWithSensitiveInfo() {
load((context, properties) -> {
Map<String, Object> nestedProperties = properties.getBeans().get("testProperties").getProperties();
assertThat(nestedProperties.get("sensitiveUri")).isEqualTo("http://user:******@localhost:8080");
});
}
@Test
void sanitizedUriWithNoPassword() {
load((context, properties) -> {
Map<String, Object> nestedProperties = properties.getBeans().get("testProperties").getProperties();
assertThat(nestedProperties.get("noPasswordUri")).isEqualTo("http://user:******@localhost:8080");
});
}
@Test
@SuppressWarnings("unchecked")
void listsOfListsAreSanitized() {
......@@ -266,6 +284,10 @@ class ConfigurationPropertiesReportEndpointTests {
private Duration duration = Duration.ofSeconds(10);
private URI sensitiveUri = URI.create("http://user:password@localhost:8080");
private URI noPasswordUri = URI.create("http://user:@localhost:8080");
TestProperties() {
this.secrets.put("mine", "myPrivateThing");
this.secrets.put("yours", "yourPrivateThing");
......@@ -377,6 +399,22 @@ class ConfigurationPropertiesReportEndpointTests {
this.duration = duration;
}
public void setSensitiveUri(URI sensitiveUri) {
this.sensitiveUri = sensitiveUri;
}
public URI getSensitiveUri() {
return this.sensitiveUri;
}
public void setNoPasswordUri(URI noPasswordUri) {
this.noPasswordUri = noPasswordUri;
}
public URI getNoPasswordUri() {
return this.noPasswordUri;
}
public static class Hidden {
private String mine = "mySecret";
......
......@@ -40,6 +40,21 @@ class SanitizerTests {
assertThat(sanitizer.sanitize("sometoken", "secret")).isEqualTo("******");
assertThat(sanitizer.sanitize("find", "secret")).isEqualTo("secret");
assertThat(sanitizer.sanitize("sun.java.command", "--spring.redis.password=pa55w0rd")).isEqualTo("******");
assertThat(sanitizer.sanitize("my.uri", "http://user:password@localhost:8080"))
.isEqualTo("http://user:******@localhost:8080");
}
@Test
void uriWithNoPasswordShouldNotBeSanitized() {
Sanitizer sanitizer = new Sanitizer();
assertThat(sanitizer.sanitize("my.uri", "http://localhost:8080")).isEqualTo("http://localhost:8080");
}
@Test
void uriWithPasswordMatchingOtherPartsOfString() {
Sanitizer sanitizer = new Sanitizer();
assertThat(sanitizer.sanitize("my.uri", "http://user://@localhost:8080"))
.isEqualTo("http://user:******@localhost:8080");
}
@Test
......
......@@ -49,6 +49,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Stephane Nicoll
* @author Madhura Bhave
* @author Andy Wilkinson
* @author HaiTao Zhang
*/
class EnvironmentEndpointTests {
......@@ -244,6 +245,14 @@ class EnvironmentEndpointTests {
assertThat(sources.get("two").getProperties().get("a").getValue()).isEqualTo("apple");
}
@Test
void uriPropertryWithSensitiveInfo() {
ConfigurableEnvironment environment = new StandardEnvironment();
TestPropertyValues.of("sensitive.uri=http://user:password@localhost:8080").applyTo(environment);
EnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment).environmentEntry("sensitive.uri");
assertThat(descriptor.getProperty().getValue()).isEqualTo("http://user:******@localhost:8080");
}
private static ConfigurableEnvironment emptyEnvironment() {
StandardEnvironment environment = new StandardEnvironment();
environment.getPropertySources().remove(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
......
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