EndpointRequest should match @ServletEndpoint
This commit also changes the request matcher for MVC endpoints to use an AntPathRequestMatcher instead of an MvcRequestMatcher. The endpoint is always available under the mapped endpoint path and this way the same matcher can be used for both MVC and Jersey. Fixes gh-17912 Co-authored-by: Phillip Webb <pwebb@pivotal.io>
This commit is contained in:
@@ -13,41 +13,48 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.AntPathRequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Auto-configuration for {@link RequestMatcherProvider}.
|
||||
* {@link ManagementContextConfiguration} that configures the appropriate
|
||||
* {@link RequestMatcherProvider}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.5
|
||||
* @since 2.1.8
|
||||
*/
|
||||
@Configuration
|
||||
@ManagementContextConfiguration
|
||||
@ConditionalOnClass({ RequestMatcher.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
public class SecurityRequestMatcherProviderAutoConfiguration {
|
||||
public class SecurityRequestMatchersManagementContextConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
@ConditionalOnBean(HandlerMappingIntrospector.class)
|
||||
@ConditionalOnBean(DispatcherServletPath.class)
|
||||
public static class MvcRequestMatcherConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
public RequestMatcherProvider requestMatcherProvider(HandlerMappingIntrospector introspector) {
|
||||
return new MvcRequestMatcherProvider(introspector);
|
||||
public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {
|
||||
return new AntPathRequestMatcherProvider(servletPath::getRelativePath);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,7 +67,7 @@ public class SecurityRequestMatcherProviderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public RequestMatcherProvider requestMatcherProvider(JerseyApplicationPath applicationPath) {
|
||||
return new JerseyRequestMatcherProvider(applicationPath);
|
||||
return new AntPathRequestMatcherProvider(applicationPath::getRelativePath);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -94,6 +94,7 @@ org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManag
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.security.servlet.SecurityRequestMatchersManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseySameManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyChildManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration,\
|
||||
|
||||
@@ -15,20 +15,24 @@
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.logging.LogLevel;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
@@ -39,9 +43,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link EndpointRequest} tests.
|
||||
*
|
||||
@@ -49,8 +50,6 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
public abstract class AbstractEndpointRequestIntegrationTests {
|
||||
|
||||
protected abstract WebApplicationContextRunner getContextRunner();
|
||||
|
||||
@Test
|
||||
public void toEndpointShouldMatch() {
|
||||
getContextRunner().run((context) -> {
|
||||
@@ -79,6 +78,17 @@ public abstract class AbstractEndpointRequestIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
protected final WebApplicationContextRunner getContextRunner() {
|
||||
return createContextRunner().withPropertyValues("management.endpoints.web.exposure.include=*")
|
||||
.withUserConfiguration(BaseConfiguration.class, SecurityConfiguration.class).withConfiguration(
|
||||
AutoConfigurations.of(JacksonAutoConfiguration.class, SecurityAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class));
|
||||
|
||||
}
|
||||
|
||||
protected abstract WebApplicationContextRunner createContextRunner();
|
||||
|
||||
protected WebTestClient getWebTestClient(AssertableWebApplicationContext context) {
|
||||
int port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)
|
||||
.getWebServer().getPort();
|
||||
@@ -108,19 +118,8 @@ public abstract class AbstractEndpointRequestIntegrationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PathMappedEndpoints pathMappedEndpoints() {
|
||||
List<ExposableEndpoint<?>> endpoints = new ArrayList<>();
|
||||
endpoints.add(mockEndpoint("e1"));
|
||||
endpoints.add(mockEndpoint("e2"));
|
||||
endpoints.add(mockEndpoint("e3"));
|
||||
return new PathMappedEndpoints("/actuator", () -> endpoints);
|
||||
}
|
||||
|
||||
private TestPathMappedEndpoint mockEndpoint(String id) {
|
||||
TestPathMappedEndpoint endpoint = mock(TestPathMappedEndpoint.class);
|
||||
given(endpoint.getEndpointId()).willReturn(EndpointId.of(id));
|
||||
given(endpoint.getRootPath()).willReturn(id);
|
||||
return endpoint;
|
||||
public TestServletEndpoint servletEndpoint() {
|
||||
return new TestServletEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -155,7 +154,13 @@ public abstract class AbstractEndpointRequestIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
public interface TestPathMappedEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {
|
||||
@ServletEndpoint(id = "se1")
|
||||
static class TestServletEndpoint implements Supplier<EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public EndpointServlet get() {
|
||||
return new EndpointServlet(AgentServlet.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,37 +15,17 @@
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.glassfish.jersey.server.model.Resource;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.web.jersey.JerseyEndpointResourceFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
@@ -57,18 +37,6 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
*/
|
||||
public class JerseyEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrationTests {
|
||||
|
||||
@Override
|
||||
protected WebApplicationContextRunner getContextRunner() {
|
||||
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.withUserConfiguration(JerseyEndpointConfiguration.class, SecurityConfiguration.class,
|
||||
BaseConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class,
|
||||
SecurityRequestMatcherProviderAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
JerseyAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLinksWhenApplicationPathSetShouldMatch() {
|
||||
getContextRunner().withPropertyValues("spring.jersey.application-path=/admin").run((context) -> {
|
||||
@@ -98,16 +66,47 @@ public class JerseyEndpointRequestIntegrationTests extends AbstractEndpointReque
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toAnyEndpointShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.security.user.password=password",
|
||||
"management.endpoints.web.exposure.include=se1").run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1/list").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toAnyEndpointWhenApplicationPathSetShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.jersey.application-path=/admin",
|
||||
"spring.security.user.password=password", "management.endpoints.web.exposure.include=se1")
|
||||
.run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/admin/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").header("Authorization", getBasicAuth())
|
||||
.exchange().expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebApplicationContextRunner createContextRunner() {
|
||||
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.withUserConfiguration(JerseyEndpointConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WebEndpointProperties.class)
|
||||
static class JerseyEndpointConfiguration {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
JerseyEndpointConfiguration(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TomcatServletWebServerFactory tomcat() {
|
||||
return new TomcatServletWebServerFactory(0);
|
||||
@@ -118,24 +117,6 @@ public class JerseyEndpointRequestIntegrationTests extends AbstractEndpointReque
|
||||
return new ResourceConfig();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ResourceConfigCustomizer webEndpointRegistrar() {
|
||||
return this::customize;
|
||||
}
|
||||
|
||||
private void customize(ResourceConfig config) {
|
||||
List<String> mediaTypes = Arrays.asList(javax.ws.rs.core.MediaType.APPLICATION_JSON,
|
||||
ActuatorMediaType.V2_JSON);
|
||||
EndpointMediaTypes endpointMediaTypes = new EndpointMediaTypes(mediaTypes, mediaTypes);
|
||||
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
|
||||
new ConversionServiceParameterValueMapper(), endpointMediaTypes,
|
||||
Arrays.asList((id) -> id.toString()), Collections.emptyList(), Collections.emptyList());
|
||||
Collection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(
|
||||
new EndpointMapping("/actuator"), discoverer.getEndpoints(), endpointMediaTypes,
|
||||
new EndpointLinksResolver(discoverer.getEndpoints()));
|
||||
config.registerResources(new HashSet<>(resources));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,38 +15,20 @@
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
|
||||
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.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link EndpointRequest} with Spring MVC.
|
||||
@@ -84,43 +66,52 @@ public class MvcEndpointRequestIntegrationTests extends AbstractEndpointRequestI
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toAnyEndpointShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.security.user.password=password",
|
||||
"management.endpoints.web.exposure.include=se1").run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1/list").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toAnyEndpointWhenServletPathSetShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.mvc.servlet.path=/admin",
|
||||
"spring.security.user.password=password", "management.endpoints.web.exposure.include=se1")
|
||||
.run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/admin/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").header("Authorization", getBasicAuth())
|
||||
.exchange().expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebApplicationContextRunner getContextRunner() {
|
||||
protected WebApplicationContextRunner createContextRunner() {
|
||||
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withUserConfiguration(WebMvcEndpointConfiguration.class, SecurityConfiguration.class,
|
||||
BaseConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
SecurityRequestMatcherProviderAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class));
|
||||
.withUserConfiguration(WebMvcEndpointConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WebEndpointProperties.class)
|
||||
static class WebMvcEndpointConfiguration {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
WebMvcEndpointConfiguration(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TomcatServletWebServerFactory tomcat() {
|
||||
return new TomcatServletWebServerFactory(0);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping() {
|
||||
List<String> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON_VALUE, ActuatorMediaType.V2_JSON);
|
||||
EndpointMediaTypes endpointMediaTypes = new EndpointMediaTypes(mediaTypes, mediaTypes);
|
||||
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
|
||||
new ConversionServiceParameterValueMapper(), endpointMediaTypes,
|
||||
Arrays.asList((id) -> id.toString()), Collections.emptyList(), Collections.emptyList());
|
||||
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"), discoverer.getEndpoints(),
|
||||
endpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,35 +13,40 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.AntPathRequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecurityRequestMatcherProviderAutoConfiguration}.
|
||||
* Tests for {@link SecurityRequestMatchersManagementContextConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class SecurityRequestMatcherProviderAutoConfigurationTests {
|
||||
public class SecurityRequestMatchersManagementContextConfigurationTests {
|
||||
|
||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void configurationConditionalOnWebApplication() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
|
||||
.withUserConfiguration(TestMvcConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(RequestMatcherProvider.class));
|
||||
}
|
||||
@@ -55,51 +60,58 @@ public class SecurityRequestMatcherProviderAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registersMvcRequestMatcherProviderIfMvcPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> assertThat(context)
|
||||
.getBean(RequestMatcherProvider.class).isInstanceOf(MvcRequestMatcherProvider.class));
|
||||
public void registersRequestMatcherProviderIfMvcPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> {
|
||||
AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class);
|
||||
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example");
|
||||
assertThat(ReflectionTestUtils.getField(requestMatcher, "pattern")).isEqualTo("/custom/example");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registersRequestMatcherForJerseyProviderIfJerseyPresentAndMvcAbsent() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.withUserConfiguration(TestJerseyConfiguration.class).run((context) -> assertThat(context)
|
||||
.getBean(RequestMatcherProvider.class).isInstanceOf(JerseyRequestMatcherProvider.class));
|
||||
.withUserConfiguration(TestJerseyConfiguration.class).run((context) -> {
|
||||
AntPathRequestMatcherProvider matcherProvider = context
|
||||
.getBean(AntPathRequestMatcherProvider.class);
|
||||
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example");
|
||||
assertThat(ReflectionTestUtils.getField(requestMatcher, "pattern")).isEqualTo("/admin/example");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnDispatcherServletClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnDispatcherServletPathBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jerseyRequestMatcherProviderConditionalOnResourceConfigClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.glassfish.jersey.server.ResourceConfig"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(JerseyRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnHandlerMappingIntrospectorBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jerseyRequestMatcherProviderConditionalOnJerseyApplicationPathBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(JerseyRequestMatcherProvider.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestMvcConfiguration {
|
||||
|
||||
@Bean
|
||||
public HandlerMappingIntrospector introspector() {
|
||||
return new HandlerMappingIntrospector();
|
||||
public DispatcherServletPath dispatcherServletPath() {
|
||||
return () -> "/custom";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,30 +13,31 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* {@link RequestMatcherProvider} that provides an {@link MvcRequestMatcher} that can be
|
||||
* used for Spring MVC applications.
|
||||
* {@link RequestMatcherProvider} that provides an {@link AntPathRequestMatcher}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.5
|
||||
* @since 2.1.8
|
||||
*/
|
||||
public class MvcRequestMatcherProvider implements RequestMatcherProvider {
|
||||
public class AntPathRequestMatcherProvider implements RequestMatcherProvider {
|
||||
|
||||
private final HandlerMappingIntrospector introspector;
|
||||
private final Function<String, String> pathFactory;
|
||||
|
||||
public MvcRequestMatcherProvider(HandlerMappingIntrospector introspector) {
|
||||
this.introspector = introspector;
|
||||
public AntPathRequestMatcherProvider(Function<String, String> pathFactory) {
|
||||
this.pathFactory = pathFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestMatcher getRequestMatcher(String pattern) {
|
||||
return new MvcRequestMatcher(this.introspector, pattern);
|
||||
return new AntPathRequestMatcher(this.pathFactory.apply(pattern));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,9 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.7
|
||||
* @deprecated since 2.1.8 in favor of {@link AntPathRequestMatcher}
|
||||
*/
|
||||
@Deprecated
|
||||
public class JerseyRequestMatcherProvider implements RequestMatcherProvider {
|
||||
|
||||
private final JerseyApplicationPath jerseyApplicationPath;
|
||||
|
||||
@@ -100,7 +100,6 @@ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
|
||||
|
||||
Reference in New Issue
Block a user