Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it easier to determine where a filter chain has been defined #15874

Closed
wilkinsona opened this issue Oct 4, 2024 · 4 comments · Fixed by #15992
Closed

Make it easier to determine where a filter chain has been defined #15874

wilkinsona opened this issue Oct 4, 2024 · 4 comments · Fixed by #15992
Assignees
Labels
in: config An issue in spring-security-config type: enhancement A general enhancement
Milestone

Comments

@wilkinsona
Copy link
Member

wilkinsona commented Oct 4, 2024

Expected Behavior

When there a multiple filter chains configured for any request, Spring Security should make it as easy as possible for the user to correct their configuration mistake by clearly identifying the filter chains that are involved.

Current Behavior

An app fails to start with an exception like this:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain': Cannot create inner bean '(inner bean)#7ddd84b5' while setting constructor argument with key [1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBeanValue(BeanDefinitionValueResolver.java:421) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.lambda$resolveValueIfNecessary$1(BeanDefinitionValueResolver.java:153) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:262) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:152) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:460) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:191) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:691) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:206) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1371) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1208) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:288) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1122) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1093) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1030) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987) ~[spring-context-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) ~[spring-context-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.4.0-SNAPSHOT.jar:3.4.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755) ~[spring-boot-3.4.0-SNAPSHOT.jar:3.4.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:442) ~[spring-boot-3.4.0-SNAPSHOT.jar:3.4.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-3.4.0-SNAPSHOT.jar:3.4.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1364) ~[spring-boot-3.4.0-SNAPSHOT.jar:3.4.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1353) ~[spring-boot-3.4.0-SNAPSHOT.jar:3.4.0-SNAPSHOT]
        at com.example.security.oauth2authorizationserver.OAuth2AuthorizationServerApplication.main(OAuth2AuthorizationServerApplication.java:31) ~[main/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#7ddd84b5' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Failed to instantiate [jakarta.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception with message: A filter chain that matches any request has already been configured, which means that this filter chain [DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@25f15f50, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52b46d52, org.springframework.security.web.context.SecurityContextHolderFilter@2b4b96a4, org.springframework.security.web.header.HeaderWriterFilter@3252747e, org.springframework.security.web.csrf.CsrfFilter@631cb129, org.springframework.security.web.authentication.logout.LogoutFilter@2bfaba70, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@b67cc70, DefaultResourcesFilter [matcher=Ant [pattern='/default-ui.css', GET], resource=org/springframework/security/default-ui.css], org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@36b9cb99, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7327a447, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2dd8ff1d, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@17e9bc9e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@67022ea, org.springframework.security.web.access.ExceptionTranslationFilter@3d20e575, org.springframework.security.web.access.intercept.AuthorizationFilter@68d6d775]]] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last.
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:489) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1351) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBeanValue(BeanDefinitionValueResolver.java:407) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        ... 29 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [jakarta.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception with message: A filter chain that matches any request has already been configured, which means that this filter chain [DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@25f15f50, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52b46d52, org.springframework.security.web.context.SecurityContextHolderFilter@2b4b96a4, org.springframework.security.web.header.HeaderWriterFilter@3252747e, org.springframework.security.web.csrf.CsrfFilter@631cb129, org.springframework.security.web.authentication.logout.LogoutFilter@2bfaba70, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@b67cc70, DefaultResourcesFilter [matcher=Ant [pattern='/default-ui.css', GET], resource=org/springframework/security/default-ui.css], org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@36b9cb99, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7327a447, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2dd8ff1d, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@17e9bc9e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@67022ea, org.springframework.security.web.access.ExceptionTranslationFilter@3d20e575, org.springframework.security.web.access.intercept.AuthorizationFilter@68d6d775]]] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last.
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:199) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) ~[spring-core-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) ~[spring-core-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:88) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:168) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        ... 35 common frames omitted
Caused by: java.lang.IllegalArgumentException: A filter chain that matches any request has already been configured, which means that this filter chain [DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@25f15f50, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52b46d52, org.springframework.security.web.context.SecurityContextHolderFilter@2b4b96a4, org.springframework.security.web.header.HeaderWriterFilter@3252747e, org.springframework.security.web.csrf.CsrfFilter@631cb129, org.springframework.security.web.authentication.logout.LogoutFilter@2bfaba70, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@b67cc70, DefaultResourcesFilter [matcher=Ant [pattern='/default-ui.css', GET], resource=org/springframework/security/default-ui.css], org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@36b9cb99, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7327a447, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2dd8ff1d, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@17e9bc9e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@67022ea, org.springframework.security.web.access.ExceptionTranslationFilter@3d20e575, org.springframework.security.web.access.intercept.AuthorizationFilter@68d6d775]]] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last.
        at org.springframework.util.Assert.isTrue(Assert.java:115) ~[spring-core-6.2.0-RC1.jar:6.2.0-RC1]
        at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:308) ~[spring-security-config-6.4.0-SNAPSHOT.jar:6.4.0-SNAPSHOT]
        at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:94) ~[spring-security-config-6.4.0-SNAPSHOT.jar:6.4.0-SNAPSHOT]
        at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:333) ~[spring-security-config-6.4.0-SNAPSHOT.jar:6.4.0-SNAPSHOT]
        at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:38) ~[spring-security-config-6.4.0-SNAPSHOT.jar:6.4.0-SNAPSHOT]
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:121) ~[spring-security-config-6.4.0-SNAPSHOT.jar:6.4.0-SNAPSHOT]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.0-RC1.jar:6.2.0-RC1]
        ... 40 common frames omitted

For me, describing a filter chain purely in terms of the filters that it contains isn't as helpful as it could be. Thanks to the DSL, the specific filters and their class names are an implementation detail. I find it difficult to map the list of 10+ filters back to a particular piece of configuration where the problematic filter chain was defined and I'd like Spring Security to do that for me. Perhaps it could provide some origin information (the name of the bean?) where each filter chain that's involved in the problem was defined?

Context

I found this while trying to adapt to the deprecation of OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http) in the AOT smoke test for authorization server:

diff --git a/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java b/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java
index d9eb0720..bf5967ae 100644
--- a/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java
+++ b/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java
@@ -48,6 +48,7 @@ import org.springframework.security.oauth2.server.authorization.client.InMemoryR
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
+import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
 import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
 import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@@ -67,8 +68,9 @@ public class OAuth2AuthorizationServerSecurityConfiguration {
        @Bean
        @Order(1)
        public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
-               OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
-               return http.formLogin(withDefaults()).build();
+               return http.with(OAuth2AuthorizationServerConfigurer.authorizationServer(), Customizer.withDefaults())
+                       .formLogin(withDefaults())
+                       .build();
        }
 
        @Bean

The above was my first attempt at following the advice in the deprecation notice. After looking at the code that was deprecated and what it does, it would appear that the following is what was needed in this case:

diff --git a/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java b/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java
index d9eb0720..eb743932 100644
--- a/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java
+++ b/security/security-oauth2-authorization-server/src/main/java/com/example/security/oauth2authorizationserver/OAuth2AuthorizationServerSecurityConfiguration.java
@@ -48,6 +48,7 @@ import org.springframework.security.oauth2.server.authorization.client.InMemoryR
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
+import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
 import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
 import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@@ -67,8 +68,12 @@ public class OAuth2AuthorizationServerSecurityConfiguration {
        @Bean
        @Order(1)
        public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
-               OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
-               return http.formLogin(withDefaults()).build();
+               OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer
+                       .authorizationServer();
+               return http.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
+                       .with(authorizationServerConfigurer, Customizer.withDefaults())
+                       .formLogin(withDefaults())
+                       .build();
        }
 
        @Bean
@wilkinsona wilkinsona added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Oct 4, 2024
@sjohnr sjohnr added in: config An issue in spring-security-config and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 4, 2024
@sjohnr
Copy link
Member

sjohnr commented Oct 4, 2024

Thanks for reporting this Andy. I'll bring this to the team's attention.

@sjohnr sjohnr added the for: team-attention This ticket should be discussed as a team before proceeding label Oct 4, 2024
@sjohnr sjohnr self-assigned this Oct 4, 2024
@jgrandja
Copy link
Contributor

jgrandja commented Oct 8, 2024

Thanks for the feedback @wilkinsona. Other than specifying the origin (e.g. Bean name) is there anything else you can think of that could help improve/expedite the troubleshooting of multiple "any request" filter chain issue?

@wilkinsona
Copy link
Member Author

If you created a specific exception type for it, Boot could provide a FailureAnalyzer for that exception. That would allow Boot to suppress (by default) the logging of the exception and its verbose stack trace in favor of a more friendly description of the problem and some suggestions on how to fix it.

The only other thing that I can think of is to perhaps reconsider including all of the fully-qualified filter class names in the exception message. They're quite far removed from the DSL that was likely used to configure them which makes me wonder how helpful they are. Perhaps a short description of each could be provided instead? For example, org.springframework.security.web.csrf.CsrfFilter@631cb129 could be just CSRF without really losing any information.

@jgrandja
Copy link
Contributor

jgrandja commented Oct 8, 2024

Thanks @wilkinsona. Great information. We'll look at these different options and provide an improvement.

@sjohnr sjohnr removed their assignment Oct 8, 2024
jzheaux added a commit to jzheaux/spring-security that referenced this issue Oct 25, 2024
jzheaux added a commit to jzheaux/spring-security that referenced this issue Oct 25, 2024
@jzheaux jzheaux self-assigned this Oct 25, 2024
@jzheaux jzheaux removed the for: team-attention This ticket should be discussed as a team before proceeding label Oct 25, 2024
jzheaux added a commit to jzheaux/spring-security that referenced this issue Nov 1, 2024
@jzheaux jzheaux closed this as completed in f46e56d Nov 7, 2024
@jzheaux jzheaux added this to the 6.4.0 milestone Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: config An issue in spring-security-config type: enhancement A general enhancement
Projects
Status: No status
Development

Successfully merging a pull request may close this issue.

4 participants