Results 1 to 7 of 7

Thread: Handling expired HTTP sessions

  1. #1
    Join Date
    Apr 2009
    Posts
    14

    Default Handling expired HTTP sessions

    I have problems in using custom error messages on my login.jsp page. I want to capture two scenarios: 1) failed login (login_error = 1), and 2) expired http session (login_error=2). I have developed a custom filter for session expiration handling based on a suggestion provided by another thread in the forum. It seems to work, but the problem is once I get redirected to the 'login.jsp?login_error=2' page, subsequent login attempts from the same browser window fails with the "session expired" message. Here is my login.jsp page snippet:
    Code:
    <c:if test="${(not empty param.login_error) && param.login_error==1}">
       <span id="errmsg" class="errormesage">Authentication failed. Please try again.</span>
    </c:if>
    <c:if test="${(not empty param.login_error)  && param.login_error==2}">
        <span id="errmsg" class="errormesage">Session expired. Please login again.                                        </c:if>
    I am using a custom SessionFilter for handling the HTTP session. Here is the Java cpde for custom sesssion filter.

    Code:
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.util.Assert;
    
    public class SessionFilter implements Filter, InitializingBean {
    
    	private FilterConfig filterConfig;
    	protected final Log logger = LogFactory.getLog(getClass());
    	private String expiredUrl;
    
    	public void destroy() {	}
    
    	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    		logger.info("Session filter called...");
    		if(req instanceof HttpServletRequest){
    			HttpServletRequest hReq = (HttpServletRequest)req;
    			HttpServletResponse hRes = (HttpServletResponse)res;
    			HttpSession session = hReq.getSession(false);
    			logger.info("--> HttpSession: "+session);
    			if(session == null && hReq.getRequestedSessionId() != null && !hReq.isRequestedSessionIdValid()){
    				logger.info("Session Id: "+hReq.getRequestedSessionId());
    				logger.info("Valid Session: "+hReq.isRequestedSessionIdValid());
    				String targetUrl = hReq.getContextPath() + expiredUrl;
    				logger.info("Session expired........... Redirecting to login page.");
    				hRes.sendRedirect(hRes.encodeRedirectURL(targetUrl));
    				return;
    			}
    			chain.doFilter(req,res);
    		}
    	}
    
    	public void init(FilterConfig config) throws ServletException {	}
    
    	public void afterPropertiesSet() throws Exception {
    		logger.info("Entry: afterPropertiesSet");
    		Assert.hasText(expiredUrl, "ExpiredUrl Required");
    		logger.info("Exit: afterPropertiesSet");		
    	}
    
    	public void setExpiredUrl(String expiredUrl) {
    		this.expiredUrl = expiredUrl;
    	}
    
    
    }
    Here is my applixationContext-security.xml file:

    Code:
    <http>
        <intercept-url pattern="/login.jsp" filters="none"/>
        <intercept-url pattern="/*.html" access="ROLE_USER" />
        <form-login login-page='/login.jsp' login-processing-url="/j_spring_security_check" default-target-url='/dashboard.html' always-use-default-target='true' authentication-failure-url="/login.jsp?login_error=1"/>
        <concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true" expired-url="/login.jsp?login_error=2"/>
    </http>
    
     <authentication-provider>
        <user-service>
          <user name="testuser" password="testing123" authorities="ROLE_USER" />
        </user-service>
      </authentication-provider>
    
     <beans:bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
         <filter-chain-map path-type="ant">
             <filter-chain pattern="/login.jsp" filters="none"/>
             <filter-chain pattern="/**" filters="sessionExpirationFilter"/>
         </filter-chain-map>
     </beans:bean>
    
    <beans:bean id="sessionExpirationFilter" class="myapp.web.SessionFilter">
        <custom-filter position="FIRST"/>
        <beans:property name="expiredUrl" value="/login.jsp?login_error=2"/>
    </beans:bean>
    
    <beans:bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
        <beans:property name="defaultTargetUrl" value="/login.jsp?login_error=1"/>
        <beans:property name="authenticationManager" ref="authenticationManager" />
    </beans:bean>
    
     <authentication-manager alias="authenticationManager" />
    My web.xml file specifies thw filter as follows:

    Code:
    <filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    
    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    Any help is greatly appreciated.

  2. #2
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    Your session expiration filter is presumably rejecting all incoming requests with the previous session ID, including the resubmission of the login form. You should see your messages in the log if this is the case.
    Spring - by Pivotal
    twitter @tekul

  3. #3
    Join Date
    Apr 2009
    Posts
    14

    Default

    The custom session filter class I am using is the same as the one suggested in this

    http://forum.springsource.org/showth...ded#post205997

    It seems to be working for the person suggested this. What I noticed is that, when the httpRequest.getSession(false) returns a null (implying that the session indeed has expired), the httpRequest.getRequestedSessionId() is NOT null but 'invalid'. The httpRequest.isRequestedSessionIdValid() is returning 'false' redirecting me to the login page with 'sesion expired' message.

    But subsequent login attempts fulfill exactly same conditions in the filter and goes back the same login page with session expired message.

  4. #4
    Join Date
    Apr 2009
    Posts
    14

    Default

    I have added more logs to the filter. I am noticing that any request posted to the application after the time-out value specified in the web.xml file seems to create a new session. The sesssion object inside the custom session filter as a result of req.getSession(false) method is NEVER becomes null, and the session id is also new.

    It is obvious that the Sprin framework is simply creating a new session automatically when the old one expires. I am not sure if this behavior is a known issue. I also think that, there has to be a special position assigned for the SESSION_EXPIRED in the filter stack. I does not look like we have one currently, though we seem to have one for concurrent session.

    This issue seems to be a glaring ommission that the Spring community needs to act upon.

  5. #5
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    It is obvious that the Sprin framework is simply creating a new session automatically when the old one expires.
    You seem to be saying that it isn't possible to get past your filter, which is at the start of the filter chain and is constantly redirecting to the login page (which has no filters associated it).

    If that's the case, please explain how Spring Security can be creating a session at any point in this loop?

    If a session is being created then you should be able to find out where by configuring a suitable listener in your web.xml and dumping the stacktrace.

    And please don't make accusations of "glaring omissions". This is an open source project, the code is freely available and the fact that you are using the framework effectively makes you part of the Spring community.
    Spring - by Pivotal
    twitter @tekul

  6. #6
    Join Date
    Apr 2009
    Posts
    14

    Default

    Thank you for your note. On further investigation of the spring-security framework in the context of this particular problem, here are some more observations:

    1. The expired session information seems to be rightly received from the container (Tomcat) and passed on to spring. I am saying this, because, any request attempt after the time-out invokes the custom session filter.

    2. The 'position' of the custom session filter seems to control the behavior of the method call 'httpRequest.getSession(false)'. According to J2EE contract, this method must return a 'null' after invocation of session expiry. But the position seems to determins how this behaves:

    - for <custom-filter position="FIRST"/> the session is null during the filter call. On the other hand, for <custom-filter position="LAST"/> the session is NOT null in the filter call, and the custom redirect with expired session message never shows up. Therefore somewhere before the LAST filter is called, a new session object gets created by the spring framework.

    3. The FIRST position definitely gives me a partial solution for my problem, but I am never able to login again since the session gets short-circuited by the filter with the same message over and over.


    It is possible there is still an issue with my configuration, but that is not readily apparent to me. I am going to setup a listener and dump a stack trace to figure out where exactly the new session gets instantiated.

  7. #7
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    If your filter is not at the first position in the chain, then Spring Security will normally create a session in order to store the authentication object when the user logs in.

    However the cookie supplied by the user may still be for an expired session, in which case your filter will still redirect them to the error page regardless. The isRequestedSessionIdValid() method refers to the session ID sent from the browser, and will return false in this case regardless of whether a session currently exists or not.
    Spring - by Pivotal
    twitter @tekul

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •