Announcement Announcement Module
Collapse
No announcement yet.
Preventing concurrent session not working when using a custom form login filter Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Preventing concurrent session not working when using a custom form login filter

    I need some help trying to figure out why session control doesn't seem to work when using a custom login filter.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
    	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">
    
    	<!-- This is where we configure Spring-Security -->
    	<security:http auto-config="false" use-expressions="true" access-denied-page="/denied" entry-point-ref="loginUrlAuthenticationEntryPoint">
    	
      		<security:custom-filter position="FORM_LOGIN_FILTER" ref="ldapUserSync" />
      		<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
      		<security:session-management session-authentication-strategy-ref="sas"/>
      		
    		<security:intercept-url pattern="/login" access="permitAll" />
    		<security:intercept-url pattern="/resources/**" filters="none" />
    		<security:intercept-url pattern="/**" access="hasAnyRole(${cpr.roles})" /> 
    		<!-- <security:intercept-url pattern="/**" access="hasAnyRole(${cpr.roles})" />  -->
    		
    		<security:logout invalidate-session="true"
    			logout-success-url="/login" logout-url="/logout" />
        
        	<!-- <security:session-management invalid-session-url="/sessionTimeout.htm">
            	<security:concurrency-control max-sessions="1" />
        	</security:session-management> -->
        	
    	</security:http>
    	
    	<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
     		<property name="loginFormUrl" value="/login" />
    	</bean>
    	
    	<bean id="ldapUserSync"	class="org.tvo.cpr.ldap.LdapUserSync">
    		<property name="authenticationManager" ref="authenticationManager" />
    		<property name="authenticationFailureHandler" ref="failureHandler" />
    		<property name="authenticationSuccessHandler" ref="successHandler" />
    		<property name="allowSessionCreation" value="true" />
    		<property name="sessionAuthenticationStrategy" ref="sas" />
    	</bean>
    
    	<bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    		<property name="defaultTargetUrl" value="/tabs" />
    	</bean>
    	<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    		<property name="defaultFailureUrl" value="/login?login_error=true" />
    	</bean>
    	
    	<!--http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-session-mgmt-->
    	<!--session management-->
    	<bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
        	<property name="sessionRegistry" ref="sessionRegistry" />
        	<property name="expiredUrl" value="/expired" />
      	</bean>
        
        <bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
        	<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
        	<property name="maximumSessions" value="1" />
        	<property name="exceptionIfMaximumExceeded" value="true"/>
      	</bean>
      	
      	<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
    	<!--end of session management-->
    		
    	<bean id="TVOUserContextMapper" class="org.tvo.cpr.ldap.TVOUserContextMapper" />
    	
    	<!-- you can specify search on a specific group as follows group-search-base="ou=User_IT" -->
    	<security:authentication-manager alias="authenticationManager">
             <security:ldap-authentication-provider 
               	user-search-filter="(sAMAccountName={0})"
               	user-search-base=""
               	group-search-filter="(member={0})"
               	group-search-base="${ldap.groupfilter}"
               	group-role-attribute="cn"
            	role-prefix="none"
            	user-context-mapper-ref="TVOUserContextMapper">
             </security:ldap-authentication-provider>
     	</security:authentication-manager>
    			
     	<security:ldap-server url="${ldap.url}" manager-dn="${ldap.manageDN}" manager-password="${ldap.password}"/>
    	
    </beans>
    Here is my custom class, which writes LDAP user info. to a table on authentication success.

    Code:
    public class LdapUserSync extends UsernamePasswordAuthenticationFilter {
    	
    	@Autowired
    	private UserService UserService;
    	
    	private static final Logger logger = LoggerFactory.getLogger(LdapUserSync.class);
    	
    	@Override
    	protected void successfulAuthentication(HttpServletRequest request,
    	         HttpServletResponse response, Authentication authResult)
    	         throws IOException, ServletException {
    
            SecurityContextHolder.getContext().setAuthentication(authResult);
    
    	    User tvoUser = (User) authResult.getPrincipal();
    	    System.out.println(tvoUser.getAuthorities().toString());
    	    tvoUser.setUserActive(true);
    	    tvoUser.setCreatedBy("CPR");
    	    
    	    try {
    		    User userCheck = UserService.findUserByName(tvoUser.getUserName());
    		    if(userCheck != null) {
    		    	tvoUser.setUserId(userCheck.getUserId());
    		    }
    
    		    UserService.updateUser(tvoUser);	
    	    } catch(Exception e) {
    	    	//get the root cause of exception and return it on login page
    	    	Exception rootCause = (Exception) ExceptionUtils.getRootCause(e);
    	    	String cause = "Unable to log into the system at this time: " + rootCause.getMessage();
    
    	    	//invalidate HttpSession to logout
    	    	HttpSession session = request.getSession(false);
    	        if (session != null) {
    	        	response.sendRedirect("/cpr/login");
    	        	session.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, new AuthenticationServiceException(cause));
    	        	//session.invalidate();
    	        	SecurityContextHolder.getContext().setAuthentication(null);
    	        	return;
    	        }
    	    }
    	    
    	    super.successfulAuthentication(request, response, authResult);
    	    
    	    logger.info("User Authentication Successful: " + tvoUser.getUsername() + " logged in.");
    	}
    
    	@Override
    	protected void unsuccessfulAuthentication(HttpServletRequest request,
    	         HttpServletResponse response, AuthenticationException failed)
    	         throws IOException, ServletException {
    	    super.unsuccessfulAuthentication(request, response, failed);
    
    	    logger.warn("User Authentication Unsuccessful: " + request.getParameter("j_username").toString() + " " + failed.getLocalizedMessage());
    	}
    }
    Listener has been added to web.xml

    Code:
    <listener>
        	<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
     </listener>
    Log in tests are successful and failures work as expected but when I try to log in with the same user on different browsers or on different machines I never get the expired url. I'm guessing my problem has something to do with the way I've extended UsernamePasswordAuthenticationFilter where the sessionAuthenticationStrategy is not getting injected correctly. Any help is appreciated.
    Thanks.

  • #2
    What version of Spring Security are you using? Have you enabled DEBUG logging and checked that the SessionRegistry is being properly updated with User objects? Do you have a custom UserDetails object and (if so) does it correctly implement equals and hashCode methods?

    Comment


    • #3
      Originally posted by pmularien View Post
      What version of Spring Security are you using? Have you enabled DEBUG logging and checked that the SessionRegistry is being properly updated with User objects? Do you have a custom UserDetails object and (if so) does it correctly implement equals and hashCode methods?
      I'm using 3.0.5. I found out what the issue was. I am using a custom userdetails object and the equals method will never work because I am changing the object in my code.

      Code:
      User tvoUser = (User) authResult.getPrincipal();
      tvoUser.setUserActive(true);
      tvoUser.setCreatedBy("CPR");
      What I ended up doing was cloning the object and making changes to the clone instead of the original.

      Thank you.

      Comment

      Working...
      X