Spring Security Authentication Every X Minutes (Without Killing Session) - java

I am interested in asking users to re-authenticate after 15 mins of inactivity without killing their session (session life is longer).
Is there a way to specify an authentication timeout within Spring Security that would accomplish this automatically or some cleaver way I can accomplish this without too much effort?

Adding a request filter seems to be the best way to achieve this goal. In order to prevent the loss of data, I chose to have a blocking popup that displays if the session has been inactive. This way I can refresh the page and the user is right where they left off instead of needing to store the initial request and having to find it and redirect them.

Related

Spring: How do I dynamically set maximum amount of concurrent sessions

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.

Event-driven way of (batch-)removing expired data in Java application

In our application, we have a concept called 'overlay', which changes the behaviour for a user account until it expires. Each user account can have zero or one overlays, which are persisted with the user account in the database.
A user can activate an overlay (which requires setting the expiration time) and manually remove it (if it should be removed before its expiry). Also the overlay's expiration time can be updated. When an overlay is removed (manually or due to expiration), an event is triggered which results in more logic being invoked (e.g. firing a webhook).
What is now a good way to automatically remove expired overlays from the database? The application is built with Grails, so it can use Java frameworks, like Quartz. The application runs on several AWS EC2 instances behind a load balancer. The mechanism need to survive application restarts.
The obvious solution is a periodic batch job, that runs every X seconds, scans for all expired overlays, and then deletes them. Downside is that this
creates peaks in the load (since removing overlays creates events which trigger more behaviour)
leaves expired overlays in the DB before they are removed
Is there a more "event-driven" way so that the overlays are removed right when they expire? We have around 50.000 user accounts.
A possible approach is to check (and possibly delete) upon use - i.e. whenever you're retrieving the possible overlay from the database, check if it's expired and delete it if so.
Technically, you could create a database procedure that will check the overlay existence and expiry, possibly delete expired record and then return the correct result to user. If you hide the table (or column) storing the expiry dates from user (= your application) and only allow access through that procedure, the result will be:
The expired entries are still in database for some time
possibly indefinitely, but if at most 1 overlay per user, it's not too much data hopefully
it is there, but the application cannot see them
From the application's viewpoint, there's no possibility to get expired entries
No peaks in resources consumption
Might add some overhead

Difference between creating a session and a cookie?

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

Getting the time in seconds in which the session will expire

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.

How do I keep a user logged into my site for months?

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.

Categories

Resources