diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java index e459335014..55317fd926 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java @@ -19,13 +19,20 @@ package org.springframework.boot.actuate.endpoint; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; + /** * Abstract base for {@link Endpoint} implementations. * * @author Phillip Webb * @author Christian Dupuis */ -public abstract class AbstractEndpoint implements Endpoint { +public abstract class AbstractEndpoint implements Endpoint, EnvironmentAware { + + private static final String ENDPOINTS_ENABLED_PROPERTY = "endpoints.enabled"; + + private Environment environment; /** * Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped @@ -36,25 +43,52 @@ public abstract class AbstractEndpoint implements Endpoint { private String id; /** - * Enable security on the endpoint. + * Mark if the endpoint exposes sensitive information. */ private boolean sensitive; /** * Enable the endpoint. */ - private boolean enabled = true; + private Boolean enabled; + /** + * Create a new sensitive endpoint instance. The enpoint will enabled flag will be + * based on the spring {@link Environment} unless explicitly set. + * @param id the endpoint ID + */ public AbstractEndpoint(String id) { - this(id, true, true); + this(id, true); + } + + /** + * 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 + */ + public AbstractEndpoint(String id, boolean sensitive) { + this.id = id; + this.sensitive = sensitive; } + /** + * Create a new endpoint instance. + * @param id the endpoint ID + * @param sensitive if the endpoint is sensitive + * @param enabled if the endpoint is enabled or not. + */ public AbstractEndpoint(String id, boolean sensitive, boolean enabled) { this.id = id; this.sensitive = sensitive; this.enabled = enabled; } + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + @Override public String getId() { return this.id; @@ -66,10 +100,16 @@ public abstract class AbstractEndpoint implements Endpoint { @Override public boolean isEnabled() { - return this.enabled; + if (this.enabled != null) { + return this.enabled; + } + if (this.environment != null) { + this.environment.getProperty(ENDPOINTS_ENABLED_PROPERTY, Boolean.class, true); + } + return true; } - public void setEnabled(boolean enabled) { + public void setEnabled(Boolean enabled) { this.enabled = enabled; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java index 7b2e1bfbc7..e39c58d71c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java @@ -18,11 +18,13 @@ package org.springframework.boot.actuate.endpoint; /** * An endpoint that can be used to expose useful information to operations. Usually - * exposed via Spring MVC but could also be exposed using some other technique. + * exposed via Spring MVC but could also be exposed using some other technique. Consider + * extending {@link AbstractEndpoint} if you are developing your own endpoint. * * @author Phillip Webb * @author Dave Syer * @author Christian Dupuis + * @see AbstractEndpoint */ public interface Endpoint { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java index 6ce6e559ec..1066adf1dc 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java @@ -47,7 +47,7 @@ public class HealthEndpoint extends AbstractEndpoint { */ public HealthEndpoint(HealthAggregator healthAggregator, Map healthIndicators) { - super("health", false, true); + super("health", false); Assert.notNull(healthAggregator, "HealthAggregator must not be null"); Assert.notNull(healthIndicators, "HealthIndicators must not be null"); CompositeHealthIndicator healthIndicator = new CompositeHealthIndicator( diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index a2ef2577a7..42a20c595e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -39,7 +39,7 @@ public class InfoEndpoint extends AbstractEndpoint> { * @param info the info to expose */ public InfoEndpoint(Map info) { - super("info", false, true); + super("info", false); Assert.notNull(info, "Info must not be null"); this.info = info; } diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 0cffc17587..dd95d1badb 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,4 +1,10 @@ {"properties": [ + { + "name": "endpoints.enabled", + "type": "java.lang.Boolean", + "description": "Enable endpoints.", + "defaultValue": true + }, { "name": "endpoints.configprops.keys-to-sanitize", "type": "java.lang.String", diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java index 28f1371ee5..3e2ef0a5b7 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java @@ -202,7 +202,7 @@ public class EndpointMBeanExportAutoConfigurationTests { protected static class ManagedEndpoint extends AbstractEndpoint { public ManagedEndpoint() { - super("managed", true, true); + super("managed", true); } @Override @@ -224,7 +224,7 @@ public class EndpointMBeanExportAutoConfigurationTests { class Nested extends AbstractEndpoint { public Nested() { - super("managed", true, true); + super("managed", true); } @Override diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java index 9c403fee9b..c3263f779b 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java @@ -102,6 +102,37 @@ public abstract class AbstractEndpointTests> { assertThat(getEndpointBean().isSensitive(), equalTo(!this.sensitive)); } + @Test + public void isEnabledByDefault() throws Exception { + assertThat(getEndpointBean().isEnabled(), equalTo(true)); + } + + @Test + public void isEnabledFallbackToEnvironment() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + PropertySource propertySource = new MapPropertySource("test", + Collections. singletonMap(this.property + ".enabled", + false)); + this.context.getEnvironment().getPropertySources().addFirst(propertySource); + this.context.register(this.configClass); + this.context.refresh(); + assertThat(getEndpointBean().isEnabled(), equalTo(false)); + } + + @Test + @SuppressWarnings("rawtypes") + public void isExplicitlyEnabled() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + PropertySource propertySource = new MapPropertySource("test", + Collections. singletonMap(this.property + ".enabled", + false)); + this.context.getEnvironment().getPropertySources().addFirst(propertySource); + this.context.register(this.configClass); + this.context.refresh(); + ((AbstractEndpoint) getEndpointBean()).setEnabled(true); + assertThat(getEndpointBean().isEnabled(), equalTo(true)); + } + @SuppressWarnings("unchecked") protected T getEndpointBean() { return (T) this.context.getBean(this.type); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java index fa99abed4c..c5336100dd 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java @@ -26,6 +26,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextClosedEvent; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -43,6 +44,12 @@ public class ShutdownEndpointTests extends AbstractEndpointTests> for details of how you can set +`endpoints.enabled` to `false` then "`opt-in`" only specific endpoints. [[production-ready-customizing-management-server-context-path]]