Make expose and exclude properties affect servlet endpoints
Closes gh-11968
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user