Stephen McCants created SHIRO-578:
-------------------------------------

             Summary: Race condition between Session.touch() and 
AbstractValidatingSessionManager.
                 Key: SHIRO-578
                 URL: https://issues.apache.org/jira/browse/SHIRO-578
             Project: Shiro
          Issue Type: Bug
          Components: Session Management
    Affects Versions: 1.3.0, 1.2.2
            Reporter: Stephen McCants


I think I've found a race condition using Shiro 1.3.0 and a trivial web 
application between Session.touch() and the 
AbstractValidatingSessionManager.validateSessions().  The reason I'm looking 
that this code so carefully for race conditions is that our production web site 
sees the occasional (a few a week) UnknownSessionException in a way that is 
likely presenting the user with a 500 error screen. 

I set my breakpoints at SimpleSession.touch() and 
AbstractValidatingSessionManager.validateSession(). 

Here are the steps to reproduce: 
# I login, which creates my session and takes me to my default Servlet/JSP. 
# I refresh my web page, which will hit the Servlet again, but I stop at the 
"touch" breakpoint. 
# I wait for the ExecutorServiceSessionValidationScheduler to hit my breakpoint 
in AbstractValidatingSessionManager. 
# Step through and let AbstractValidatingSessionManager.validateSession() 
invalidate my session and delete it because it is expired. 
# Resume at the "touch" breakpoint and I get a 500 error page with 
UnknownSessionException: 

It really seems like there could be a race condition were a user reloads a web 
page right as their session is expiring.  The user get the session, but the 
ExecutorServiceSessionValidationScheduler immediately invalidates it before the 
user can "touch" it.  This results in the Servlet failing if it needs something 
out the Session (such as the Principal - it has no problem retrieving the 
Subject). 

Here is my shiro.ini file: 
{code}
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager

# Set the timeout to one minute, so we don't have to wait so long
sessionDAO = org.apache.shiro.session.mgt.eis.MemorySessionDAO
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.globalSessionTimeout = 60000
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager
sessionValidationScheduler = 
org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
sessionValidationScheduler.interval = 60000
sessionValidationScheduler.sessionManager = $sessionManager
securityManager.sessionManager.sessionValidationScheduler = 
$sessionValidationScheduler
#securityManager.sessionManager.sessionValidationInterval = 6000
securityManager.sessionManager.sessionValidationSchedulerEnabled = true

testRealm = com.hcs.shiro.race.TestRealm
testFilter = org.apache.shiro.web.filter.authc.FormAuthenticationFilter
testFilter.loginUrl = /login.jsp
testFilter.usernameParam = j_username
testFilter.passwordParam = j_password
testFilter.rememberMeParam = rememberMe
testFilter.successUrl = /myAccount

logout = org.apache.shiro.web.filter.authc.LogoutFilter
logout.redirectUrl = /login.jsp

# Permission
[urls]
/logout = logout
/** = testFilter
{code}

As you can see, the only custom code I'm using is the TestRealm, which 
authenticates anyone who provides a username and password. 

Here is my trivial Servlet: 
{code}
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        Subject subject = SecurityUtils.getSubject();
        Object principal = subject.getPrincipal();
        request.setAttribute(ATTR_PRINCIPAL, principal.toString());
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher = 
context.getRequestDispatcher("/myAccount.jsp");
        dispatcher.forward(request, response);
}
{code}

It fails on "subject.getPrincipal()" in the scenario described above and has 
been seen to fail in my production code in a similar line with a similar error 
message. 

Here is the exception: 
{noformat}
org.apache.shiro.session.StoppedSessionException: Session with id 
[1c59c589-2920-4ba6-b3c8-118997110844] has been explicitly stopped.  No further 
interaction under this session is allowed.
        
org.apache.shiro.session.mgt.SimpleSession.validate(SimpleSession.java:270)
        
org.apache.shiro.session.mgt.AbstractValidatingSessionManager.doValidate(AbstractValidatingSessionManager.java:186)
        
org.apache.shiro.session.mgt.AbstractValidatingSessionManager.validate(AbstractValidatingSessionManager.java:143)
        
org.apache.shiro.session.mgt.AbstractValidatingSessionManager.doGetSession(AbstractValidatingSessionManager.java:120)
        
org.apache.shiro.session.mgt.AbstractNativeSessionManager.lookupSession(AbstractNativeSessionManager.java:148)
        
org.apache.shiro.session.mgt.AbstractNativeSessionManager.lookupRequiredSession(AbstractNativeSessionManager.java:152)
        
org.apache.shiro.session.mgt.AbstractNativeSessionManager.getAttribute(AbstractNativeSessionManager.java:249)
        
org.apache.shiro.session.mgt.DelegatingSession.getAttribute(DelegatingSession.java:141)
        
org.apache.shiro.session.ProxiedSession.getAttribute(ProxiedSession.java:121)
        
org.apache.shiro.subject.support.DelegatingSubject.getRunAsPrincipalsStack(DelegatingSubject.java:469)
        
org.apache.shiro.subject.support.DelegatingSubject.getPrincipals(DelegatingSubject.java:153)
        
org.apache.shiro.subject.support.DelegatingSubject.getPrincipal(DelegatingSubject.java:149)
        com.hcs.shiro.race.MyAccount.doGet(MyAccount.java:30)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
{noformat}

Original discussion for in Shiro Users' Group: 
http://shiro-user.582556.n2.nabble.com/Race-condition-between-Session-touch-and-AbstractValidatingSessionManager-td7581196.html

Note: My trivial test case uses Shiro 1.3.0 code while my production code is 
using 1.2.2. 



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to