Prevent serialization exception from Env actuator
When `EnvironmentEndpoint` is building a response to return to the web infrastructure, it creates a data structure containing all property values from all property sources. Prior to this commit, it was possible for the response data structure to contain property values that were not serializable to JSON by Jackson, which would cause an exception to be thrown by the web infrastructure. This commit ensures the data structure is serializable to JSON by ensuring property values are primitives or Strings, and returning a placeholder value if a property value is of any other type. Fixes gh-23805
This commit is contained in:
parent
008ab4da25
commit
1a3f810cd8
|
|
@ -57,6 +57,7 @@ import org.springframework.util.SystemPropertyUtils;
|
|||
* @author Christian Dupuis
|
||||
* @author Madhura Bhave
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "env")
|
||||
|
|
@ -143,7 +144,7 @@ public class EnvironmentEndpoint {
|
|||
PlaceholdersResolver resolver) {
|
||||
Object resolved = resolver.resolvePlaceholders(source.getProperty(name));
|
||||
Origin origin = ((source instanceof OriginLookup) ? ((OriginLookup<Object>) source).getOrigin(name) : null);
|
||||
return new PropertyValueDescriptor(sanitize(name, resolved), origin);
|
||||
return new PropertyValueDescriptor(stringifyIfNecessary(sanitize(name, resolved)), origin);
|
||||
}
|
||||
|
||||
private PlaceholdersResolver getResolver() {
|
||||
|
|
@ -182,6 +183,16 @@ public class EnvironmentEndpoint {
|
|||
return this.sanitizer.sanitize(name, object);
|
||||
}
|
||||
|
||||
protected Object stringifyIfNecessary(Object value) {
|
||||
if (value == null || value.getClass().isPrimitive()) {
|
||||
return value;
|
||||
}
|
||||
if (CharSequence.class.isAssignableFrom(value.getClass())) {
|
||||
return value.toString();
|
||||
}
|
||||
return "Complex property type " + value.getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link PropertySourcesPlaceholdersResolver} that sanitizes sensitive placeholders
|
||||
* if present.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.env;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -39,6 +42,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
|||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
@ -54,6 +58,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Andy Wilkinson
|
||||
* @author HaiTao Zhang
|
||||
* @author Chris Bono
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class EnvironmentEndpointTests {
|
||||
|
||||
|
|
@ -194,15 +199,22 @@ class EnvironmentEndpointTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void propertyWithTypeOtherThanStringShouldNotFail() {
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
environment.getPropertySources()
|
||||
.addFirst(singleKeyPropertySource("test", "foo", Collections.singletonMap("bar", "baz")));
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment).environment(null);
|
||||
Map<String, String> foo = (Map<String, String>) propertySources(descriptor).get("test").getProperties()
|
||||
.get("foo").getValue();
|
||||
assertThat(foo.get("bar")).isEqualTo("baz");
|
||||
String value = (String) propertySources(descriptor).get("test").getProperties().get("foo").getValue();
|
||||
assertThat(value).isEqualTo("Complex property type java.util.Collections$SingletonMap");
|
||||
}
|
||||
|
||||
@Test
|
||||
void propertyWithCharSequenceTypeIsConvertedToString() throws Exception {
|
||||
ConfigurableEnvironment environment = emptyEnvironment();
|
||||
environment.getPropertySources().addFirst(singleKeyPropertySource("test", "foo", new CharSequenceProperty()));
|
||||
EnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment).environment(null);
|
||||
String value = (String) propertySources(descriptor).get("test").getProperties().get("foo").getValue();
|
||||
assertThat(value).isEqualTo("test value");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -360,4 +372,35 @@ class EnvironmentEndpointTests {
|
|||
|
||||
}
|
||||
|
||||
public static class CharSequenceProperty implements CharSequence, InputStreamSource {
|
||||
|
||||
private final String value = "test value";
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return this.value.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return this.value.charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return this.value.subSequence(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(this.value.getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue