Summary

When I enable global method security on an app that already subclasses WebSecurityConfigurerAdapter, the application context fails to load in my test environment, with the message that the AuthenticationManager was already built.

Actual Behavior

I have a vacuous test class that is just intended to check if the application context is loading properly:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=ShibaApplication.class)
@WebAppConfiguration
public class ShibaApplicationTests {
    @Test
    public void contextLoads() {}
}

(I have other test classes of course, and they fail with the same error.)

When I add the annotation @EnableGlobalMethodSecurity(prePostEnabled=true) to an existing (working) subclass of WebSecurityConfigurerAdapter and add a @PreAuthorize annotation to any of my controller classes, my test classes fail (including the vacuous one above). The stack trace is enormous, but the outermost thread gives the following cause (linebreaks added):

Caused by:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'channelMarksController' defined in file [/Users/jason/Code/shiba/build/classes/main/co/masslab/shiba/transfer/ChannelMarksController.class]:
Initialization of bean failed;

nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]:
Bean instantiation via factory method failed;

nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.aopalliance.intercept.MethodInterceptor]:
Factory method 'methodSecurityInterceptor' threw exception;

nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'webSecurityConfig':
Injection of autowired dependencies failed;

nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field:
private com.auth0.spring.security.auth0.Auth0AuthenticationFilter co.masslab.shiba.WebSecurityConfig.auth0Filter;

nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'auth0Filter':
Injection of autowired dependencies failed;

nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field:
private org.springframework.security.authentication.AuthenticationManager com.auth0.spring.security.auth0.Auth0AuthenticationFilter.authenticationManager;

nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'authenticationManager' defined in class path resource [org/springframework/boot/autoconfigure/security/AuthenticationManagerConfiguration.class]:
Bean instantiation via factory method failed;

nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]:
Factory method 'authenticationManager' threw exception;

nested exception is org.springframework.security.config.annotation.AlreadyBuiltException:
This object has already been built

Interestingly, outside of the test environment, the app runs without error and the @PreAuthorize annotation even works as expected.

Expected Behavior

I expect the application context to load successfully within the test environment.

Configuration

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private Auth0AuthenticationEntryPoint auth0EntryPoint;

    @Autowired
    private Auth0AuthenticationFilter auth0Filter;

    @Autowired
    private Auth0AuthenticationProvider auth0AuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests().anyRequest().hasRole("USER")
            .and()
            .exceptionHandling().authenticationEntryPoint(auth0EntryPoint)
            .and()
            .addFilterAfter(auth0Filter, SecurityContextPersistenceFilter.class)
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .csrf().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(auth0AuthenticationProvider);
    }
}

Version

The app uses Spring Boot v1.3.3 BOMs. The observed issue is also present using Spring Boot v1.3.2 BOMs.

Sample

The project in question is private, but I have privileges sufficient to add individuals as contributors. Please contact me directly @whittle for access.

Comment From: bitsofalex

I am getting exactly the same issue. +1

Comment From: jgrandja

Hi @whittle I haven't been able to reproduce the issue. Would you be able to provide me a sample with this issue?

Comment From: davidkey

I had the same issue.

I was wiring a custom AuthenticationSuccessHandler into my security configuration that indirectly referenced a @Service bean with an @Autowired reference to AuthenticationManager. After some thought, I'm surprised it worked - but no problems at all at runtime! Perhaps some sort of wiring order / race condition helped me out? However, while running the same vacuous test mentioned by @whittle, I encountered the dreaded AlreadyBuiltException.

Note that in a very stripped down version of my application I was debugging this issue with, I did receive a BeanCurrentlyInCreationException on AuthenticationManager but only during testing - not at runtime. Not exactly the same issue, but could be related behavior. See here: https://github.com/davidkey/SecurityTestErrorPOC.

My fix was to add @Lazy to my AuthenticationSuccessHandler in my security configuration while I rethink my architecture a bit.

HTH.

Comment From: rwinch

@davidkey Thanks for the reply! I created #3916 to address your issue since it is slightly different.

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.