Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 23957
  • Last Modified:

JSESSIONID suddenly changed and user http session is lost

We're having problems with users being timed out prematurely in our web application.
It happens sometimes, not always.

The timeout is random and the server assigns a NEW jsessionid to them.  

It seems that Internet Explorer suddenly sends a new jsessionid in the cookie, or not send at all, so the server (tomcat) doesn't associate the request to the correct http session, and so the user lose his session data.
We have verified that the http session is still alive in that moment, so it doesn't happen as it has been invalidated.

Thank you

Antonio Vivalda
0
Decisionisti
Asked:
Decisionisti
  • 18
  • 13
  • 10
  • +1
1 Solution
 
rrzCommented:
>It seems that Internet Explorer suddenly sends a new jsessionid in the cookie
Is this problem in IE only ? Does it happen in other browsers ?
>We have verified that the http session is still alive in that moment
How did you do that ?  
0
 
mrcoffee365Commented:
We have never had Tomcat change sessions randomly.

I have never seen a browser stop sending cookies to a server randomly.

This is good news for you, because it means that it's probably a problem with your configuration or your application code.

For example, do you have multiple Web servers?  Maybe you're not handling load balancing correctly for your application, and users are being routed to different servers but not getting their sessions.

Are you switching users between https and http?  Jsessionid is not shared between https and http in Tomcat.

Has someone changed the browser configurations to turn off accepting cookies?

And finally -- did someone change the session timeout time for your Tomcat server (or for one of them?)?
0
 
DecisionistiAuthor Commented:
Answer to rrz@871311:

We have a listener that writes on a log file when a HttpSession is destroyed, and, when a HttpSession is created, another listener put it apart so we can check its content. We have verified and it is alive.


Answer to mrcoffee365:

Thanks for the suggestions but non of those cases.

Could it be due to a proxy bad configuration that sometimes return a old information to the client?

Do you know if can it be prevented by the application, setting for example in the http response the "no-cache" attribute?

Do you know if there is a way to diagnose this problem so to have some evidences?

Thank you
0
The Lifecycle Approach to Managing Security Policy

Managing application connectivity and security policies can be achieved more effectively when following a framework that automates repeatable processes and ensures that the right activities are performed in the right order.

 
rrzCommented:
I agree with mrcoffee.  It is probably one of the cases he posted.
Are you saying that you have only one server and there is no load balancing ?
What is your session timeout time ? Did you leave it at default ?  
What did the log report ?
How long did the sessions live ?
Can you show us your listener code ?
0
 
mrcoffee365Commented:
If you answer rrz@871311's questions, that will help.

>>Could it be due to a proxy bad configuration that sometimes return a old information to the client?

If a user is getting a new JSessionid, then they're getting to the server.  With this question, you're thinking that they're not getting to the server, and their session is timing out?  It might be possible.  If you think this is happening, you might try the "no-cache" option.

However, you stated above that you thought you had checked the user sessions and they were still valid.

Also -- you said that you are writing code to invalidate sessions.  The most likely cause, then, is your code.  Search your code for every time you invalidate a session, and write to a log.

Debugging your problem can be helped quite a bit by just looking at your access log (as rrz@871311 mentioned).  If you put cookies in your access log, you can see exactly how users are accessing your server and what their sessionids are.
0
 
DecisionistiAuthor Commented:
Thanxs for the answers,

The session is alive, so it cannot be a invalidation problem..

In the log file I write the "JSESSIONID" value and that suddenly changes, when a user navigates.
It happens sometimes, generally everything works fine...

Any other idea?

Thanxs again
0
 
rrzCommented:
>In the log file I write the "JSESSIONID" value and that suddenly changes, when a user navigates.
That could occur if the user was idle for a longer period than the MaxInactiveInterval .  
In your HttpSessionListener, you could get the age of the session by using
    long age = new Date().getTime() - event.getSession().getCreationTime();  
This way you can see if the sessions are timing out.
0
 
mrcoffee365Commented:
Please answer rrz's questions, and post a fragment of your access log which shows the changed Jsessionid's for a single user.

Questions from above:
Are you saying that you have only one server and there is no load balancing ?
What is your session timeout time ? Did you leave it at default ?  
What did the log report ?
How long did the sessions live ?
Can you show us your listener code ?
0
 
rrzCommented:
Additional questions.
At the top, you posted  
>the timeout is random and the server assigns a NEW jsessionid to them.  
I gather from this that the users are not logged -in  ??  
If they are logged-in, then isn't that fact held in a session-scoped object ?
>In the log file I write the "JSESSIONID" value and that suddenly changes, when a user navigates.
How do you keep track of who's who ?  Logged-In flag ? ip Address ?
0
 
rrzCommented:
I am sorry. I posted bad code.  
>long age = new Date().getTime() - event.getSession().getCreationTime();  
this listener code should been
HttpSession session = event.getSession();
long inactivePeriod = session.getLastAccessedTime()  - session.getCreationTime();  // in milliseconds
In this way, you can compare to
int interval = session.getMaxInactiveInterval(); // in seconds
0
 
rrzCommented:
No still wrong.
Not
>long inactivePeriod = session.getLastAccessedTime()  - session.getCreationTime();  // in milliseconds
but  
long inactivePeriod =  new Date().getTime() -  session.getLastAccessedTime();  // in milliseconds
0
 
DecisionistiAuthor Commented:
Sorry for the late in the answer,

In the log file, I see clearly that the sessionid changes, as i write it on every request done to the app. server.
The last thing i can imagine is a Proxy problem, that caches in some way some requests and so the client receives an old cookie with an old JSESSIONID.
Then in the next request,as that JSESSIONID is invalid, the server generates a new HttpSession associated to that client.

Do you think it could be possible?

Thanxs again
0
 
mrcoffee365Commented:
It's hard to randomly speculate.  Please post
1) access logs for the user sessions with the problem
2) your code which checks and invalidates a session


0
 
mrcoffee365Commented:
Have you not been posting logs because you don't know how to hide proprietary info?  Just change the IP addresses -- but make sure that they are consistently changed.  Same with variables in the code, if that's also an issue.  Just post the relevant fragments, we don't want to see an entire day's log.
0
 
rrzCommented:
I agree with mrcoffee. If you give us more information, then mabye we could see the problem.
>The last thing i can imagine is a Proxy problem, that caches in some way some requests  
Are you saying that some of the responses are sent by the proxy and that the server doesn't receive all the requests ?  If this happens, the server could think that the client is in-active for a period longer than the web app's MaxInactiveInterval, thus the session is killed when it really should not be killed.
I guess it is possible.  
If logs are a hassle for you, then you could use a test JSP something like what I included below here. Just browse to it and let it go for a half hour.
You could also test to see if no-cache options solve your problem.
There is a lot of different opinions as to how to prevent caching. Here are a few links that might help you.
See accepted answer at
http://www.experts-exchange.com/Programming/Languages/Java/J2EE/JSP/Q_21358743.html
and bottom of  
http://www.experts-exchange.com/Programming/Languages/Java/J2EE/JSP/Q_20619664.html
<%@ page import="java.util.*,java.io.*" %>
<%!
   String instanceString = " Start:<br/>";
%>
<%
   instanceString += "Time is " + new Date().toString() + " Session Id is " + session.getId() 
                      + " IP is " + request.getRemoteHost() + "<br/>";
%>
<html>
<head>
      <meta http-equiv="refresh" content="250" />
</head>
<body>
To clear the string, make a change to the .jsp file. 
<%=instanceString%>
</body>
</html>

Open in new window

0
 
rrzCommented:
I wrote some code that uses HTML5. I tested it with IE8 and Google Chrome 10.  The refresh rate is determined by the content attribute in the meta tag. Please copy and paste.


<%@ page import="java.util.*,java.io.*" %>
<%!
   int requestCount = 0;
   String instanceString = "";
%>
<%
   String clear = request.getParameter("clear");
   if(clear != null && "yes".equals(clear)){
                                              requestCount = 0;
                                              instanceString = "";
   }
   requestCount++;
   instanceString += "Time is " + new Date().toString() + " Session Id is " + session.getId() 
               + " IP is " + request.getRemoteHost() + " Server count is " + requestCount + "<br/>";
%>
<html>
<head>
  <meta http-equiv="refresh" content="180" />
<script type="text/javascript">
     function doCount(){
        document.forms[0].clear.value = "no";
        var count = window.sessionStorage.getItem("count");
        count++;
        document.forms[0].countBox.value = count;
        window.sessionStorage.setItem("count", count);
     }
     function clearCount(){
               window.sessionStorage.clear();
               document.forms[0].clear.value = "yes";
               return true;
     }
</script>
</head>
<body onload="doCount()">
<form method="post" onsubmit="return clearCount()">
Count at client is 
<input type="text" name="countBox" size="5"/>
<input type="hidden" name="clear" value="no"/>
<input type="submit" value="Clear" /><br/>
<%=instanceString%>
</form>
</body>
</html>

Open in new window

0
 
rrzCommented:
The following code is even better. I added a session-scoped count.
<%@ page import="java.util.*,java.io.*" %>
<%!
   int requestCount = 0;
   String instanceString = "";
%>
<%
   Integer sessionCount = (Integer)session.getAttribute("count");
   if(sessionCount == null){
                            session.setAttribute("count", 0);
                            sessionCount = 0;
   }
   sessionCount++;
   session.setAttribute("count", sessionCount);
   String clear = request.getParameter("clear");
   if(clear != null && "yes".equals(clear)){
                                              requestCount = 0;
                                              instanceString = "";
                                              sessionCount = 1;
                                              session.setAttribute("count", 1);
   }
   requestCount++;
   instanceString += "Time is " + new Date().toString() + " Session Id is " + session.getId() 
                     + " IP is " + request.getRemoteHost() + " Server count is " 
                     + requestCount + " SessionCount is " + sessionCount +"<br/>";
%>
<html>
<head>
  <meta http-equiv="refresh" content="3" />
<script type="text/javascript">
     function doCount(){
        document.forms[0].clear.value = "no";
        var count = window.sessionStorage.getItem("count");
        count++;
        document.forms[0].countBox.value = count;
        window.sessionStorage.setItem("count", count);
     }
     function clearCount(){
               window.sessionStorage.clear();
               document.forms[0].clear.value = "yes";
               return true;
     }
</script>
</head>
<body onload="doCount()">
<form method="post" onsubmit="return clearCount()">
Count at client is 
<input type="text" name="countBox" size="5"/>
<input type="hidden" name="clear" value="no"/>
<input type="submit" value="Clear" /><br/>
<%=instanceString%>
</form>
</body>
</html>

Open in new window

0
 
mrcoffee365Commented:
Wow rrz@871311 -- you're really going to town on this one!
0
 
rrzCommented:
Thanks for noticing, mrcoffee.  I wanted to play with HTML5 web storage API. It is really nice. <canvas>  is nice too. Have you had a chance to play with any HTML5 features ?    rrz
0
 
mrcoffee365Commented:
We've only used HTML5 in the context of iPhone apps.  Our customers are not reliably on browsers which support it, so it looks great but we can't use it.
0
 
DecisionistiAuthor Commented:
Thank you, the page works fine, everything seems to be OK... unfortunately it's not a

#### THIS IS OK, The user is navigating, and the httpSessionID is: A54D32160561A8C01793BFA64A7FB221

26-mar-2011 16:11:37 DEBUG [http-8080-6]:  [Administrator] [SQL] executeQuery: SELECT OBJECT_NAME FROM DSH_CATALOGUE WHERE OWNER = 'EK0XZ99' AND OBJECT_ID='268222801240328' [threadSessionInfo - USR:Administrator Conn:-6(A) httpSessionID:A54D32160561A8C01793BFA64A7FB221 ]
 26-mar-2011 16:11:37 DEBUG [http-8080-6]:  [Administrator] [SQL] executeQuery: SELECT OBJECT_NAME FROM DSH_CATALOGUE WHERE OWNER = 'EK0XZ99' AND OBJECT_ID='133222805884484' [threadSessionInfo - USR:Administrator Conn:-6(A) httpSessionID:A54D32160561A8C01793BFA64A7FB221 ]
 26-mar-2011 16:11:37 DEBUG [http-8080-6]:  [Administrator] [SQL] executeQuery: SELECT OBJECT_NAME FROM DSH_CATALOGUE WHERE OWNER = 'EK0XZ99' AND OBJECT_ID='99225301523390' [threadSessionInfo - USR:Administrator Conn:-6(A) httpSessionID:A54D32160561A8C01793BFA64A7FB221 ]
 26-mar-2011 16:11:37 DEBUG [http-8080-6]:  [Administrator] [SQL] executeQuery: select OBJECT_ID from CATALOGUE where OBJECT_ID = 1111111110 and OWNER = 'EK0XZ99' [threadSessionInfo - USR:Administrator Conn:-7(A) httpSessionID:A54D32160561A8C01793BFA64A7FB221 ]
 26-mar-2011 16:11:37 DEBUG [http-8080-6]:  [Administrator] User Photo /userPhotos/administrator.jpg load error:Document Repository Not Definded [threadSessionInfo - USR:Administrator Conn:-9(A) httpSessionID:A54D32160561A8C01793BFA64A7FB221 ]
 
#### PROBLEM!, The user was navigating, but the httpSessionID is now:2697F6F2BE8421AC8B173F5433D5891E. The user is redirected to the error page as the session is new. The session A54D32160561A8C01793BFA64A7FB221  is still alive on the server!
 
 26-mar-2011 16:11:40 DEBUG [http-8080-8]:  [NA] Redirect to error page as null session.   CsSession:null  httpSession:org.apache.catalina.session.StandardSessionFacade@713ba5  request:/DecisyonPRJ/cassiopeaWeb/dsh/dshPages.jsp.cas [threadSessionInfo - USR:System Conn:-29 EVT:LW_DSH_GROUP_ORGANIZE(A) httpSessionID:2697F6F2BE8421AC8B173F5433D5891E ]
 26-mar-2011 16:11:40 DEBUG [http-8080-8]:  [NA] Ajax function called as null session.   CsSession:null  httpSession:org.apache.catalina.session.StandardSessionFacade@713ba5  request:/DecisyonPRJ/cassiopeaWeb/misc/administration/empty.jsp.cas [threadSessionInfo - USR:System Conn:-29 EVT:LW_LOGOUT(A) httpSessionID:2697F6F2BE8421AC8B173F5433D5891E ]
 
0
 
DecisionistiAuthor Commented:
I was writing: "Thank you, the page works fine, everything seems to be OK... unfortunately it's not a problem that occurs always"

0
 
rrzCommented:
I really don't know what the problem could be.  But I am wondering about:  
> /userPhotos/administrator.jpg load error:Document Repository Not Definded  
How does your web app react to this error ?  
0
 
rrzCommented:
Another thought.
>The session A54D32160561A8C01793BFA64A7FB221  is still alive on the server!
I don't know how you determined this, but did you check to see if your objects are still bound to it ? Specifically, the username or whatever object that was used to identify the Administrator.  
0
 
mrcoffee365Commented:
You never answered how many servers you have.  Do you have more than 1?  If you do not handle sessions correctly, then going to a different server will result in a new session.

Do you serve the /DecisyonPRJ/cassiopeaWeb/dsh/dshPages.jsp.cas url from a different webapp under the same server?  Each webapp has its own sessions, unless you configure Tomcat for singlesignon.  

Or rrz is right, and the problem is the request for /userPhotos/administrator.jpg
What serves that jpg?





0
 
DecisionistiAuthor Commented:
The web server is just one, the " Document Repository Not Definded  " is not a problem, it's a configuration issue.

The Session is still alive on the server, and the objects are still bound to it.

It happens sometimes, and randomly so... i don't really have any further idea about it

Thank you for all your support and time, we try to increase the log of the webapp and app.server to discover it... anyway i think it's a proxy caching problem, hope to find it!

Antonio
0
 
mrcoffee365Commented:
>>The Session is still alive on the server, and the objects are still bound to it.

We understand that this is what puzzles you, but it isn't what we've been talking about.  The user is returning to the server, and the server thinks that a new session has to be created.  There are only a few cases that would cause this, and a proxy or nocache will not fix them.

>>It happens sometimes, and randomly so... i don't really have any further idea about it

Posting the actual log you create was helpful -- the access log would have been even more helpful.  Your log shows that we are not dealing with a session timeout, so it cannot be fixed with nocache on the page or looking for a proxy of some sort.

If you would post your server.xml for the relevant webapps (and let us know whether singlesignon is configured for your server), as well as the actual access log at the time of one of these errors, that would help a great deal.

Your current state points to 3 possible cases in my opinion:
1) you have misunderstood which user is returning to the server, or you don't realize that the same user is using 2 different browsers, which would mean that they would get 2 different sessions
2) your users are sometimes going to https urls
3) your users are sometimes going to a different webapp in their request, which results in a different sessionid.  Not an error, but desired behavior.  You have to configure singlesignon for that to go away.

And it's still very possible that your session code is actually causing the invalidation under certain conditions, and you just haven't been able to find it.
0
 
rrzCommented:
I would add a Filter that is mapped to  to your whole web app(url pattern "/*").  In that Filter I would have something like
  public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain)
     throws ServletException, IOException {
          HttpServletRequest request = (HttpServletRequest)req;
          Cookie[] cookies = request.getCookies(); 
          for(Cookie cookie : cookies){
             if("JSESSIONID".equals(cookie.getName()))
                System.out.println("Remote Host is " + request.getRemoteHost() 
                                     + " " + new Date().toString()     + "  " 
                                     + "JSESSIONID==" + cookie.getValue()); 
          }          
          chain.doFilter(req,resp);
  }

Open in new window

It will show you each request and the session id associated with it.  Using this Filter code in conjunction with your listener, you should be able to determine if the problem is at the server or not.
0
 
rrzCommented:
I made some improvements. Please try this instead.
public class TestFilter implements Filter {
  public void init(FilterConfig config) throws ServletException{
                         System.out.println("init of TestFilter");
  }
  public void destroy(){}        
  public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain)
     throws ServletException, IOException {
          HttpServletRequest request = (HttpServletRequest)req;
          boolean isSession = false;
          Cookie[] cookies = request.getCookies();
          if(cookies != null){
             for(Cookie cookie : cookies){
                if("JSESSIONID".equals(cookie.getName())){
                   isSession = true;
                   System.out.println("Remote Host is " + request.getRemoteHost() 
                                     + " " + new Date().toString()     + "  " 
                                     + "JSESSIONID==" + cookie.getValue()); 
                }
             } 
          }
          if(!isSession) System.out.println("Remote Host is " + request.getRemoteHost() 
                                     + " " + new Date().toString()     + "  no session id");      
          chain.doFilter(req,resp);
  }
}

Open in new window

0
 
rrzCommented:
Even better.
public class TestFilter implements Filter {
  public void init(FilterConfig config) throws ServletException{
                         System.out.println("init of TestFilter");
  }
  public void destroy(){}        
  public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain)
     throws ServletException, IOException {
          HttpServletRequest request = (HttpServletRequest)req;
          String sessionId = "  no session id";  
          Cookie[] cookies = request.getCookies();
          if(cookies != null){
             for(Cookie cookie : cookies){
                if("JSESSIONID".equals(cookie.getName())){
                     sessionId = "JSESSIONID==" + cookie.getValue(); 
                }
             } 
          }
          System.out.println("Remote Host is " + request.getRemoteHost() 
                               + " " + new Date().toString()     + sessionId);      
          chain.doFilter(req,resp);
  }
}

Open in new window

0
 
DecisionistiAuthor Commented:
####Aswer to mrcoffee365:

1) you have misunderstood which user is returning to the server, or you don't realize that the same user is using 2 different browsers, which would mean that they would get 2 different sessions

-> The browser used was just one


2) your users are sometimes going to https urls

-> no https URL is active for that webapp


3) your users are sometimes going to a different webapp in their request, which results in a different sessionid.  Not an error, but desired behavior.  You have to configure singlesignon for that to go away.

-> How this could change the cookie or the session settings in my webapp?


### Answer to rrz@871311:

Thanxs, i've added a Filter similar to the one you suggested. I'm now waiting to the next error to understand what is happening
0
 
mrcoffee365Commented:
>>3) your users are sometimes going to a different webapp in their request, which results in a different sessionid.  Not an error, but desired behavior.  You have to configure singlesignon for that to go away.
>>-> How this could change the cookie or the session settings in my webapp?

Each webapp has a different session.  If you do not have singlesignon set, then each context in Tomcat creates its own session.  If you are using multiple war's, for example, then each war has its own session.


0
 
DecisionistiAuthor Commented:
I've found other information, throught the improved logging:

A user is normally navigating in the application. He have a sessionId "DA8A7681B73DAEB9BA33561C6E18C9AC".

Half an hour later, a different user, from a different PC is navigating, and suddenly he sends the cookie with this http sessionID "DA8A7681B73DAEB9BA33561C6E18C9AC". The server, obiusly, kick out the user as that session is not valid.

I think again it's a proxy caching problem...
0
 
mrcoffee365Commented:
Look for your proxy, then.   Theoretically proxies should honor the no-cache settings in a page, so you could try that.

It could still be your code, especially since you are playing with sessions.  If a developer has accidentally put the sessionid into a servlet instance variable, then it will show up for other users.  Non-thread safe code does get written sometimes.
0
 
rrzCommented:
>The server, obiusly, kick out the user as that session is not valid.  
Isn't this a different problem from what you reported in your question at the top of this page?

>I've found other information, throught the improved logging:
Is that by using the request filter I posted ?
0
 
DecisionistiAuthor Commented:
Thanxs for the support, i think that everything possibile cause has been mentioned.

We will continue with our tests, hoping it's a proxy problem.
0
 
mrcoffee365Commented:
Then you can assign points.  Other people would be helped by the answers rrz and I have provided.  If you decide to provide more information in the future, you can open another question.
0
 
DecisionistiAuthor Commented:
Very good job and assistance from the experts
0
 
rrzCommented:
What was the problem with your web app ?
>Very good job and assistance from the experts  
Why did you give all the points to mrcoffee ?
0
 
mrcoffee365Commented:
Great, thanks.  Points can be awarded to more than one expert -- in this case rrz helped as well.

In any case, good luck.  If you find it, and can get back to this question, you can post how you dealt with it.
0
 
rrzCommented:
You posted above
>Thanxs, i've added a Filter similar to the one you suggested.    
You  used some of my Filter code. I think I deserve some points.
0
 
fantabkCommented:
Antonio: did you solve the issue? If so could you share what you did. I think we are having a very similar problem.

Thanks.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 18
  • 13
  • 10
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now