Summary

I am currently on spring security 5.7.5 and working on upgrading to 6. When running with 6.0.0-M6 my app boots up. But once I change to 6.0.0-RC1 I start seeing an error while it is configuring and starting up. Also, I use an XML config.

Actual Behavior

I receive the following stacktrace:

Caused by: java.lang.IllegalArgumentException: Found 47 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary
2022-12-14T19:34:46.812217246Z  at org.springframework.util.Assert.isTrue(Assert.java:139)
2022-12-14T19:34:46.812219595Z  at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getBeanName(AuthenticationConfiguration.java:174)
2022-12-14T19:34:46.812221941Z  at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.lazyBean(AuthenticationConfiguration.java:160)
2022-12-14T19:34:46.812224389Z  at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManagerBean(AuthenticationConfiguration.java:196)
2022-12-14T19:34:46.812229284Z  at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManager(AuthenticationConfiguration.java:123)
2022-12-14T19:34:46.812232179Z  at org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.authenticationManager(HttpSecurityConfiguration.java:132)
2022-12-14T19:34:46.812235454Z  at org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity(HttpSecurityConfiguration.java:108)
2022-12-14T19:34:46.812238663Z  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2022-12-14T19:34:46.812241062Z  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2022-12-14T19:34:46.812243689Z  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2022-12-14T19:34:46.812246290Z  at java.base/java.lang.reflect.Method.invoke(Unknown Source)
2022-12-14T19:34:46.812248692Z  at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:138)
2022-12-14T19:34:46.812251096Z  ... 69 common frames omitted

If I slowly remove some of my XML config, I get less and less beans in that error message. For instance if my XML is just

<security:http pattern="/customers/**" auto-config="true" use-expressions="true" servlet-api-provision="true">
    <security:intercept-url pattern="/customers/login" access="permitAll" />
    <security:intercept-url pattern="/customers/**" access="hasRole('ROLE_FULLY_AUTH')" />
</security:http>

Then I get this error:

Caused by: java.lang.IllegalArgumentException: Found 3 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary

If I remove that security:http block all together, it starts, but I obviously don't have any of paths secured.

Expected Behavior

The app starts successfully.

Configuration

XML Spring security.

Auth manager defined in the XML

<security:authentication-manager>
    <security:authentication-provider ref="customAuthenticationProvider" />
</security:authentication-manager>

Version

6.0.0-RC1 or newer

Comment From: vandykej17

By adding an alias on my auth manager

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider ref="customAuthenticationProvider" />
</security:authentication-manager>

And referencing that in my security settings, I have reduced the error to 2 beans. authentication-manager-ref="authenticationManager"

Caused by: java.lang.IllegalArgumentException: Found 2 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary

Comment From: marcusdacoregio

Hi @vandykej17, thanks for the report.

Can you share what your configuration that is using the custom AuthenticationManager looks like? Or, if possible, provide a minimal, reproducible sample that we can just clone and run.

Comment From: vandykej17

Unfortunately, it will be difficult for me to separate this large app into a minimal reproducible sample.

After researching more, it looks like each security:http entry generates 2 auth managers. If I set authentication-manager-ref="authenticationManager" it generates only 1 here - https://github.com/spring-projects/spring-security/blob/main/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java#L152

Spring Security Auth Manager troubles upgrading from 6.0.0-M6 to 6.0.0-RC1

After realizing this I implemented the following and am up and running again.

@Configuration
public class CustomBeanProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Arrays.stream(beanFactory.getBeanNamesForType(AuthenticationManager.class)).filter(beanName -> beanName.equals("org.springframework.security.authenticationManager"))
                .findFirst().ifPresent(beanName -> beanFactory.getBeanDefinition(beanName).setPrimary(true));
    }
}

Although I don't love this solution, it is working.

Comment From: marcusdacoregio

I tried a few ways and unfortunately, I was not able to reproduce this problem. It would be great if you could share your XML configuration

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

Comment From: antenia-lhubert

Hi, I encountered the same issue on a project, any eta on this for xml configurations?

Comment From: BeardOverflow

Hi @antenia-lhubert If you want to revert the legacy behaviour with no primary AuthenticationManager bean constraint for HttpSecurity context, try the following snippet:

@Configuration
public class NullAuthenticationManagerConfiguration {
    @Bean
    public AuthenticationManager nullAuthenticationManager() {
        return new ProviderManager(new NullAuthenticationProvider());
    }

    @Lazy
    @Autowired
    public void configure(
        final AuthenticationManagerBuilder builder,
        final AuthenticationManager nullAuthenticationManager
    ) {
        builder.parentAuthenticationManager(nullAuthenticationManager);
    }
}

In few words, with the above snippet, HttpSecurity context refers to a dummy AuthenticationManager which always goes to error 401 instead of a primary AuthenticationManager. Now remember to configure your SecurityFilterChain(s) with an AuthenticationManager fits your needs.

@Configuration
public class SecurityConfiguration {
    @Bean
    public SecurityFilterChain mySecurityFilterChain(final HttpSecurity http) throws Exception {
       return http.authenticationManager(myAuthenticationManagerWhichIsNotMarkedAsPrimaryBecauseOfComplexReasons).build();
    }
}

My answer is based on: https://github.com/spring-projects/spring-security/blob/bc8ba7f3b7fa03346337fe99177da60aaaa96c34/docs/modules/ROOT/pages/servlet/authentication/passwords/index.adoc#customize-the-authenticationmanager

For digging deeper, see HttpSecurityConfiguration.java and AuthenticationConfiguration.java files: - https://github.com/spring-projects/spring-security/blob/bc8ba7f3b7fa03346337fe99177da60aaaa96c34/config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java#L140-L142 - https://github.com/spring-projects/spring-security/blob/bc8ba7f3b7fa03346337fe99177da60aaaa96c34/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java#L114

Comment From: vandykej17

For what it's worth, when we upgraded, we converted our XML security config to Java config and did not see the bug again. Not sure if that was a purposeful decision to not support the XML config or not, but that was the easier route for us. Plus, it made it more readable and modern.

Comment From: antenia-lhubert

Thanks a lot for your answers, but I am working on a legacy project and converting the xml based configuration to Java would be quite complex.

By messing around I have found a solution: Instead of declaring the authentication manager with spring security tags, I do it with beans and set primary to true

<!-- before -->
<security:authentication-manager id="myAuthenticationManager">
    <security:authentication-provider ref="customAuthenticationProvider" />
</security:authentication-manager>

<!-- after -->
<bean id="myAuthenticationManager" class="org.springframework.security.authentication.ProviderManager" primary="true">
    <constructor-arg>
        <list>
            <ref bean="customAuthenticationProvider"/>
        </list>
    </constructor-arg>
</bean>