6

I have updated recently to spring-security-3.2.0.RC2 from RC1, and according to the blog post the QUIESCENT_POST_PROCESSOR have been removed. Before I used to create an AuthenticationManager bean like this below:

@Bean(name = {"defaultAuthenticationManager", "authenticationManager"})
public AuthenticationManager defaultAuthenticationManager() throws Exception {
    return new AuthenticationManagerBuilder(null).userDetailsService(context.getBean(MyUserDetailsService.class)).passwordEncoder(new Md5PasswordEncoder()).and().build();
}

so I've changed it to:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws BeansException, Exception {
    auth.userDetailsService(context.getBean(MyUserDetailsService.class)).passwordEncoder(new Md5PasswordEncoder());
}

but unfortunately I can't get hold of the AuthenticationManager any more. I'm also creating RememberMeAuthenticationFilter like this:

@Bean(name = { "defaultRememberMeAuthenticationFilter", "rememberMeAuthenticationFilter" })
protected RememberMeAuthenticationFilter defaultRememberMeAuthenticationFilter() throws Exception {
    return new RememberMeAuthenticationFilter(defaultAuthenticationManager(), context.getBean(DefaultRememberMeServices.class));
}

so as you can see I need to get hold of AuthenticationManager, but I don't know how???

Petar Tahchiev
  • 4,336
  • 4
  • 35
  • 48

2 Answers2

15

You really shouldn't need to get a hold of the AuthenticationManager. From the javadoc of HttpSecurity the following should work just fine:

@Configuration
@EnableWebSecurity
public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth
             .inMemoryAuthentication()
                  .withUser("user").password("password").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/**").hasRole("USER")
                .and()
            .formLogin()
                .permitAll()
                .and()
            // Example Remember Me Configuration
            .rememberMe();
    }
}

Of course if you are using global AuthenticationManager, this will work too:

@Configuration
@EnableWebSecurity
public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth
             .inMemoryAuthentication()
                  .withUser("user").password("password").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/**").hasRole("USER")
                .and()
            .formLogin()
                .permitAll()
                .and()
            // Example Remember Me Configuration
            .rememberMe();
    }
}

The only difference is the first example isolates the AuthenticationManger to the HttpSecurity where as the second example will allow the AuthenticationManager to be used by global method security or another HttpSecurity (WebSecurityConfigurerAdapter).

The reason this works is the .rememberMe() will automatically find the AuthenticationManager, UserDetailsService and use that when creating the RememberMeAuthenticationFilter. It also creates the appropriate RememberMeServices so there is no need to do that. Of course there are additional options on .rememberMe() if you want to customize it, so refer to the RememberMeConfigurer javadoc for additional options.

If you REALLY need a reference to the AuthenticationManager instance you can do the following:

@Configuration
@EnableWebSecurity
public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private AuthenticationManagerBuilder auth;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth
             .inMemoryAuthentication()
                  .withUser("user").password("password").roles("USER");
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return auth.build();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/**").hasRole("USER")
                .and()
            .formLogin()
                .permitAll()
                .and()
            // Example Remember Me Configuration
            .rememberMe();
    }
}

If you want to have multiple AuthenticationManager instances, you can do the following:

    @Autowired
    private ObjectPostProcessor<Object> opp;

    public AuthenticationManager authenticationManager()
            throws Exception {
        return new AuthenticationManagerBuilder(opp)
            .inMemoryAuthentication()
               .withUser("user").password("password").roles("USER").and()
            .and()
            .build();
    }

    public AuthenticationManager authenticationManager2()
            throws Exception {
        return new AuthenticationManagerBuilder(opp)
            .inMemoryAuthentication()
               .withUser("admin").password("password").roles("ADMIN").and()
            .and()
            .build();
    }

NOTE This is almost the same as you had things before hand except instead of using the QUIESENT_POST_PROCESSOR you are using a real ObjectPostProcessor using the @Autowired annotation

PS: Thanks for giving RC2 a try!

Rob Winch
  • 21,440
  • 2
  • 59
  • 76
  • Hi Rob,I have this service which uses – Petar Tahchiev Nov 06 '13 at 22:51
  • Hi Rob, I have this service which uses the AuthenticationManager like this: `\@Resource private AuthenticationManager authenticationManager; ` and if I declare the authenticationManager global with \@Autowired the service doesn't find it. So I guess I'll go the old way and manually create the authManager with \@Autowired ObjectPostProcessors. Thanks for your thorough response and for your hard on spring security. – Petar Tahchiev Nov 06 '13 at 22:58
  • With the latest release you can use a custom AuthenticationManager by exposing it as a Bean – Rob Winch May 28 '14 at 13:20
  • @RobWinch - I wonder if you could comment on this question/answer, since you seem to know about the AuthenticationManager internals: http://stackoverflow.com/a/26615970/1017787 – JBCP Oct 28 '14 at 18:40
  • The only problem i had with this solution was that I needed to call auth.getObject() instead of build() as the manager had already been built. Thanks for solving several days of problems. – Pablo Jomer Apr 27 '16 at 14:18
3

The way to expose and get access to the AuthenticationManager bean is as follows:

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
   return super.authenticationManagerBean();
}
sudr
  • 133
  • 1
  • 1
  • 5