Skip to content

Commit 54f4e44

Browse files
committed
Merge pull request #17939 from htztomic
* pr/17939: Polish "Sanitize password in URI properties" Sanitize password in URI properties Closes gh-17939
2 parents 0fee0ca + 7829593 commit 54f4e44

File tree

4 files changed

+80
-1
lines changed

4 files changed

+80
-1
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Sanitizer.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
package org.springframework.boot.actuate.endpoint;
1818

19+
import java.util.regex.Matcher;
1920
import java.util.regex.Pattern;
2021

2122
import org.springframework.util.Assert;
23+
import org.springframework.util.StringUtils;
2224

2325
/**
2426
* Strategy that should be used by endpoint implementations to sanitize potentially
@@ -29,16 +31,19 @@
2931
* @author Phillip Webb
3032
* @author Nicolas Lejeune
3133
* @author Stephane Nicoll
34+
* @author HaiTao Zhang
3235
* @since 2.0.0
3336
*/
3437
public class Sanitizer {
3538

3639
private static final String[] REGEX_PARTS = { "*", "$", "^", "+" };
3740

41+
private static final Pattern URI_USERINFO_PATTERN = Pattern.compile("[A-Za-z]+://.+:(.*)@.+$");
42+
3843
private Pattern[] keysToSanitize;
3944

4045
public Sanitizer() {
41-
this("password", "secret", "key", "token", ".*credentials.*", "vcap_services", "sun.java.command");
46+
this("password", "secret", "key", "token", ".*credentials.*", "vcap_services", "sun.java.command", "uri");
4247
}
4348

4449
public Sanitizer(String... keysToSanitize) {
@@ -86,10 +91,22 @@ public Object sanitize(String key, Object value) {
8691
}
8792
for (Pattern pattern : this.keysToSanitize) {
8893
if (pattern.matcher(key).matches()) {
94+
if (pattern.matcher("uri").matches()) {
95+
return sanitizeUri(value);
96+
}
8997
return "******";
9098
}
9199
}
92100
return value;
93101
}
94102

103+
private Object sanitizeUri(Object value) {
104+
Matcher matcher = URI_USERINFO_PATTERN.matcher(value.toString());
105+
String password = matcher.matches() ? matcher.group(1) : null;
106+
if (password != null) {
107+
return StringUtils.replace(value.toString(), ":" + password + "@", ":******@");
108+
}
109+
return value;
110+
}
111+
95112
}

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.context.properties;
1818

19+
import java.net.URI;
1920
import java.time.Duration;
2021
import java.util.ArrayList;
2122
import java.util.Arrays;
@@ -46,6 +47,7 @@
4647
* @author Dave Syer
4748
* @author Andy Wilkinson
4849
* @author Stephane Nicoll
50+
* @author HaiTao Zhang
4951
*/
5052
class ConfigurationPropertiesReportEndpointTests {
5153

@@ -174,6 +176,22 @@ void listsAreSanitized() {
174176
});
175177
}
176178

179+
@Test
180+
void sanitizedUriWithSensitiveInfo() {
181+
load((context, properties) -> {
182+
Map<String, Object> nestedProperties = properties.getBeans().get("testProperties").getProperties();
183+
assertThat(nestedProperties.get("sensitiveUri")).isEqualTo("http://user:******@localhost:8080");
184+
});
185+
}
186+
187+
@Test
188+
void sanitizedUriWithNoPassword() {
189+
load((context, properties) -> {
190+
Map<String, Object> nestedProperties = properties.getBeans().get("testProperties").getProperties();
191+
assertThat(nestedProperties.get("noPasswordUri")).isEqualTo("http://user:******@localhost:8080");
192+
});
193+
}
194+
177195
@Test
178196
@SuppressWarnings("unchecked")
179197
void listsOfListsAreSanitized() {
@@ -266,6 +284,10 @@ public static class TestProperties {
266284

267285
private Duration duration = Duration.ofSeconds(10);
268286

287+
private URI sensitiveUri = URI.create("http://user:password@localhost:8080");
288+
289+
private URI noPasswordUri = URI.create("http://user:@localhost:8080");
290+
269291
TestProperties() {
270292
this.secrets.put("mine", "myPrivateThing");
271293
this.secrets.put("yours", "yourPrivateThing");
@@ -377,6 +399,22 @@ public void setDuration(Duration duration) {
377399
this.duration = duration;
378400
}
379401

402+
public void setSensitiveUri(URI sensitiveUri) {
403+
this.sensitiveUri = sensitiveUri;
404+
}
405+
406+
public URI getSensitiveUri() {
407+
return this.sensitiveUri;
408+
}
409+
410+
public void setNoPasswordUri(URI noPasswordUri) {
411+
this.noPasswordUri = noPasswordUri;
412+
}
413+
414+
public URI getNoPasswordUri() {
415+
return this.noPasswordUri;
416+
}
417+
380418
public static class Hidden {
381419

382420
private String mine = "mySecret";

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizerTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ void defaults() {
4040
assertThat(sanitizer.sanitize("sometoken", "secret")).isEqualTo("******");
4141
assertThat(sanitizer.sanitize("find", "secret")).isEqualTo("secret");
4242
assertThat(sanitizer.sanitize("sun.java.command", "--spring.redis.password=pa55w0rd")).isEqualTo("******");
43+
assertThat(sanitizer.sanitize("my.uri", "http://user:password@localhost:8080"))
44+
.isEqualTo("http://user:******@localhost:8080");
45+
}
46+
47+
@Test
48+
void uriWithNoPasswordShouldNotBeSanitized() {
49+
Sanitizer sanitizer = new Sanitizer();
50+
assertThat(sanitizer.sanitize("my.uri", "http://localhost:8080")).isEqualTo("http://localhost:8080");
51+
}
52+
53+
@Test
54+
void uriWithPasswordMatchingOtherPartsOfString() {
55+
Sanitizer sanitizer = new Sanitizer();
56+
assertThat(sanitizer.sanitize("my.uri", "http://user://@localhost:8080"))
57+
.isEqualTo("http://user:******@localhost:8080");
4358
}
4459

4560
@Test

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* @author Stephane Nicoll
5050
* @author Madhura Bhave
5151
* @author Andy Wilkinson
52+
* @author HaiTao Zhang
5253
*/
5354
class EnvironmentEndpointTests {
5455

@@ -244,6 +245,14 @@ void multipleSourcesWithSameProperty() {
244245
assertThat(sources.get("two").getProperties().get("a").getValue()).isEqualTo("apple");
245246
}
246247

248+
@Test
249+
void uriPropertryWithSensitiveInfo() {
250+
ConfigurableEnvironment environment = new StandardEnvironment();
251+
TestPropertyValues.of("sensitive.uri=http://user:password@localhost:8080").applyTo(environment);
252+
EnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment).environmentEntry("sensitive.uri");
253+
assertThat(descriptor.getProperty().getValue()).isEqualTo("http://user:******@localhost:8080");
254+
}
255+
247256
private static ConfigurableEnvironment emptyEnvironment() {
248257
StandardEnvironment environment = new StandardEnvironment();
249258
environment.getPropertySources().remove(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);

0 commit comments

Comments
 (0)