Skip to content

Commit f231ea2

Browse files
committed
Merge branch '5.8.x' into 6.2.x
Closes gh-15210
2 parents d6228e0 + 6aabd76 commit f231ea2

File tree

3 files changed

+120
-27
lines changed

3 files changed

+120
-27
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java

+54-24
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@
4343
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
4444
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
4545
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
46+
import org.springframework.security.web.util.matcher.OrRequestMatcher;
4647
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
4748
import org.springframework.security.web.util.matcher.RequestMatcher;
4849
import org.springframework.util.Assert;
4950
import org.springframework.util.ClassUtils;
5051
import org.springframework.web.context.WebApplicationContext;
52+
import org.springframework.web.servlet.DispatcherServlet;
5153
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
5254

5355
/**
@@ -216,10 +218,10 @@ public C requestMatchers(HttpMethod method, String... patterns) {
216218
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
217219
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
218220
if (registrations.isEmpty()) {
219-
return ant;
221+
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
220222
}
221223
if (!hasDispatcherServlet(registrations)) {
222-
return ant;
224+
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
223225
}
224226
ServletRegistration dispatcherServlet = requireOneRootDispatcherServlet(registrations);
225227
if (dispatcherServlet != null) {
@@ -486,55 +488,83 @@ public String toString() {
486488

487489
}
488490

491+
static class MockMvcRequestMatcher implements RequestMatcher {
492+
493+
@Override
494+
public boolean matches(HttpServletRequest request) {
495+
return request.getAttribute("org.springframework.test.web.servlet.MockMvc.MVC_RESULT_ATTRIBUTE") != null;
496+
}
497+
498+
}
499+
500+
static class DispatcherServletRequestMatcher implements RequestMatcher {
501+
502+
private final ServletContext servletContext;
503+
504+
DispatcherServletRequestMatcher(ServletContext servletContext) {
505+
this.servletContext = servletContext;
506+
}
507+
508+
@Override
509+
public boolean matches(HttpServletRequest request) {
510+
String name = request.getHttpServletMapping().getServletName();
511+
ServletRegistration registration = this.servletContext.getServletRegistration(name);
512+
Assert.notNull(name, "Failed to find servlet [" + name + "] in the servlet context");
513+
try {
514+
Class<?> clazz = Class.forName(registration.getClassName());
515+
return DispatcherServlet.class.isAssignableFrom(clazz);
516+
}
517+
catch (ClassNotFoundException ex) {
518+
return false;
519+
}
520+
}
521+
522+
}
523+
489524
static class DispatcherServletDelegatingRequestMatcher implements RequestMatcher {
490525

491526
private final AntPathRequestMatcher ant;
492527

493528
private final MvcRequestMatcher mvc;
494529

495-
private final ServletContext servletContext;
530+
private final RequestMatcher dispatcherServlet;
496531

497532
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc,
498533
ServletContext servletContext) {
534+
this(ant, mvc, new OrRequestMatcher(new MockMvcRequestMatcher(),
535+
new DispatcherServletRequestMatcher(servletContext)));
536+
}
537+
538+
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc,
539+
RequestMatcher dispatcherServlet) {
499540
this.ant = ant;
500541
this.mvc = mvc;
501-
this.servletContext = servletContext;
542+
this.dispatcherServlet = dispatcherServlet;
543+
}
544+
545+
RequestMatcher requestMatcher(HttpServletRequest request) {
546+
if (this.dispatcherServlet.matches(request)) {
547+
return this.mvc;
548+
}
549+
return this.ant;
502550
}
503551

504552
@Override
505553
public boolean matches(HttpServletRequest request) {
506-
String name = request.getHttpServletMapping().getServletName();
507-
ServletRegistration registration = this.servletContext.getServletRegistration(name);
508-
Assert.notNull(registration, "Failed to find servlet [" + name + "] in the servlet context");
509-
if (isDispatcherServlet(registration)) {
554+
if (this.dispatcherServlet.matches(request)) {
510555
return this.mvc.matches(request);
511556
}
512557
return this.ant.matches(request);
513558
}
514559

515560
@Override
516561
public MatchResult matcher(HttpServletRequest request) {
517-
String name = request.getHttpServletMapping().getServletName();
518-
ServletRegistration registration = this.servletContext.getServletRegistration(name);
519-
Assert.notNull(registration, "Failed to find servlet [" + name + "] in the servlet context");
520-
if (isDispatcherServlet(registration)) {
562+
if (this.dispatcherServlet.matches(request)) {
521563
return this.mvc.matcher(request);
522564
}
523565
return this.ant.matcher(request);
524566
}
525567

526-
private boolean isDispatcherServlet(ServletRegistration registration) {
527-
Class<?> dispatcherServlet = ClassUtils
528-
.resolveClassName("org.springframework.web.servlet.DispatcherServlet", null);
529-
try {
530-
Class<?> clazz = Class.forName(registration.getClassName());
531-
return dispatcherServlet.isAssignableFrom(clazz);
532-
}
533-
catch (ClassNotFoundException ex) {
534-
return false;
535-
}
536-
}
537-
538568
@Override
539569
public String toString() {
540570
return "DispatcherServletDelegating [" + "ant = " + this.ant + ", mvc = " + this.mvc + "]";

config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java

+65-3
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,35 @@
2626

2727
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2828
import org.springframework.context.ApplicationContext;
29+
import org.springframework.context.annotation.Configuration;
2930
import org.springframework.http.HttpMethod;
3031
import org.springframework.mock.web.MockHttpServletRequest;
3132
import org.springframework.security.config.MockServletContext;
3233
import org.springframework.security.config.TestMockHttpServletMappings;
3334
import org.springframework.security.config.annotation.ObjectPostProcessor;
3435
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.DispatcherServletDelegatingRequestMatcher;
36+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
37+
import org.springframework.security.config.test.SpringTestContext;
3538
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
3639
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
3740
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
3841
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
3942
import org.springframework.security.web.util.matcher.RequestMatcher;
43+
import org.springframework.test.web.servlet.MockMvc;
44+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
4045
import org.springframework.web.context.WebApplicationContext;
4146
import org.springframework.web.servlet.DispatcherServlet;
47+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
4248

4349
import static org.assertj.core.api.Assertions.assertThat;
4450
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
51+
import static org.assertj.core.api.InstanceOfAssertFactories.type;
4552
import static org.mockito.BDDMockito.given;
4653
import static org.mockito.Mockito.mock;
4754
import static org.mockito.Mockito.verify;
4855
import static org.mockito.Mockito.verifyNoInteractions;
4956
import static org.mockito.Mockito.verifyNoMoreInteractions;
57+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
5058

5159
/**
5260
* Tests for {@link AbstractRequestMatcherRegistry}.
@@ -167,18 +175,65 @@ public void requestMatchersWhenNoDispatcherServletThenAntPathRequestMatcherType(
167175
mockMvcIntrospector(true);
168176
MockServletContext servletContext = new MockServletContext();
169177
given(this.context.getServletContext()).willReturn(servletContext);
178+
MockHttpServletRequest request = new MockHttpServletRequest();
179+
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
180+
assertThat(requestMatchers).isNotEmpty();
181+
assertThat(requestMatchers).hasSize(1);
182+
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
183+
.extracting((matcher) -> matcher.requestMatcher(request))
184+
.isInstanceOf(AntPathRequestMatcher.class);
170185
servletContext.addServlet("servletOne", Servlet.class).addMapping("/one");
171186
servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two");
172-
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
187+
requestMatchers = this.matcherRegistry.requestMatchers("/**");
173188
assertThat(requestMatchers).isNotEmpty();
174189
assertThat(requestMatchers).hasSize(1);
175-
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
190+
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
191+
.extracting((matcher) -> matcher.requestMatcher(request))
192+
.isInstanceOf(AntPathRequestMatcher.class);
176193
servletContext.addServlet("servletOne", Servlet.class);
177194
servletContext.addServlet("servletTwo", Servlet.class);
178195
requestMatchers = this.matcherRegistry.requestMatchers("/**");
179196
assertThat(requestMatchers).isNotEmpty();
180197
assertThat(requestMatchers).hasSize(1);
181-
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
198+
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
199+
.extracting((matcher) -> matcher.requestMatcher(request))
200+
.isInstanceOf(AntPathRequestMatcher.class);
201+
}
202+
203+
// gh-14418
204+
@Test
205+
public void requestMatchersWhenNoDispatcherServletMockMvcThenMvcRequestMatcherType() throws Exception {
206+
MockServletContext servletContext = new MockServletContext();
207+
try (SpringTestContext spring = new SpringTestContext(this)) {
208+
spring.register(MockMvcConfiguration.class)
209+
.postProcessor((context) -> context.setServletContext(servletContext))
210+
.autowire();
211+
this.matcherRegistry.setApplicationContext(spring.getContext());
212+
MockMvc mvc = MockMvcBuilders.webAppContextSetup(spring.getContext()).build();
213+
MockHttpServletRequest request = mvc.perform(get("/")).andReturn().getRequest();
214+
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
215+
assertThat(requestMatchers).isNotEmpty();
216+
assertThat(requestMatchers).hasSize(1);
217+
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
218+
.extracting((matcher) -> matcher.requestMatcher(request))
219+
.isInstanceOf(MvcRequestMatcher.class);
220+
servletContext.addServlet("servletOne", Servlet.class).addMapping("/one");
221+
servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two");
222+
requestMatchers = this.matcherRegistry.requestMatchers("/**");
223+
assertThat(requestMatchers).isNotEmpty();
224+
assertThat(requestMatchers).hasSize(1);
225+
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
226+
.extracting((matcher) -> matcher.requestMatcher(request))
227+
.isInstanceOf(MvcRequestMatcher.class);
228+
servletContext.addServlet("servletOne", Servlet.class);
229+
servletContext.addServlet("servletTwo", Servlet.class);
230+
requestMatchers = this.matcherRegistry.requestMatchers("/**");
231+
assertThat(requestMatchers).isNotEmpty();
232+
assertThat(requestMatchers).hasSize(1);
233+
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
234+
.extracting((matcher) -> matcher.requestMatcher(request))
235+
.isInstanceOf(MvcRequestMatcher.class);
236+
}
182237
}
183238

184239
@Test
@@ -320,4 +375,11 @@ private List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
320375

321376
}
322377

378+
@Configuration
379+
@EnableWebSecurity
380+
@EnableWebMvc
381+
static class MockMvcConfiguration {
382+
383+
}
384+
323385
}

etc/checkstyle/checkstyle.xml

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<property name="avoidStaticImportExcludes" value="org.springframework.security.web.util.matcher.AntPathRequestMatcher.*" />
2222
<property name="avoidStaticImportExcludes" value="org.springframework.security.web.util.matcher.RegexRequestMatcher.*" />
2323
<property name="avoidStaticImportExcludes" value="org.springframework.core.annotation.MergedAnnotations.SearchStrategy.*" />
24+
<property name="avoidStaticImportExcludes" value="org.assertj.core.api.InstanceOfAssertFactories.*"/>
2425
</module>
2526
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
2627
<module name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">

0 commit comments

Comments
 (0)