Supporting Sessions Without Cookies in Tomcat - java

I am currently running an application with the following properties:
Java-based with Spring and Acegi
Running on Tomcat 5
I need the ability to support user sessions without cookies. Could someone please point me in the right direction.
Thank you.

The complete answer to this question is a combination of all your responses, so I'm going to summarize:
There is no need to set cookies="false" in the context.xml file. The ideal functionality is for tomcat to use it's url-based session identification, which will be used by default if cookies are not supported by the user.
When a user doesn't have cookies enabled, tomcat will identify the session by the "JSESSIONID" parameter from the url of the request. A couple sample urls are as follows
http://www.myurl.com;jsessionid=123456AFGT3
http://www.myurl.com;jsessionid=123456AFGT3?param1=value&param2=value2
Notice how the session id is not part of the url query string (this is a j2ee standard)
In order to ensure the jsessionid parameter gets appended to all your request URLs, you can't have plain url references. For example, in JSTL, you have to use < c:url>. The servlet engine will then automatically append the jsessionid to the url if it is necessary. Here's an example:
<%--this is bad:--%>
< a href="page.html">link< / a>
<%--this is good:--%>
< a href="< c:url value='page.html'/>">link< / a>

See http://tomcat.apache.org/tomcat-5.5-doc/config/context.html.
In a file META-INF/context.xml,
<?xml version='1.0' encoding='UTF-8'?>
<Context path='/myApplicationContext' cookies='false'>
<!-- other settings -->
</Context>

You could track by IP address, but proxy servers (and NAT?) could mess you up.
You could force all URLs to have the session as a parameter, and all forms as a hidden field. Maybe a custom tag for generating URLs could help here, but I've not done much work with taglibs.
You will need to consider security - people might email links to someone else with the session id in it, so you will want to have an IP address check for each access to check that the address matches the session.

As matt b commented this should work out of the box (tomcat will try cookies, and if that fails fall back on encoding the session in the url). However, this will not work if you create a 'plain' link yourself - always use a method like JSTL's so tomcat can add the tracking parameter to all urls.

Best way is to use URL rewriting . So, when you use request.getSession() ,the container will send "Set-Cookie" header for session-id in HTTP-response as well as session-id appended to URL (but you must use response.encodeURL(session_info) for url rewriting).
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter pw=resp.getWriter();
HttpSession session=req.getSession();
pw.println("<html><body>");
pw.println("Click");
pw.println("</body></html>");
}

Related

How can I retrieve all cookies, even with the same name and same domain, in java servlet filter?

I have a java web application. I implemented a login system, with user rights a while ago, and included a "remember-me" functionality with unique string ID's saved client side in cookies.
This has worked ok, except for the fact that the remember me functionality always fails on first page load whenever a new session starts. However, since most users access a non-restricted page first, complaints has been absent. Nonetheless, I'd like to fix it. Here is what I have learned.
I use implementations of javax.servlet.Filter to check if a user has rights to se a page. for example baseURL/pages/admin/*. Filter interface has a method called doFilter, which accepts a ServletRequest, and ServletResponse object as parameters. I cast these to HttpServletRequest and HttpServletResponse. The HttpServletRequest gives me access to cookies and session.
If i iterate through the cookies, I find my "remember"-cookie, with the unique ID as a value. However, this ID is wrong.
Now, in my Servlet class, which follows the front controller pattern, I also have a check for user logged in, and remember me. But because this is executed after the filter, it is not sufficient to check only here. Still, I do want to check for every page, even if it is not restricted, as it changes the layout slightly if you are logged in.
The java HttpServlet service method accepts a HttpServletRequest and HttpServletResponse object. In other words, no need for casting here. Funny thing is though, If i try to access my cookies from here, it will give me an identical id for the session cookie, but a completely different uid for my "remember"-cookie.
I have found that my system adds new remember cookies for each of my filters. And if I try to access a page in the admin path, both cookies from /webapp/pages, and cookie from /webapp/pages/admin will be present in chrome inspector. When accessing the cookies in the filter, the /webapp/pages/admin is the only one that will exist. Oppositely, the /webapp/pages is the only one that will exist in the front controller servlet service method.
I guess this is because of the mapping of said filter and servlet, which matches the path of the cookie. The problem is that I never intended there to be cookies stored hierarchically, and only want the one to be stored, at /webapp/pages. My system has now stored plenty of these deeper pathed cookies all over my client network, and whenever a user logs in and out, they might get out of sync with a new uid.
Is there a way I can force retrieving the /webapp/pages cookie over the /webapp/pages/admin cookie? Or is there a way to retrieve both? I could just check both uid's for a match if I can manage that (hence the title of my question)
For the future, I have made sure to set the path of cookie storage, so that the same path will be used, but as the cookies has a year to expire, this will not solve my problems for a long time, unless I find a way to check the correct cookie.
The answer to the title question is; you can't.
The browser will decide which cookies it deems most relevant, and there is nothing you can do to change that. When your filter is mapped to a subpath, and servlet is mapped to a higher path, you will get the best matching cookie for each path.
The specific problem in the question text is caused by a bad coding pattern. The remember me cookies should be stored at a specific path when created, in this case /webapp/pages. This will prevent the cookie from being created as multiples, in hierarchical paths.
There is still the problem of already existing cookies client side. These can be handled by adding the following javascript in a central area of your code, somewhere where you'd know that all users will encounter it:
document.cookie = 'remember=; path=/webapp/pages/user; expires=' + new Date(0).toUTCString();
document.cookie = 'remember=; path=/webapp/pages/admin; expires=' + new Date(0).toUTCString();
This will set the unwanted cookies to expire at an already past date, effectively deleting it.
Now only one cookie with name "remember" will exist for the domain, and both servlet and filters will fetch the same cookie, regardless of their mapped subpaths.

New Session is created with each servlet request from JSPs?

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

Preserving session in Java with sendredirect

I am creating a Login Application in JAVA.I am making the presentation in JSP and all the logic (Database connectivity) in Servlet [this is not a right approach I know that].
I check the username Password in Servlet and then create a session variable.
and add the session like this
sess.setAttribute("username",oName);
Then I redirect the user to its homepage say student.jsp
response.sendRedirect("student.jsp");
It removes the session variable.I need a way to preserve the session variable and move to student.jsp.I tried to use forwading but that didn't worked out.
RequestDispatcher dispatcher =
getServletContext()
.getRequestDispatcher("/student.jsp");
if (dispatcher != null) {
dispatcher.forward(request, response);
}
It forward request but the Page address doesn't change to student.jsp which is not good.
Any help in this regard will be appreciated
Thank you
For the redirected request to come back and attach to the same session, it needs a session ID, usually carried in a JSESSIONID (or another name) cookie or in the URL as a parameter.
This cookie or URL parameter should be added by the servlet container and you should not have to add it yourself.
If you do not see the cookie in your browser, and you are not attaching the JSESSIONID to the URL, then it is creating a new session with each request, and not attaching to the same session.
Try to edit your tomcat context.xml file and replace <Context> tag to <Context useHttpOnly="false"> , this helped me.
Some browsers like Chromium for instance do not allow cookies from localhost or IP addresses, so the session cannot be preserved and changes on every refresh. This can be easily checked with the browser developer tools that show all cookies of the request.
For development, set up your workstation to resolve some more serious name (like host.kitty.com) into localhosts. Under Linux, just add entry to /etc/hosts.
Use the RequestDispatcher and set your username variable using request.setAttribute(). In this case the dispatcher will not create a new request but the same request will be forwarded using the forward() method.

Ignore cookies for specific URIs in Tomcat

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.

Java SessionID: How to get the Name of the GET SessionID Parameter?

it seems that the Parameter-Name in the GET request, that represents the SessionID (like jsessionid=XXXXXXXXXXXXXXXXXXXXXXXXXX in Tomcat) is not standardized in the servlet-spec? How can I get the (Servelt Container Specific) name of the SessionID? (At least in Websphere there seems to be the possibilty to change the name of the SessionID-Parameter-Name)
=> The underlaying problem is, I need to encode a URL in a servlet ALWYAS with the session ID. But it seems that the "response.encodeURL()" Method only does this if Cookies are disabled (=>therefor using URL-Rewriting with the sessionID in the URL).
What would be an alternative to always encode a URL with a session ID in a servlet? As the first question implies I wanted to build the sessionid on my own but I therefore need the sessionID-Parameter Name that however seems not be be standardized, so I somehow need to get the Parameter-Name from somewhere...)
UPDATE:
The intention is to keep the SessionManagement Functionality provided by the Servlet-Container and not turn it off completely. I need to pass a Callback URL to a third party system that I want to always contain the SessionURL. So I only want to encode this single URL always with the sessionID to minimize any security issues...
Thank you very much
Jan
The jsessionid isn't actually a request parameter, it's encoded on to the URL itself, and then decoded and removed by the container before it gets as far as your controller. The value of jsessionid itself can be retrieved from HttpSession.getId().
If you want to stop Tomcat from using cookies, then you can provide a tomcat-specific context.xml file under WEB-INF, containing something like this:
<Context cookies="false" path="/path/to/my/webapp">
</Context>
This will disable all cookies for that webapp, and tomcat should then automatically encode all session IDs on to the URL instead.

Categories

Resources