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
.