Skip to content

Commit

Permalink
Merge branch '6.1.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
jzheaux committed Dec 1, 2023
2 parents b9b2df8 + 6417228 commit 3ab235c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.function.Function;

import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
Expand All @@ -44,7 +46,6 @@
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

Expand Down Expand Up @@ -76,6 +77,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
AbstractRequestMatcherRegistry.class.getClassLoader());
}

private final Log logger = LogFactory.getLog(getClass());

protected final void setApplicationContext(ApplicationContext context) {
this.context = context;
}
Expand Down Expand Up @@ -209,7 +212,12 @@ public C requestMatchers(HttpMethod method, String... patterns) {
matchers.add(resolve(ant, mvc, servletContext));
}
else {
matchers.add(new DeferredRequestMatcher(() -> resolve(ant, mvc, servletContext), mvc, ant));
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));
}
}
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
Expand Down Expand Up @@ -466,27 +474,34 @@ static List<RequestMatcher> regexMatchers(String... regexPatterns) {

static class DeferredRequestMatcher implements RequestMatcher {

final Supplier<RequestMatcher> requestMatcher;
final Function<HttpServletRequest, RequestMatcher> requestMatcherFactory;

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

DeferredRequestMatcher(Supplier<RequestMatcher> resolver, RequestMatcher... candidates) {
this.requestMatcher = SingletonSupplier.of(() -> {
RequestMatcher matcher = resolver.get();
this.description.set(matcher.toString());
return matcher;
});
volatile RequestMatcher requestMatcher;

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;
};
this.description.set("Deferred " + Arrays.toString(candidates));
}

@Override
public boolean matches(HttpServletRequest request) {
return this.requestMatcher.get().matches(request);
return this.requestMatcherFactory.apply(request).matches(request);
}

@Override
public MatchResult matcher(HttpServletRequest request) {
return this.requestMatcher.get().matcher(request);
return this.requestMatcherFactory.apply(request).matcher(request);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ private static 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.get());
requestMatchers.add(((DeferredRequestMatcher) requestMatcher).requestMatcher);
}
else {
requestMatchers.add(requestMatcher);
Expand Down
34 changes: 31 additions & 3 deletions docs/modules/ROOT/pages/servlet/configuration/java.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public class SecurityWebApplicationInitializer

This onlys register the `springSecurityFilterChain` for every URL in your application.
After that, we need to ensure that `WebSecurityConfig` was loaded in our existing `ApplicationInitializer`.
For example, if we use Spring MVC it is added in the `getRootConfigClasses()`:
For example, if we use Spring MVC it is added in the `getServletConfigClasses()`:

[[message-web-application-inititializer-java]]
[source,java]
Expand All @@ -123,14 +123,42 @@ public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class };
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
// ... other overrides ...
}
----

The reason for this is that Spring Security needs to be able to inspect some Spring MVC configuration in order to appropriately configure xref:servlet/authorization/authorize-http-requests.adoc#_request_matchers[underlying request matchers], so they need to be in the same application context.
Placing Spring Security in `getRootConfigClasses` places it into a parent application context that may not be able to find Spring MVC's `HandlerMappingIntrospector`.

==== Configuring for Multiple Spring MVC Dispatchers

If desired, any Spring Security configuration that is unrelated to Spring MVC may be placed in a different configuration class like so:

[source,java]
----
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { NonWebSecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
// ... other overrides ...
}
----

This can be helpful if you have multiple instances of `AbstractAnnotationConfigDispatcherServletInitializer` and don't want to duplicate the general security configuration across both of them.

[[jc-httpsecurity]]
== HttpSecurity

Expand Down

0 comments on commit 3ab235c

Please sign in to comment.