3
votes

I am working on one project where I am using Spring Security and it authenticates user nicely from DB.

Now my need is I want to authenticate user using LDAP and Keep existing DB authentication as well.

Also, I can't use standard LDAP authentication way by using Spring security because I only have one function call to authenticate whether user is present or not by method like,

        com.company.ldap.Authentication  auth = new com.company.ldap.Authentication();
        int status = auth.authenticate(userName, userPassword);

if I receive the status as 1 then user is authenticated otherwise not.

So for this scenario, I have created seperate url "/j_spring_facebook_security_check" (here name is facebook but actually it is for LDAP)

My applicationContext-Security File

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <security:http auto-config="true" use-expressions="true" access-denied-page="/accessDenied.jsp">

        <security:form-login login-page="/index.jsp"
            default-target-url="/jsp/home.jsp"
            authentication-failure-handler-ref="authenticationFailureHandler" />


        <security:intercept-url pattern="/jsp/listInBetweenPlaces.jsp"
            access="permitAll" />

        <security:intercept-url pattern="/jsp/home.jsp"
            access="permitAll" />


        <security:intercept-url pattern="/jsp/*"
            access="isAuthenticated()" />


        <security:logout logout-url="/j_spring_security_logout" logout-success-url="/index.jsp?logout=success" 
            invalidate-session="true"  />


    <security:custom-filter before="FORM_LOGIN_FILTER"
            ref="facebookAuthenticationFilter" />

    </security:http> 



    <bean id="facebookAuthenticationFilter" class="org.springframework.security.facebook.FacebookAuthenticationFilter">
      <property name="authenticationManager" ref="authenticationManager"/>

       <property  name = "authenticationSuccessHandler">
         <bean  class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
           <property  name = "defaultTargetUrl"  value = "/jsp/home.jsp"  />
           <property  name = "alwaysUseDefaultTargetUrl"  value = "true"  />
         </bean>
       </property>

       <property  name = "authenticationFailureHandler">
        <bean  class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
            <property  name = "defaultFailureUrl"  value = "/fb/failure.jsp"  />
        </bean>
       </property>

    </bean>




    <bean id="ldapAuthenticationProvider"  class="org.springframework.security.facebook.FacebookAuthenticationProvider">
        <property name="roles" value="ROLE_FACEBOOK_USER" />
    </bean>


    <security:authentication-manager alias="authenticationManager">  

        <security:authentication-provider user-service-ref="customUserDetailsService">
            <security:password-encoder hash="md5" />
        </security:authentication-provider>

        <security:authentication-provider ref="ldapAuthenticationProvider">
        </security:authentication-provider>

    </security:authentication-manager>




    <bean id="customUserDetailsService" class="com.abc.carpool.authentication.CustomUserDetailsService">
    </bean>

</beans>

FacebookAuthenticationFilter.java

public class FacebookAuthenticationFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {

    @Autowired
    CarpoolService carpoolService=null;

    public CarpoolService getCarpoolService() {
        return carpoolService;
    }
    public void setCarpoolService(CarpoolService carpoolService) {
        this.carpoolService = carpoolService;
    }


    public static final String DEFAULT_FILTER_PROCESS_URL = "/j_spring_facebook_security_check";

    private ApplicationContext ctx;
    protected FacebookAuthenticationFilter() {
        super(DEFAULT_FILTER_PROCESS_URL);
    }

    public Authentication attemptAuthentication(HttpServletRequest req,
            HttpServletResponse res) throws AuthenticationException,
            IOException, ServletException {


        HttpServletRequest request = (HttpServletRequest) req;

        String userName = request.getParameter("j_username");
        String userPassword = request.getParameter("j_password");


        System.out.println("Username and pswd is :"+userName + " " + userPassword);
        System.out.println("SYS PATH :"+System.getenv("MC_ENV_PATH"));

        User user = null;

        try{
            com.abc.ldap.Authentication  auth = new com.abc.ldap.Authentication();

            int status = auth.authenticate(userName, userPassword);

            //int status=2;
            if(status==1){

//CREATE NEW USER AND SAVE IN DB                    



                }

            }else{
                throw new UsernameNotFoundException("Incorrect Email Id or Password.");
            }

            System.out.println("status is :"+status);
        }catch (Exception e) {
            System.out.println("Exception is "+e.getMessage());
            e.printStackTrace();
            return null;
        }

        System.out.println("FacebookAuthenticationFilter.attemptAuthentication() :"+userName + " " + userPassword);     


        UsernamePasswordAuthenticationToken upatToken = new UsernamePasswordAuthenticationToken(userName, userPassword);
        AuthenticationManager authenticationManager = getAuthenticationManager();
        Authentication auth = authenticationManager.authenticate(upatToken);

        return auth;
    }

    public void setApplicationContext(ApplicationContext ctx)
            throws BeansException {
        this.ctx = ctx;
    }


}

FacebookAuthenticationProvider .java

public class FacebookAuthenticationProvider implements AuthenticationProvider {

    private String[] roles;

    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {

        System.out.println("FacebookAuthenticationProvider.authenticate()");

        return authentication;
    }

    public boolean supports(Class<? extends Object> authentication) {
        boolean supports = true;
        return supports;
    }

    public void setRoles(String[] roles) {
        this.roles = roles;
    }

    public String[] getRoles() {
        return roles;
    }
}

In the above case things are working fine, Control is going to Filter class and verifying for user using LDAP and if user is present then I am saving user one copy to my DB and want to go ahead with normal flow.

actually when I call

Authentication auth = authenticationManager.authenticate(upatToken);

from FacebookAuthenticationFilter, control, goes to CustomUserDetailsService class.

My need is CustomUserDetailsService is only for DB authentication, I don't want control to go there.

How to achieve this thing in a nice way.

1

1 Answers

0
votes

AuthenticationProvider.supports(Class<? extends Object> authentication) can help you. At this moment you use UsernamePasswordAuthenticationToken for both cases (DB and LDAP). Both authentication providers supports this type so both are used. In a case of LDAP try to add your custom authentication object:

public class CustomLdapAuthenticationToken extends AbstractAuthenticationToken {

Then use it in your FacebookAuthenticationFilter instead of UsernamePasswordAuthenticationToken.

Change your FacebookAuthenticationProvider.supports(...) implementation:

public boolean supports(Class<? extends Object> authentication) {
    boolean result = false;
    if(authentication instanceof CustomLdapAuthenticationToken) {
        result = true;
    }
    return result;
}

From this moment each authentication provider will process only corresponding authentication request.