From d27c255d8bae6d159eec74bac4b046debd88fbb2 Mon Sep 17 00:00:00 2001 From: HaiTao Zhang Date: Thu, 22 Aug 2019 11:18:34 -0700 Subject: [PATCH] fix to gh-8293 and gh-17930 --- .../boot/actuate/endpoint/Sanitizer.java | 24 +++++++++++- ...gurationPropertiesReportEndpointTests.java | 38 +++++++++++++++++++ .../boot/actuate/endpoint/SanitizerTests.java | 2 + .../actuate/env/EnvironmentEndpointTests.java | 9 +++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Sanitizer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Sanitizer.java index 386b916df96c..ffab6c7fe86e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Sanitizer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Sanitizer.java @@ -16,9 +16,11 @@ package org.springframework.boot.actuate.endpoint; +import java.net.URI; 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,6 +31,7 @@ * @author Phillip Webb * @author Nicolas Lejeune * @author Stephane Nicoll + * @author HaiTao Zhang * @since 2.0.0 */ public class Sanitizer { @@ -38,7 +41,7 @@ public class Sanitizer { 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 +89,29 @@ public Object sanitize(String key, Object value) { } 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) { + URI uri = URI.create(value.toString()); + String userInfo = uri.getUserInfo(); + if (!StringUtils.hasText(userInfo) || userInfo.split(":").length == 0) { + return value; + } + String[] parts = userInfo.split(":"); + String userName = parts[0]; + if (StringUtils.hasText(userName)) { + String sanitizedPassword = "******"; + return uri.getScheme() + "://" + userName + ":" + sanitizedPassword + "@" + uri.getHost() + ":" + + uri.getPort() + uri.getPath(); + } + return value; + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java index 292de006e025..7e15053f9432 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java @@ -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 @@ * @author Dave Syer * @author Andy Wilkinson * @author Stephane Nicoll + * @author HaiTao Zhang */ class ConfigurationPropertiesReportEndpointTests { @@ -174,6 +176,22 @@ void listsAreSanitized() { }); } + @Test + void sanitizedUriWithSensitiveInfo() { + load((context, properties) -> { + Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); + assertThat(nestedProperties.get("sensitiveUri")).isEqualTo("http://user:******@localhost:8080"); + }); + } + + @Test + void sanitizedUriWithNoPassword() { + load((context, properties) -> { + Map nestedProperties = properties.getBeans().get("testProperties").getProperties(); + assertThat(nestedProperties.get("noPasswordUri")).isEqualTo("http://user:******@localhost:8080"); + }); + } + @Test @SuppressWarnings("unchecked") void listsOfListsAreSanitized() { @@ -266,6 +284,10 @@ public static class TestProperties { private Duration duration = Duration.ofSeconds(10); + private URI sensitiveUri = URI.create("http://user:password@localhost:8080"); + + private URI noPasswordUri = URI.create("http://user:p@localhost:8080"); + TestProperties() { this.secrets.put("mine", "myPrivateThing"); this.secrets.put("yours", "yourPrivateThing"); @@ -377,6 +399,22 @@ public void setDuration(Duration duration) { 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"; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizerTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizerTests.java index 1677cde539d4..62ef9447d060 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizerTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizerTests.java @@ -40,6 +40,8 @@ void defaults() { 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 diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java index 5b0c75e379fa..ecaa47813cb7 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java @@ -49,6 +49,7 @@ * @author Stephane Nicoll * @author Madhura Bhave * @author Andy Wilkinson + * @author HaiTao Zhang */ class EnvironmentEndpointTests { @@ -244,6 +245,14 @@ void multipleSourcesWithSameProperty() { 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);