19

There are several references of multiple authentication providers in spring security, but no example in Java config could be located.

The following link gives the XML notation: Multiple Authentication Providers in Spring Security

We need to authenticate using LDAP or DB

Below is our sample code:

@Configuration
@EnableWebSecurity
public class XSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationProvider authenticationProvider;

    @Autowired
    private AuthenticationProvider authenticationProviderDB;


    @Override
    @Order(1)

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


    @Order(2)
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProviderDB);
    }

    @Override
      public void configure(WebSecurity web) throws Exception {
        web
          .ignoring()
             .antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
      }
    ______

    @Override
    @Order(1)
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/","/logout","/time").permitAll()
                    .antMatchers("/admin").hasRole("ADMIN")         
                        .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/index")
            .loginProcessingUrl("/perform_login")
            .usernameParameter("email")
            .passwordParameter("password")
            .failureUrl("/index?failed=true")
            .defaultSuccessUrl("/summary",true)
            .permitAll()
            .and()
         .logout().logoutUrl("/logout")
                  .logoutSuccessUrl("/index?logout=true").permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/error403")
        .and().authenticationProvider(authenticationProvider);

    }

    @Order(1)
    protected void configureDB(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/","/logout").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/index")
            .loginProcessingUrl("/perform_login")
            .usernameParameter("email")
            .passwordParameter("password")
            .failureUrl("/index?failed=true")
            .defaultSuccessUrl("/summary",true)
            .permitAll()
            .authenticationProvider(authenticationProviderDB)
    //This line giving compilation error stating authenticationProvider is not available in formloginconfigurer

         .and()
         .logout().logoutUrl("/logout")
                  .logoutSuccessUrl("/index?logout=true").permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/error403");
    }

}
Zounadire
  • 1,496
  • 2
  • 18
  • 38
Matt Jerry
  • 501
  • 1
  • 3
  • 12
  • 3
    Just call `authenticationProvider` multiple times with different `AuthenticationProvider` instances. Both will be registered and consulted in the order specified. – M. Deinum Sep 06 '16 at 10:59

3 Answers3

14

May be this will help you :-

@Configuration
@EnableWebSecurity
@Profile("container")
public class XSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AuthenticationProvider authenticationProvider;

@Autowired
private AuthenticationProvider authenticationProviderDB;

@Override
@Order(1)

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

@Order(2)
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProviderDB);
}

@Override
  public void configure(WebSecurity web) throws Exception {
    web
      .ignoring()
         .antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
  }

@Override
public void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/rest/**").authenticated()
            .antMatchers("/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .successHandler(new AuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(
                        HttpServletRequest request,
                        HttpServletResponse response,
                        Authentication a) throws IOException, ServletException {
                            //To change body of generated methods,
                            response.setStatus(HttpServletResponse.SC_OK);
                        }
            })
            .failureHandler(new AuthenticationFailureHandler() {

                @Override
                public void onAuthenticationFailure(
                        HttpServletRequest request,
                        HttpServletResponse response,
                        AuthenticationException ae) throws IOException, ServletException {
                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        }
            })
            .loginProcessingUrl("/access/login")
            .and()
            .logout()
            .logoutUrl("/access/logout")                
            .logoutSuccessHandler(new LogoutSuccessHandler() {
                @Override
                public void onLogoutSuccess(
                        HttpServletRequest request, 
                        HttpServletResponse response, 
                        Authentication a) throws IOException, ServletException {
                    response.setStatus(HttpServletResponse.SC_NO_CONTENT);
                }
            })
            .invalidateHttpSession(true)
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(new Http403ForbiddenEntryPoint())
            .and()
            .csrf()//Disabled CSRF protection
            .disable();
    }
} 
ojus kulkarni
  • 1,877
  • 3
  • 25
  • 41
  • 1
    Thank you will try out. I don't see any reference of authenticationProviderDB or authenticationProvider(which represents ldap) – Matt Jerry Feb 13 '16 at 01:04
  • here that `.authenticated()` authenticate any request which you are getting from `antMatcher` then it will set the status in its successHandler – ojus kulkarni Feb 13 '16 at 04:34
  • I tried with this code and it works only either for ldap or db and not both. There are no examples in spring java config which speak about multiple authentication mechanisms and hence difficult to proceed – Matt Jerry Feb 14 '16 at 11:13
  • Then why you don't maintain DB configuration and Mvc configuration separately. in something like DatabaseConfiguration class and MvcConfiguration Class – ojus kulkarni Feb 15 '16 at 04:35
13

In Spring Boot this worked for me:

Each Authentication provider is tested in order. If one passes, then its following Authentication providers are skipped

auth.userDetailsService(userDetailsService)...

then:

auth.ldapAuthentication()....

@EnableRedisHttpSession
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private CustomUserDetailsService userDetailsService;

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

    //each Authentication provider is tested in order
    //if one passes then its following Authentication providers are skipped

    //DataBase Authentication
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());



    LdapContextSource ldapContextSource = new LdapContextSource();


    ldapContextSource.setUrl("ldap://192.168.XXX.XXX:389");
    ldapContextSource.setBase("dc=companyname,dc=com");
    ldapContextSource.setUserDn("cn=user,cn=testgroup,ou=Test,dc=companyname,dc=com");
    ldapContextSource.setPassword("user1234");
    ldapContextSource.afterPropertiesSet();



    //LDAP Authentication
    auth.ldapAuthentication()
        //The {0} in the (uid={0}) will be replaced by the username entered in the form.
        .userSearchBase("ou=Group")
        .userSearchFilter("uid={0}")

        //.userDnPatterns("uid={0},ou=people")//does the same thing 

        //Specifies where the search for Roles start
        //.groupSearchBase("ou=mathematicians")
        //in groups we search for member
        //.groupSearchFilter("member={0}")
        //.contextSource().ldif("classpath:test-server.ldif");

    .contextSource(ldapContextSource);



}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()


            .antMatchers("/hello").access("hasRole('ROLE_ADMIN')")
            .antMatchers("/index").fullyAuthenticated()
            .antMatchers("/").fullyAuthenticated()
            .antMatchers("/home").fullyAuthenticated()
            .anyRequest().permitAll()

            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .usernameParameter("username").passwordParameter("password")
            .and()
            .logout()
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            .and()
                .exceptionHandling()
                .accessDeniedPage("/403")
            .and()
                .csrf()
                .disable();



}

@Bean(name = "passwordEncoder")
public PasswordEncoder passwordencoder() {
    return new BCryptPasswordEncoder();
}
}
Zounadire
  • 1,496
  • 2
  • 18
  • 38
Ryan Augustine
  • 1,455
  • 17
  • 14
  • Thanks Ryan Augustine. This is an elegant approach for anyone looking to have multiple authentication providers. In my case, with Spring boot2, I also had to add: @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } to resolve the "No qualifying bean of type 'org.springframework.security.authentication.AuthenticationManager' available" issue – dipan66 Nov 19 '21 at 01:31
12

This is a successful configuration which helps configure multiple authentication providers in java config. Thanks a lot ojus for your inputs. It did help in nailing down the issue. The key is to have

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
    auth.authenticationProvider(authenticationProviderDB);

}

Full code below

@Configuration
@EnableWebSecurity
public class XSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private LDAPAuthenticationProvider authenticationProvider;

    @Autowired
    private DBAuthenticationProvider authenticationProviderDB;

    @Override
      public void configure(WebSecurity web) throws Exception {
        web
          .ignoring()
             .antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
      }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
        auth.authenticationProvider(authenticationProviderDB);

    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/","/logout").permitAll()
            .antMatchers("/admin").hasRole("ADMIN")         
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/index")
            .loginProcessingUrl("/perform_login")
            .usernameParameter("user")
            .passwordParameter("password")
            .failureUrl("/index?failed=true")
            .defaultSuccessUrl("/test",true)
            .permitAll()
            .and()
         .logout().logoutUrl("/logout")
                  .logoutSuccessUrl("/index?logout=true").permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/error");
    }


}
Zounadire
  • 1,496
  • 2
  • 18
  • 38
Matt Jerry
  • 501
  • 1
  • 3
  • 12