Skip to content

Commit cdd6266

Browse files
committed
Use Request-Level Servlet Context
Spring Security cannot use the ServletContext attached to the ApplicationContext since there may be child ApplicationContext's with their own ServletContext. Because of that, it is necessary to always use the ServletContext attached to the request. Closes gh-14418
1 parent 5a798e9 commit cdd6266

File tree

2 files changed

+20
-43
lines changed

2 files changed

+20
-43
lines changed

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

+14-39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import java.util.LinkedHashMap;
2323
import java.util.List;
2424
import java.util.Map;
25+
import java.util.concurrent.ConcurrentHashMap;
2526
import java.util.concurrent.atomic.AtomicReference;
2627
import java.util.function.Function;
2728

@@ -322,36 +323,15 @@ public C requestMatchers(HttpMethod method, String... patterns) {
322323
if (servletContext == null) {
323324
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
324325
}
325-
boolean isProgrammaticApiAvailable = isProgrammaticApiAvailable(servletContext);
326326
List<RequestMatcher> matchers = new ArrayList<>();
327327
for (String pattern : patterns) {
328328
AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null);
329329
MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0);
330-
if (isProgrammaticApiAvailable) {
331-
matchers.add(resolve(ant, mvc, servletContext));
332-
}
333-
else {
334-
this.logger
335-
.warn("The ServletRegistration API was not available at startup time. This may be due to a misconfiguration; "
336-
+ "if you are using AbstractSecurityWebApplicationInitializer, please double-check the recommendations outlined in "
337-
+ "https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#abstractsecuritywebapplicationinitializer-with-spring-mvc");
338-
matchers.add(new DeferredRequestMatcher((request) -> resolve(ant, mvc, request.getServletContext()),
339-
mvc, ant));
340-
}
330+
matchers.add(new DeferredRequestMatcher((c) -> resolve(ant, mvc, c), mvc, ant));
341331
}
342332
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
343333
}
344334

345-
private static boolean isProgrammaticApiAvailable(ServletContext servletContext) {
346-
try {
347-
servletContext.getServletRegistrations();
348-
return true;
349-
}
350-
catch (UnsupportedOperationException ex) {
351-
return false;
352-
}
353-
}
354-
355335
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
356336
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
357337
if (registrations.isEmpty()) {
@@ -593,34 +573,29 @@ static List<RequestMatcher> regexMatchers(String... regexPatterns) {
593573

594574
static class DeferredRequestMatcher implements RequestMatcher {
595575

596-
final Function<HttpServletRequest, RequestMatcher> requestMatcherFactory;
576+
final Function<ServletContext, RequestMatcher> requestMatcherFactory;
597577

598578
final AtomicReference<String> description = new AtomicReference<>();
599579

600-
volatile RequestMatcher requestMatcher;
601-
602-
DeferredRequestMatcher(Function<HttpServletRequest, RequestMatcher> resolver, RequestMatcher... candidates) {
603-
this.requestMatcherFactory = (request) -> {
604-
if (this.requestMatcher == null) {
605-
synchronized (this) {
606-
if (this.requestMatcher == null) {
607-
this.requestMatcher = resolver.apply(request);
608-
}
609-
}
610-
}
611-
return this.requestMatcher;
612-
};
580+
final Map<ServletContext, RequestMatcher> requestMatchers = new ConcurrentHashMap<>();
581+
582+
DeferredRequestMatcher(Function<ServletContext, RequestMatcher> resolver, RequestMatcher... candidates) {
583+
this.requestMatcherFactory = (sc) -> this.requestMatchers.computeIfAbsent(sc, resolver);
613584
this.description.set("Deferred " + Arrays.toString(candidates));
614585
}
615586

587+
RequestMatcher requestMatcher(ServletContext servletContext) {
588+
return this.requestMatcherFactory.apply(servletContext);
589+
}
590+
616591
@Override
617592
public boolean matches(HttpServletRequest request) {
618-
return this.requestMatcherFactory.apply(request).matches(request);
593+
return this.requestMatcherFactory.apply(request.getServletContext()).matches(request);
619594
}
620595

621596
@Override
622597
public MatchResult matcher(HttpServletRequest request) {
623-
return this.requestMatcherFactory.apply(request).matcher(request);
598+
return this.requestMatcherFactory.apply(request.getServletContext()).matcher(request);
624599
}
625600

626601
@Override

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

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -381,11 +381,13 @@ protected List<RequestMatcher> chainRequestMatchers(List<RequestMatcher> request
381381
return requestMatchers;
382382
}
383383

384-
private static List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
384+
private List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
385385
List<RequestMatcher> requestMatchers = new ArrayList<>();
386386
for (RequestMatcher requestMatcher : wrappedMatchers) {
387-
if (requestMatcher instanceof AbstractRequestMatcherRegistry.DeferredRequestMatcher) {
388-
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher);
387+
if (requestMatcher instanceof DeferredRequestMatcher) {
388+
DeferredRequestMatcher deferred = (DeferredRequestMatcher) requestMatcher;
389+
WebApplicationContext web = (WebApplicationContext) getApplicationContext();
390+
requestMatchers.add(deferred.requestMatcher(web.getServletContext()));
389391
}
390392
else {
391393
requestMatchers.add(requestMatcher);

0 commit comments

Comments
 (0)