Spring SecurityでStackOverFlowErrorの対処法


## はじめに
Spring Securityで謎のStackOverFlowが発生し、どうにか解決できたので今後のその対応方法をメモしておく。

## 環境
 - Java : 1.8.0 Update 45
 - Spring Framework : 4.2.0.RELEASE
 - Spring Security : 4.0.2.RELEASE
 - Tomcat : 8.0.23

## 現象
以下のような実装をしたところ、Tomcat起動後にトップページにアクセスするだけで、StackOverFlowが発生。
処理が循環しているっぽかった。

### 実装

```Java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.anonymous()
            .and()
            .formLogin().loginPage("/login")
            .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .invalidateHttpSession(true)
                .logoutSuccessUrl("/login")
            .and()
            .exceptionHandling().accessDeniedHandler(accessDeniedHandler())
            .and()
            .csrf()
            .and()
            .requestMatcher(securityRequestMatcher());
    }
    　　　　　　　　・
    　　　　　　　　・
    　　　　　　　　・
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        SystemWideSaltSource saltSource = new SystemWideSaltSource();
        saltSource.setSystemWideSalt("system");

        ShaPasswordEncoder shaPasswordEncoder = new ShaPasswordEncoder(256);
        shaPasswordEncoder.setEncodeHashAsBase64(true);

        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setSaltSource(saltSource);
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(shaPasswordEncoder);

        auth.authenticationProvider(provider);
    }

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

### ログ

```Java
12-Aug-2015 17:16:28.013 SEVERE [http-nio-8080-exec-3] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [dispatcher] in context with path [/] threw exception [フィルタの実行により例外を投げました] with root cause
 java.lang.StackOverflowError
        at org.apache.commons.logging.impl.SLF4JLocationAwareLog.isDebugEnabled(SLF4JLocationAwareLog.java:67)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:154)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:446)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
```

## 対応
```super.authenticationManagerBean()``` を ```super.authenticationManager()``` とした。

```Java
    @Override
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
```

## 今後
Spring Securityの実装をもう少し詳細に見てみて、使い方が悪いのかSpringがおかしいのか見極める予定。