Skip to content

Commit fe5a55f

Browse files
committed
Merge branch '6.1.x'
Closes gh-13723
2 parents 47acdc7 + 0df1884 commit fe5a55f

File tree

3 files changed

+54
-9
lines changed

3 files changed

+54
-9
lines changed

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

+32-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.Arrays;
21+
import java.util.Collection;
22+
import java.util.LinkedHashMap;
2123
import java.util.List;
2224
import java.util.Map;
2325

@@ -194,18 +196,31 @@ public C requestMatchers(HttpMethod method, String... patterns) {
194196
if (servletContext == null) {
195197
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
196198
}
197-
Map<String, ? extends ServletRegistration> registrations = servletContext.getServletRegistrations();
198-
if (registrations == null) {
199+
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
200+
if (registrations.isEmpty()) {
199201
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
200202
}
201203
if (!hasDispatcherServlet(registrations)) {
202204
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
203205
}
204-
Assert.isTrue(registrations.size() == 1,
205-
"This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).");
206+
if (registrations.size() > 1) {
207+
String errorMessage = computeErrorMessage(registrations.values());
208+
throw new IllegalArgumentException(errorMessage);
209+
}
206210
return requestMatchers(createMvcMatchers(method, patterns).toArray(new RequestMatcher[0]));
207211
}
208212

213+
private Map<String, ? extends ServletRegistration> mappableServletRegistrations(ServletContext servletContext) {
214+
Map<String, ServletRegistration> mappable = new LinkedHashMap<>();
215+
for (Map.Entry<String, ? extends ServletRegistration> entry : servletContext.getServletRegistrations()
216+
.entrySet()) {
217+
if (!entry.getValue().getMappings().isEmpty()) {
218+
mappable.put(entry.getKey(), entry.getValue());
219+
}
220+
}
221+
return mappable;
222+
}
223+
209224
private boolean hasDispatcherServlet(Map<String, ? extends ServletRegistration> registrations) {
210225
if (registrations == null) {
211226
return false;
@@ -226,6 +241,19 @@ private boolean hasDispatcherServlet(Map<String, ? extends ServletRegistration>
226241
return false;
227242
}
228243

244+
private String computeErrorMessage(Collection<? extends ServletRegistration> registrations) {
245+
String template = "This method cannot decide whether these patterns are Spring MVC patterns or not. "
246+
+ "If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); "
247+
+ "otherwise, please use requestMatchers(AntPathRequestMatcher).\n\n"
248+
+ "This is because there is more than one mappable servlet in your servlet context: %s.\n\n"
249+
+ "For each MvcRequestMatcher, call MvcRequestMatcher#setServletPath to indicate the servlet path.";
250+
Map<String, Collection<String>> mappings = new LinkedHashMap<>();
251+
for (ServletRegistration registration : registrations) {
252+
mappings.put(registration.getClassName(), registration.getMappings());
253+
}
254+
return String.format(template, mappings);
255+
}
256+
229257
/**
230258
* <p>
231259
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an

Diff for: config/src/test/java/org/springframework/security/config/MockServletContext.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package org.springframework.security.config;
1818

19+
import java.util.Arrays;
1920
import java.util.Collection;
2021
import java.util.LinkedHashMap;
22+
import java.util.LinkedHashSet;
2123
import java.util.Map;
2224
import java.util.Set;
2325

@@ -35,7 +37,7 @@ public class MockServletContext extends org.springframework.mock.web.MockServlet
3537

3638
public static MockServletContext mvc() {
3739
MockServletContext servletContext = new MockServletContext();
38-
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class);
40+
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
3941
return servletContext;
4042
}
4143

@@ -59,6 +61,8 @@ private static class MockServletRegistration implements ServletRegistration.Dyna
5961

6062
private final Class<?> clazz;
6163

64+
private final Set<String> mappings = new LinkedHashSet<>();
65+
6266
MockServletRegistration(String name, Class<?> clazz) {
6367
this.name = name;
6468
this.clazz = clazz;
@@ -91,12 +95,13 @@ public void setAsyncSupported(boolean isAsyncSupported) {
9195

9296
@Override
9397
public Set<String> addMapping(String... urlPatterns) {
94-
return null;
98+
this.mappings.addAll(Arrays.asList(urlPatterns));
99+
return this.mappings;
95100
}
96101

97102
@Override
98103
public Collection<String> getMappings() {
99-
return null;
104+
return this.mappings;
100105
}
101106

102107
@Override

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

+14-2
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,24 @@ public void requestMatchersWhenNoDispatcherServletThenAntPathRequestMatcherType(
174174
public void requestMatchersWhenAmbiguousServletsThenException() {
175175
MockServletContext servletContext = new MockServletContext();
176176
given(this.context.getServletContext()).willReturn(servletContext);
177-
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class);
178-
servletContext.addServlet("servletTwo", Servlet.class);
177+
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
178+
servletContext.addServlet("servletTwo", Servlet.class).addMapping("/servlet/**");
179179
assertThatExceptionOfType(IllegalArgumentException.class)
180180
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
181181
}
182182

183+
@Test
184+
public void requestMatchersWhenUnmappableServletsThenSkips() {
185+
mockMvcIntrospector(true);
186+
MockServletContext servletContext = new MockServletContext();
187+
given(this.context.getServletContext()).willReturn(servletContext);
188+
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
189+
servletContext.addServlet("servletTwo", Servlet.class);
190+
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
191+
assertThat(requestMatchers).hasSize(1);
192+
assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
193+
}
194+
183195
private void mockMvcIntrospector(boolean isPresent) {
184196
ApplicationContext context = this.matcherRegistry.getApplicationContext();
185197
given(context.containsBean("mvcHandlerMappingIntrospector")).willReturn(isPresent);

0 commit comments

Comments
 (0)