Skip to content

When enabling global method security, AuthenticationManager gets built twice, but only in test environment #3825

Closed
@whittle

Description

@whittle

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions