Make expose and exclude properties affect servlet endpoints

Closes gh-11968
This commit is contained in:
Andy Wilkinson
2018-02-09 11:23:47 +00:00
parent a97a762086
commit a6ecd55f1f
2 changed files with 132 additions and 75 deletions

View File

@@ -16,7 +16,11 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.Set;
import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
@@ -28,6 +32,7 @@ import org.springframework.context.annotation.Configuration;
* {@link ManagementContextConfiguration} for servlet endpoints.
*
* @author Phillip Webb
* @author Andy Wilkinson
*
* @since 2.0.0
*/
@@ -43,4 +48,13 @@ public class ServletEndpointManagementContextConfiguration {
servletEndpointsSupplier.getEndpoints());
}
@Bean
public ExposeExcludePropertyEndpointFilter<ExposableServletEndpoint> servletExposeExcludePropertyEndpointFilter(
WebEndpointProperties properties) {
Set<String> expose = properties.getExpose();
Set<String> exclude = properties.getExclude();
return new ExposeExcludePropertyEndpointFilter<>(ExposableServletEndpoint.class,
expose, exclude);
}
}

View File

@@ -16,6 +16,14 @@
package org.springframework.boot.actuate.autoconfigure.integrationtest;
import java.io.IOException;
import java.util.function.Supplier;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
@@ -23,23 +31,26 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAu
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.trace.HttpTraceAutoConfiguration;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.test.web.reactive.server.EntityExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.bind.annotation.GetMapping;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
/**
* Integration tests for Endpoints over Spring MVC.
@@ -49,38 +60,42 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
*/
public class WebMvcEndpointExposureIntegrationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
HttpTraceAutoConfiguration.class))
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL))
.withUserConfiguration(CustomMvcEndpoint.class);
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new).withConfiguration(
AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
HttpTraceAutoConfiguration.class))
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL))
.withUserConfiguration(CustomMvcEndpoint.class,
CustomServletEndpoint.class)
.withPropertyValues("server.port:0");
@Test
public void webEndpointsAreDisabledByDefault() {
this.contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "custommvc")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "httptrace")).isFalse();
WebTestClient client = createClient(context);
assertThat(isExposed(client, HttpMethod.GET, "beans")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "conditions")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "configprops")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "custommvc")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "customservlet")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "env")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "mappings")).isFalse();
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "threaddump")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "httptrace")).isFalse();
});
}
@@ -89,18 +104,19 @@ public class WebMvcEndpointExposureIntegrationTests {
WebApplicationContextRunner contextRunner = this.contextRunner
.withPropertyValues("management.endpoints.web.expose=*");
contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "custommvc")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "httptrace")).isTrue();
WebTestClient client = createClient(context);
assertThat(isExposed(client, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "conditions")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "configprops")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "custommvc")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "customservlet")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "env")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "mappings")).isTrue();
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "threaddump")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "httptrace")).isTrue();
});
}
@@ -109,18 +125,19 @@ public class WebMvcEndpointExposureIntegrationTests {
WebApplicationContextRunner contextRunner = this.contextRunner
.withPropertyValues("management.endpoints.web.expose=beans");
contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "custommvc")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "httptrace")).isFalse();
WebTestClient client = createClient(context);
assertThat(isExposed(client, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "conditions")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "configprops")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "custommvc")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "customservlet")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "env")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "health")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "info")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "mappings")).isFalse();
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "threaddump")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "httptrace")).isFalse();
});
}
@@ -130,34 +147,43 @@ public class WebMvcEndpointExposureIntegrationTests {
"management.endpoints.web.expose=*",
"management.endpoints.web.exclude=shutdown");
contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "custommvc")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "httptrace")).isTrue();
WebTestClient client = createClient(context);
assertThat(isExposed(client, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "conditions")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "configprops")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "custommvc")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "customservlet")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "env")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "mappings")).isTrue();
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(client, HttpMethod.GET, "threaddump")).isTrue();
assertThat(isExposed(client, HttpMethod.GET, "httptrace")).isTrue();
});
}
private boolean isExposed(MockMvc mockMvc, HttpMethod method, String path)
private WebTestClient createClient(AssertableWebApplicationContext context) {
int port = context
.getSourceApplicationContext(ServletWebServerApplicationContext.class)
.getWebServer().getPort();
return WebTestClient.bindToServer().baseUrl("http://localhost:" + port).build();
}
private boolean isExposed(WebTestClient client, HttpMethod method, String path)
throws Exception {
path = "/actuator/" + path;
MvcResult mvcResult = mockMvc.perform(request(method, path)).andReturn();
int status = mvcResult.getResponse().getStatus();
if (status == HttpStatus.OK.value()) {
EntityExchangeResult<byte[]> result = client.method(method).uri(path).exchange()
.expectBody().returnResult();
if (result.getStatus() == HttpStatus.OK) {
return true;
}
if (status == HttpStatus.NOT_FOUND.value()) {
if (result.getStatus() == HttpStatus.NOT_FOUND) {
return false;
}
throw new IllegalStateException(String
.format("Unexpected %s HTTP status for " + "endpoint %s", status, path));
throw new IllegalStateException(
String.format("Unexpected %s HTTP status for " + "endpoint %s",
result.getStatus(), path));
}
@RestControllerEndpoint(id = "custommvc")
@@ -170,4 +196,21 @@ public class WebMvcEndpointExposureIntegrationTests {
}
@ServletEndpoint(id = "customservlet")
static class CustomServletEndpoint implements Supplier<EndpointServlet> {
@Override
public EndpointServlet get() {
return new EndpointServlet(new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
});
}
}
}