Even for me it seems quite odd to raise this question, as it contradicts my initial understanding.
Problem
Tomcat creates jsessionid on the first request (request1) and sends response (response1-with JSessionID) to the client. And client sends the same via cookies to the server on the next request (request2-with JSessionID). Now server understands that this is on the same session and responds, but the response doesn't contain JSessionID(response2-without JSessionID).
So now the client doesn't get any JSessionID, so the next request from that client seems to be a new one for the server, so server creates another session, which is wrong.
Relative Posts
http://lazyjavadev.blogspot.ie/2013/04/servlet-session-tracking-with-cookies.html
Why isn't getSession() returning the same session in subsequent requests distanced in short time periods? Under what conditions is a JSESSIONID created?
http://grokbase.com/t/tomcat/users/084pdye7fz/tomcat-not-sending-jsessionid-servlet-session-cookie-with-new-sessions
Attempted Solutions
Solution1
Add all cookies from the request to response - IT WORKS, but i think this is tomcat's job.
// Add cookies from request
Cookie[] cookies = req.getCookies();
if(cookies != null){
for (int i = 0; i < cookies.length; i++) {
resp.addCookie(cookies[i]);
}
}
Solution2
Add JSessionID cookie from client from the time of session initiation till session destruction (no matter whether server sends the session id in the response or not) - But this is a workaround and can't be the solution because clients are out of control in real time situation.
Question - ?
It's clear that tomcat maintain's session based on JSessionID via cookies or URL Rewriting or Hidden form fields. I have no special case like disableing cookies. Now the questions are
Why my tomcat doesn't send JSessionID on the subsequent response?
If that's a normal behaviour how tomcat maintains session integrity?
Or is it client's responsibility to send JSessionId cookiee to server untill the cookiee expires?
Thanks for your time in helping me.. :)
Related
I noticed our code is adding the access token / authorization token to the response in the form of a cookie, using
((HttpServletResponse) response).addCookie(accessTokenCookie);
I've done some research and discovered this info:
Request cookies are the cookies sent from browser to server
Response cookies are the cookies sent out (from server to browser).
If this is the case, wouldn't my request interceptor / doFilterInternal need to apply the access token cookie to the request before it goes through, and not the response?
What makes it more confusing is the access token cookie is being created by fetching the access token value using request.getAttribute. If the request already has the access token as an attribute, why does a cookie needed to be added to the response?
You misunderstand how cookies work.
The browser sends a request to some resource on some server.
The server returns the bytes that comprise the resource.
That's the basic flow. Now, let's talk about cookies:
When the server returns those bytes, it can send headers along with it. It is in fact required; for example, to talk about what the data is representing. For example, if you ask for /img/background.png, the server returns the image data and also sends Content-Type: image/png. Because browsers don't actually do the whole 'extensions indicate what the data is' thing, that's what that Content-Type header is for.
One of those headers is a Set-Cookie header.
Set-Cookie headers tell the browser: Take this data and save it somewhere. Next time you load this resource, send it again. There's some control about when to send it (you can make a Set-Cookie header sent when the server reponds for request /foo/bar make the browser send that cookie back even when asking for /foo/baz, or e.g. when foo.myserver.com sends a cookie, it can tell the browser: Send that back also when requesting resources from bar.myserver.com. There are limits though; when setting a cookie when responding to a request on myserver.com, you can't tell the browser to send that back when sending to google.com. Browsers are complex beasts; they ship with a huge list of top-level-ish domains and won't let you do this.
You don't 'add' cookies to a 'request' - the request stuff (the data you can obtain from an HttpServletRequest object) is just representing what the browser sent the server. The model for HttpServletRequest/Response is strictly two phases: The browser sends a request, and the server responds. That's it. It's not a long conversation. Just one message each way, that is all you get.
So, you add a cookie to the 'response' which means that future requests made by that same browser will then send it in the 'request'.
I have a legacy Java 1.6 running localhost with Tomcat 7 application using JSP pages, a frameset with frames, javascript, but no framework like Struts. I pass an object to display in the page from the servlet using the request or session and that works fine.
However, I made some changes recently and now I can't retrieve that same object back from the session or request. It had been working fine previously, so I'm not sure what is broken, but I can't even send a string value back from the JSP's back to the servlet.
I created a new stripped down JSP and I can't get anything back from that either using the request or session. It does the same thing when I push the code our Tomcat 6 web server. Using the debugger, I see the objects populated in the session, but then lost later when a new session is created each time as in using this simple code to get the sessionid:
System.out.println("The session id is: " + session.getId());
The session id is: EB431C19B41957B2BB2EFC3DBAF32241
The session id is: C9CBD30E84D5C93DF6114C1412AE5523
I then see this in firebug under the Header, response headers:
Set-Cookie JSESSIONID=C9CBD30E84D5C93DF6114C1412AE5523; Path=/Name omitted here/; HttpOnly,
so I know cookies are set. I also removed jquery and I"m stripping down the jsp code as much as possible, but that doesn't seem to be the issue.
I'm using:
HttpSession session = request.getSession(true); but using false didn't matter.
session.setAttribute("ObjNameList", objNameList);
The context.xml has cookies set to true and we do use response.sendRedirect, but only if an error is thrown as in: response.sendRedirect("Error.jsp"); There is no place in the code with session invalidate either.
All I'm doing from the jsp is sending a form back using something like:
document.formName.submit(); which works fine. Using this code to try and set a simple string in the session doesn't work either:
session.setAttribute("somevalue","someValue");
Gives me null in the servlet here:
String val = (String) session.getAttribute("somevalue");
Any ideas as to what could be causing this?
Resultion:
It turned out to be an issue with the url, a typo actually, as BalusC mentioned, so the path for the session cookies didn't match between the jsp and the servlet.
Doublecheck if the request URL to that servlet matches the session cookie domain and path. If it doesn't match, then the browser simply won't send the session cookie back along with the request and the server will think that there's no means of an established session and will therefore simply create a new one.
You can check cookies in the HTTP traffic monitor of browser's web developer toolset (press F12 in Chrome/Firefox23+/IE9+ and open "Network" tab). When a new session starts, the server must have returned a response with Set-Cookie header with therein the cookie value and path (and implicitly domain). When the browser sends a subsequent request on the same domain and path, then it must have passed that cookie back via Cookie request header.
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading
When a user has an associated HttpSession object and then want to "log out" of the application you would invalidate that HttpSession which in turn would remove it from the map that the ServletContext keep of all sessions. But this only removes it on the server side, what happens on the client side? Does the user still keep keep the cookie with the session ID which now no longer has a corresponding session object on the server and keeps sending this to the webserver? And what happens when the user wants to login again after logging out?
I imagine the sessionId cookie will still be kept, but since this sessionId will not match any session object in the server's memory, it will be discarded by the server next time user tries to login again. On the server side it will be quite transparent, request.getSession() will return a new session object automatically.
I would like to add to the answer of maksimov.
Although the cookie is still present on the client side, it is possible for the server to delete the cookie also on the client side. Spring Security does that when a user logs out. Here's the code:
Cookie cookie = new Cookie(cookieName, null);
String cookiePath = //cookie's path
cookie.setPath(cookiePath);
cookie.setMaxAge(0);
response.addCookie(cookie);
The important instruction is cookie.setMaxAge(0). Setting the max age to 0 means the cookie has to be deleted. Thus, the server may ask the client to delete the cookie by sending it the same cookie with a max age of 0.
We have the following situation:
JSESSIONID is being sent by both cookies and URL, but because of a Adobe Flash BUG, they are different (actually, the cookie JSESSIONID is wrong).
What we would like to do is to use the URL JSESSIONID instead of the one sent in the cookies. In other words, when I execute request.getSession(), it should return the HttpSession associated to the ID in the URL and not in the cookie.
We looked into Tomcat7 source code and, in fact, Tomcat first parses the URL, searching for an identifier. Then it overrides it with cookies SESSIONID if they are present. Here is the code snipped in CoyoteAdapter.java (tomcat 7.0.26):
String sessionID = null;
if (request.getServletContext().getEffectiveSessionTrackingModes()
.contains(SessionTrackingMode.URL)) {
// Get the session ID if there was one
sessionID = request.getPathParameter(
SessionConfig.getSessionUriParamName(
request.getContext()));
if (sessionID != null) {
request.setRequestedSessionId(sessionID);
request.setRequestedSessionURL(true);
}
}
// Look for session ID in cookies and SSL session
parseSessionCookiesId(req, request);
parseSessionSslId(request);
We could disable cookies JSESSIONID at all, but we can't because we use it for all URLs in the website. We'd like to disable cookies for JUST THIS SPECIFIC URL.
Is it possible? Is there any other idea or workaround to solve this problem?
You could implement a custom servlet filter that would replace request, response and session objects with your own wrappers. The wrappers then can behave differently based on the URL, e.g. delegate or not to the original session instance. Though you won't be able to access session data for some other id, without changing Tomcat code.
I'm trying to invalidate/expire an insecure cookie from a securely accessed servlet and send a redirect back to the client. However, when the redirect is followed, the request still contains the original, unexpired, uninvalidated (is that a word) cookie.
Here's a more detailed description of the flow:
1) Client requests a particular insecure url backed by Servlet A.
2) Servlet A detects that there is a Cookie XX and redirects to a secure url backed by Servlet B
3) Servlet B does its magic, then invalidates Cookie XX by setting the MaxAge to 0 and redirects to Servlet A via an insecure url.
4) In Servlet A, I'm still able to access the cookie just as it was in the first request.
Can anyone lend a hand? I was under the impression and can't find evidence to the contrary that when a cookie is sent back with a redirect response, it is still processed before the new request is sent out. This is happening in all browsers (Chrome, FF, IE) that I have access to, so I don't think its a browser thing. In HTTPFox and the Chrome Developer tools I can see the original cookie getting sent in the first and second request, the invalidated cookie coming back in the response to the second request, and the original cookie being sent again in the third request. I've tried setting the MaxAge to 0, setting the value of the cookie to null/empty string, and another value but it never changes. All of the server side code is done in Java if it matters.
Help is very much appreciated.
Have you tried making sure that the domain and paths for the invalidated cookie is the same as the original cookie?
Also, a better way to handle sensitive cookies is setting the 'secure' flag on the original cookie. That will tell the browser to never send the cookie over an insecure connection.
This turned out to be an oversight on my part. When Servlet B invalidated Cookie XX, it also set the cookie's path to something other than what it originally was. That, in effect, created a Cookie XX-B and had no effect on the original Cookie XX. Making sure my cookie's paths were the same fixed it.
In two separate projects I've had to invalidate a cookie. This is what I have had to do:
Get the cookie in question from the HTTP request object
Set cookie max age to by invoking Cookie.setMaxAge(int).
Call the Cookie.setPath(String) method, even if path is to remain the same
Add the cookie back into the HTTP response object, I.e. HttpServletRespons.addCookie(cookie)
Only after executing all the steps above did the browser stop passing the cookie back to server on subsequent requests.