|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright 2002-2022 the original author or authors.
|
|
|
+ * 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.
|
|
@@ -22,6 +22,7 @@ import java.util.List;
|
|
|
|
|
|
import javax.servlet.DispatcherType;
|
|
|
import javax.servlet.Servlet;
|
|
|
+import javax.servlet.http.HttpServletMapping;
|
|
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
import org.junit.jupiter.api.Test;
|
|
@@ -29,8 +30,11 @@ 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.mock.web.MockHttpServletRequest;
|
|
|
import org.springframework.security.config.MockServletContext;
|
|
|
+import org.springframework.security.config.TestMockHttpServletMappings;
|
|
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
|
|
+import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.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.DispatcherTypeRequestMatcher;
|
|
@@ -43,6 +47,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|
|
import static org.mockito.BDDMockito.given;
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.verify;
|
|
|
+import static org.mockito.Mockito.verifyNoInteractions;
|
|
|
+import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|
|
|
|
|
/**
|
|
|
* Tests for {@link AbstractRequestMatcherRegistry}.
|
|
@@ -197,6 +204,8 @@ public class AbstractRequestMatcherRegistryTests {
|
|
|
public void requestMatchersWhenNoDispatcherServletThenAntPathRequestMatcherType() {
|
|
|
MockServletContext servletContext = new MockServletContext();
|
|
|
given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
+ servletContext.addServlet("servletOne", Servlet.class).addMapping("/one");
|
|
|
+ servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two");
|
|
|
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
|
|
assertThat(requestMatchers).isNotEmpty();
|
|
|
assertThat(requestMatchers).hasSize(1);
|
|
@@ -214,7 +223,26 @@ public class AbstractRequestMatcherRegistryTests {
|
|
|
MockServletContext servletContext = new MockServletContext();
|
|
|
given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
|
|
- servletContext.addServlet("servletTwo", Servlet.class).addMapping("/servlet/**");
|
|
|
+ servletContext.addServlet("servletTwo", DispatcherServlet.class).addMapping("/servlet/*");
|
|
|
+ assertThatExceptionOfType(IllegalArgumentException.class)
|
|
|
+ .isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void requestMatchersWhenMultipleDispatcherServletMappingsThenException() {
|
|
|
+ MockServletContext servletContext = new MockServletContext();
|
|
|
+ given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
+ servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/mvc/*");
|
|
|
+ assertThatExceptionOfType(IllegalArgumentException.class)
|
|
|
+ .isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void requestMatchersWhenPathDispatcherServletAndOtherServletsThenException() {
|
|
|
+ MockServletContext servletContext = new MockServletContext();
|
|
|
+ given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
+ servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
|
|
+ servletContext.addServlet("default", Servlet.class).addMapping("/");
|
|
|
assertThatExceptionOfType(IllegalArgumentException.class)
|
|
|
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
|
|
}
|
|
@@ -231,6 +259,87 @@ public class AbstractRequestMatcherRegistryTests {
|
|
|
assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ public void requestMatchersWhenOnlyDispatcherServletThenAllows() {
|
|
|
+ mockMvcIntrospector(true);
|
|
|
+ MockServletContext servletContext = new MockServletContext();
|
|
|
+ given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
+ servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
|
|
+ List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
|
|
+ assertThat(requestMatchers).hasSize(1);
|
|
|
+ assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void requestMatchersWhenImplicitServletsThenAllows() {
|
|
|
+ mockMvcIntrospector(true);
|
|
|
+ MockServletContext servletContext = new MockServletContext();
|
|
|
+ given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
+ servletContext.addServlet("defaultServlet", Servlet.class);
|
|
|
+ servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
|
|
|
+ servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
|
|
+ List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
|
|
+ assertThat(requestMatchers).hasSize(1);
|
|
|
+ assertThat(requestMatchers.get(0)).isInstanceOf(DispatcherServletDelegatingRequestMatcher.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void requestMatchersWhenPathBasedNonDispatcherServletThenAllows() {
|
|
|
+ mockMvcIntrospector(true);
|
|
|
+ MockServletContext servletContext = new MockServletContext();
|
|
|
+ given(this.context.getServletContext()).willReturn(servletContext);
|
|
|
+ servletContext.addServlet("path", Servlet.class).addMapping("/services/*");
|
|
|
+ servletContext.addServlet("default", DispatcherServlet.class).addMapping("/");
|
|
|
+ List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/services/*");
|
|
|
+ assertThat(requestMatchers).hasSize(1);
|
|
|
+ assertThat(requestMatchers.get(0)).isInstanceOf(DispatcherServletDelegatingRequestMatcher.class);
|
|
|
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/services/endpoint") {
|
|
|
+ @Override
|
|
|
+ public HttpServletMapping getHttpServletMapping() {
|
|
|
+ return TestMockHttpServletMappings.defaultMapping();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ assertThat(requestMatchers.get(0).matcher(request).isMatch()).isTrue();
|
|
|
+ request = new MockHttpServletRequest("GET", "/services/endpoint") {
|
|
|
+ @Override
|
|
|
+ public HttpServletMapping getHttpServletMapping() {
|
|
|
+ return TestMockHttpServletMappings.path(this, "/services");
|
|
|
+ }
|
|
|
+ };
|
|
|
+ request.setServletPath("/services");
|
|
|
+ request.setPathInfo("/endpoint");
|
|
|
+ assertThat(requestMatchers.get(0).matcher(request).isMatch()).isTrue();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void matchesWhenDispatcherServletThenMvc() {
|
|
|
+ MockServletContext servletContext = new MockServletContext();
|
|
|
+ servletContext.addServlet("default", DispatcherServlet.class).addMapping("/");
|
|
|
+ servletContext.addServlet("path", Servlet.class).addMapping("/services/*");
|
|
|
+ MvcRequestMatcher mvc = mock(MvcRequestMatcher.class);
|
|
|
+ AntPathRequestMatcher ant = mock(AntPathRequestMatcher.class);
|
|
|
+ DispatcherServletDelegatingRequestMatcher requestMatcher = new DispatcherServletDelegatingRequestMatcher(ant,
|
|
|
+ mvc, servletContext);
|
|
|
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/services/endpoint") {
|
|
|
+ @Override
|
|
|
+ public HttpServletMapping getHttpServletMapping() {
|
|
|
+ return TestMockHttpServletMappings.defaultMapping();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ assertThat(requestMatcher.matches(request)).isFalse();
|
|
|
+ verify(mvc).matches(request);
|
|
|
+ verifyNoInteractions(ant);
|
|
|
+ request = new MockHttpServletRequest("GET", "/services/endpoint") {
|
|
|
+ @Override
|
|
|
+ public HttpServletMapping getHttpServletMapping() {
|
|
|
+ return TestMockHttpServletMappings.path(this, "/services");
|
|
|
+ }
|
|
|
+ };
|
|
|
+ assertThat(requestMatcher.matches(request)).isFalse();
|
|
|
+ verify(ant).matches(request);
|
|
|
+ verifyNoMoreInteractions(mvc);
|
|
|
+ }
|
|
|
+
|
|
|
private void mockMvcIntrospector(boolean isPresent) {
|
|
|
ApplicationContext context = this.matcherRegistry.getApplicationContext();
|
|
|
given(context.containsBean("mvcHandlerMappingIntrospector")).willReturn(isPresent);
|