Reputation: 4130
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.
Upvotes: 0
Views: 1490
Reputation: 4130
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.
Upvotes: 1