Selection based AuthProvider Spring Security










3















I have configured Spring security to work with both LDAP and DB based login. First it tries to login via LDAP and if required permissions is not there then it takes to username/password entry page.



<security:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customPreAuthFilter" position="PRE_AUTH_FILTER"/> // This is for LDAP
<security:custom-filter ref="customAuthFilter" position="FORM_LOGIN_FILTER"/> // This is for DB Based

/** intercept urls

**/

</security:http>


I want to add a new screen on the top and user need to select between the two button LDAP or username/pass. How do I proceed?



The data to be accessed is the same url i.e. /home but both ldap and DB users should be able to access.










share|improve this question
























  • How is your Filter implementation looks like? I am wondering if you are checking what kind of authentication to be executed in filter and what do you do if authentication fails? are you seeing any error?

    – secret super star
    Nov 19 '18 at 9:50











  • As seen in the xml, there are 2 filters. First one is to extract the header value for LDAP check. Second one am using filter for passing a 3rd value i.e. captcha. after that in both cases the getAuthenticationManager().authenticate(authentication); is called. Filter doesn't perform extra actions rather than passing control to auth manager

    – Akhil K Nambiar
    Nov 19 '18 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.

    – shadow
    Nov 22 '18 at 5:47












  • You want to change "spring security config" based on user selection!? I think you won't be able to "change the config dynamically", but what seems an approach: 1. "permitAll" for the "new screen" 2. set a (session) flag (designated by you) 3. check that flag and adjust your filters accordingly ..and another approach 'd be: multiple security configurations

    – xerx593
    Nov 22 '18 at 8:31












  • Edited the answer to select auth provider based on input and redirect to different login page based on condition, if this was your original question

    – secret super star
    Nov 23 '18 at 11:54















3















I have configured Spring security to work with both LDAP and DB based login. First it tries to login via LDAP and if required permissions is not there then it takes to username/password entry page.



<security:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customPreAuthFilter" position="PRE_AUTH_FILTER"/> // This is for LDAP
<security:custom-filter ref="customAuthFilter" position="FORM_LOGIN_FILTER"/> // This is for DB Based

/** intercept urls

**/

</security:http>


I want to add a new screen on the top and user need to select between the two button LDAP or username/pass. How do I proceed?



The data to be accessed is the same url i.e. /home but both ldap and DB users should be able to access.










share|improve this question
























  • How is your Filter implementation looks like? I am wondering if you are checking what kind of authentication to be executed in filter and what do you do if authentication fails? are you seeing any error?

    – secret super star
    Nov 19 '18 at 9:50











  • As seen in the xml, there are 2 filters. First one is to extract the header value for LDAP check. Second one am using filter for passing a 3rd value i.e. captcha. after that in both cases the getAuthenticationManager().authenticate(authentication); is called. Filter doesn't perform extra actions rather than passing control to auth manager

    – Akhil K Nambiar
    Nov 19 '18 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.

    – shadow
    Nov 22 '18 at 5:47












  • You want to change "spring security config" based on user selection!? I think you won't be able to "change the config dynamically", but what seems an approach: 1. "permitAll" for the "new screen" 2. set a (session) flag (designated by you) 3. check that flag and adjust your filters accordingly ..and another approach 'd be: multiple security configurations

    – xerx593
    Nov 22 '18 at 8:31












  • Edited the answer to select auth provider based on input and redirect to different login page based on condition, if this was your original question

    – secret super star
    Nov 23 '18 at 11:54













3












3








3


0






I have configured Spring security to work with both LDAP and DB based login. First it tries to login via LDAP and if required permissions is not there then it takes to username/password entry page.



<security:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customPreAuthFilter" position="PRE_AUTH_FILTER"/> // This is for LDAP
<security:custom-filter ref="customAuthFilter" position="FORM_LOGIN_FILTER"/> // This is for DB Based

/** intercept urls

**/

</security:http>


I want to add a new screen on the top and user need to select between the two button LDAP or username/pass. How do I proceed?



The data to be accessed is the same url i.e. /home but both ldap and DB users should be able to access.










share|improve this question
















I have configured Spring security to work with both LDAP and DB based login. First it tries to login via LDAP and if required permissions is not there then it takes to username/password entry page.



<security:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customPreAuthFilter" position="PRE_AUTH_FILTER"/> // This is for LDAP
<security:custom-filter ref="customAuthFilter" position="FORM_LOGIN_FILTER"/> // This is for DB Based

/** intercept urls

**/

</security:http>


I want to add a new screen on the top and user need to select between the two button LDAP or username/pass. How do I proceed?



The data to be accessed is the same url i.e. /home but both ldap and DB users should be able to access.







java spring spring-security






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 '18 at 6:52







Akhil K Nambiar

















asked Nov 13 '18 at 7:10









Akhil K NambiarAkhil K Nambiar

1,741113774




1,741113774












  • How is your Filter implementation looks like? I am wondering if you are checking what kind of authentication to be executed in filter and what do you do if authentication fails? are you seeing any error?

    – secret super star
    Nov 19 '18 at 9:50











  • As seen in the xml, there are 2 filters. First one is to extract the header value for LDAP check. Second one am using filter for passing a 3rd value i.e. captcha. after that in both cases the getAuthenticationManager().authenticate(authentication); is called. Filter doesn't perform extra actions rather than passing control to auth manager

    – Akhil K Nambiar
    Nov 19 '18 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.

    – shadow
    Nov 22 '18 at 5:47












  • You want to change "spring security config" based on user selection!? I think you won't be able to "change the config dynamically", but what seems an approach: 1. "permitAll" for the "new screen" 2. set a (session) flag (designated by you) 3. check that flag and adjust your filters accordingly ..and another approach 'd be: multiple security configurations

    – xerx593
    Nov 22 '18 at 8:31












  • Edited the answer to select auth provider based on input and redirect to different login page based on condition, if this was your original question

    – secret super star
    Nov 23 '18 at 11:54

















  • How is your Filter implementation looks like? I am wondering if you are checking what kind of authentication to be executed in filter and what do you do if authentication fails? are you seeing any error?

    – secret super star
    Nov 19 '18 at 9:50











  • As seen in the xml, there are 2 filters. First one is to extract the header value for LDAP check. Second one am using filter for passing a 3rd value i.e. captcha. after that in both cases the getAuthenticationManager().authenticate(authentication); is called. Filter doesn't perform extra actions rather than passing control to auth manager

    – Akhil K Nambiar
    Nov 19 '18 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.

    – shadow
    Nov 22 '18 at 5:47












  • You want to change "spring security config" based on user selection!? I think you won't be able to "change the config dynamically", but what seems an approach: 1. "permitAll" for the "new screen" 2. set a (session) flag (designated by you) 3. check that flag and adjust your filters accordingly ..and another approach 'd be: multiple security configurations

    – xerx593
    Nov 22 '18 at 8:31












  • Edited the answer to select auth provider based on input and redirect to different login page based on condition, if this was your original question

    – secret super star
    Nov 23 '18 at 11:54
















How is your Filter implementation looks like? I am wondering if you are checking what kind of authentication to be executed in filter and what do you do if authentication fails? are you seeing any error?

– secret super star
Nov 19 '18 at 9:50





How is your Filter implementation looks like? I am wondering if you are checking what kind of authentication to be executed in filter and what do you do if authentication fails? are you seeing any error?

– secret super star
Nov 19 '18 at 9:50













As seen in the xml, there are 2 filters. First one is to extract the header value for LDAP check. Second one am using filter for passing a 3rd value i.e. captcha. after that in both cases the getAuthenticationManager().authenticate(authentication); is called. Filter doesn't perform extra actions rather than passing control to auth manager

– Akhil K Nambiar
Nov 19 '18 at 11:05






As seen in the xml, there are 2 filters. First one is to extract the header value for LDAP check. Second one am using filter for passing a 3rd value i.e. captcha. after that in both cases the getAuthenticationManager().authenticate(authentication); is called. Filter doesn't perform extra actions rather than passing control to auth manager

– Akhil K Nambiar
Nov 19 '18 at 11:05














<intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.

– shadow
Nov 22 '18 at 5:47






<intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.

– shadow
Nov 22 '18 at 5:47














You want to change "spring security config" based on user selection!? I think you won't be able to "change the config dynamically", but what seems an approach: 1. "permitAll" for the "new screen" 2. set a (session) flag (designated by you) 3. check that flag and adjust your filters accordingly ..and another approach 'd be: multiple security configurations

– xerx593
Nov 22 '18 at 8:31






You want to change "spring security config" based on user selection!? I think you won't be able to "change the config dynamically", but what seems an approach: 1. "permitAll" for the "new screen" 2. set a (session) flag (designated by you) 3. check that flag and adjust your filters accordingly ..and another approach 'd be: multiple security configurations

– xerx593
Nov 22 '18 at 8:31














Edited the answer to select auth provider based on input and redirect to different login page based on condition, if this was your original question

– secret super star
Nov 23 '18 at 11:54





Edited the answer to select auth provider based on input and redirect to different login page based on condition, if this was your original question

– secret super star
Nov 23 '18 at 11:54












1 Answer
1






active

oldest

votes


















2





+25









If you look at code in UsernamePasswordAuthenticationFilter there is setDetails method.



from docs:




Provided so that subclasses may configure what is put into the
authentication request's details property.




Idea from here
Provision to change ldap/Ad provider url at run time



You can set the details like authtype here and use it authentication provider, But to achieve the things you would lik adds little more work.



Adding details and hope it helps.



CustomUsernamePasswordAuthenticationFilter.java



import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

@Component
public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter

private static final Logger logger = LoggerFactory.getLogger(CustomUsernamePasswordAuthenticationFilter.class);

@Autowired
@Override
public void setAuthenticationManager(AuthenticationManager authenticationManager)
// TODO Auto-generated method stub
super.setAuthenticationManager(authenticationManager);


@Autowired
@Override
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource)
super.setAuthenticationDetailsSource(authenticationDetailsSource);


@Override
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest)
String authType = request.getParameter("authType");
logger.info("authType ",authType);
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));





But this is not sufficient you would need to extend WebAuthenticationDetails.



Reason is WebAuthenticationDetails provides only remote IP address and sessionId so, to add authType we need to extend this class.



You have to extend WebAuthenticationDetailsSource to return CustomAuthenticationDetails as shown below.



CustomAuthenticationDetails.java



public class CustomAuthenticationDetails extends WebAuthenticationDetails


private final String authType;

public CustomAuthenticationDetails(HttpServletRequest request)
super(request);
authType = request.getParameter("authType");


public String getAuthType()
return authType;




CustomWebAuthenticationDetailsSource.java



public class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource 

@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest context)
return new CustomAuthenticationDetails(context);





Please note these classes for demo purpose only.



Need to autowire actual authentication providers in these classes.



import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.stereotype.Component;

@Component
public class AuthenicationProviderJdbcLdapImpl implements AuthenticationProvider

// you need to autowire jdbc auth provider
@Autowired(required = false)
DaoAuthenticationProvider authenticationProvider;

//you need to autowire ldap auth provider
@Autowired(required = false)
LdapAuthenticationProvider ldapAuthenticationProvider;



protected static class User
private final String userId;
private final String password;
public User(String userId,String password)
this.userId = userId;
this.password = password;

public String getUserId()
return userId;

public String getPassword()
return password;

@Override
public String toString()
return "User [userId=" + userId + ", password=" + password + "]";



private final static Logger logger = LoggerFactory.getLogger(AuthenicationProviderJdbcLdapImpl.class);
private static final List<User> users1 = Arrays.asList(new User("admin1", "password"),new User("admin2", "password"));
private static final List<User> users2 = Arrays.asList(new User("admin3", "password"),new User("admin4", "password"));

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException

CustomAuthenticationDetails details = (CustomAuthenticationDetails) authentication.getDetails();

String authType = details.getAuthType();
logger.info("authType ",authType);
if("jdbc".equalsIgnoreCase(authType))
logger.info("perfrom jdbc authentication");

//perform your authentication using jdbc
//the below is just for explaination

return performAuthentication(authentication, users1);

else if("ldap".equalsIgnoreCase(authType))
logger.info("perfrom ldap authentication");

//perform your authentication using ldap
//the below is just for explaination

return performAuthentication(authentication, users2);


return null;


private Authentication performAuthentication(Authentication authentication,List<User> users)
String credential = (String) authentication.getCredentials();
String userId = authentication.getName();
for(User user: users)
if(user.getUserId().equals(userId)&& user.getPassword().equals(credential))
authentication = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),authentication.getAuthorities());

return authentication;


return null;

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







If you would need to redirect different login page (not sure, if you have the requirement) you register AuthenticationFailureHandler shown in security config. Here it is redirected to login and login1 based on condition.



http.failureHandler(new AuthenticationFailureHandler() 

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException
String whichPage = request.getParameter("whichPage");
System.out.println("inside login failure handler "+whichPage);
if("login1".equals(whichPage))
response.sendRedirect(request.getContextPath() +"/login1");
else
response.sendRedirect(request.getContextPath() +"/login");


)


WebSecurityConfig.java



import java.io.IOException;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;

import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter

@Autowired
private UserDetailsService userDetailsService;

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


@Bean
public AuthenticationManager getAuthenticationManager() throws Exception
return super.authenticationManagerBean();



@Autowired
AuthenticationSuccessHandler authenticationSuccessHandler;

@Autowired()
AuthenicationProviderJdbcImpl authenicationProviderJdbcImpl;

@Autowired()
AuthenicationProviderLdapImpl authenicationProviderLdapImpl;


@Autowired
CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter;


@Override
protected void configure(HttpSecurity http) throws Exception
http.addFilterAt(customUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

http
.authorizeRequests()
.antMatchers("/resources/**", "/registration","/login1").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()//.successHandler(authenticationSuccessHandler)
.failureHandler(new AuthenticationFailureHandler()

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException
String whichPage = request.getParameter("whichPage");
System.out.println("inside login failure handler "+whichPage);
if("login1".equals(whichPage))
response.sendRedirect(request.getContextPath() +"/login1");
else
response.sendRedirect(request.getContextPath() +"/login");


)
.and()
.logout()
.permitAll();


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(authenicationProviderLdapImpl).authenticationProvider(authenicationProviderJdbcImpl);





@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
/*auth.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());*/





The below is from logs when authType = jdbc or authType=ldap



login called
2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] stomUsernamePasswordAuthenticationFilter : authType jdbc
2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : authType jdbc
2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom jdbc authentication
login called
login1 called
login1 called
2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] stomUsernamePasswordAuthenticationFilter : authType ldap
2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : authType ldap
2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom ldap authentication returning true in ldap





share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53275645%2fselection-based-authprovider-spring-security%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2





    +25









    If you look at code in UsernamePasswordAuthenticationFilter there is setDetails method.



    from docs:




    Provided so that subclasses may configure what is put into the
    authentication request's details property.




    Idea from here
    Provision to change ldap/Ad provider url at run time



    You can set the details like authtype here and use it authentication provider, But to achieve the things you would lik adds little more work.



    Adding details and hope it helps.



    CustomUsernamePasswordAuthenticationFilter.java



    import javax.servlet.http.HttpServletRequest;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationDetailsSource;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    import org.springframework.stereotype.Component;

    @Component
    public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter

    private static final Logger logger = LoggerFactory.getLogger(CustomUsernamePasswordAuthenticationFilter.class);

    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager)
    // TODO Auto-generated method stub
    super.setAuthenticationManager(authenticationManager);


    @Autowired
    @Override
    public void setAuthenticationDetailsSource(
    AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource)
    super.setAuthenticationDetailsSource(authenticationDetailsSource);


    @Override
    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest)
    String authType = request.getParameter("authType");
    logger.info("authType ",authType);
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));





    But this is not sufficient you would need to extend WebAuthenticationDetails.



    Reason is WebAuthenticationDetails provides only remote IP address and sessionId so, to add authType we need to extend this class.



    You have to extend WebAuthenticationDetailsSource to return CustomAuthenticationDetails as shown below.



    CustomAuthenticationDetails.java



    public class CustomAuthenticationDetails extends WebAuthenticationDetails


    private final String authType;

    public CustomAuthenticationDetails(HttpServletRequest request)
    super(request);
    authType = request.getParameter("authType");


    public String getAuthType()
    return authType;




    CustomWebAuthenticationDetailsSource.java



    public class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource 

    @Override
    public WebAuthenticationDetails buildDetails(HttpServletRequest context)
    return new CustomAuthenticationDetails(context);





    Please note these classes for demo purpose only.



    Need to autowire actual authentication providers in these classes.



    import java.util.Arrays;
    import java.util.List;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationProvider;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
    import org.springframework.stereotype.Component;

    @Component
    public class AuthenicationProviderJdbcLdapImpl implements AuthenticationProvider

    // you need to autowire jdbc auth provider
    @Autowired(required = false)
    DaoAuthenticationProvider authenticationProvider;

    //you need to autowire ldap auth provider
    @Autowired(required = false)
    LdapAuthenticationProvider ldapAuthenticationProvider;



    protected static class User
    private final String userId;
    private final String password;
    public User(String userId,String password)
    this.userId = userId;
    this.password = password;

    public String getUserId()
    return userId;

    public String getPassword()
    return password;

    @Override
    public String toString()
    return "User [userId=" + userId + ", password=" + password + "]";



    private final static Logger logger = LoggerFactory.getLogger(AuthenicationProviderJdbcLdapImpl.class);
    private static final List<User> users1 = Arrays.asList(new User("admin1", "password"),new User("admin2", "password"));
    private static final List<User> users2 = Arrays.asList(new User("admin3", "password"),new User("admin4", "password"));

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException

    CustomAuthenticationDetails details = (CustomAuthenticationDetails) authentication.getDetails();

    String authType = details.getAuthType();
    logger.info("authType ",authType);
    if("jdbc".equalsIgnoreCase(authType))
    logger.info("perfrom jdbc authentication");

    //perform your authentication using jdbc
    //the below is just for explaination

    return performAuthentication(authentication, users1);

    else if("ldap".equalsIgnoreCase(authType))
    logger.info("perfrom ldap authentication");

    //perform your authentication using ldap
    //the below is just for explaination

    return performAuthentication(authentication, users2);


    return null;


    private Authentication performAuthentication(Authentication authentication,List<User> users)
    String credential = (String) authentication.getCredentials();
    String userId = authentication.getName();
    for(User user: users)
    if(user.getUserId().equals(userId)&& user.getPassword().equals(credential))
    authentication = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),authentication.getAuthorities());

    return authentication;


    return null;

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







    If you would need to redirect different login page (not sure, if you have the requirement) you register AuthenticationFailureHandler shown in security config. Here it is redirected to login and login1 based on condition.



    http.failureHandler(new AuthenticationFailureHandler() 

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
    AuthenticationException exception) throws IOException, ServletException
    String whichPage = request.getParameter("whichPage");
    System.out.println("inside login failure handler "+whichPage);
    if("login1".equals(whichPage))
    response.sendRedirect(request.getContextPath() +"/login1");
    else
    response.sendRedirect(request.getContextPath() +"/login");


    )


    WebSecurityConfig.java



    import java.io.IOException;


    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.context.annotation.Bean;

    import org.springframework.context.annotation.Configuration;

    import org.springframework.security.authentication.AuthenticationManager;

    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.AuthenticationException;

    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter

    @Autowired
    private UserDetailsService userDetailsService;

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


    @Bean
    public AuthenticationManager getAuthenticationManager() throws Exception
    return super.authenticationManagerBean();



    @Autowired
    AuthenticationSuccessHandler authenticationSuccessHandler;

    @Autowired()
    AuthenicationProviderJdbcImpl authenicationProviderJdbcImpl;

    @Autowired()
    AuthenicationProviderLdapImpl authenicationProviderLdapImpl;


    @Autowired
    CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter;


    @Override
    protected void configure(HttpSecurity http) throws Exception
    http.addFilterAt(customUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

    http
    .authorizeRequests()
    .antMatchers("/resources/**", "/registration","/login1").permitAll()
    .anyRequest().authenticated()
    .and()
    .formLogin()
    .loginPage("/login")
    .permitAll()//.successHandler(authenticationSuccessHandler)
    .failureHandler(new AuthenticationFailureHandler()

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
    AuthenticationException exception) throws IOException, ServletException
    String whichPage = request.getParameter("whichPage");
    System.out.println("inside login failure handler "+whichPage);
    if("login1".equals(whichPage))
    response.sendRedirect(request.getContextPath() +"/login1");
    else
    response.sendRedirect(request.getContextPath() +"/login");


    )
    .and()
    .logout()
    .permitAll();


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    auth.authenticationProvider(authenicationProviderLdapImpl).authenticationProvider(authenicationProviderJdbcImpl);





    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
    /*auth.userDetailsService(userDetailsService)
    .passwordEncoder(bCryptPasswordEncoder());*/





    The below is from logs when authType = jdbc or authType=ldap



    login called
    2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] stomUsernamePasswordAuthenticationFilter : authType jdbc
    2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : authType jdbc
    2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom jdbc authentication
    login called
    login1 called
    login1 called
    2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] stomUsernamePasswordAuthenticationFilter : authType ldap
    2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : authType ldap
    2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom ldap authentication returning true in ldap





    share|improve this answer





























      2





      +25









      If you look at code in UsernamePasswordAuthenticationFilter there is setDetails method.



      from docs:




      Provided so that subclasses may configure what is put into the
      authentication request's details property.




      Idea from here
      Provision to change ldap/Ad provider url at run time



      You can set the details like authtype here and use it authentication provider, But to achieve the things you would lik adds little more work.



      Adding details and hope it helps.



      CustomUsernamePasswordAuthenticationFilter.java



      import javax.servlet.http.HttpServletRequest;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.security.authentication.AuthenticationDetailsSource;
      import org.springframework.security.authentication.AuthenticationManager;
      import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
      import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
      import org.springframework.stereotype.Component;

      @Component
      public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter

      private static final Logger logger = LoggerFactory.getLogger(CustomUsernamePasswordAuthenticationFilter.class);

      @Autowired
      @Override
      public void setAuthenticationManager(AuthenticationManager authenticationManager)
      // TODO Auto-generated method stub
      super.setAuthenticationManager(authenticationManager);


      @Autowired
      @Override
      public void setAuthenticationDetailsSource(
      AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource)
      super.setAuthenticationDetailsSource(authenticationDetailsSource);


      @Override
      protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest)
      String authType = request.getParameter("authType");
      logger.info("authType ",authType);
      authRequest.setDetails(authenticationDetailsSource.buildDetails(request));





      But this is not sufficient you would need to extend WebAuthenticationDetails.



      Reason is WebAuthenticationDetails provides only remote IP address and sessionId so, to add authType we need to extend this class.



      You have to extend WebAuthenticationDetailsSource to return CustomAuthenticationDetails as shown below.



      CustomAuthenticationDetails.java



      public class CustomAuthenticationDetails extends WebAuthenticationDetails


      private final String authType;

      public CustomAuthenticationDetails(HttpServletRequest request)
      super(request);
      authType = request.getParameter("authType");


      public String getAuthType()
      return authType;




      CustomWebAuthenticationDetailsSource.java



      public class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource 

      @Override
      public WebAuthenticationDetails buildDetails(HttpServletRequest context)
      return new CustomAuthenticationDetails(context);





      Please note these classes for demo purpose only.



      Need to autowire actual authentication providers in these classes.



      import java.util.Arrays;
      import java.util.List;

      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.security.authentication.AuthenticationProvider;
      import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
      import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
      import org.springframework.security.core.Authentication;
      import org.springframework.security.core.AuthenticationException;
      import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
      import org.springframework.stereotype.Component;

      @Component
      public class AuthenicationProviderJdbcLdapImpl implements AuthenticationProvider

      // you need to autowire jdbc auth provider
      @Autowired(required = false)
      DaoAuthenticationProvider authenticationProvider;

      //you need to autowire ldap auth provider
      @Autowired(required = false)
      LdapAuthenticationProvider ldapAuthenticationProvider;



      protected static class User
      private final String userId;
      private final String password;
      public User(String userId,String password)
      this.userId = userId;
      this.password = password;

      public String getUserId()
      return userId;

      public String getPassword()
      return password;

      @Override
      public String toString()
      return "User [userId=" + userId + ", password=" + password + "]";



      private final static Logger logger = LoggerFactory.getLogger(AuthenicationProviderJdbcLdapImpl.class);
      private static final List<User> users1 = Arrays.asList(new User("admin1", "password"),new User("admin2", "password"));
      private static final List<User> users2 = Arrays.asList(new User("admin3", "password"),new User("admin4", "password"));

      @Override
      public Authentication authenticate(Authentication authentication) throws AuthenticationException

      CustomAuthenticationDetails details = (CustomAuthenticationDetails) authentication.getDetails();

      String authType = details.getAuthType();
      logger.info("authType ",authType);
      if("jdbc".equalsIgnoreCase(authType))
      logger.info("perfrom jdbc authentication");

      //perform your authentication using jdbc
      //the below is just for explaination

      return performAuthentication(authentication, users1);

      else if("ldap".equalsIgnoreCase(authType))
      logger.info("perfrom ldap authentication");

      //perform your authentication using ldap
      //the below is just for explaination

      return performAuthentication(authentication, users2);


      return null;


      private Authentication performAuthentication(Authentication authentication,List<User> users)
      String credential = (String) authentication.getCredentials();
      String userId = authentication.getName();
      for(User user: users)
      if(user.getUserId().equals(userId)&& user.getPassword().equals(credential))
      authentication = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),authentication.getAuthorities());

      return authentication;


      return null;

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







      If you would need to redirect different login page (not sure, if you have the requirement) you register AuthenticationFailureHandler shown in security config. Here it is redirected to login and login1 based on condition.



      http.failureHandler(new AuthenticationFailureHandler() 

      @Override
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException exception) throws IOException, ServletException
      String whichPage = request.getParameter("whichPage");
      System.out.println("inside login failure handler "+whichPage);
      if("login1".equals(whichPage))
      response.sendRedirect(request.getContextPath() +"/login1");
      else
      response.sendRedirect(request.getContextPath() +"/login");


      )


      WebSecurityConfig.java



      import java.io.IOException;


      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;

      import org.springframework.beans.factory.annotation.Autowired;

      import org.springframework.context.annotation.Bean;

      import org.springframework.context.annotation.Configuration;

      import org.springframework.security.authentication.AuthenticationManager;

      import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

      import org.springframework.security.config.annotation.web.builders.HttpSecurity;
      import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.security.core.AuthenticationException;

      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.web.authentication.AuthenticationFailureHandler;
      import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
      import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

      @Configuration
      @EnableWebSecurity
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter

      @Autowired
      private UserDetailsService userDetailsService;

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


      @Bean
      public AuthenticationManager getAuthenticationManager() throws Exception
      return super.authenticationManagerBean();



      @Autowired
      AuthenticationSuccessHandler authenticationSuccessHandler;

      @Autowired()
      AuthenicationProviderJdbcImpl authenicationProviderJdbcImpl;

      @Autowired()
      AuthenicationProviderLdapImpl authenicationProviderLdapImpl;


      @Autowired
      CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter;


      @Override
      protected void configure(HttpSecurity http) throws Exception
      http.addFilterAt(customUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

      http
      .authorizeRequests()
      .antMatchers("/resources/**", "/registration","/login1").permitAll()
      .anyRequest().authenticated()
      .and()
      .formLogin()
      .loginPage("/login")
      .permitAll()//.successHandler(authenticationSuccessHandler)
      .failureHandler(new AuthenticationFailureHandler()

      @Override
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException exception) throws IOException, ServletException
      String whichPage = request.getParameter("whichPage");
      System.out.println("inside login failure handler "+whichPage);
      if("login1".equals(whichPage))
      response.sendRedirect(request.getContextPath() +"/login1");
      else
      response.sendRedirect(request.getContextPath() +"/login");


      )
      .and()
      .logout()
      .permitAll();


      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception
      auth.authenticationProvider(authenicationProviderLdapImpl).authenticationProvider(authenicationProviderJdbcImpl);





      @Autowired
      public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
      /*auth.userDetailsService(userDetailsService)
      .passwordEncoder(bCryptPasswordEncoder());*/





      The below is from logs when authType = jdbc or authType=ldap



      login called
      2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] stomUsernamePasswordAuthenticationFilter : authType jdbc
      2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : authType jdbc
      2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom jdbc authentication
      login called
      login1 called
      login1 called
      2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] stomUsernamePasswordAuthenticationFilter : authType ldap
      2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : authType ldap
      2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom ldap authentication returning true in ldap





      share|improve this answer



























        2





        +25







        2





        +25



        2




        +25





        If you look at code in UsernamePasswordAuthenticationFilter there is setDetails method.



        from docs:




        Provided so that subclasses may configure what is put into the
        authentication request's details property.




        Idea from here
        Provision to change ldap/Ad provider url at run time



        You can set the details like authtype here and use it authentication provider, But to achieve the things you would lik adds little more work.



        Adding details and hope it helps.



        CustomUsernamePasswordAuthenticationFilter.java



        import javax.servlet.http.HttpServletRequest;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.security.authentication.AuthenticationDetailsSource;
        import org.springframework.security.authentication.AuthenticationManager;
        import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
        import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
        import org.springframework.stereotype.Component;

        @Component
        public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter

        private static final Logger logger = LoggerFactory.getLogger(CustomUsernamePasswordAuthenticationFilter.class);

        @Autowired
        @Override
        public void setAuthenticationManager(AuthenticationManager authenticationManager)
        // TODO Auto-generated method stub
        super.setAuthenticationManager(authenticationManager);


        @Autowired
        @Override
        public void setAuthenticationDetailsSource(
        AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource)
        super.setAuthenticationDetailsSource(authenticationDetailsSource);


        @Override
        protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest)
        String authType = request.getParameter("authType");
        logger.info("authType ",authType);
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));





        But this is not sufficient you would need to extend WebAuthenticationDetails.



        Reason is WebAuthenticationDetails provides only remote IP address and sessionId so, to add authType we need to extend this class.



        You have to extend WebAuthenticationDetailsSource to return CustomAuthenticationDetails as shown below.



        CustomAuthenticationDetails.java



        public class CustomAuthenticationDetails extends WebAuthenticationDetails


        private final String authType;

        public CustomAuthenticationDetails(HttpServletRequest request)
        super(request);
        authType = request.getParameter("authType");


        public String getAuthType()
        return authType;




        CustomWebAuthenticationDetailsSource.java



        public class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource 

        @Override
        public WebAuthenticationDetails buildDetails(HttpServletRequest context)
        return new CustomAuthenticationDetails(context);





        Please note these classes for demo purpose only.



        Need to autowire actual authentication providers in these classes.



        import java.util.Arrays;
        import java.util.List;

        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.security.authentication.AuthenticationProvider;
        import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
        import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
        import org.springframework.security.core.Authentication;
        import org.springframework.security.core.AuthenticationException;
        import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
        import org.springframework.stereotype.Component;

        @Component
        public class AuthenicationProviderJdbcLdapImpl implements AuthenticationProvider

        // you need to autowire jdbc auth provider
        @Autowired(required = false)
        DaoAuthenticationProvider authenticationProvider;

        //you need to autowire ldap auth provider
        @Autowired(required = false)
        LdapAuthenticationProvider ldapAuthenticationProvider;



        protected static class User
        private final String userId;
        private final String password;
        public User(String userId,String password)
        this.userId = userId;
        this.password = password;

        public String getUserId()
        return userId;

        public String getPassword()
        return password;

        @Override
        public String toString()
        return "User [userId=" + userId + ", password=" + password + "]";



        private final static Logger logger = LoggerFactory.getLogger(AuthenicationProviderJdbcLdapImpl.class);
        private static final List<User> users1 = Arrays.asList(new User("admin1", "password"),new User("admin2", "password"));
        private static final List<User> users2 = Arrays.asList(new User("admin3", "password"),new User("admin4", "password"));

        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException

        CustomAuthenticationDetails details = (CustomAuthenticationDetails) authentication.getDetails();

        String authType = details.getAuthType();
        logger.info("authType ",authType);
        if("jdbc".equalsIgnoreCase(authType))
        logger.info("perfrom jdbc authentication");

        //perform your authentication using jdbc
        //the below is just for explaination

        return performAuthentication(authentication, users1);

        else if("ldap".equalsIgnoreCase(authType))
        logger.info("perfrom ldap authentication");

        //perform your authentication using ldap
        //the below is just for explaination

        return performAuthentication(authentication, users2);


        return null;


        private Authentication performAuthentication(Authentication authentication,List<User> users)
        String credential = (String) authentication.getCredentials();
        String userId = authentication.getName();
        for(User user: users)
        if(user.getUserId().equals(userId)&& user.getPassword().equals(credential))
        authentication = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),authentication.getAuthorities());

        return authentication;


        return null;

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







        If you would need to redirect different login page (not sure, if you have the requirement) you register AuthenticationFailureHandler shown in security config. Here it is redirected to login and login1 based on condition.



        http.failureHandler(new AuthenticationFailureHandler() 

        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException
        String whichPage = request.getParameter("whichPage");
        System.out.println("inside login failure handler "+whichPage);
        if("login1".equals(whichPage))
        response.sendRedirect(request.getContextPath() +"/login1");
        else
        response.sendRedirect(request.getContextPath() +"/login");


        )


        WebSecurityConfig.java



        import java.io.IOException;


        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;

        import org.springframework.beans.factory.annotation.Autowired;

        import org.springframework.context.annotation.Bean;

        import org.springframework.context.annotation.Configuration;

        import org.springframework.security.authentication.AuthenticationManager;

        import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

        import org.springframework.security.config.annotation.web.builders.HttpSecurity;
        import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
        import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
        import org.springframework.security.core.AuthenticationException;

        import org.springframework.security.core.userdetails.UserDetailsService;
        import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
        import org.springframework.security.web.authentication.AuthenticationFailureHandler;
        import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
        import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

        @Configuration
        @EnableWebSecurity
        public class WebSecurityConfig extends WebSecurityConfigurerAdapter

        @Autowired
        private UserDetailsService userDetailsService;

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


        @Bean
        public AuthenticationManager getAuthenticationManager() throws Exception
        return super.authenticationManagerBean();



        @Autowired
        AuthenticationSuccessHandler authenticationSuccessHandler;

        @Autowired()
        AuthenicationProviderJdbcImpl authenicationProviderJdbcImpl;

        @Autowired()
        AuthenicationProviderLdapImpl authenicationProviderLdapImpl;


        @Autowired
        CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter;


        @Override
        protected void configure(HttpSecurity http) throws Exception
        http.addFilterAt(customUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        http
        .authorizeRequests()
        .antMatchers("/resources/**", "/registration","/login1").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login")
        .permitAll()//.successHandler(authenticationSuccessHandler)
        .failureHandler(new AuthenticationFailureHandler()

        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException
        String whichPage = request.getParameter("whichPage");
        System.out.println("inside login failure handler "+whichPage);
        if("login1".equals(whichPage))
        response.sendRedirect(request.getContextPath() +"/login1");
        else
        response.sendRedirect(request.getContextPath() +"/login");


        )
        .and()
        .logout()
        .permitAll();


        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception
        auth.authenticationProvider(authenicationProviderLdapImpl).authenticationProvider(authenicationProviderJdbcImpl);





        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
        /*auth.userDetailsService(userDetailsService)
        .passwordEncoder(bCryptPasswordEncoder());*/





        The below is from logs when authType = jdbc or authType=ldap



        login called
        2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] stomUsernamePasswordAuthenticationFilter : authType jdbc
        2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : authType jdbc
        2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom jdbc authentication
        login called
        login1 called
        login1 called
        2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] stomUsernamePasswordAuthenticationFilter : authType ldap
        2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : authType ldap
        2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom ldap authentication returning true in ldap





        share|improve this answer















        If you look at code in UsernamePasswordAuthenticationFilter there is setDetails method.



        from docs:




        Provided so that subclasses may configure what is put into the
        authentication request's details property.




        Idea from here
        Provision to change ldap/Ad provider url at run time



        You can set the details like authtype here and use it authentication provider, But to achieve the things you would lik adds little more work.



        Adding details and hope it helps.



        CustomUsernamePasswordAuthenticationFilter.java



        import javax.servlet.http.HttpServletRequest;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.security.authentication.AuthenticationDetailsSource;
        import org.springframework.security.authentication.AuthenticationManager;
        import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
        import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
        import org.springframework.stereotype.Component;

        @Component
        public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter

        private static final Logger logger = LoggerFactory.getLogger(CustomUsernamePasswordAuthenticationFilter.class);

        @Autowired
        @Override
        public void setAuthenticationManager(AuthenticationManager authenticationManager)
        // TODO Auto-generated method stub
        super.setAuthenticationManager(authenticationManager);


        @Autowired
        @Override
        public void setAuthenticationDetailsSource(
        AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource)
        super.setAuthenticationDetailsSource(authenticationDetailsSource);


        @Override
        protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest)
        String authType = request.getParameter("authType");
        logger.info("authType ",authType);
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));





        But this is not sufficient you would need to extend WebAuthenticationDetails.



        Reason is WebAuthenticationDetails provides only remote IP address and sessionId so, to add authType we need to extend this class.



        You have to extend WebAuthenticationDetailsSource to return CustomAuthenticationDetails as shown below.



        CustomAuthenticationDetails.java



        public class CustomAuthenticationDetails extends WebAuthenticationDetails


        private final String authType;

        public CustomAuthenticationDetails(HttpServletRequest request)
        super(request);
        authType = request.getParameter("authType");


        public String getAuthType()
        return authType;




        CustomWebAuthenticationDetailsSource.java



        public class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource 

        @Override
        public WebAuthenticationDetails buildDetails(HttpServletRequest context)
        return new CustomAuthenticationDetails(context);





        Please note these classes for demo purpose only.



        Need to autowire actual authentication providers in these classes.



        import java.util.Arrays;
        import java.util.List;

        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.security.authentication.AuthenticationProvider;
        import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
        import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
        import org.springframework.security.core.Authentication;
        import org.springframework.security.core.AuthenticationException;
        import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
        import org.springframework.stereotype.Component;

        @Component
        public class AuthenicationProviderJdbcLdapImpl implements AuthenticationProvider

        // you need to autowire jdbc auth provider
        @Autowired(required = false)
        DaoAuthenticationProvider authenticationProvider;

        //you need to autowire ldap auth provider
        @Autowired(required = false)
        LdapAuthenticationProvider ldapAuthenticationProvider;



        protected static class User
        private final String userId;
        private final String password;
        public User(String userId,String password)
        this.userId = userId;
        this.password = password;

        public String getUserId()
        return userId;

        public String getPassword()
        return password;

        @Override
        public String toString()
        return "User [userId=" + userId + ", password=" + password + "]";



        private final static Logger logger = LoggerFactory.getLogger(AuthenicationProviderJdbcLdapImpl.class);
        private static final List<User> users1 = Arrays.asList(new User("admin1", "password"),new User("admin2", "password"));
        private static final List<User> users2 = Arrays.asList(new User("admin3", "password"),new User("admin4", "password"));

        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException

        CustomAuthenticationDetails details = (CustomAuthenticationDetails) authentication.getDetails();

        String authType = details.getAuthType();
        logger.info("authType ",authType);
        if("jdbc".equalsIgnoreCase(authType))
        logger.info("perfrom jdbc authentication");

        //perform your authentication using jdbc
        //the below is just for explaination

        return performAuthentication(authentication, users1);

        else if("ldap".equalsIgnoreCase(authType))
        logger.info("perfrom ldap authentication");

        //perform your authentication using ldap
        //the below is just for explaination

        return performAuthentication(authentication, users2);


        return null;


        private Authentication performAuthentication(Authentication authentication,List<User> users)
        String credential = (String) authentication.getCredentials();
        String userId = authentication.getName();
        for(User user: users)
        if(user.getUserId().equals(userId)&& user.getPassword().equals(credential))
        authentication = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),authentication.getAuthorities());

        return authentication;


        return null;

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







        If you would need to redirect different login page (not sure, if you have the requirement) you register AuthenticationFailureHandler shown in security config. Here it is redirected to login and login1 based on condition.



        http.failureHandler(new AuthenticationFailureHandler() 

        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException
        String whichPage = request.getParameter("whichPage");
        System.out.println("inside login failure handler "+whichPage);
        if("login1".equals(whichPage))
        response.sendRedirect(request.getContextPath() +"/login1");
        else
        response.sendRedirect(request.getContextPath() +"/login");


        )


        WebSecurityConfig.java



        import java.io.IOException;


        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;

        import org.springframework.beans.factory.annotation.Autowired;

        import org.springframework.context.annotation.Bean;

        import org.springframework.context.annotation.Configuration;

        import org.springframework.security.authentication.AuthenticationManager;

        import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

        import org.springframework.security.config.annotation.web.builders.HttpSecurity;
        import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
        import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
        import org.springframework.security.core.AuthenticationException;

        import org.springframework.security.core.userdetails.UserDetailsService;
        import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
        import org.springframework.security.web.authentication.AuthenticationFailureHandler;
        import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
        import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

        @Configuration
        @EnableWebSecurity
        public class WebSecurityConfig extends WebSecurityConfigurerAdapter

        @Autowired
        private UserDetailsService userDetailsService;

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


        @Bean
        public AuthenticationManager getAuthenticationManager() throws Exception
        return super.authenticationManagerBean();



        @Autowired
        AuthenticationSuccessHandler authenticationSuccessHandler;

        @Autowired()
        AuthenicationProviderJdbcImpl authenicationProviderJdbcImpl;

        @Autowired()
        AuthenicationProviderLdapImpl authenicationProviderLdapImpl;


        @Autowired
        CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter;


        @Override
        protected void configure(HttpSecurity http) throws Exception
        http.addFilterAt(customUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        http
        .authorizeRequests()
        .antMatchers("/resources/**", "/registration","/login1").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login")
        .permitAll()//.successHandler(authenticationSuccessHandler)
        .failureHandler(new AuthenticationFailureHandler()

        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException
        String whichPage = request.getParameter("whichPage");
        System.out.println("inside login failure handler "+whichPage);
        if("login1".equals(whichPage))
        response.sendRedirect(request.getContextPath() +"/login1");
        else
        response.sendRedirect(request.getContextPath() +"/login");


        )
        .and()
        .logout()
        .permitAll();


        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception
        auth.authenticationProvider(authenicationProviderLdapImpl).authenticationProvider(authenicationProviderJdbcImpl);





        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
        /*auth.userDetailsService(userDetailsService)
        .passwordEncoder(bCryptPasswordEncoder());*/





        The below is from logs when authType = jdbc or authType=ldap



        login called
        2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] stomUsernamePasswordAuthenticationFilter : authType jdbc
        2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : authType jdbc
        2018-11-23 17:45:25.606 INFO 7232 --- [nio-8080-exec-6] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom jdbc authentication
        login called
        login1 called
        login1 called
        2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] stomUsernamePasswordAuthenticationFilter : authType ldap
        2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : authType ldap
        2018-11-23 17:45:42.435 INFO 7232 --- [nio-8080-exec-5] c.t.a.AuthenicationProviderJdbcLdapImpl : perfrom ldap authentication returning true in ldap






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 23 '18 at 12:17

























        answered Nov 19 '18 at 10:23









        secret super starsecret super star

        977114




        977114



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53275645%2fselection-based-authprovider-spring-security%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Use pre created SQLite database for Android project in kotlin

            Darth Vader #20

            Ondo