javaspring-bootspring-security

I have a question about "AuthenticationFilter.class" in Spring Security


http
        .csrf(AbstractHttpConfigurer::disable)
        .cors(AbstractHttpConfigurer::disable)
        .addFilterAfter(CoustomAuthCheckFilter, UsernamePasswordAuthenticationFilter.class)
...

I used AuthenticationFilter.class in the addFilterAfter method and encountered an error. After changing it to UsernamePasswordAuthenticationFilter.class, it worked. Why does the compiler not throw an error when using AuthenticationFilter.class even though it's not a concrete filter that is typically used directly?"

try

http
        .csrf(AbstractHttpConfigurer::disable)
        .cors(AbstractHttpConfigurer::disable)
        .addFilterAfter(CoustomAuthCheckFilter, AuthenticationFilter.class)

I expecting server start. but

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Unsatisfied dependency expressed through method 'setFilterChains' parameter 0: Error creating bean with name 'filterChain' defined in class path resource [com/wincubemkt/mediagw/global/config/SecurityConfig.class]: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'filterChain' threw exception with message: The Filter class org.springframework.security.web.authentication.AuthenticationFilter does not have a registered order
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:895) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:848) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:508) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1439) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.2.jar:3.3.2]
    at com.wincubemkt.mediagw.MEDIAGWApplication.main(MEDIAGWApplication.java:11) ~[main/:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.3.2.jar:3.3.2]

I encountered the following error when using AuthenticationFilter.class


Solution

  • The error message says:

    org.springframework.security.web.authentication.AuthenticationFilter does not have a registered order
    

    which kind of tells you what the issue is. In Spring for you to use the methods:

    the second parameter has to have an Order set by Spring inside of FilterOrderRegistration. Here is a snippet out of FilterOrderRegistration:

    //...
    put(X509AuthenticationFilter.class, order.next());
    put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
    this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
    this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter", order.next());
    this.filterToOrder.put("org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter", order.next());
    put(UsernamePasswordAuthenticationFilter.class, order.next());
    order.next(); // gh-8105
    //...
    

    as you can see among other classes it sets an order for UsernamePasswordAuthenticationFilter. If you look at the complete code however, it doesn't register order for AuthenticationFilter (for whatever reason).


    When you call either addFilterBefore or addFilterAfter they both internally refer to the addFilterAtOffsetOf method which then throws the exception you are facing:

    @Override
    public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
        return addFilterAtOffsetOf(filter, 1, afterFilter);
    }
    
    @Override
    public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) {
        return addFilterAtOffsetOf(filter, -1, beforeFilter);
    }
    
    private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
        Integer registeredFilterOrder = this.filterOrders.getOrder(registeredFilter);
        if (registeredFilterOrder == null) {
            throw new IllegalArgumentException(
                    "The Filter class " + registeredFilter.getName() + " does not have a registered order");
        }
        int order = registeredFilterOrder + offset;
        this.filters.add(new OrderedFilter(filter, order));
        this.filterOrders.put(filter.getClass(), order);
        return this;
    }
    

    Which is why as of this writing (Spring Security 6.3.1) you are limited to the following Filters that you can reference in addFilterAfter since these are the only ones that are registered in FilterOrderRegistration:

     - DisableEncodeUrlFilter.class
     - ForceEagerSessionCreationFilter.class
     - ChannelProcessingFilter.class
     - WebAsyncManagerIntegrationFilter.class
     - SecurityContextHolderFilter.class
     - SecurityContextPersistenceFilter.class
     - HeaderWriterFilter.class
     - CorsFilter.class
     - CsrfFilter.class
     - LogoutFilter.class
     - X509AuthenticationFilter.class
     - AbstractPreAuthenticatedProcessingFilter.class
     - UsernamePasswordAuthenticationFilter.class
     - DefaultLoginPageGeneratingFilter.class
     - DefaultLogoutPageGeneratingFilter.class
     - ConcurrentSessionFilter.class
     - DigestAuthenticationFilter.class
     - BasicAuthenticationFilter.class
     - RequestCacheAwareFilter.class
     - SecurityContextHolderAwareRequestFilter.class
     - JaasApiIntegrationFilter.class
     - RememberMeAuthenticationFilter.class
     - AnonymousAuthenticationFilter.class
     - SessionManagementFilter.class
     - ExceptionTranslationFilter.class
     - FilterSecurityInterceptor.class
     - AuthorizationFilter.class
     - SwitchUserFilter.class