0

I followed these 2 articles to implement multiple authentication profiles in a Spring Boot application:

and the final SecurityConfiguration class looks as follows:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Configuration
    @Profile({"qa", "prod"})
    public static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .cors()
                    .and()
                    .csrf()
                    .disable()
                    .authorizeRequests()
                    .antMatchers("/someUrl").permitAll()
                    .antMatchers("/someUrl").fullyAuthenticated()
                    .antMatchers("/api/ping").permitAll()
                    .antMatchers("/**").fullyAuthenticated()
                    
                    ...
                    .

        }
    }

    @Configuration
    public static class LocalSecurityConfiguration extends WebSecurityConfigurerAdapter {
...

        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .cors()
                    .and()
                    .csrf()
                    .disable()
                    .authorizeRequests()
                    .antMatchers("/someUrl").permitAll()
                    .antMatchers("/someUrl").fullyAuthenticated()
                    .antMatchers("/api/ping").permitAll()
                    .antMatchers("/**").permitAll().
                    ...
                    .

        }
    }
}

I also have separate application-{profile}.yaml files for both qa and prod profiles (environments).

When starting the app with

mvn spring-boot:run -Dspring.profiles.active=qa

I see that the right profile was applied (qa):

Running with Spring Boot v2.1.3.RELEASE, Spring v5.1.5.RELEASE
...
 The following profiles are active: a
...

but it fails later with:

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'authenticationManagerBean', defined in class path resource [com/.../SecurityConfiguration$WebSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/../SecurityConfiguration$LocalSecurityConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

[WARNING] 
java.lang.reflect.InvocationTargetException
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:558)
    at java.lang.Thread.run (Thread.java:834)
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'authenticationManagerBean' defined in class path resource [com/../SecurityConfiguration$WebSecurityConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=securityConfiguration.WebSecurityConfiguration; factoryMethodName=authenticationManagerBean; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/.../SecurityConfiguration$WebSecurityConfiguration.class]] for bean 'authenticationManagerBean': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=securityConfiguration.LocalSecurityConfiguration; factoryMethodName=authenticationManagerBean; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/..../SecurityConfiguration$LocalSecurityConfiguration.class]] bound.

When running without specifying any profiles it starts without errors. What's wrong with that?

Thank you.

belgoros
  • 3,590
  • 7
  • 38
  • 76
  • 1
    you have not customized the authenticationManager, so i dont see any reason to why you need to create a bean out of it?, i would suggest you try out removing the `@Bean` definitions above the authenticationManager functions. – Toerktumlare Apr 14 '21 at 07:15
  • You are exposing two beans of `AuthenticationManager` at the same time. This should be a problem. `LocalSecurityConfiguration ` is always executed and additionally `WebSecurityConfiguration` for the profiles. – dur Apr 14 '21 at 12:20

2 Answers2

1

To my understanding, when you enable the qa profile, both beans of type WebSecurityConfiguration are active, therefore Spring can not handle both of them being enabled at the same time and this is why you have the error. When you run that with no profiles, then the WebSecurityConfiguration is not enabled therefore only one bean of type WebSecurityConfigurerAdapter is active. One solution would be to annotate the LocalSecurityConfiguration bean with the negative condition, for example

@Profile("!qa & !prod")

That would work with Spring versions > 5.1 (Spring Boot 2.1), in previous version you can use the @Conditional annotation (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Conditional.html) and create a custom implementation to express your logic exterding the SpringBootCondition class

dimcookies
  • 1,930
  • 7
  • 31
  • 37
  • 1
    Should the right syntax rather be as `@Profile({"!qa & !prod"})` using the braces? – belgoros Apr 15 '21 at 07:09
  • 1
    You are correct, the data type of value in Profiles interface is String [] so using the braces will work. But it is not mandatory if you want to specify one value. Java language specification: `If the element type is an array type, then it is not required to use curly braces to specify the element value of the element-value pair. If the element value is not an ElementValueArrayInitializer, then an array value whose sole element is the element value is associated with the element` This means that if you specify a string instead of an array, an array will be created with just one element – dimcookies Apr 15 '21 at 07:55
-1

Have you tried the action suggested in logs ?

Consider renaming one of the beans or enabling overriding by setting

spring.main.allow-bean-definition-overriding=true

You can find related answer here. it might help. SpringBoot - BeanDefinitionOverrideException: Invalid bean definition

Here is an another suggested post from baeldung https://www.baeldung.com/spring-boot-bean-definition-override-exception

satyen
  • 109
  • 5