Lee Theobald Lee Theobald - 1 month ago 49
Java Question

Custom Authentication Provider Not Being Called

I'm trying to setup a customer AuthenticationProvider with Spring Security but not having much luck getting it working. I'm using Java configuration so I'm probably missing something simple but as most the learning material is XML config based, it's not jumping out at me.

This is using Spring v4.0.1.RELEASE but with Spring Security v3.2.2.RELEASE. Version number clash perhaps?

As far as I could tell, all I had to do was create my provider:

public class KBServicesAuthProvider implements AuthenticationProvider {
@Autowired
private ApplicationConfig applicationConfig;

@Autowired
private SessionServiceClient sessionServiceClient;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();

try {
KBSessionInfo sessionInfo = sessionServiceClient.login(applicationConfig.getKbServicesPresenceId(), email,
password);

List<GrantedAuthority> grantedRoles = new ArrayList<>();
for (KBRoleMembership role : sessionInfo.getAuthenticatedUser().getRoleMemberships()) {
grantedRoles.add(new SimpleGrantedAuthority(role.getRoleId()));
}

return new UsernamePasswordAuthenticationToken(email, password, grantedRoles);
} catch (InvalidSessionException e) {
throw new AuthenticationCredentialsNotFoundException("Username or password was not accepted", e);
}
}

@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}


And then setup a class to describe my security setup. This class links in my provider:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired(required = true)
SessionServiceClient sessionServiceClient;

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll().anyRequest().authenticated();
http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getKBServicesAuthenticationProvider());
}

@Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new KBServicesAuthProvider();
}
}


But I'm not seeing anything in the logs & none of my debug points are being hit. The app acts as it's unsecured (so I can reach various URLs etc. still).

Any ideas on what I should be checking?

Bal Bal
Answer

This might not be the complete answer, as I'm struggling with this a bit myself. I'm using a custom authentication provider and a custom user details service. I see the same behavior as you -- breakpoints get hit in my user details service, but not in my authentication provider. Here is what my entire config class looks like:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthenticationProvider rememberMeAuthenticationProvider = rememberMeAuthenticationProvider();
        TokenBasedRememberMeServices tokenBasedRememberMeServices = tokenBasedRememberMeServices();

        List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(2);
        authenticationProviders.add(rememberMeAuthenticationProvider);
        authenticationProviders.add(customAuthenticationProvider);
        AuthenticationManager authenticationManager = authenticationManager(authenticationProviders);

        http
                .csrf().disable()
                .headers().disable()
                .addFilter(new RememberMeAuthenticationFilter(authenticationManager, tokenBasedRememberMeServices))
                .rememberMe().rememberMeServices(tokenBasedRememberMeServices)
                .and()
                .authorizeRequests()
                .antMatchers("/js/**", "/css/**", "/img/**", "/login", "/processLogin").permitAll()
                .antMatchers("/index.jsp", "/index.html", "/index").hasRole("USER")
                .antMatchers("/admin", "/admin.html", "/admin.jsp", "/js/saic/jswe/admin/**").hasRole("ADMIN")
                .and()
                .formLogin().loginProcessingUrl("/processLogin").loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
                .and()
                .exceptionHandling().accessDeniedPage("/login")
                .and()
                .logout().permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/img/**");
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(List<AuthenticationProvider> authenticationProviders) {
        return new ProviderManager(authenticationProviders);
    }

    @Bean
    public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
        return new TokenBasedRememberMeServices("testKey", userDetailsService);
    }

    @Bean
    public AuthenticationProvider rememberMeAuthenticationProvider() {
        return new org.springframework.security.authentication.RememberMeAuthenticationProvider("testKey");
    }

    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}

I've just discovered that if I specifically add my authentication provider to the HttpSecurity object, my breakpoints start getting hit:

http
                .csrf().disable()
                .headers().disable()
                .authenticationProvider(customAuthenticationProvider)

My goal is to get a BCryptPasswordEncoder working, which does not with this config -- everything returns as bad credentials. Anyway, just thought I'd share.