Spring Security java.lang.StackOverflowError exception after all providers
Asked Answered
S

2

12

Environment:

  • Spring 4.1.6
  • Spring Security 4.0.1

I have 2 authentication providers - one that hits ActiveDirectory, and then one that hits a custom database provider I've created. Logging in as a user that is in either of those environments works perfectly. The user is authenticated and the app continues.

However, when an invalid user is entered and neither provider is able to authenticate, I get this exception on the page:

java.lang.StackOverflowError
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:393)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:394)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:394)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:394)

Here is my WebSecurityConfigurerAdapter configuration:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            .formLogin().loginPage("/login").failureUrl("/login?error").defaultSuccessUrl("/overview").permitAll()
            .and()
                .logout().logoutSuccessUrl("/login?logout").permitAll()
            .and()
                .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers("/favicon.ico").permitAll()
                .antMatchers("/**").hasRole("AUTH");
}

@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
    authManagerBuilder
            .authenticationProvider(activeDirectoryLdapAuthenticationProvider())
            .userDetailsService(userDetailsService());

    authManagerBuilder
            .authenticationProvider(databaseAuthenticationProvider())
            .userDetailsService(userDetailsService());
}

@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
    ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
    provider.setConvertSubErrorCodesToExceptions(true);
    provider.setUseAuthenticationRequestCredentials(true);
    provider.setUserDetailsContextMapper(userDetailsContextMapper());
    return provider;
}

@Bean
public UserDetailsContextMapper userDetailsContextMapper() {
    UserDetailsContextMapper contextMapper = new MyUserDetailsContextMapper();
    return contextMapper;
}

@Bean
public MyDatabaseAuthenticationProvider databaseAuthenticationProvider() {
    return new MyDatabaseAuthenticationProvider();
}

There's really nothing special in the "MyDatabaseAuthenticationProvider" or "MyUserDetailsContextMapper" classes except for some custom logic for mapping and looking up users.

The app doesn't crash, but obviously not the page I want to show the user. :)

Any thoughts on how I can get rid of the StackOverflowError?

Sheepdip answered 10/6, 2015 at 19:57 Comment(0)
D
13

I had the same problem, this was the solution for me:

@Override
protected void configure(AuthenticationManagerBuilder
authManagerBuilder) throws Exception {
...
.userDetailsService(userDetailsService());
...
}

The problem where the brackets after userDetailsService - removed them and it works as expected. From your code snippet I can't be sure where you get the userDetailsService from, for me I had it @Autowired.

Dunlin answered 15/6, 2015 at 20:19 Comment(4)
This is exactly it! Since I'm just using the default Spring Security userDetailsService, it's actually redundant to set it again in the provider - it's completely unnecessary! As soon as I remove that line from both providers, it works as it should. Thanks!!!Sheepdip
@BrianWaldhart - and zeisi too. I'm glad this solved your problem, but I am having the same problem and can't make any sense out of the solution zeisi provided. "The problem where the brackets after userDetailsService - removed them and it works as expected." What brackets? What does this mean???Oppidan
@SteveCohen - if you look at my example above, the two lines I removed were the ".userDetailsService(userDetailsService());" lines from the "config" method. As soon as I removed those two lines, everything worked. It makes sense, because basically you're calling the setter with the getter (it becomes cyclical!).Sheepdip
To be even clearer: delete the line .userDetailsService(userDetailsService()) as it is the default and you're creating an infinite recusion passing it into itself.Nordin
M
1

I had the same problem and another solution worked in my case. The difference is, that I had simply username and password, database authentication.

@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
    authManagerBuilder
            .userDetailsService(userDetailsService())
            .passwordEncoder(passwordEncoder());
}

@Bean
UserDetailsService userDetailsService() {
    return new UserDetailsService();
}

The fix was to add the @Override annotation to the @Bean annotated method:

@Bean
@Override
UserDetailsService userDetailsService() {
    return new UserDetailsService();
}
Maryrosemarys answered 28/11, 2019 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.