Skip to content

Commit 2fec86a

Browse files
committed
Merge pull request #30006 from terminux
* gh-30006: Polish "Support overriding the default SanitizingFunction" Support overriding the default SanitizingFunction Closes gh-30006
2 parents a5d900d + ff7321c commit 2fec86a

File tree

8 files changed

+99
-21
lines changed

8 files changed

+99
-21
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/context/properties/ConfigurationPropertiesReportEndpointAutoConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

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

19+
import java.util.stream.Collectors;
20+
1921
import org.springframework.beans.factory.ObjectProvider;
2022
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
2123
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
@@ -48,7 +50,8 @@ public class ConfigurationPropertiesReportEndpointAutoConfiguration {
4850
public ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint(
4951
ConfigurationPropertiesReportEndpointProperties properties,
5052
ObjectProvider<SanitizingFunction> sanitizingFunctions) {
51-
ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(sanitizingFunctions);
53+
ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(
54+
sanitizingFunctions.orderedStream().collect(Collectors.toList()));
5255
String[] keysToSanitize = properties.getKeysToSanitize();
5356
if (keysToSanitize != null) {
5457
endpoint.setKeysToSanitize(keysToSanitize);

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/env/EnvironmentEndpointAutoConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.env;
1818

19+
import java.util.stream.Collectors;
20+
1921
import org.springframework.beans.factory.ObjectProvider;
2022
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
2123
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
@@ -46,7 +48,8 @@ public class EnvironmentEndpointAutoConfiguration {
4648
@ConditionalOnMissingBean
4749
public EnvironmentEndpoint environmentEndpoint(Environment environment, EnvironmentEndpointProperties properties,
4850
ObjectProvider<SanitizingFunction> sanitizingFunctions) {
49-
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(environment, sanitizingFunctions);
51+
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(environment,
52+
sanitizingFunctions.orderedStream().collect(Collectors.toList()));
5053
String[] keysToSanitize = properties.getKeysToSanitize();
5154
if (keysToSanitize != null) {
5255
endpoint.setKeysToSanitize(keysToSanitize);

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
import org.springframework.boot.test.context.runner.ContextConsumer;
3333
import org.springframework.context.annotation.Bean;
3434
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.core.annotation.Order;
3536

3637
import static org.assertj.core.api.Assertions.assertThat;
3738

@@ -75,11 +76,11 @@ void additionalKeysToSanitizeCanBeConfiguredViaTheEnvironment() {
7576
}
7677

7778
@Test
78-
void customSanitizingFunctionShouldBeApplied() {
79+
void customSanitizingFunctionsAreAppliedInOrder() {
7980
this.contextRunner.withUserConfiguration(Config.class, SanitizingFunctionConfiguration.class)
8081
.withPropertyValues("management.endpoints.web.exposure.include=configprops",
8182
"test.my-test-property=abc")
82-
.run(validateTestProperties("******", "$$$"));
83+
.run(validateTestProperties("$$$111$$$", "$$$222$$$"));
8384
}
8485

8586
@Test
@@ -152,10 +153,22 @@ public void setMyTestProperty(String myTestProperty) {
152153
static class SanitizingFunctionConfiguration {
153154

154155
@Bean
155-
SanitizingFunction testSanitizingFunction() {
156+
@Order(0)
157+
SanitizingFunction firstSanitizingFunction() {
156158
return (data) -> {
157-
if (data.getKey().contains("my")) {
158-
return data.withValue("$$$");
159+
if (data.getKey().contains("Password")) {
160+
return data.withValue("$$$111$$$");
161+
}
162+
return data;
163+
};
164+
}
165+
166+
@Bean
167+
@Order(1)
168+
SanitizingFunction secondSanitizingFunction() {
169+
return (data) -> {
170+
if (data.getKey().contains("Password") || data.getKey().contains("test")) {
171+
return data.withValue("$$$222$$$");
159172
}
160173
return data;
161174
};

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
import org.springframework.boot.test.context.runner.ContextConsumer;
3333
import org.springframework.context.annotation.Bean;
3434
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.core.annotation.Order;
3536

3637
import static org.assertj.core.api.Assertions.assertThat;
3738

@@ -72,7 +73,7 @@ void keysToSanitizeCanBeConfiguredViaTheEnvironment() {
7273
}
7374

7475
@Test
75-
void sanitizingFunctionsCanBeConfiguredViaTheEnvironment() {
76+
void customSanitizingFunctionsAreAppliedInOrder() {
7677
this.contextRunner.withUserConfiguration(SanitizingFunctionConfiguration.class)
7778
.withPropertyValues("management.endpoints.web.exposure.include=env")
7879
.withSystemProperties("custom=123456", "password=123456").run((context) -> {
@@ -81,8 +82,8 @@ void sanitizingFunctionsCanBeConfiguredViaTheEnvironment() {
8182
EnvironmentDescriptor env = endpoint.environment(null);
8283
Map<String, PropertyValueDescriptor> systemProperties = getSource("systemProperties", env)
8384
.getProperties();
84-
assertThat(systemProperties.get("custom").getValue()).isEqualTo("$$$");
85-
assertThat(systemProperties.get("password").getValue()).isEqualTo("******");
85+
assertThat(systemProperties.get("custom").getValue()).isEqualTo("$$$111$$$");
86+
assertThat(systemProperties.get("password").getValue()).isEqualTo("$$$222$$$");
8687
});
8788
}
8889

@@ -123,8 +124,25 @@ private PropertySourceDescriptor getSource(String name, EnvironmentDescriptor de
123124
static class SanitizingFunctionConfiguration {
124125

125126
@Bean
126-
SanitizingFunction testSanitizingFunction() {
127-
return (data) -> data.withValue("$$$");
127+
@Order(0)
128+
SanitizingFunction firstSanitizingFunction() {
129+
return (data) -> {
130+
if (data.getKey().contains("custom")) {
131+
return data.withValue("$$$111$$$");
132+
}
133+
return data;
134+
};
135+
}
136+
137+
@Bean
138+
@Order(1)
139+
SanitizingFunction secondSanitizingFunction() {
140+
return (data) -> {
141+
if (data.getKey().contains("custom") || data.getKey().contains("password")) {
142+
return data.withValue("$$$222$$$");
143+
}
144+
return data;
145+
};
128146
}
129147

130148
}

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -184,13 +184,18 @@ public Object sanitize(String key, Object value) {
184184
* @since 2.6.0
185185
*/
186186
public Object sanitize(SanitizableData data) {
187-
if (data.getValue() == null) {
187+
Object value = data.getValue();
188+
if (value == null) {
188189
return null;
189190
}
190191
for (SanitizingFunction sanitizingFunction : this.sanitizingFunctions) {
191192
data = sanitizingFunction.apply(data);
193+
Object sanitizedValue = data.getValue();
194+
if (!value.equals(sanitizedValue)) {
195+
return sanitizedValue;
196+
}
192197
}
193-
return data.getValue();
198+
return value;
194199
}
195200

196201
private boolean keyIsUriWithUserInfo(Pattern pattern) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -293,7 +293,7 @@ void sanitizeWithCustomSanitizingFunction() {
293293
new ApplicationContextRunner().withUserConfiguration(CustomSanitizingEndpointConfig.class,
294294
SanitizingFunctionConfiguration.class, TestPropertiesConfiguration.class)
295295
.run(assertProperties("test", (properties) -> {
296-
assertThat(properties.get("dbPassword")).isEqualTo("******");
296+
assertThat(properties.get("dbPassword")).isEqualTo("$$$");
297297
assertThat(properties.get("myTestProperty")).isEqualTo("$$$");
298298
}));
299299
}

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,9 @@
1616

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

19+
import java.util.ArrayList;
1920
import java.util.Collections;
21+
import java.util.List;
2022
import java.util.stream.Stream;
2123

2224
import org.junit.jupiter.api.Test;
@@ -87,6 +89,39 @@ void whenCustomSanitizingFunctionPresentValueShouldBeSanitized() {
8789
assertThat(sanitizer.sanitize(hello)).isEqualTo("abc");
8890
}
8991

92+
@Test
93+
void overridingDefaultSanitizingFunction() {
94+
Sanitizer sanitizer = new Sanitizer(Collections.singletonList((data) -> {
95+
if (data.getKey().equals("password")) {
96+
return data.withValue("------");
97+
}
98+
return data;
99+
}));
100+
SanitizableData password = new SanitizableData(null, "password", "123456");
101+
assertThat(sanitizer.sanitize(password)).isEqualTo("------");
102+
}
103+
104+
@Test
105+
void whenValueSanitizedLaterSanitizingFunctionsShouldBeSkipped() {
106+
final String sameKey = "custom";
107+
List<SanitizingFunction> sanitizingFunctions = new ArrayList<>();
108+
sanitizingFunctions.add((data) -> {
109+
if (data.getKey().equals(sameKey)) {
110+
return data.withValue("------");
111+
}
112+
return data;
113+
});
114+
sanitizingFunctions.add((data) -> {
115+
if (data.getKey().equals(sameKey)) {
116+
return data.withValue("******");
117+
}
118+
return data;
119+
});
120+
Sanitizer sanitizer = new Sanitizer(sanitizingFunctions);
121+
SanitizableData custom = new SanitizableData(null, sameKey, "123456");
122+
assertThat(sanitizer.sanitize(custom)).isEqualTo("------");
123+
}
124+
90125
@ParameterizedTest(name = "key = {0}")
91126
@MethodSource("matchingUriUserInfoKeys")
92127
void uriWithSingleValueWithPasswordShouldBeSanitized(String key) {

spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto/actuator.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ Alternatively, additional patterns can be configured using configprop:management
6565
To take more control over the santization, define a `SanitizingFunction` bean.
6666
The `SanitizableData` with which the function is called provides access to the key and value as well as the `PropertySource` from which they came.
6767
This allows you to, for example, sanitize every value that comes from a particular property source.
68-
Each `SanitizingFunction` is called before and in addition to the built-in key-based sanitization.
68+
Each `SanitizingFunction` is called in order until a function changes the value of the santizable data.
69+
If no function changes its value, the built-in key-based santization is performed.
6970

7071

7172

0 commit comments

Comments
 (0)