Merge branch '5.8.x' into 6.2.x

Closes gh-15196
This commit is contained in:
Josh Cummings 2024-06-03 17:42:25 -06:00
commit d6228e0882
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
5 changed files with 25 additions and 48 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
@ -203,36 +204,15 @@ public abstract class AbstractRequestMatcherRegistry<C> {
if (servletContext == null) {
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
}
boolean isProgrammaticApiAvailable = isProgrammaticApiAvailable(servletContext);
List<RequestMatcher> matchers = new ArrayList<>();
for (String pattern : patterns) {
AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null);
MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0);
if (isProgrammaticApiAvailable) {
matchers.add(resolve(ant, mvc, servletContext));
}
else {
this.logger
.warn("The ServletRegistration API was not available at startup time. This may be due to a misconfiguration; "
+ "if you are using AbstractSecurityWebApplicationInitializer, please double-check the recommendations outlined in "
+ "https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#abstractsecuritywebapplicationinitializer-with-spring-mvc");
matchers.add(new DeferredRequestMatcher((request) -> resolve(ant, mvc, request.getServletContext()),
mvc, ant));
}
matchers.add(new DeferredRequestMatcher((c) -> resolve(ant, mvc, c), mvc, ant));
}
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
}
private static boolean isProgrammaticApiAvailable(ServletContext servletContext) {
try {
servletContext.getServletRegistrations();
return true;
}
catch (UnsupportedOperationException ex) {
return false;
}
}
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
if (registrations.isEmpty()) {
@ -474,34 +454,29 @@ public abstract class AbstractRequestMatcherRegistry<C> {
static class DeferredRequestMatcher implements RequestMatcher {
final Function<HttpServletRequest, RequestMatcher> requestMatcherFactory;
final Function<ServletContext, RequestMatcher> requestMatcherFactory;
final AtomicReference<String> description = new AtomicReference<>();
volatile RequestMatcher requestMatcher;
final Map<ServletContext, RequestMatcher> requestMatchers = new ConcurrentHashMap<>();
DeferredRequestMatcher(Function<HttpServletRequest, RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcherFactory = (request) -> {
if (this.requestMatcher == null) {
synchronized (this) {
if (this.requestMatcher == null) {
this.requestMatcher = resolver.apply(request);
}
}
}
return this.requestMatcher;
};
DeferredRequestMatcher(Function<ServletContext, RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcherFactory = (sc) -> this.requestMatchers.computeIfAbsent(sc, resolver);
this.description.set("Deferred " + Arrays.toString(candidates));
}
RequestMatcher requestMatcher(ServletContext servletContext) {
return this.requestMatcherFactory.apply(servletContext);
}
@Override
public boolean matches(HttpServletRequest request) {
return this.requestMatcherFactory.apply(request).matches(request);
return this.requestMatcherFactory.apply(request.getServletContext()).matches(request);
}
@Override
public MatchResult matcher(HttpServletRequest request) {
return this.requestMatcherFactory.apply(request).matcher(request);
return this.requestMatcherFactory.apply(request.getServletContext()).matcher(request);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@ -303,11 +303,13 @@ public class AbstractRequestMatcherRegistryTests {
return requestMatchers;
}
private static List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
private List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
List<RequestMatcher> requestMatchers = new ArrayList<>();
for (RequestMatcher requestMatcher : wrappedMatchers) {
if (requestMatcher instanceof AbstractRequestMatcherRegistry.DeferredRequestMatcher) {
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher);
if (requestMatcher instanceof DeferredRequestMatcher) {
DeferredRequestMatcher deferred = (DeferredRequestMatcher) requestMatcher;
WebApplicationContext web = (WebApplicationContext) getApplicationContext();
requestMatchers.add(deferred.requestMatcher(web.getServletContext()));
}
else {
requestMatchers.add(requestMatcher);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@ -78,7 +78,7 @@ public class AuthorizeRequestsTests {
@BeforeEach
public void setup() {
this.servletContext = spy(MockServletContext.mvc());
this.request = new MockHttpServletRequest("GET", "");
this.request = new MockHttpServletRequest(this.servletContext, "GET", "");
this.request.setMethod("GET");
this.response = new MockHttpServletResponse();
this.chain = new MockFilterChain();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@ -75,7 +75,7 @@ public class HttpSecuritySecurityMatchersTests {
@BeforeEach
public void setup() throws Exception {
this.request = new MockHttpServletRequest("GET", "");
this.request = new MockHttpServletRequest(MockServletContext.mvc(), "GET", "");
this.request.setMethod("GET");
this.response = new MockHttpServletResponse();
this.chain = new MockFilterChain();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@ -72,7 +72,7 @@ public class UrlAuthorizationConfigurerTests {
@BeforeEach
public void setup() {
this.request = new MockHttpServletRequest("GET", "");
this.request = new MockHttpServletRequest(MockServletContext.mvc(), "GET", "");
this.request.setMethod("GET");
this.response = new MockHttpServletResponse();
this.chain = new MockFilterChain();