I am building a web application that has a top thin frame which should show the time in seconds in which the servlet session will timeout.
The problem is that a AJAX call to a servlet which returns the last access time, and the inactiveInterval itself updates the session.
So is there a way I can get information about the session via a servlet that does not incrementing the lastAccessedTime?
Thanks
It seems that no one really answered the question as asked. The last response is closest - and probably best - piggy back the information needed on another request. I would add that if you can count on XHR activity that you can set a response header with the value(s) you want.
Assuming you really want want you asked for - to summarize / restate - a servlet that participates in the session but doesn't update the last accessed time, you should be able to accomplish that with a Filter that chains an overriden HttpServletResponse that returns an overridden Session object - overriding the getLastAccessedTime() method with its own (stored as an attribute in the real session of course). It will probably need to perform its own manual invalidation of the real session.
Questions like this show the age of the Servlet specification, even in its latest forms, there isn't enough control of some of the low-level authentication mechanisms, and overriding can be difficult even with Filters. These limitations manifest themselves using technologies like AJAX.
In thesis, you should not relay the session expiry time on the session time itself, in your case a counter should be implemented by decreasing the login time from the current time.
RemainingTime = CurrentTime - LoginTime
Your ajax call should query this variable.
Hope that solves your problem.
Can I ask for some more details?
What is the real requirement? Is it that the session time out within x seconds of a user logging in?
In that case, you you can use the getCreationTime() method on the HTTPSession object
http://java.sun.com/javaee/5/docs/api/javax/servlet/http/HttpSession.html#getCreationTime%28%29
remainingTimeInMilliseconds = System.currentTimeMillis - session.getCreationTime()
OR
Is the requirement for the session to time out after x seconds of inactivity? If so then do a
remainingTimeInMilliseconds = System.currentTimeMillis - session.getLastAccessedTime()
There's no need for your top frame to ask the server for the last access time. Why not let every HTML page contain a JavaScript snippet, which sets a defined variable to either last access, or perhaps more convenient, set the variable to the assumed expiration date of the HTTP session. Depending on how you generate your web pages, you can add the code snippet to a default template, or perhaps even add a Filter, which will embed the required code on every HTML page.
Be aware though, that IMHO, the servlet specification only states, that the server may invalidate the session at some point after the expiration time has passed, so accessing the session after the expiration time is not guaranteed to fail.
Related
Let's say I have app with several account types and each type has its own allowed maximum of concurrent sessions. For example, if the maximum is 1 then when user tries to log in from his laptop while being logged in on his desktop PC he should get an error.
How can I achive that with Spring? I know about concurrency-control but as far as I know it allows to "statically" set the limit for entire context.
I was thinking about SpEL but didn't came up with anything.
P.S.
Also I would like to know is there a specific exception being thrown when user exceeds the limit so I could handle it and show page with explanation why he can't log in.
UPD
Thanks to #Nándor for clever thoughts: when user tries to log in on another device he should be asked to either logout on the current device or on the other.
UPD2
I found that there is a bean of class SessionRegistry and it holds all the neccessery information, also it allows to manually expire sessions. Also I can control amount of sessions with it.
But there's still problem remaining: how do I notify another device that session has been shut down? When I manually expire the session with SessionInformation.expireNow() it give me a page with following text on it:
This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).
The text means exactly what I want but I'd like to handle this as I want. I tried #ExceptionHandler on java.lang.Exception but it hasn't catched anything.
Thanks in advance!
Thanks #Nándor for thoughts, I finally found a solution.
As to managing number of active sessions:
I use SessionRegistry bean, it can manage active sessions on all principals. Also, I think it's worth mentioning that SessionRegistry appears to be empty until I took off the security configuration from servlet config to applicationContext.xml. Spring logs that it successfully put session id to the registry but its still empty unless it's declared in the applicationContext.xml.
As to handle session expiring:
concurrency-control tag has expire-url tag that holds url to which user will be redirected in case of expired session. I can map controller to it and do what I want.
I'd like to update user session attributes (for example, user's money amount) every 20 minutes. How can I achieve this? Any ideas?
Your problem has two distinct parts:
How do I update user session attributes whenever I want to?
How do I do something every 20 minutes?
For the first part, you just need to keep a collection of all current sessions that you can access from anywhere (i.e. without the need of having an HttpServletRequest). This is answered in this post:
How do I get a list of all HttpSession objects in a web application?
For the second part, your best fit is probably a ScheduledExecutorService. See also: Running a Java Thread in intervals
You can use Timer Service for this task.
If you use Spring you can try TaskExecutor
I've been researching how to fix this issue for sometime but can't seem to find a proper solution.
Here's the issue:
I have a Java EE application where many users can login, they are presented with an item list, and they can select and edit any one of those.
All users see the same item list.
As mentioned, they can edit an item but I'd like to restrict the editing function to one user. That is, many users can edit different items simultaneously but only one user can edit a particular item.
When one user is editing an item, an message should appear to any other user trying to edit that item.
I have implemented this by setting a flag on the item, inUse, to true and then check for that. When the user is done editing the item, either by clicking save or cancel, the flag is set to false.
Problem with this approach is to account for cases when the user leaves his browser open or the browser is closed.
I tried setting a session timeout but can't seem to make that work because when the session times out, I don't have access to that item. I only have access to the httprequest session id.
Perhaps this is the wrong approach since it seems it's an issues that many applications would have and a less hackie solution should exist.
I looked into using threads and synchronized methods but don't know how that would work because once the user enters into the edit item screen, the method exits and releases the lock.
I found this solution Only one user allowed to edit content at a time but not sure if that's the way to go in Java.
Is there a more elegant/java solution? If so can you point me in the right direction please? How would you implement this?
Thanks!
The solution:
Although originally I thought optimistic locking was the way to go, I quickly realized that it wouldn't really work for my environment. I decided to go with a combination of pessimistic locking (http://www.agiledata.org/essays/concurrencyControl.html#PessimisticLocking) and timeouts.
When an item is accessed, I set an inUse field to true and the object's last accessed field to the current time.
Everytime when somebody tries to edit the object, I check the inUse field and the lastAccessed field + 5 mins. So basically, I give 5 mins to edit the user.
Do it like they do in a database, where a timestamp is used. The timestamp is kept with the record and when a person submits his edit, the edit does not go through unless the timestamp is the same (meaning 'no edits have occurred since I read this record'). Then when the edit does go through, a new timestamp is created.
First of all, in your persistence layer, you really should be doing optimistic locking, using a version/timestamp field.
At a UI level, to handle your use case I would do resource leasing:
Add two fields to your table:
LAST_LEASE_TIME: Time of the last lease
LAST_LEASE_USER: User that leased the record for the last time.
When a user tries to edit your record, first check that the record is not leased, or that the lease has expired (that is, the lease is not older that the specified lease time) or that the user is the one that was granted the lease.
From your web browser, periodically renew the lease, for example with an AJAX call.
When the user ends editing the record, explicitly expire the lease.
By doing leasing, you solve the "closed browser" problem: after the lease period expires without any lease renovation, the algorithm automatically "releases" the resource.
Sounds like you could use : Session Beans Quote:
In general, you should use a session bean if the following circumstances hold:
At any given time, only one client has access to the bean instance.
The state of the bean is not persistent, existing only for a short period of time (perhaps a few hours).
Martin Fowler describes 4 patterns for such a problem:
Online Optimistic Locking
Online Pessimistic Locking
Offline Optimistic Locking
Offline Pessimistic Locking
You should decide which one to use according to your problem.
JPA, JDO and Hibernate provide 1 and 2 out of the box.
Hibernate can handle 3 too, (I'm not sure about JPA and JDO).
None handle 4 out of the box and you shall implement it yourself.
I'm working on my first website with the Play! framework, and at one point I'm calling this method when the user logs in:
static void connect(User user){
session.put("userid", user.id);
}
Simply storing the userid in a session, and I can check if it's set on each request, works fine. Problem is, once the browser is closed the cookie is lost, and the user needs to login again. I want to create a "remember me" option, and it seems that the only way to do that is create a cookie and send it with the respons, like this:
response.setCookie("user", userdata, "14d");
So I'm wondering, what's the point in creating a session, when it does the exact same thing? (But does not give me any control over the cookie time). And another thing I havn't found yet, is how to read the cookie from the request?
(And I'm aware of the fact that cookies created with setCookie are not encrypted and I need to call Crypto.sign())
1) A Session in Play! is always maintained via cookie (i.e in client side), this is attributed to 'Share nothing' approach.
2) If you use Secure module (or you can take a look at the code and follow if you are writing your own), the 'authenticate()' method takes the parameter 'remember' and set the session for 30 days (response.setCookie("rememberme", Crypto.sign(username) + "-" + username, "30d");)
ie. if user doesn't choose to be 'remembered', their session last only until the browser is closed.
3) The real difference is, as you mentioned, session.put() doesn't allow to set session time out. If you want to extend the session then set it on the cookie.
4) If you want additional authentication while user performing CRUD, (even if user choose to be 'remembered' or their session got extended explicitly by you) its better to set the username/id to cache (rather than setting another identifier to session again) and clear it off when user logout. This will scale well if you choose to use a distributed cache like memcache.
5) To read from cookie, request.cookies.get("name") comes handy.
There are two ways to store state in web apps - client side and server side.
On Server-side either you can use Session or Application objects.
On Client-side you can use View State, Cookies, hidden fields, etc.
Session has a timeout duration after which it expires. When ever you access a web application a session is created for you which lasts for a duration. Hence it is per user thing. Even if you increase the timeout duration, it still expires if you close the browser. Application object is shared between all users.
Cookies are a better way to store such information which needs to be remembered for a longer duration e.g. a day or more. You would have noticed that google allows you to stay logged in for days. That is because they use cookies for state management and not sessions.
You should store the user id in cookie in exactly the same point where you did with session attribute. Use HttpServletRequest.getCookies() for reading cookie. This method returns array of cookies, so you have to iterate over the array to identify relevant cookie.
To change cookie, just override it.
The session lets you tie server-side data to the specific browser session: under the hood a cookie is automatically created that the server uses to look up the server-side data associated with a specific browser.
Control over the session cookie expiry is typically done somewhere in your framework's configuration (or sometimes in the web.xml file used by the app server). You can read the cookie from the HttpServletRequest's getCookies method.
EDIT: this is the getCookies documentation, and for the Play! framework see http://groups.google.com/group/play-framework/msg/6e40b07ff9b49a8a for an example of persistent login and cookie retrieval.
Basically a session is only viable for the period of time in which a user is interacting with your application + the session timeout that you specify. The usability of cookies is to store relevant information to the user so that, when they come back to the website again, you may identify them once more.
For instance, if you have both sensitive and insensitive information regarding a user, you could make your application more friendly by determining who they are via a cookie and loading all of the insensitive information. Once they authenticate themselves then you can load the sensitive information as well.
MSDN has some great reference material as to how to work with cookies at http://msdn.microsoft.com/en-us/library/ms178194.aspx
I'm using OpenID. How do I make it so that the user stays logged in for a long time even after closing the browser window?
How do I store and get access to the user's User object?
Basically, I guess I just don't really understand how sessions work in Java.
So you actually want like a "Remember me on this computer" option? This is actually unrelated to OpenID part. Here's a language-agnostic way how you can do it:
First create a DB table with at least cookie_id and user_id columns. If necessary also add a cookie_ttl and ip_lock. The column names speaks for itself I guess.
On first-time login (if necessary only with the "Remember me" option checked), generate a long, unique, hard-to-guess key (which is in no way related to the user) which represents the cookie_id and store this in the DB along with the user_id. Store the cookie_id as cookie value of a cookie with known cookie name, e.g. remember. Give the cookie a long lifetime, e.g. one year.
On every request, check if the user is logged in. If not, then check the cookie value cookie_id associated with the cookie name remember. If it is there and it is valid according the DB, then automagically login the user associated with the user_id and postpone the cookie age again and if any, also the cookie_ttl in DB.
In Java/JSP/Servlet terms, make use of HttpServletResponse#addCookie() to add a cookie and HttpServletRequest#getCookies() to get cookies. You can do all the first-time checking in a Filter which listens on the desired recources, e.g. /* or maybe a bit more restricted.
With regard to sessions, you don't need it here. It has a shorter lifetime than you need. Only use it to put the logged-in user or the "found" user when it has a valid remember cookie. This way the Filter can just check its presence in the session and then don't need to check the cookies everytime.
It's after all fairly straight forward. Good luck.
See also:
How to implement "Stay Logged In" when user login in to the web application
How do servlets work? Instantiation, sessions, shared variables and multithreading
Well, the original reason I chose OpenID was so someone else could handle as much of the implementation and security of authentication for me.
After looking into OpenID more, it appears there is something called an "Immediate Request" (http://openid.net/specs/openid-authentication-2_0.html#anchor28).
When requesting authentication, the Relying Party MAY request that the OP not interact with the end user. In this case the OP MUST respond immediately with either an assertion that authentication is successful, or a response indicating that the request cannot be completed without further user interaction.
Because of this I think I could just store the user's openID url in the cookie, and use an immediate request to see if the user is authenticated or not. This way I don't have to do anything with my database, or implement any logic for preventing session hijacking of the long-lived cookie.
This method of doing it seems to be the way OpenID suggests to do it with their Relying Party Best Practices document.