grails-core icon indicating copy to clipboard operation
grails-core copied to clipboard

Found 3 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary

Open ChiranjibKarn opened this issue 2 years ago • 13 comments

Issue description

After upgrading my running application from Grails 4.0.6 to Grails 5.1.2, it refuse to start up. Stacktrace:

07.02.2022 16:08:47.278 [restartedMain] ERROR o.s.boot.SpringApplication - Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'managementSecurityFilterChain' defined in class path resource [org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.class]: Unsatisfied dependency expressed through method 'managementSecurityFilterChain' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity' defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.config.annotation.web.builders.HttpSecurity]: Factory method 'httpSecurity' threw exception; nested exception is java.lang.IllegalArgumentException: Found 3 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) at grails.boot.GrailsApp.run(GrailsApp.groovy:99) at grails.boot.GrailsApp.run(GrailsApp.groovy:485) at grails.boot.GrailsApp.run(GrailsApp.groovy:472) at grails.boot.GrailsApp$run.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:148) at io.backend.Application.main(Application.groovy:14) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

Following are my dependencies:

developmentOnly("org.springframework.boot:spring-boot-devtools")
    implementation "org.grails:grails-dependencies:$grailsVersion", {
        exclude module:'grails-datastore-simple'
    }
    implementation 'org.springframework.boot:spring-boot-starter-logging'
    implementation "org.springframework.boot:spring-boot-starter-validation" 
    implementation 'org.springframework.boot:spring-boot-autoconfigure'
    implementation 'org.grails:grails-core'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    providedCompile 'org.springframework.boot:spring-boot-starter-tomcat'
    implementation 'org.grails:grails-plugin-url-mappings'
    implementation 'org.grails:grails-plugin-rest'
    implementation 'org.grails:grails-plugin-codecs'
    implementation 'org.grails:grails-plugin-interceptors'
    implementation 'org.grails:grails-plugin-services'
    implementation 'org.grails:grails-plugin-datasource'
    implementation 'org.grails:grails-plugin-databinding'
    implementation 'org.grails:grails-web-boot'
    implementation 'org.grails:grails-logging'
    implementation 'org.grails.plugins:cache'
    implementation 'org.grails.plugins:async'
    implementation 'org.grails.plugins:mongodb'
    implementation 'org.grails.plugins:events'
    implementation 'org.grails.plugins:gsp'
    implementation 'org.grails.plugins:views-json'
    implementation 'org.grails.plugins:views-json-templates'
    compileOnly "io.micronaut:micronaut-inject-groovy"
    console "org.grails:grails-console"
    profile 'org.grails.profiles:web'
    providedCompile 'org.grails.plugins:embedded-mongodb:2.0.0.M1'
    implementation 'org.grails:grails-plugin-i18n'
    implementation 'org.grails:grails-dependencies'
    implementation 'org.grails.plugins:scaffolding'
    implementation 'org.grails.plugins:spring-security-rest:3.0.1' 
    implementation 'org.grails.plugins:spring-security-rest-gorm:3.0.1' 
    //Mail
    implementation 'org.grails.plugins:mail:3.0.0' 
    //Http clients
    String httpclientVersion = '4.5.13' //4.5.12
    implementation "org.apache.httpcomponents:httpclient:$httpclientVersion"
    implementation "org.apache.httpcomponents:fluent-hc:$httpclientVersion"
    implementation "org.apache.httpcomponents:httpclient-cache:$httpclientVersion"
    implementation "org.apache.httpcomponents:httpmime:$httpclientVersion"
    //GSP renderer
    implementation 'org.grails.plugins:rendering:2.0.3'
    implementation 'org.xhtmlrenderer:core-renderer:R8'
    //Websocket and it's security 
    implementation 'org.grails.plugins:grails-spring-websocket:2.5.0.RC1'
    implementation "org.springframework.security:spring-security-config"
    implementation "org.springframework.security:spring-security-messaging"
    implementation "org.springframework.security:spring-security-web"
    runtimeOnly 'org.springframework:spring-test:4.2.1.RELEASE'
    //AWS: S3, SQS
    implementation 'org.grails.plugins:aws-sdk-s3:2.4.8' 
    implementation 'org.grails.plugins:aws-sdk-sqs:2.4.8'    
    //Oauth2 provider
    implementation 'org.grails.plugins:spring-security-oauth2-provider:4.0.0-RC1'	    
    implementation 'javax.xml.bind:jaxb-api:2.3.1'
    implementation 'javax.activation:activation:1.1.1'
    implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.1'

ChiranjibKarn avatar Feb 07 '22 13:02 ChiranjibKarn

I put your dependencies in a project at https://github.com/jeffbrown/chiranjibkarn-issue12376. Can you send a PR to that repo that demonstrates the problem?

Thank you for any feedback!

osscontributor avatar Feb 07 '22 22:02 osscontributor

Hi Jeff,

PR for issue 12376 has been sent to you https://github.com/jeffbrown/chiranjibkarn-issue12376/pull/1

Thanks, Chiranjib

On Tue, Feb 8, 2022 at 3:48 AM Jeff Scott Brown @.***> wrote:

I put your dependencies in a project at https://github.com/jeffbrown/chiranjibkarn-issue12376. Can you send a PR to that repo that demonstrates the problem?

Thank you for any feedback!

— Reply to this email directly, view it on GitHub https://github.com/grails/grails-core/issues/12376#issuecomment-1031979518, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE6QAQ4XCHC5XRASBA6DKEDU2A6THANCNFSM5NXQFB3Q . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you authored the thread.Message ID: @.***>

ChiranjibKarn avatar Feb 08 '22 09:02 ChiranjibKarn

Thank you. I have deleted my repo. The repo at github.com/ChiranjibKarn/chiranjibkarn-issue12376 now contains code to reproduce the issue.

osscontributor avatar Feb 08 '22 13:02 osscontributor

@jeffbrown any update on this?

ChiranjibKarn avatar Feb 09 '22 09:02 ChiranjibKarn

@jeffbrown none has been assigned this issue. Does someone looking into it?

ChiranjibKarn avatar Feb 21 '22 10:02 ChiranjibKarn

It seems none from Grails team are active nowadays, is Grails project really dying ?

ChiranjibKarn avatar Feb 24 '22 04:02 ChiranjibKarn

Found 3 beans for type interface org.springframework.security.authentication.AuthenticationManager

I think your errors is related three plugins: spring-security-core:4.0.0.RC3, spring-security-rest:3.0.1, spring-security-oauth2-provider:4.0.0-RC1, spring-security-core has one AuthenticationManager and spring-security-oauth2-provider plugin has two: clientAuthenticationManager and oauth2AuthenticationManager, spring-security-rest only need one AuthenticationManager in spring-security-core plugin. so you can set it as primary bean in spring-security-core plugin. But I think this error may be not fixed yet in v5.0.0-RC1.

If you comment off implementation 'org.grails.plugins:spring-security-oauth2-provider:4.0.0-RC1', run app will have another error.

Bean named 'corsFilter' is expected to be of type 'org.springframework.web.filter.CorsFilter' but was actually of type 'CorsFilter'

This error was related CorsFilter defined in conf/spring/resources.groovy. Grails has already support CORS, please check it first.

I hope this should help you.

rainboyan avatar Feb 24 '22 05:02 rainboyan

@rainboyan sorry for the late response. Yes, I understand there are multiple auth managers in my app. The problem is how can I annotate one of them as Primary as they are in plugins? Do I have to override one of the AuthManager in my app?

And, as far as CORS is concerned, I am OK with my own implementation. This app is old one (built on Grails 3.0) and we gradually upgraded it to all major/minor releases so far. I do not want to put my energy to migrate it to Grails CORS as of now.

ChiranjibKarn avatar Feb 28 '22 11:02 ChiranjibKarn

I post a workaround method here, may be it's not the best, but it works. you could create a new issue in plugin https://github.com/grails/grails-spring-security-core, or submit a PR to fixed this issue in the plugin.

First create a class AuthenticationManagerBeanPostProcessor to update the bean authenticationManager,

package io.sparkwork.security

import org.springframework.beans.BeansException
import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.factory.BeanFactoryAware
import org.grails.spring.beans.BeanPostProcessorAdapter

class AuthenticationManagerBeanPostProcessor extends BeanPostProcessorAdapter implements BeanFactoryAware {
    private BeanFactory beanFactory
    
    @Override
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName == 'authenticationManager') {
            def bd = this.beanFactory.getBeanDefinition(beanName)
            bd.primary = true
        }
        bean
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}

then define it in grails-app/conf/spring/resources.groovy

beans = { authenticationManagerBeanPostProcessor(AuthenticationManagerBeanPostProcessor) ... }

rainboyan avatar Feb 28 '22 13:02 rainboyan

In plugin spring-security-core:4.0.0.RC3, open SpringSecurityCoreGrailsPlugin.groovy, search configureAuthenticationManager , you will find authenticationManager, then add one line code bean.primary = true. sorry, I don't test this in a real project, you can try it and do a test.


	private configureAuthenticationManager = { conf ->

		// create the default list here, will be replaced in doWithApplicationContext
		def providerRefs = createRefList(SpringSecurityUtils.providerNames)

		/** authenticationManager */
		authenticationManager(classFor('authenticationManager', ProviderManager), providerRefs) { bean ->
			**bean.primary = true**
			authenticationEventPublisher = ref('authenticationEventPublisher')
			eraseCredentialsAfterAuthentication = conf.providerManager.eraseCredentialsAfterAuthentication // true
		}
	}

rainboyan avatar Feb 28 '22 14:02 rainboyan

Thank you @rainboyan for sharing the workaround. It worked, at-least the original error has disappeared, but as you mentioned I am getting following error: Bean named 'corsFilter' is expected to be of type 'org.springframework.web.filter.CorsFilter' but was actually of type 'CorsFilter'

In my custom CorsFilter I am doing check for whole loads of things, so I do not want to migrate it to Grails CORS filter which config is in Yml. Is there any other way (like extending springs CorsFilter) for this where I can retain my existing logic?

ChiranjibKarn avatar Mar 02 '22 06:03 ChiranjibKarn

@ChiranjibKarn use another bean name in conf/spring/resources.groovy

beans = {
    
    ...

    customCorsFilter(CorsFilter)
    
    ...
}

more detail please check the plugin's documentation:

https://grails.github.io/grails-spring-security-core/4.0.x/index.html

rainboyan avatar Mar 05 '22 05:03 rainboyan

Thanks @rainboyan , I also had the same problem and this solved it!

lucas-napse avatar Apr 20 '23 15:04 lucas-napse