Bug 63531 - Session staying alive across different context paths
Summary: Session staying alive across different context paths
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Servlet & JSP API (show other bugs)
Version: 7.0.91
Hardware: PC Mac OS X 10.1
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-06-27 19:15 UTC by malini.kesavan
Modified: 2019-06-28 08:47 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description malini.kesavan 2019-06-27 19:15:50 UTC
Session stays alive as it’s tickled by org.apache.catalina.authenticator.AuthenticatoreBase.java 
invoke(Request request , Response response) method, when calling request.getSessionInternal(false).
 
I am using tomcat version 7.0.91 . This issue was reported in tomcat 7.0.14 as well.  Here is the case that was open to address this issue:
https://issues.apache.org/bugzilla/show_bug.cgi?id=51812

How to reproduce this issue:

We have 2 different context paths
• https://abc123.com:<1234>/contextPath-000   - context path contextPath-000
• https://abc123.com:<1234>/contextPath-999    - context path contextPath-999

Context path - contextPath-000 is where all the user action is and the user will be alive/active if user was active in the application

Context-path - contextPath-999  does not access user session at all.   However , every 30 second we make a GET request  from this context-path for a certain use case.
Note:  We do not touch user session at all in this context path –No calls to request.getSession(false).  We get the JSESSIONID from cookie and use just that.

When debugging the code, I see that the httpSession.getLastAccessTime () in - context path contextPath-000 is always set to the timestamp when a (every 30 sec) GET call from - Context-path contextPath-999 occurs  .

We made the following changes to org.apache.catalina.authenticator.AuthenticatoreBase.java to fix this issue:
•  Set cache=false ;
•  With that the code that was tickling the session(please see below) 
   is not invoked if cache =false
  //Code --
  public void invoke(Request request, Response response) throws IOException, 
     ServletException {
    if (this.log.isDebugEnabled()) {
        this.log.debug("Security checking request " + request.getMethod() + " " + 
        request.getRequestURI());
    }

    LoginConfig config = this.context.getLoginConfig();
    if (this.cache) {
        Principal principal = request.getUserPrincipal();
        if (principal == null) {
            Session session = request.getSessionInternal(false);
            if (session != null) {
                principal = session.getPrincipal();
                if (principal != null) {
                    if (this.log.isDebugEnabled()) {
                        this.log.debug("We have cached auth type " + 
                        session.getAuthType() + " for principal " + 
                        session.getPrincipal());
                    }

                    request.setAuthType(session.getAuthType());
                    request.setUserPrincipal(principal);
                }
            }
        }
    }

• Also wrapped this block of code in if (cache) condition in the same method:
//Code--
// Special handling for form-based logins to deal with the case where
// a resource is protected for some HTTP methods but not protected for
// GET which is used after authentication when redirecting to the
// protected resource.
// TODO: This is similar to the FormAuthenticator.matchRequest() logic
//       Is there a way to remove the duplication?
if (cache) {
    Session session = request.getSessionInternal(false);
    if (session != null) {
        SavedRequest savedRequest =
                (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
        if (savedRequest != null) {
            String decodedRequestURI = request.getDecodedRequestURI();
            if (decodedRequestURI != null &&
                    decodedRequestURI.equals(
                            savedRequest.getDecodedRequestURI())) {
                if (!authenticate(request, response)) {
                    if (log.isDebugEnabled()) {
                        log.debug(" Failed authenticate() test");
                    }
                    /*
                     * ASSERT: Authenticator already set the appropriate
                     * HTTP status code, so we do not have to do anything
                     * special
                     */
                    return;
                }
            }
        }
    }
}





These changes ensured that the access to session from different context paths are not keeping it alive across.
(Browser assigns the same JSESSIONID to the sessions created from both the requests (in spite of  different context path), as it does for different tabs on the same browser window.)

Please validate if this is a known issue and if there is a workaround to fix it without having to modify tomcat src.

FYI, We did try adding <Valve “org.apache.catalina.authenticator.BasicAuthenticator” cache=”false” /> and that didn’t work. As not all relevant code is wrapped around if(cache) block in the invoke method.


Thanks,
Malini
Comment 1 Mark Thomas 2019-06-27 20:09:22 UTC
I think this report is using the term "context path" incorrectly. Web applications on the same host have unique context paths and completely separate session managers (and hence sessions). Therefore, if separate context paths - and hence web applications - were in use then the behaviour described in this report would be impossible.

My working assumption is that, in terms of the Servlet spec, context path should be read as HttpServletRequest.getRequestURI().

This can be tested with a default Tomcat install using the examples web application for the requests and the manager web application to monitor session access time. I edited web.xml for the examples web application to use BASIC authentication to match this report.

With the default configuration (cache="true") once the session is created, any request to the web application will update the session last accessed time.

I'll note at this point that a strict reading of the Servlet specification requires that any access to a web application updates that last accessed time of the associated session irrespective of whether or not the web application explicitly accesses the session. See the org.apache.catalina.core.StandardHostValve.ACCESS_SESSION system property for more details.

With cache="false" I can see the issue described. The special handling for FORM auth triggers an update of the session accessed time. It should be possible to refactor that so it only applies with FORM auth is being used.

The proposed fix would break FORM authentication.
Comment 2 Mark Thomas 2019-06-28 08:47:27 UTC
The fix was already present in 8.5.x and 9.0.x.

I have back-ported the fix for 7.0.95 onwards.

I also back-ported  a fair amount of clean-up, refactoring and improved i18n messages as that enabled the fix for this issue to be identified and back-ported cleanly.