Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide multiple Authentication providers with java configuration of spring security

I store information about users in seperated tables owners,employees,users i am trying to use java configuration in spring security.

I have created three diferent authentication providers for each user type, but only the Users Provider is being triggered. I have read the spring security docs and the only way to do this seems to be is create class with multiple embedded classes extended from WebSecurityConfigurerAdapter but i don't want to do it this way because it requires a lot of duplicating code, is there any other way

I tryed to use the simple userDetailService inside which i send request to all tables in databese but still there is not results, only one query is buing executed and nothing, the only responce i get is:

2016-02-09 23:06:25.976 DEBUG 8780 --- [nio-8080-exec-1] .s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException

2016-02-09 23:06:25.976 DEBUG 8780 --- [nio-8080-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter : Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException: No entity found for query; nested exception is javax.persistence.NoResultException: No entity found for query

But i never throw any exception!! And the most strange is that i can see in the debugger how the execution rapidly stops right after em.createQuery(..).getSingleResult().. and that's it, nothing more! There is no return statement no exception nothing, wtf!!

This is part of my current configuration:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
            .authenticationProvider(createAuthenticationProvider(employeeDetailService()))
            .authenticationProvider(createAuthenticationProvider(ownerDetailsService()))
            .authenticationProvider(createAuthenticationProvider(userDetailsService()));
}
 @Bean
    public OwnerDetailsService ownerDetailsService() {
        return new OwnerDetailsService();
    }

    @Bean
    public EmployeeDetailServiceImpl employeeDetailService() {
        return new EmployeeDetailServiceImpl();
    }

    @Bean
    public UserDetailsServiceImpl userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(6);
    }

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new MySimpleUrlAuthenticationSuccessHendler();
    }



    private AuthenticationProvider createAuthenticationProvider(UserDetailsService service) {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(service);
    provider.setPasswordEncoder(passwordEncoder());
    provider.setHideUserNotFoundExceptions(true);
    return provider;
}

User detail services:

  @Service
    public abstract class CustomUserDetailService implements UserDetailsService{

        @Autowired
        IDBBean dao;

        protected CustomUserDetails getUser(GetUserByNameFunction function, String name) {
            return createUser(function.get(name));
        }

        protected CustomUserDetails createUser(Authenticational user) {
            return new CustomUserDetails(user, getAuthorities(user.getAuthority()));
        }

        protected List<GrantedAuthority> getAuthorities(String authority) {
            return Collections.singletonList(new SimpleGrantedAuthority(authority));
        }
    }

Implementations

    public class EmployeeDetailServiceImpl extends CustomUserDetailService {

        @Override
        public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
            return super.getUser(dao::getEmployeeByEmail, email);
        }
    }

    public class OwnerDetailsService extends CustomUserDetailService {

        @Override
        public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
            return super.getUser(dao::getOwnerByEmail, email);
        }
    }

public class UserDetailsServiceImpl extends CustomUserDetailService {


    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        return super.getUser(dao::getUserByEmail, userName);
    }
}

Custom user details:

private Long id;
    private String userEmail;


    public CustomUserDetails(Authenticational user,
                             Collection<? extends GrantedAuthority> authorities) {
        super(
                user.getName(),
                user.getPassword().toLowerCase(),
                user.isEnabled(),
                true,
                true,
                true,
                authorities);
        upadateValues(user);
    }

    private void upadateValues(Authenticational user) {
        this.id = user.getId();
        this.userEmail = user.getEmail();
    }
like image 868
Dmitrij Kostyushko Avatar asked Sep 02 '25 10:09

Dmitrij Kostyushko


1 Answers

Just to clarify something from the other answer:

Your authentication providers are stored in a list inside ProviderManager that iterates your authentication request through them. If your authentication provider throws AuthenticationException (BadCredentialsException extends AuthenticationException), then the ProviderManager will try another provider. If you set the hideUserNotFoundExceptions property, then it will also wrap and ignore UsernameNotFoundException and try another provider in this case too.

If I were you I would start by placing a debugging point inside ProviderManager's authenticate method. From there you can find out why the other authentication providers are not being called for their authenticate method.

Also I would think about having only one authentication provider with one UserDetailsService. It seems to me that you are doing a lot of complex not really needed operations like passing function to your abstract implementation when all you could do would be to have one UserDetailsService that would ask all your DAOs for a user. Which is basically what you're trying to accomplish but minus 2 authentication providers, minus 1 abstract class and minus 2 UserDetailsService implementations.

like image 105
JIMI Avatar answered Sep 04 '25 05:09

JIMI