Add forServletPattern
Closes gh-13562
This commit is contained in:
@@ -25,8 +25,12 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.test.support.ClassPathExclusions;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractRequestMatcherRegistry} with no Spring MVC in the classpath
|
||||
@@ -41,6 +45,9 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.matcherRegistry = new TestRequestMatcherRegistry();
|
||||
WebApplicationContext context = mock(WebApplicationContext.class);
|
||||
given(context.getBeanNamesForType((Class<?>) any())).willReturn(new String[0]);
|
||||
this.matcherRegistry.setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -163,12 +163,6 @@ public class AbstractRequestMatcherRegistryTests {
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
servletContext.addServlet("servletOne", Servlet.class);
|
||||
servletContext.addServlet("servletTwo", Servlet.class);
|
||||
requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jakarta.servlet.Servlet;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.MockServletContext;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractRequestMatcherBuilderRegistry}
|
||||
*/
|
||||
class AbstractRequestMatcherBuilderRegistryTests {
|
||||
|
||||
@Test
|
||||
void defaultServletMatchersWhenDefaultDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/mvc").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/mvc");
|
||||
assertThatMvc(matchers).method().isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletHttpMethodMatchersWhenDefaultDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers(HttpMethod.GET, "/mvc").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/mvc");
|
||||
assertThatMvc(matchers).method().isEqualTo(HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenPathDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*")
|
||||
.requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenAlsoExtraServletContainerMappingsThenMvc() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class);
|
||||
servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
|
||||
servletContext.addServlet("facesServlet", Servlet.class).addMapping("/faces/", "*.jsf", "*.faces", "*.xhtml");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*")
|
||||
.requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletMatchersWhenOnlyDefaultServletThenAnt() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
|
||||
assertThatAnt(matchers).pattern().isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultDispatcherServletMatchersWhenNoHandlerMappingIntrospectorThenException() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
|
||||
.isThrownBy(() -> defaultServlet(servletContext, (context) -> {
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void dispatcherServletMatchersWhenNoHandlerMappingIntrospectorThenException() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
|
||||
.isThrownBy(() -> servletPattern(servletContext, (context) -> {
|
||||
}, "/mvc/*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenNoDispatchServletThenAnt() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/services/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
|
||||
assertThatAnt(matchers).pattern().isEqualTo("/services/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenMixedServletsThenDeterminesByServletPath() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
|
||||
List<RequestMatcher> matchers = servletPattern(servletContext, "/services/*")
|
||||
.requestMatchers("/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
|
||||
assertThatAnt(matchers).pattern().isEqualTo("/services/endpoint");
|
||||
matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenDispatcherServletNotDefaultThenDeterminesByServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*")
|
||||
.requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
matchers = defaultServlet(servletContext).requestMatchers("/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
|
||||
assertThatAnt(matchers).pattern().isEqualTo("/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletHttpMatchersWhenDispatcherServletNotDefaultThenDeterminesByServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*").requestMatchers(HttpMethod.GET,
|
||||
"/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).method().isEqualTo(HttpMethod.GET);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
matchers = defaultServlet(servletContext).requestMatchers(HttpMethod.GET, "/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
|
||||
assertThatAnt(matchers).method().isEqualTo(HttpMethod.GET);
|
||||
assertThatAnt(matchers).pattern().isEqualTo("/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenTwoDispatcherServletsThenDeterminesByServletPath() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("two", DispatcherServlet.class).addMapping("/other/*");
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
matchers = servletPattern(servletContext, "/other/*").requestMatchers("/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/other");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenMoreThanOneMappingThenDeterminesByServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
matchers = servletPattern(servletContext, "/two/*").requestMatchers("/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/two");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMatchersWhenMoreThanOneMappingAndDefaultServletsThenDeterminesByServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
|
||||
servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
matchers = servletPattern(servletContext, "/two/*").requestMatchers("/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isEqualTo("/two");
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletWhenDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
|
||||
List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
|
||||
assertThatMvc(matchers).servletPath().isNull();
|
||||
assertThatMvc(matchers).pattern().isEqualTo("/controller");
|
||||
matchers = servletPattern(servletContext, "/services/*").requestMatchers("/endpoint").matchers;
|
||||
assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
|
||||
assertThatAnt(matchers).pattern().isEqualTo("/services/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletWhenNoDefaultServletThenException() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> defaultServlet(servletContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletPathWhenNoMatchingServletThenException() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> servletPattern(servletContext, "/wrong/*"));
|
||||
}
|
||||
|
||||
TestServletRequestMatcherRegistry defaultServlet(ServletContext servletContext) {
|
||||
return servletPattern(servletContext, "/");
|
||||
}
|
||||
|
||||
TestServletRequestMatcherRegistry defaultServlet(ServletContext servletContext,
|
||||
Consumer<GenericWebApplicationContext> consumer) {
|
||||
return servletPattern(servletContext, consumer, "/");
|
||||
}
|
||||
|
||||
TestServletRequestMatcherRegistry servletPattern(ServletContext servletContext, String pattern) {
|
||||
return servletPattern(servletContext, (context) -> {
|
||||
context.registerBean("mvcHandlerMappingIntrospector", HandlerMappingIntrospector.class);
|
||||
context.registerBean(ObjectPostProcessor.class, () -> mock(ObjectPostProcessor.class));
|
||||
}, pattern);
|
||||
}
|
||||
|
||||
TestServletRequestMatcherRegistry servletPattern(ServletContext servletContext,
|
||||
Consumer<GenericWebApplicationContext> consumer, String pattern) {
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext(servletContext);
|
||||
consumer.accept(context);
|
||||
context.refresh();
|
||||
return new TestServletRequestMatcherRegistry(context, pattern);
|
||||
}
|
||||
|
||||
static MvcRequestMatcherAssert assertThatMvc(List<RequestMatcher> matchers) {
|
||||
RequestMatcher matcher = matchers.get(0);
|
||||
if (matcher instanceof AndRequestMatcher matching) {
|
||||
List<RequestMatcher> and = (List<RequestMatcher>) ReflectionTestUtils.getField(matching, "requestMatchers");
|
||||
assertThat(and).hasSize(2);
|
||||
assertThat(and.get(1)).isInstanceOf(MvcRequestMatcher.class);
|
||||
return new MvcRequestMatcherAssert((MvcRequestMatcher) and.get(1));
|
||||
}
|
||||
assertThat(matcher).isInstanceOf(MvcRequestMatcher.class);
|
||||
return new MvcRequestMatcherAssert((MvcRequestMatcher) matcher);
|
||||
}
|
||||
|
||||
static AntPathRequestMatcherAssert assertThatAnt(List<RequestMatcher> matchers) {
|
||||
RequestMatcher matcher = matchers.get(0);
|
||||
if (matcher instanceof AndRequestMatcher matching) {
|
||||
List<RequestMatcher> and = (List<RequestMatcher>) ReflectionTestUtils.getField(matching, "requestMatchers");
|
||||
assertThat(and).hasSize(2);
|
||||
assertThat(and.get(1)).isInstanceOf(AntPathRequestMatcher.class);
|
||||
return new AntPathRequestMatcherAssert((AntPathRequestMatcher) and.get(1));
|
||||
}
|
||||
assertThat(matcher).isInstanceOf(AntPathRequestMatcher.class);
|
||||
return new AntPathRequestMatcherAssert((AntPathRequestMatcher) matcher);
|
||||
}
|
||||
|
||||
static final class TestServletRequestMatcherRegistry
|
||||
extends AbstractRequestMatcherBuilderRegistry<TestServletRequestMatcherRegistry> {
|
||||
|
||||
List<RequestMatcher> matchers;
|
||||
|
||||
TestServletRequestMatcherRegistry(ApplicationContext context, String pattern) {
|
||||
super(context, RequestMatcherBuilders.createForServletPattern(context, pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestServletRequestMatcherRegistry chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
||||
this.matchers = requestMatchers;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class MvcRequestMatcherAssert extends ObjectAssert<MvcRequestMatcher> {
|
||||
|
||||
private MvcRequestMatcherAssert(MvcRequestMatcher matcher) {
|
||||
super(matcher);
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> servletPath() {
|
||||
return extracting("servletPath");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> pattern() {
|
||||
return extracting("pattern");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> method() {
|
||||
return extracting("method");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class AntPathRequestMatcherAssert extends ObjectAssert<AntPathRequestMatcher> {
|
||||
|
||||
private AntPathRequestMatcherAssert(AntPathRequestMatcher matcher) {
|
||||
super(matcher);
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> pattern() {
|
||||
return extracting("pattern");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> method() {
|
||||
return extracting("httpMethod");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.Servlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
@@ -33,6 +35,7 @@ import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.config.MockServletContext;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@@ -58,6 +61,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
@@ -71,6 +75,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -121,7 +126,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
public void configureWhenMvcMatcherAfterAnyRequestThenException() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(AfterAnyRequestConfig.class).autowire())
|
||||
.withMessageContaining("Can't configure mvcMatchers after anyRequest");
|
||||
.withMessageContaining("Can't configure requestMatchers after anyRequest");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -362,7 +367,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void getWhenServletPathRoleAdminConfiguredAndRoleIsUserThenRespondsWithForbidden() throws Exception {
|
||||
this.spring.register(ServletPathConfig.class, BasicController.class).autowire();
|
||||
this.spring.register(MvcServletPathConfig.class, BasicController.class).autowire();
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder requestWithUser = get("/spring/")
|
||||
.servletPath("/spring")
|
||||
@@ -375,7 +380,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
@Test
|
||||
public void getWhenServletPathRoleAdminConfiguredAndRoleIsUserAndWithoutServletPathThenRespondsWithForbidden()
|
||||
throws Exception {
|
||||
this.spring.register(ServletPathConfig.class, BasicController.class).autowire();
|
||||
this.spring.register(MvcServletPathConfig.class, BasicController.class).autowire();
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder requestWithUser = get("/")
|
||||
.with(user("user")
|
||||
@@ -386,7 +391,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void getWhenServletPathRoleAdminConfiguredAndRoleIsAdminThenRespondsWithOk() throws Exception {
|
||||
this.spring.register(ServletPathConfig.class, BasicController.class).autowire();
|
||||
this.spring.register(MvcServletPathConfig.class, BasicController.class).autowire();
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder requestWithAdmin = get("/spring/")
|
||||
.servletPath("/spring")
|
||||
@@ -596,6 +601,200 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenNoDispatcherServletThenSucceeds() throws Exception {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
this.spring.register(AuthorizeHttpRequestsConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path")).andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenOnlyDispatcherServletThenSucceeds() throws Exception {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
this.spring.register(AuthorizeHttpRequestsConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/mvc/path").servletPath("/mvc")).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/mvc")).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenMultipleServletsThenSucceeds() throws Exception {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
|
||||
this.spring.register(AuthorizeHttpRequestsConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path").with(servletPath("/path"))).andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenAmbiguousServletsThenWiringException() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(AuthorizeHttpRequestsConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletMatchersWhenDefaultServletThenPermits() throws Exception {
|
||||
this.spring.register(DefaultServletConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(MockServletContext.mvc()))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path/path").with(defaultServlet())).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/path/path").with(servletPath("/path"))).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletHttpMethodMatchersWhenDefaultServletThenPermits() throws Exception {
|
||||
this.spring.register(DefaultServletConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(MockServletContext.mvc()))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path/method").with(defaultServlet())).andExpect(status().isNotFound());
|
||||
this.mvc.perform(head("/path/method").with(defaultServlet())).andExpect(status().isUnauthorized());
|
||||
this.mvc.perform(get("/path/method").with(servletPath("/path"))).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultServletWhenNoDefaultServletThenWiringException() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(DefaultServletConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(new MockServletContext()))
|
||||
.autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletPathMatchersWhenMatchingServletThenPermits() throws Exception {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
|
||||
this.spring.register(ServletPathConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path/path").with(servletPath("/path"))).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/path/path").with(defaultServlet())).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletPathHttpMethodMatchersWhenMatchingServletThenPermits() throws Exception {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
|
||||
this.spring.register(ServletPathConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path/method").with(servletPath("/path"))).andExpect(status().isNotFound());
|
||||
this.mvc.perform(head("/path/method").with(servletPath("/path"))).andExpect(status().isUnauthorized());
|
||||
this.mvc.perform(get("/path/method").with(defaultServlet())).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletPathWhenNoMatchingPathThenWiringException() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(ServletPathConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMappingMatchersWhenMatchingServletThenPermits() throws Exception {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("jsp", Servlet.class).addMapping("*.jsp");
|
||||
this.spring.register(ServletMappingConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/path/file.jsp").with(servletExtension(".jsp"))).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/path/file.jsp").with(defaultServlet())).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMappingHttpMethodMatchersWhenMatchingServletThenPermits() throws Exception {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("jsp", Servlet.class).addMapping("*.jsp");
|
||||
this.spring.register(ServletMappingConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/method/file.jsp").with(servletExtension(".jsp"))).andExpect(status().isNotFound());
|
||||
this.mvc.perform(head("/method/file.jsp").with(servletExtension(".jsp"))).andExpect(status().isUnauthorized());
|
||||
this.mvc.perform(get("/method/file.jsp").with(defaultServlet())).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMappingWhenNoMatchingExtensionThenWiringException() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(ServletMappingConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
void anyRequestWhenUsedWithDefaultServletThenDoesNotWire() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(MixedServletEndpointConfig.class).autowire())
|
||||
.withMessageContaining("forServletPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletWhenNoMatchingPathThenDenies() throws Exception {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
this.spring.register(DefaultServletAndServletPathConfig.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.mvc.perform(get("/js/color.js").with(servletPath("/js"))).andExpect(status().isUnauthorized());
|
||||
this.mvc.perform(get("/mvc/controller").with(defaultServlet())).andExpect(status().isUnauthorized());
|
||||
this.mvc.perform(get("/js/color.js").with(defaultServlet())).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/mvc/controller").with(servletPath("/mvc"))).andExpect(status().isUnauthorized());
|
||||
this.mvc.perform(get("/mvc/controller").with(user("user")).with(servletPath("/mvc")))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
void permitAllWhenDefaultServletThenDoesNotWire() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(MixedServletPermitAllConfig.class).autowire())
|
||||
.withMessageContaining("forServletPattern");
|
||||
}
|
||||
|
||||
static RequestPostProcessor defaultServlet() {
|
||||
return (request) -> {
|
||||
String uri = request.getRequestURI();
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.defaultMapping());
|
||||
request.setServletPath(uri);
|
||||
request.setPathInfo("");
|
||||
return request;
|
||||
};
|
||||
}
|
||||
|
||||
static RequestPostProcessor servletPath(String path) {
|
||||
return (request) -> {
|
||||
String uri = request.getRequestURI();
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.path(request, path));
|
||||
request.setServletPath(path);
|
||||
request.setPathInfo(uri.substring(path.length()));
|
||||
return request;
|
||||
};
|
||||
}
|
||||
|
||||
static RequestPostProcessor servletExtension(String extension) {
|
||||
return (request) -> {
|
||||
String uri = request.getRequestURI();
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.extension(request, extension));
|
||||
request.setServletPath(uri);
|
||||
request.setPathInfo("");
|
||||
return request;
|
||||
};
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class GrantedAuthorityDefaultHasRoleConfig {
|
||||
@@ -693,6 +892,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class AfterAnyRequestConfig {
|
||||
|
||||
@Bean
|
||||
@@ -954,7 +1154,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
static class ServletPathConfig {
|
||||
static class MvcServletPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
@@ -1136,6 +1336,163 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class AuthorizeHttpRequestsConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.requestMatchers("/path/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class DefaultServletConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.forServletPattern("/", (root) -> root
|
||||
.requestMatchers(HttpMethod.GET, "/path/method/**").permitAll()
|
||||
.requestMatchers("/path/path/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class ServletPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.forServletPattern("/path/*", (root) -> root
|
||||
.requestMatchers(HttpMethod.GET, "/method/**").permitAll()
|
||||
.requestMatchers("/path/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class ServletMappingConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.forServletPattern("*.jsp", (jsp) -> jsp
|
||||
.requestMatchers(HttpMethod.GET, "/method/**").permitAll()
|
||||
.requestMatchers("/path/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class MixedServletEndpointConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.forServletPattern("/", (root) -> root.anyRequest().permitAll())
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class MixedServletPermitAllConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.formLogin((form) -> form.loginPage("/page").permitAll())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.forServletPattern("/", (root) -> root
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class DefaultServletAndServletPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain chain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.forServletPattern("/", (root) -> root
|
||||
.requestMatchers("/js/**", "/css/**").permitAll()
|
||||
)
|
||||
.forServletPattern("/mvc/*", (mvc) -> mvc
|
||||
.requestMatchers("/controller/**").authenticated()
|
||||
)
|
||||
.forServletPattern("*.jsp", (jsp) -> jsp
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthorizationEventPublisherConfig {
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jakarta.servlet.Servlet;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.MockServletContext;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.configurers.DispatcherServletDelegatingRequestMatcherBuilder.DispatcherServletDelegatingRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class RequestMatcherBuildersTests {
|
||||
|
||||
@Test
|
||||
void matchersWhenDefaultDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
|
||||
List<RequestMatcher> matchers = builder.matchers("/mvc");
|
||||
assertThat(matchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
||||
MvcRequestMatcher matcher = (MvcRequestMatcher) matchers.get(0);
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "servletPath")).isNull();
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/mvc");
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpMethodMatchersWhenDefaultDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
|
||||
List<RequestMatcher> matchers = builder.matchers(HttpMethod.GET, "/mvc");
|
||||
assertThat(matchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
||||
MvcRequestMatcher matcher = (MvcRequestMatcher) matchers.get(0);
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "servletPath")).isNull();
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/mvc");
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "method")).isEqualTo(HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenPathDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
|
||||
List<RequestMatcher> matchers = builder.matchers("/controller");
|
||||
assertThat(matchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
||||
MvcRequestMatcher matcher = (MvcRequestMatcher) matchers.get(0);
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "servletPath")).isEqualTo("/mvc");
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenAlsoExtraServletContainerMappingsThenRequiresServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
|
||||
servletContext.addServlet("facesServlet", Servlet.class).addMapping("/faces/", "*.jsf", "*.faces", "*.xhtml");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path"))
|
||||
.withMessageContaining(".forServletPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenOnlyDefaultServletThenAnt() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
|
||||
List<RequestMatcher> matchers = builder.matchers("/controller");
|
||||
assertThat(matchers.get(0)).isInstanceOf(AntPathRequestMatcher.class);
|
||||
AntPathRequestMatcher matcher = (AntPathRequestMatcher) matchers.get(0);
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenNoHandlerMappingIntrospectorThenAnt() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext, (context) -> {
|
||||
});
|
||||
List<RequestMatcher> matchers = builder.matchers("/controller");
|
||||
assertThat(matchers.get(0)).isInstanceOf(AntPathRequestMatcher.class);
|
||||
AntPathRequestMatcher matcher = (AntPathRequestMatcher) matchers.get(0);
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenNoDispatchServletThenAnt() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
|
||||
List<RequestMatcher> matchers = builder.matchers("/services/endpoint");
|
||||
assertThat(matchers.get(0)).isInstanceOf(AntPathRequestMatcher.class);
|
||||
AntPathRequestMatcher matcher = (AntPathRequestMatcher) matchers.get(0);
|
||||
assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/services/endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenMixedServletsThenServletPathDelegating() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
|
||||
RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
|
||||
assertThat(builder.matchers("/services/endpoint").get(0))
|
||||
.isInstanceOf(DispatcherServletDelegatingRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenDispatcherServletNotDefaultAndOtherServletsThenRequiresServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
|
||||
.withMessageContaining(".forServletPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpMatchersWhenDispatcherServletNotDefaultAndOtherServletsThenRequiresServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/pattern"))
|
||||
.withMessageContaining(".forServletPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenTwoDispatcherServletsThenException() {
|
||||
MockServletContext servletContext = MockServletContext.mvc();
|
||||
servletContext.addServlet("two", DispatcherServlet.class).addMapping("/other/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
|
||||
.withMessageContaining(".forServletPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenMoreThanOneMappingThenException() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
|
||||
.withMessageContaining(".forServletPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchersWhenMoreThanOneMappingAndDefaultServletsThenRequiresServletPath() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
|
||||
servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
|
||||
.withMessageContaining(".forServletPattern");
|
||||
}
|
||||
|
||||
RequestMatcherBuilder requestMatchersBuilder(ServletContext servletContext) {
|
||||
return requestMatchersBuilder(servletContext, (context) -> {
|
||||
context.registerBean("mvcHandlerMappingIntrospector", HandlerMappingIntrospector.class,
|
||||
() -> mock(HandlerMappingIntrospector.class));
|
||||
context.registerBean(ObjectPostProcessor.class, () -> mock(ObjectPostProcessor.class));
|
||||
});
|
||||
}
|
||||
|
||||
RequestMatcherBuilder requestMatchersBuilder(ServletContext servletContext,
|
||||
Consumer<GenericWebApplicationContext> consumer) {
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext(servletContext);
|
||||
consumer.accept(context);
|
||||
context.refresh();
|
||||
return RequestMatcherBuilders.createDefault(context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServletPatternRequestMatcher}
|
||||
*/
|
||||
class ServletPatternRequestMatcherTests {
|
||||
|
||||
ServletPatternRequestMatcher matcher = new ServletPatternRequestMatcher("*.jsp");
|
||||
|
||||
@Test
|
||||
void matchesWhenDefaultServletThenTrue() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.extension(request, ".jsp"));
|
||||
assertThat(this.matcher.matches(request)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchesWhenNotDefaultServletThenFalse() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/a"));
|
||||
request.setServletPath("/a/uri.jsp");
|
||||
assertThat(this.matcher.matches(request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenDefaultServletThenTrue() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.extension(request, ".jsp"));
|
||||
request.setServletPath("/a/uri.jsp");
|
||||
assertThat(this.matcher.matcher(request).isMatch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenNotDefaultServletThenFalse() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/a"));
|
||||
request.setServletPath("/a/uri.jsp");
|
||||
assertThat(this.matcher.matcher(request).isMatch()).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.MappingMatch;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletMapping;
|
||||
|
||||
final class TestMockHttpServletMappings {
|
||||
|
||||
private TestMockHttpServletMappings() {
|
||||
|
||||
}
|
||||
|
||||
static MockHttpServletMapping extension(HttpServletRequest request, String extension) {
|
||||
String uri = request.getRequestURI();
|
||||
String matchValue = uri.substring(0, uri.lastIndexOf(extension));
|
||||
return new MockHttpServletMapping(matchValue, "*" + extension, "extension", MappingMatch.EXTENSION);
|
||||
}
|
||||
|
||||
static MockHttpServletMapping path(HttpServletRequest request, String path) {
|
||||
String uri = request.getRequestURI();
|
||||
String matchValue = uri.substring(path.length());
|
||||
return new MockHttpServletMapping(matchValue, path + "/*", "path", MappingMatch.PATH);
|
||||
}
|
||||
|
||||
static MockHttpServletMapping defaultMapping() {
|
||||
return new MockHttpServletMapping("", "/", "default", MappingMatch.DEFAULT);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user