Selection based AuthProvider Spring Security











up vote
3
down vote

favorite
1












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

















This question had a bounty worth +50
reputation from Akhil K Nambiar that ended 20 hours ago. Grace period ends in 3 hours


This question has not received enough attention.


I am able to get both provider running together in order. But am not able to get the two providers running based on option from a login page to select between those.
















  • 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 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 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.
    – shadow
    Nov 22 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 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 at 11:54















up vote
3
down vote

favorite
1












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

















This question had a bounty worth +50
reputation from Akhil K Nambiar that ended 20 hours ago. Grace period ends in 3 hours


This question has not received enough attention.


I am able to get both provider running together in order. But am not able to get the two providers running based on option from a login page to select between those.
















  • 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 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 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.
    – shadow
    Nov 22 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 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 at 11:54













up vote
3
down vote

favorite
1









up vote
3
down vote

favorite
1






1





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 at 6:52

























asked Nov 13 at 7:10









Akhil K Nambiar

1,706113773




1,706113773






This question had a bounty worth +50
reputation from Akhil K Nambiar that ended 20 hours ago. Grace period ends in 3 hours


This question has not received enough attention.


I am able to get both provider running together in order. But am not able to get the two providers running based on option from a login page to select between those.








This question had a bounty worth +50
reputation from Akhil K Nambiar that ended 20 hours ago. Grace period ends in 3 hours


This question has not received enough attention.


I am able to get both provider running together in order. But am not able to get the two providers running based on option from a login page to select between those.














  • 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 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 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.
    – shadow
    Nov 22 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 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 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 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 at 11:05












  • <intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.
    – shadow
    Nov 22 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 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 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 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 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 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 at 11:05














<intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.
– shadow
Nov 22 at 5:47






<intercept-url pattern="/home*" access="permitAll" /> this will allow users to enter that page with out authentication.
– shadow
Nov 22 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 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 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 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 at 11:54












1 Answer
1






active

oldest

votes

















up vote
2
down vote













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',
    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








    up vote
    2
    down vote













    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



























      up vote
      2
      down vote













      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

























        up vote
        2
        down vote










        up vote
        2
        down vote









        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 at 12:17

























        answered Nov 19 at 10:23









        secret super star

        59011




        59011






























             

            draft saved


            draft discarded



















































             


            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

            Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

            ComboBox Display Member on multiple fields

            Is it possible to collect Nectar points via Trainline?