Disable web endpoints by default

Since the handler interceptors have been removed, web endpoints
are all disabled by default to prevent accidental exposure of
sensitive information.

Closes gh-7958
This commit is contained in:
Madhura Bhave 2017-08-27 21:24:31 -07:00
parent e08ddbf838
commit bacbe0459b
8 changed files with 66 additions and 43 deletions

View File

@ -103,6 +103,10 @@ public class EndpointEnablementProvider {
if (globalTypeOutcome != null) {
return globalTypeOutcome;
}
else if (!endpointType.isEnabledByDefault()) {
return new EndpointEnablement(false, createDefaultEnablementMessage("all", false,
endpointType));
}
}
else {
// Check if there is a global tech required

View File

@ -184,6 +184,7 @@ public class ConditionalOnEnabledEndpointTests {
@Test
public void enabledOnlyWebByDefault() {
this.contextRunner.withUserConfiguration(OnlyWebConfig.class)
.withPropertyValues("endpoints.all.web.enabled=true")
.run((context) -> assertThat(context).hasBean("onlyweb"));
}

View File

@ -55,40 +55,12 @@ public class WebMvcEndpointInfrastructureAutoConfigurationTests {
ServletEndpointAutoConfiguration.class));
@Test
public void webEndpointsAreExposed() {
this.contextRunner.run((context) -> {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/autoconfig"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans")).isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/configprops"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/env")).isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/health"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/info")).isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/mappings"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/metrics"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.POST, "/application/shutdown"))
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/threaddump"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace")).isTrue();
});
}
@Test
public void webEndpointsCanBeDisabled() {
WebApplicationContextRunner contextRunner = this.contextRunner
.withPropertyValues("endpoints.all.web.enabled=false");
contextRunner.run((context) -> {
public void webEndpointsAreDisabledByDefault() {
this.contextRunner.run(context -> {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/autoconfig"))
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans"))
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans")).isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/configprops"))
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/env")).isFalse();
@ -103,8 +75,36 @@ public class WebMvcEndpointInfrastructureAutoConfigurationTests {
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/threaddump"))
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace"))
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace")).isFalse();
});
}
@Test
public void webEndpointsCanBeEnabled() {
WebApplicationContextRunner contextRunner = this.contextRunner
.withPropertyValues("endpoints.all.web.enabled=true");
contextRunner.run(context -> {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/autoconfig"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/configprops"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/env")).isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/health"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/info")).isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/mappings"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/metrics"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.POST, "/application/shutdown"))
.isFalse();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/threaddump"))
.isTrue();
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace"))
.isTrue();
});
}

View File

@ -185,8 +185,8 @@ public class EndpointEnablementProviderTests {
@Test
public void specificEnabledByDefault() {
validate(determineEnablement("foo", true, EndpointType.WEB), true,
"endpoint 'foo' (web) is enabled by default");
validate(determineEnablement("foo", true, EndpointType.JMX), true,
"endpoint 'foo' (jmx) is enabled by default");
}
@Test
@ -208,15 +208,15 @@ public class EndpointEnablementProviderTests {
@Test
public void specificNotDisabledViaUnrelatedTechProperty() {
validate(
determineEnablement("foo", true, EndpointType.WEB,
"endpoints.foo.jmx.enabled=false"),
true, "endpoint 'foo' (web) is enabled by default");
determineEnablement("foo", true, EndpointType.JMX,
"endpoints.foo.web.enabled=false"),
true, "endpoint 'foo' (jmx) is enabled by default");
}
@Test
public void specificDisabledViaGeneralProperty() {
validate(
determineEnablement("foo", true, EndpointType.WEB,
determineEnablement("foo", true, EndpointType.JMX,
"endpoints.all.enabled=false"),
false, "found property endpoints.all.enabled");
}
@ -256,8 +256,8 @@ public class EndpointEnablementProviderTests {
@Test
public void specificEnabledOverrideHasNoEffectWithUnrelatedTechProperty() {
validate(
determineEnablement("foo", true, EndpointType.WEB,
"endpoints.all.enabled=false", "endpoints.all.jmx.enabled=true"),
determineEnablement("foo", true, EndpointType.JMX,
"endpoints.all.enabled=false", "endpoints.all.web.enabled=true"),
false, "found property endpoints.all.enabled");
}

View File

@ -161,7 +161,9 @@ public class WebEndpointManagementContextConfigurationTests {
}
private void beanIsAutoConfigured(Class<?> beanType, Class<?>... config) {
contextRunner().withUserConfiguration(config)
contextRunner()
.withPropertyValues("endpoints.all.web.enabled:true")
.withUserConfiguration(config)
.run((context) -> assertThat(context).hasSingleBean(beanType));
}

View File

@ -65,6 +65,8 @@ public class MvcEndpointCorsIntegrationTests {
EndpointInfrastructureAutoConfiguration.class,
EndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,
ServletEndpointAutoConfiguration.class);
TestPropertyValues.of("endpoints.all.web.enabled:true")
.applyTo(this.context);
}
@Test

View File

@ -79,6 +79,8 @@ import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
* {@link org.springframework.core.env.Environment} are reset at the end of every test.
* This means that {@link TestPropertyValues} can be used in a test without affecting the
* {@code Environment} of other tests in the same class.
* The runner always sets the flag `endpoints.all.web.enabled` to true so that web endpoints
* are enabled.
*
* @author Andy Wilkinson
*/
@ -190,6 +192,7 @@ public class WebEndpointsRunner extends Suite {
private MvcWebEndpointsRunner(Class<?> klass) throws InitializationError {
super(klass, "Spring MVC", (classes) -> {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
TestPropertyValues.of("endpoints.all.web.enabled:true").applyTo(context);
classes.add(MvcTestConfiguration.class);
context.register(classes.toArray(new Class<?>[classes.size()]));
context.refresh();
@ -221,6 +224,7 @@ public class WebEndpointsRunner extends Suite {
private JerseyWebEndpointsRunner(Class<?> klass) throws InitializationError {
super(klass, "Jersey", (classes) -> {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
TestPropertyValues.of("endpoints.all.web.enabled:true").applyTo(context);
classes.add(JerseyAppConfiguration.class);
classes.add(JerseyInfrastructureConfiguration.class);
context.register(classes.toArray(new Class<?>[classes.size()]));
@ -260,6 +264,7 @@ public class WebEndpointsRunner extends Suite {
private ReactiveWebEndpointsRunner(Class<?> klass) throws InitializationError {
super(klass, "Reactive", (classes) -> {
ReactiveWebServerApplicationContext context = new ReactiveWebServerApplicationContext();
TestPropertyValues.of("endpoints.all.web.enabled:true").applyTo(context);
classes.add(ReactiveInfrastructureConfiguration.class);
context.register(classes.toArray(new Class<?>[classes.size()]));
context.refresh();

View File

@ -27,11 +27,20 @@ public enum EndpointType {
/**
* Expose the endpoint as a JMX MBean.
*/
JMX,
JMX(true),
/**
* Expose the endpoint as a Web endpoint.
*/
WEB
WEB(false);
private final boolean enabledByDefault;
EndpointType(boolean enabledByDefault) {
this.enabledByDefault = enabledByDefault;
}
public boolean isEnabledByDefault() {
return this.enabledByDefault;
}
}