Merge pull request #30006 from terminux
* gh-30006: Polish "Support overriding the default SanitizingFunction" Support overriding the default SanitizingFunction Closes gh-30006
This commit is contained in:
commit
2fec86a551
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.context.properties;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
|
||||
|
@ -48,7 +50,8 @@ public class ConfigurationPropertiesReportEndpointAutoConfiguration {
|
|||
public ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint(
|
||||
ConfigurationPropertiesReportEndpointProperties properties,
|
||||
ObjectProvider<SanitizingFunction> sanitizingFunctions) {
|
||||
ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(sanitizingFunctions);
|
||||
ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(
|
||||
sanitizingFunctions.orderedStream().collect(Collectors.toList()));
|
||||
String[] keysToSanitize = properties.getKeysToSanitize();
|
||||
if (keysToSanitize != null) {
|
||||
endpoint.setKeysToSanitize(keysToSanitize);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.env;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
|
||||
|
@ -46,7 +48,8 @@ public class EnvironmentEndpointAutoConfiguration {
|
|||
@ConditionalOnMissingBean
|
||||
public EnvironmentEndpoint environmentEndpoint(Environment environment, EnvironmentEndpointProperties properties,
|
||||
ObjectProvider<SanitizingFunction> sanitizingFunctions) {
|
||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(environment, sanitizingFunctions);
|
||||
EnvironmentEndpoint endpoint = new EnvironmentEndpoint(environment,
|
||||
sanitizingFunctions.orderedStream().collect(Collectors.toList()));
|
||||
String[] keysToSanitize = properties.getKeysToSanitize();
|
||||
if (keysToSanitize != null) {
|
||||
endpoint.setKeysToSanitize(keysToSanitize);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -32,6 +32,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -75,11 +76,11 @@ class ConfigurationPropertiesReportEndpointAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void customSanitizingFunctionShouldBeApplied() {
|
||||
void customSanitizingFunctionsAreAppliedInOrder() {
|
||||
this.contextRunner.withUserConfiguration(Config.class, SanitizingFunctionConfiguration.class)
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=configprops",
|
||||
"test.my-test-property=abc")
|
||||
.run(validateTestProperties("******", "$$$"));
|
||||
.run(validateTestProperties("$$$111$$$", "$$$222$$$"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -152,10 +153,22 @@ class ConfigurationPropertiesReportEndpointAutoConfigurationTests {
|
|||
static class SanitizingFunctionConfiguration {
|
||||
|
||||
@Bean
|
||||
SanitizingFunction testSanitizingFunction() {
|
||||
@Order(0)
|
||||
SanitizingFunction firstSanitizingFunction() {
|
||||
return (data) -> {
|
||||
if (data.getKey().contains("my")) {
|
||||
return data.withValue("$$$");
|
||||
if (data.getKey().contains("Password")) {
|
||||
return data.withValue("$$$111$$$");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
SanitizingFunction secondSanitizingFunction() {
|
||||
return (data) -> {
|
||||
if (data.getKey().contains("Password") || data.getKey().contains("test")) {
|
||||
return data.withValue("$$$222$$$");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -32,6 +32,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -72,7 +73,7 @@ class EnvironmentEndpointAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void sanitizingFunctionsCanBeConfiguredViaTheEnvironment() {
|
||||
void customSanitizingFunctionsAreAppliedInOrder() {
|
||||
this.contextRunner.withUserConfiguration(SanitizingFunctionConfiguration.class)
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=env")
|
||||
.withSystemProperties("custom=123456", "password=123456").run((context) -> {
|
||||
|
@ -81,8 +82,8 @@ class EnvironmentEndpointAutoConfigurationTests {
|
|||
EnvironmentDescriptor env = endpoint.environment(null);
|
||||
Map<String, PropertyValueDescriptor> systemProperties = getSource("systemProperties", env)
|
||||
.getProperties();
|
||||
assertThat(systemProperties.get("custom").getValue()).isEqualTo("$$$");
|
||||
assertThat(systemProperties.get("password").getValue()).isEqualTo("******");
|
||||
assertThat(systemProperties.get("custom").getValue()).isEqualTo("$$$111$$$");
|
||||
assertThat(systemProperties.get("password").getValue()).isEqualTo("$$$222$$$");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -123,8 +124,25 @@ class EnvironmentEndpointAutoConfigurationTests {
|
|||
static class SanitizingFunctionConfiguration {
|
||||
|
||||
@Bean
|
||||
SanitizingFunction testSanitizingFunction() {
|
||||
return (data) -> data.withValue("$$$");
|
||||
@Order(0)
|
||||
SanitizingFunction firstSanitizingFunction() {
|
||||
return (data) -> {
|
||||
if (data.getKey().contains("custom")) {
|
||||
return data.withValue("$$$111$$$");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
SanitizingFunction secondSanitizingFunction() {
|
||||
return (data) -> {
|
||||
if (data.getKey().contains("custom") || data.getKey().contains("password")) {
|
||||
return data.withValue("$$$222$$$");
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -184,13 +184,18 @@ public class Sanitizer {
|
|||
* @since 2.6.0
|
||||
*/
|
||||
public Object sanitize(SanitizableData data) {
|
||||
if (data.getValue() == null) {
|
||||
Object value = data.getValue();
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
for (SanitizingFunction sanitizingFunction : this.sanitizingFunctions) {
|
||||
data = sanitizingFunction.apply(data);
|
||||
Object sanitizedValue = data.getValue();
|
||||
if (!value.equals(sanitizedValue)) {
|
||||
return sanitizedValue;
|
||||
}
|
||||
}
|
||||
return data.getValue();
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean keyIsUriWithUserInfo(Pattern pattern) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -293,7 +293,7 @@ class ConfigurationPropertiesReportEndpointTests {
|
|||
new ApplicationContextRunner().withUserConfiguration(CustomSanitizingEndpointConfig.class,
|
||||
SanitizingFunctionConfiguration.class, TestPropertiesConfiguration.class)
|
||||
.run(assertProperties("test", (properties) -> {
|
||||
assertThat(properties.get("dbPassword")).isEqualTo("******");
|
||||
assertThat(properties.get("dbPassword")).isEqualTo("$$$");
|
||||
assertThat(properties.get("myTestProperty")).isEqualTo("$$$");
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,7 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -87,6 +89,39 @@ class SanitizerTests {
|
|||
assertThat(sanitizer.sanitize(hello)).isEqualTo("abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overridingDefaultSanitizingFunction() {
|
||||
Sanitizer sanitizer = new Sanitizer(Collections.singletonList((data) -> {
|
||||
if (data.getKey().equals("password")) {
|
||||
return data.withValue("------");
|
||||
}
|
||||
return data;
|
||||
}));
|
||||
SanitizableData password = new SanitizableData(null, "password", "123456");
|
||||
assertThat(sanitizer.sanitize(password)).isEqualTo("------");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenValueSanitizedLaterSanitizingFunctionsShouldBeSkipped() {
|
||||
final String sameKey = "custom";
|
||||
List<SanitizingFunction> sanitizingFunctions = new ArrayList<>();
|
||||
sanitizingFunctions.add((data) -> {
|
||||
if (data.getKey().equals(sameKey)) {
|
||||
return data.withValue("------");
|
||||
}
|
||||
return data;
|
||||
});
|
||||
sanitizingFunctions.add((data) -> {
|
||||
if (data.getKey().equals(sameKey)) {
|
||||
return data.withValue("******");
|
||||
}
|
||||
return data;
|
||||
});
|
||||
Sanitizer sanitizer = new Sanitizer(sanitizingFunctions);
|
||||
SanitizableData custom = new SanitizableData(null, sameKey, "123456");
|
||||
assertThat(sanitizer.sanitize(custom)).isEqualTo("------");
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "key = {0}")
|
||||
@MethodSource("matchingUriUserInfoKeys")
|
||||
void uriWithSingleValueWithPasswordShouldBeSanitized(String key) {
|
||||
|
|
|
@ -65,7 +65,8 @@ Alternatively, additional patterns can be configured using configprop:management
|
|||
To take more control over the santization, define a `SanitizingFunction` bean.
|
||||
The `SanitizableData` with which the function is called provides access to the key and value as well as the `PropertySource` from which they came.
|
||||
This allows you to, for example, sanitize every value that comes from a particular property source.
|
||||
Each `SanitizingFunction` is called before and in addition to the built-in key-based sanitization.
|
||||
Each `SanitizingFunction` is called in order until a function changes the value of the santizable data.
|
||||
If no function changes its value, the built-in key-based santization is performed.
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue