Support global endpoint.sensitive override

Add support for an `endpoint.sensitive` property that can be used to
override the endpoint `sensitive` default.

Fixes gh-4419
pull/4432/head
Phillip Webb 9 years ago
parent 332c6911cf
commit 8c642bec74

@ -35,6 +35,7 @@ import org.springframework.boot.actuate.endpoint.BeansEndpoint;
import org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEndpoint;
import org.springframework.boot.actuate.endpoint.DumpEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.FlywayEndpoint;
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
@ -60,6 +61,7 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.bind.PropertiesConfigurationFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
@ -82,6 +84,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
*/
@Configuration
@AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
@EnableConfigurationProperties(EndpointProperties.class)
public class EndpointAutoConfiguration {
@Autowired

@ -31,8 +31,6 @@ import org.springframework.core.env.Environment;
*/
public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAware {
private static final String ENDPOINTS_ENABLED_PROPERTY = "endpoints.enabled";
private Environment environment;
/**
@ -43,10 +41,12 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
@Pattern(regexp = "\\w+", message = "ID must only contains letters, numbers and '_'")
private String id;
private final boolean sensitiveDefaut;
/**
* Mark if the endpoint exposes sensitive information.
*/
private boolean sensitive;
private Boolean sensitive;
/**
* Enable the endpoint.
@ -66,11 +66,11 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
* Create a new endpoint instance. The enpoint will enabled flag will be based on the
* spring {@link Environment} unless explicitly set.
* @param id the endpoint ID
* @param sensitive if the endpoint is sensitive
* @param sensitive if the endpoint is sensitive by default
*/
public AbstractEndpoint(String id, boolean sensitive) {
this.id = id;
this.sensitive = sensitive;
this.sensitiveDefaut = sensitive;
}
/**
@ -81,7 +81,7 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
*/
public AbstractEndpoint(String id, boolean sensitive, boolean enabled) {
this.id = id;
this.sensitive = sensitive;
this.sensitiveDefaut = sensitive;
this.enabled = enabled;
}
@ -105,14 +105,7 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
@Override
public boolean isEnabled() {
if (this.enabled != null) {
return this.enabled;
}
if (this.environment != null) {
return this.environment.getProperty(ENDPOINTS_ENABLED_PROPERTY, Boolean.class,
true);
}
return true;
return EndpointProperties.isEnabled(this.environment, this.enabled);
}
public void setEnabled(Boolean enabled) {
@ -121,10 +114,11 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
@Override
public boolean isSensitive() {
return this.sensitive;
return EndpointProperties.isSensitive(this.environment, this.sensitive,
this.sensitiveDefaut);
}
public void setSensitive(boolean sensitive) {
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}

@ -0,0 +1,100 @@
/*
* Copyright 2012-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
/**
* Global endpoint properties.
*
* @author Phillip Webb
* @since 1.3.0
*/
@ConfigurationProperties(prefix = "endpoints")
public class EndpointProperties {
private static final String ENDPOINTS_ENABLED_PROPERTY = "endpoints.enabled";
private static final String ENDPOINTS_SENSITIVE_PROPERTY = "endpoints.sensitive";
/**
* Enable endpoints.
*/
private Boolean enabled = true;
/**
* Default endpoint sensitive setting.
*/
private Boolean sensitive;
public Boolean getEnabled() {
return this.enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getSensitive() {
return this.sensitive;
}
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}
/**
* Determine if an endpoint is enabled based on its specific property and taking into
* account the global default.
* @param environment the Spring environment or {@code null}.
* @param enabled the endpoint property or {@code null}
* @return if the endpoint is enabled
*/
public static boolean isEnabled(Environment environment, Boolean enabled) {
if (enabled != null) {
return enabled;
}
if (environment != null
&& environment.containsProperty(ENDPOINTS_ENABLED_PROPERTY)) {
return environment.getProperty(ENDPOINTS_ENABLED_PROPERTY, Boolean.class);
}
return true;
}
/**
* Determine if an endpoint is sensitive based on its specific property and taking
* into account the global default.
* @param environment the Spring environment or {@code null}.
* @param sensitive the endpoint property or {@code null}
* @param sensitiveDefaut the default setting to use if no environment property is
* defined
* @return if the endpoint is sensitive
*/
public static boolean isSensitive(Environment environment, Boolean sensitive,
boolean sensitiveDefaut) {
if (sensitive != null) {
return sensitive;
}
if (environment != null
&& environment.containsProperty(ENDPOINTS_SENSITIVE_PROPERTY)) {
return environment.getProperty(ENDPOINTS_SENSITIVE_PROPERTY, Boolean.class);
}
return sensitiveDefaut;
}
}

@ -17,7 +17,10 @@
package org.springframework.boot.actuate.endpoint.mvc;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@ -30,10 +33,13 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @since 1.3.0
*/
@ConfigurationProperties("endpoints.docs")
public class DocsMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEndpoint {
public class DocsMvcEndpoint extends WebMvcConfigurerAdapter
implements MvcEndpoint, EnvironmentAware {
private static final String DOCS_LOCATION = "classpath:/META-INF/resources/spring-boot-actuator/docs/";
private Environment environment;
private String path = "/docs";
/**
@ -44,12 +50,17 @@ public class DocsMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEndpo
/**
* Mark if the endpoint exposes sensitive information.
*/
private boolean sensitive;
private Boolean sensitive;
private final ManagementServletContext managementServletContext;
private Curies curies = new Curies();
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public Curies getCuries() {
return this.curies;
}
@ -96,10 +107,10 @@ public class DocsMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEndpo
@Override
public boolean isSensitive() {
return this.sensitive;
return EndpointProperties.isSensitive(this.environment, this.sensitive, false);
}
public void setSensitive(boolean sensitive) {
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}

@ -20,7 +20,10 @@ import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
@ -37,7 +40,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @since 1.3.0
*/
@ConfigurationProperties("endpoints.actuator")
public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEndpoint {
public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter
implements MvcEndpoint, EnvironmentAware {
private Environment environment;
/**
* Endpoint URL path.
@ -54,7 +60,7 @@ public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEn
/**
* Mark if the endpoint exposes sensitive information.
*/
private boolean sensitive = false;
private Boolean sensitive;
private final ManagementServletContext managementServletContext;
@ -63,6 +69,11 @@ public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEn
this.path = getDefaultPath(managementServletContext);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
private String getDefaultPath(ManagementServletContext managementServletContext) {
if (StringUtils.hasText(managementServletContext.getContextPath())) {
return "";
@ -95,10 +106,10 @@ public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter implements MvcEn
@Override
public boolean isSensitive() {
return this.sensitive;
return EndpointProperties.isSensitive(this.environment, this.sensitive, false);
}
public void setSensitive(boolean sensitive) {
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}

@ -30,9 +30,12 @@ import org.jolokia.http.AgentServlet;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
@ -48,7 +51,9 @@ import org.springframework.web.util.UrlPathHelper;
@ConfigurationProperties(prefix = "endpoints.jolokia", ignoreUnknownFields = false)
@HypermediaDisabled
public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean,
ApplicationContextAware, ServletContextAware {
ApplicationContextAware, ServletContextAware, EnvironmentAware {
private Environment environment;
/**
* Endpoint URL path.
@ -65,7 +70,7 @@ public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean,
/**
* Mark if the endpoint exposes sensitive information.
*/
private boolean sensitive = true;
private Boolean sensitive;
private final ServletWrappingController controller = new ServletWrappingController();
@ -94,6 +99,11 @@ public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean,
this.controller.setApplicationContext(context);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public boolean isEnabled() {
return this.enabled;
}
@ -104,10 +114,10 @@ public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean,
@Override
public boolean isSensitive() {
return this.sensitive;
return EndpointProperties.isSensitive(this.environment, this.sensitive, true);
}
public void setSensitive(boolean sensitive) {
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}

@ -25,6 +25,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.logging.LogFile;
import org.springframework.context.EnvironmentAware;
@ -67,7 +68,7 @@ public class LogFileMvcEndpoint implements MvcEndpoint, EnvironmentAware {
/**
* Mark if the endpoint exposes sensitive information.
*/
private boolean sensitive = true;
private Boolean sensitive;
private Environment environment;
@ -95,10 +96,10 @@ public class LogFileMvcEndpoint implements MvcEndpoint, EnvironmentAware {
@Override
public boolean isSensitive() {
return this.sensitive;
return EndpointProperties.isSensitive(this.environment, this.sensitive, true);
}
public void setSensitive(boolean sensitive) {
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}

@ -1,10 +1,4 @@
{"properties": [
{
"name": "endpoints.enabled",
"type": "java.lang.Boolean",
"description": "Enable endpoints.",
"defaultValue": true
},
{
"name": "endpoints.configprops.keys-to-sanitize",
"type": "java.lang.String[]",

@ -108,6 +108,19 @@ public abstract class AbstractEndpointTests<T extends Endpoint<?>> {
assertThat(getEndpointBean().isSensitive(), equalTo(!this.sensitive));
}
@Test
public void isSensitiveOverrideWithGlobal() throws Exception {
this.context = new AnnotationConfigApplicationContext();
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("endpoint.sensitive", this.sensitive);
properties.put(this.property + ".sensitive", String.valueOf(!this.sensitive));
PropertySource<?> propertySource = new MapPropertySource("test", properties);
this.context.getEnvironment().getPropertySources().addFirst(propertySource);
this.context.register(this.configClass);
this.context.refresh();
assertThat(getEndpointBean().isSensitive(), equalTo(!this.sensitive));
}
@Test
public void isEnabledByDefault() throws Exception {
assertThat(getEndpointBean().isEnabled(), equalTo(true));
@ -169,6 +182,26 @@ public abstract class AbstractEndpointTests<T extends Endpoint<?>> {
}
}
@Test
public void isAllEndpointsSensitive() throws Exception {
testGlobalEndpointsSensitive(true);
}
@Test
public void isAllEndpointsNotSensitive() throws Exception {
testGlobalEndpointsSensitive(false);
}
private void testGlobalEndpointsSensitive(boolean sensitive) {
this.context = new AnnotationConfigApplicationContext();
PropertySource<?> propertySource = new MapPropertySource("test", Collections
.<String, Object>singletonMap("endpoints.sensitive", sensitive));
this.context.getEnvironment().getPropertySources().addFirst(propertySource);
this.context.register(this.configClass);
this.context.refresh();
assertThat(getEndpointBean().isSensitive(), equalTo(sensitive));
}
@SuppressWarnings("unchecked")
protected T getEndpointBean() {
return (T) this.context.getBean(this.type);

@ -724,6 +724,8 @@ content into your application; rather pick only the properties that you need.
# ----------------------------------------
# ENDPOINTS ({sc-spring-boot-actuator}/endpoint/AbstractEndpoint.{sc-ext}[AbstractEndpoint] subclasses)
endpoints.enabled=true # Enable endpoints.
endpoints.sensitive= # Default endpoint sensitive setting.
endpoints.actuator.enabled=true # Enable the endpoint.
endpoints.actuator.path= # Endpoint URL path.
endpoints.actuator.sensitive=false # Enable security on the endpoint.
@ -744,7 +746,6 @@ content into your application; rather pick only the properties that you need.
endpoints.dump.enabled= # Enable the endpoint.
endpoints.dump.id= # Endpoint identifier.
endpoints.dump.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.enabled=true # Enable endpoints.
endpoints.env.enabled= # Enable the endpoint.
endpoints.env.id= # Endpoint identifier.
endpoints.env.keys-to-sanitize=password,secret,key,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions.

@ -65,7 +65,7 @@ The following endpoints are available:
[cols="2,5,1"]
|===
| ID | Description | Sensitive
| ID | Description | Sensitive Default
|`actuator`
|Provides a hypermedia-based "`discovery page`" for the other endpoints. Requires Spring
@ -166,6 +166,18 @@ For example, the following will disable _all_ endpoints except for `info`:
endpoints.info.enabled=true
----
Likewise, you can also choose to globally set the "`sensitive`" flag of all endpoints. By
default, the sensitive flag depends on the type of endpoint (see the table above).
For example, to mark _all_ endpoints as sensitive except `info`:
[source,properties,indent=0]
----
endpoints.sensitive=true
endpoints.info.sensitive=false
----
[[production-ready-endpoint-hypermedia]]
=== Hypermedia for actuator MVC endpoints
If http://projects.spring.io/spring-hateoas[Spring HATEOAS] is on the classpath (e.g.

Loading…
Cancel
Save