Skip to content
Advertisement

How to have the same type of User object when using multiple AuthenticationProviders?

I have two working AuthenticationProviders in my Server:

@Bean
public AuthenticationManager authenticationManager(final DataSource dataSource, final ContextSource contextSource,
    final ObjectPostProcessor<Object> objectPostProcessor) throws Exception {
    final AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(objectPostProcessor);
    auth.ldapAuthentication()
        .contextSource((BaseLdapPathContextSource) contextSource)
        .userSearchFilter("(| (sAMAccountName={0}))");
    auth.jdbcAuthentication()
        .passwordEncoder(new BCryptPasswordEncoder())
        .dataSource(dataSource)
        .usersByUsernameQuery("select username, password, enabled from Users where lower(username) = lower(?)")
        .authoritiesByUsernameQuery("select username, role from UserRoles where lower(username) = lower(?)");
    return auth.build();
}

Once a user is logged in, I access their data via SecurityContextHolder.getContext().getAuthentication().getPrincipal() (with appropriate checks for no or anonymous logins). For the JDBC login the principal is a org.springframework.security.core.userdetails.User object and for LDAP it is a org.springframework.security.ldap.userdetails.LdapUserDetailsImpl object. I would like to ultimately use the same custom User class for both providers, which would contain some additional data (full name, avatar and such).

Where do I add this custom behavior? I could probably get away with replacing the original Principal the first time it would be accessed, but that seems hacky and errorprone, in case someone skips my code.

EDIT: I found userDetailsContextMapper(UserDetailsContextMapper) on the ldapAuthentication, but for the jdbcAuthentication the equivalent (?) UserDetailsService (or UserDetailsManager) is set directly in the constructor of the Configurer. Would these allow me to customize the generated User object, and if yes, how do I set one on the jdbcAuthentication?

Advertisement

Answer

I don’t think the JdbcUserDetailsManagerConfigurer has some way to configure the return type.

What you could do is to create your own UserDetailsService and use it instead of auth.jdbcAuthentication()..., like so:

@Bean
public AuthenticationManager authenticationManager(final DataSource dataSource, final ContextSource contextSource,
    final ObjectPostProcessor<Object> objectPostProcessor, UserDetailsService myUserDetailsService) throws Exception {
    final AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(objectPostProcessor);
    auth.ldapAuthentication()
        .contextSource((BaseLdapPathContextSource) contextSource)
        .userSearchFilter("(| (sAMAccountName={0}))");
    auth.userDetailsService(myUserDetailsService)
        .passwordEncoder(new BcryptPasswordEncoder());
    return auth.build();
}

This way you have total control over the return type of the UserDetailsService.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement