Configuring Spring Security 3.x to have multiple entry points

I used Spring Security 3.x to handle user authentication for my projects, and so far it has worked flawlessly.

I recently received requirements for a new project. This project requires two sets of user authentication: one for authenticating employees using LDAP, and the other for authenticating the client against the database. I am a little puzzled by how to configure this in Spring Security.

My initial idea was to create a login screen that has the following fields: -

  • radio button - for users to choose whether they are employees or customers.
  • j_username user field.
  • j_password password field.

If the user selects "employee", then I want Spring Security to validate them for LDAP, otherwise the credentials will be authenticated against the database. However, the problem is that the form will be submitted to /j_spring_security_check and I will not be able to submit the switch field to my implemented custom authentication provider. My initial thought is that I probably need two submit URLs, not the default /j_spring_security_check . Each URL will be handled by different authentication providers, but I'm not sure how to configure it in Spring Security.

I know in Spring security, I can configure return authentication, for example, if LDAP authentication fails, then it will return to database authentication, but this is not what I am shooting in this new project.

Can someone share how exactly should I configure this in Spring Security 3.x?

Thank.




UPDATE - 01-28-2011 - Technique @EasyAngel

I am trying to do the following: -

  • Login for employee form is sent to /j_spring_security_check_for_employee
  • Login to the client form is sent to /j_spring_security_check_for_customer

The reason I want 2 different logins is to let me handle authentication differently based on the user, instead of having to authenticate with a return. Perhaps the employee and client have the same user ID, in my case.

I included the idea of ​​@EasyAngel, but I need to replace some obsolete classes. The problem I'm currently facing is neither filtering processes, nor URLs that look like URLs in Spring Security because I keep getting Error 404: SRVE0190E: File not found: /j_spring_security_check_for_employee . The feeling of my intestines springSecurityFilterChain bean is not connected properly, so my custom filters are not used at all.

By the way, I use WebSphere, and I have the com.ibm.ws.webcontainer.invokefilterscompatibility=true property set on the server. I can hit default /j_spring_security_check without problems.

Here is my full security configuration: -

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="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.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <sec:http auto-config="true"> <sec:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" default-target-url="/welcome.jsp" always-use-default-target="true" /> <sec:logout logout-success-url="/login.jsp" /> <sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE" /> <sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER" /> <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> </sec:http> <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> <sec:filter-chain-map path-type="ant"> <sec:filter-chain pattern="/**" filters="authenticationProcessingFilterForEmployee, authenticationProcessingFilterForCustomer" /> </sec:filter-chain-map> </bean> <bean id="authenticationProcessingFilterForEmployee" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManagerForEmployee" /> <property name="filterProcessesUrl" value="/j_spring_security_check_for_employee" /> </bean> <bean id="authenticationProcessingFilterForCustomer" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManagerForCustomer" /> <property name="filterProcessesUrl" value="/j_spring_security_check_for_customer" /> </bean> <bean id="authenticationManagerForEmployee" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <ref bean="employeeCustomAuthenticationProvider" /> </list> </property> </bean> <bean id="authenticationManagerForCustomer" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <ref bean="customerCustomAuthenticationProvider" /> </list> </property> </bean> <bean id="employeeCustomAuthenticationProvider" class="ss.EmployeeCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.EmployeeUserDetailsService"/> </property> </bean> <bean id="customerCustomAuthenticationProvider" class="ss.CustomerCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.CustomerUserDetailsService"/> </property> </bean> <sec:authentication-manager> <sec:authentication-provider ref="employeeCustomAuthenticationProvider" /> <sec:authentication-provider ref="customerCustomAuthenticationProvider" /> </sec:authentication-manager> </beans> 

I start generosity here because I can’t get this work to work for several days ... disappointment is the word. I hope someone points out the problem (s), or if you can show me a better or cleaner way to handle this (in code).

I am using Spring Security 3.x.

Thank.




UPDATE 01-29-2011 - @Ritesh appliances

Well, I managed to get @Ritesh's approach to work very close to what I wanted. I have a radio alarm clock that allows the user to choose whether they are a client or an employee. This approach seems to work quite well, with one problem ...

  • If an employee is registered with access rights, they are allowed in ... WORK AS EXPECTED .
  • If an employee logs in with incorrect credentials, they are not allowed in ... WORK AS EXPECTED .
  • If the client is registered with access rights, they are allowed in ... WORK AS EXPECTED .
  • If the client registers with the wrong credentials, authentication returns to the employee check ... DOES NOT WORK . This is dangerous because if I select the client authentication and click on the credentials of the employee, it will also allow the user, and this is not what I want.
  <sec:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint"> <sec:logout logout-success-url="/login.jsp"/> <sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE"/> <sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER"/> <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <sec:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthenticationFilter"/> </sec:http> <bean id="myAuthenticationFilter" class="ss.MyAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationFailureHandler" ref="failureHandler"/> <property name="authenticationSuccessHandler" ref="successHandler"/> </bean> <bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp"/> </bean> <bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <property name="defaultTargetUrl" value="/welcome.jsp"/> <property name="alwaysUseDefaultTargetUrl" value="true"/> </bean> <bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <property name="defaultFailureUrl" value="/login.jsp?login_error=1"/> </bean> <bean id="employeeCustomAuthenticationProvider" class="ss.EmployeeCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.EmployeeUserDetailsService"/> </property> </bean> <bean id="customerCustomAuthenticationProvider" class="ss.CustomerCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.CustomerUserDetailsService"/> </property> </bean> <sec:authentication-manager alias="authenticationManager"> <sec:authentication-provider ref="customerCustomAuthenticationProvider"/> <sec:authentication-provider ref="employeeCustomAuthenticationProvider"/> </sec:authentication-manager> </beans> 

Here is my updated configuration. It must be some very small setting that I need to do to prevent authentication, but I can’t figure it out right now.

Thank.

UPDATE - SOLUTION to @Ritesh Method

Ok, I think I solved the problem here. Instead of having EmployeeCustomAuthenticationProvider rely on the default UsernamePasswordAuthenticationToken , I created an EmployeeUsernamePasswordAuthenticationToken for it, like the one I created CustomerUsernamePasswordAuthenticationToken for CustomerCustomAuthenticationProvider . These providers then override supports() : -

Class CustomerCustomAuthenticationProvider

 @Override public boolean supports(Class<? extends Object> authentication) { return (CustomerUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } 

Class EmployeeCustomAuthenticationProvider

 @Override public boolean supports(Class<? extends Object> authentication) { return (EmployeeUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } 

Class MyAuthenticationFilter

 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { ... UsernamePasswordAuthenticationToken authRequest = null; if ("customer".equals(request.getParameter("radioAuthenticationType"))) { authRequest = new CustomerUsernamePasswordAuthenticationToken(username, password); } else { authRequest = new EmployeeUsernamePasswordAuthenticationToken(username, password); } setDetails(request, authRequest); return super.getAuthenticationManager().authenticate(authRequest); } 

... and WALAA! It works great after a few days of frustration!

Hope this post can help someone who does the same thing as me here.

+64
java spring authentication spring-security forms-authentication
Jan 24 2018-11-11T00:
source share
4 answers

You do not need to create /j_spring_security_check_for_employee and /j_security_check_for_customer filterProcessingUrl .

By default, everything will work just fine with the idea of ​​a switch box.

In the user login LoginFilter you need to create different tokens for the employee and the client.

Here are the steps:

  • Use the default UsernamePasswordAuthenticationToken to log in.

  • Create a CustomerAuthenticationToken to log in. Extend AbstractAuthenticationToken so that its class type is different from UsernamePasswordAuthenticationToken .

  • Define a custom login filter:

     <security:http> <security:custom-filter position="FORM_LOGIN_FILTER" ref="customFormLoginFilter" /> </security:http> 
  • In customFormLoginFilter override attemptAuthentication as follows (pseudocode):

     if (radiobutton_param value employee) { UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(whatever); return getAuthenticationManager().authenticate(authRequest); } else if (radiobutton_param value customer) { CustomerAuthenticationToken authRequest = new CustomerAuthenticationToken(username, password); setDetails(whatever); return getAuthenticationManager().authenticate(authRequest); } 
  • Override the supports method in EmployeeCustomAuthenticationProvider to support UsernamePasswordAuthenticationToken .

  • Override the supports method in CustomerCustomAuthenticationProvider to support CustomerAuthenticationToken .

     @Override public boolean supports(Class<?> authentication) { return (CustomerAuthenticationToken.class.isAssignableFrom(authentication)); } 
  • Use both providers in authentication-manager :

     <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref='employeeCustomAuthenticationProvider ' /> <security:authentication-provider ref='customerCustomAuthenticationProvider ' /> </security:authentication-manager> 
+27
Jan 29 '11 at 17:25
source share

You can define multiple AuthenticationProcessingFilter filters. Each of them can have a different URL, for example / j_security_check_for_employee and / j_security_check_for_customer . Here is an example security application context that demonstrates this idea:

 <bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy"> <security:filter-chain-map pathType="ant"> <security:filter-chain pattern="/**" filters="authenticationProcessingFilterForCustomer, authenticationProcessingFilterForEmployee, ..." /> </security:filter-chain-map> </bean> <bean id="authenticationProcessingFilterForCustomer" class="org.springframework.security.web.authentication.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManagerForCustomer"/> <property name="filterProcessesUrl" value="/j_security_check_for_customer"/> </bean> <bean id="authenticationProcessingFilterForEmployee" class="org.springframework.security.web.authentication.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManagerForEmployee"/> <property name="filterProcessesUrl" value="/j_security_check_for_employee"/> </bean> <bean id="authenticationManagerForCustomer" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <property name="userDetailsService"> <ref bean="customerUserDetailsServiceThatUsesDB"/> </property> </bean> </list> </property> </bean> <bean id="authenticationManagerForEmployee" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <property name="userDetailsService"> <ref bean="employeeUserDetailsServiceThatUsesLDAP"/> </property> </bean> </list> </property> </bean> 

As you can see, in this case you also have different UserDetailService - for auth DB and LDAP.

I find it a good idea to have different authorization URLs for clients and employees (especially if they use different authentication strategies). You can even have different login pages for them.

+5
Jan 25 '11 at 19:15
source share

You can save this information in the database. For example, you may have a column named ldap_auth in the Users table. You can see my other answer (as an example):

Spring login form example

If you carefully study the UserService class, you will notice that I really check this LDAP flag and take the user password from either LDAP or the database.

0
Jan 24 2018-11-21T00:
source share

he told me again :) Can you try using the following filters:

 <sec:http auto-config="true"> ... <sec:custom-filter ref="authenticationProcessingFilterForCustomer" after="FIRST"/> <sec:custom-filter ref="authenticationProcessingFilterForEmployee" after="FIRST"/> </sec:http> 

instead of defining a bean springSecurityFilterChain .

0
Jan 28 2018-11-21T00:
source share



All Articles