Sorry for the broad topic. Basically, WSC is supposed to have out-of-the-box session timeout handling by forwarding the user to the ReLogonFormView, which the user can presumably configure (through Struts) to any jsp that they choose. We use a custom logoff command, and it seems to be affecting that view showing up.
I'm not looking for a specific solution to this problem, I'm just looking for general knowledge about how WSC (v6) handles session timeouts (how it determines that the session has timed out) and what command(s) it runs by default when / if / to determine the session has expired.
This is my current knowledge on this subject...
The session timeout is a global value for all web modules and can be found in the wc-server.xml and is set to 30 minutes OOTB.
When a timout occurs, the OOTB LogoffCmd would normally be called, which will set up the necessary URLs to navigate to the ReLogonFormView URL while keeping hold of the URL where the session timeout occurred.
If the ReLogonFormView contains userid/password fields to allow the user to logon again, the user will then be redirected back to the page they were originally on.
More info can be found in IBM InfoCenter under "LoginTimeout".
If you extend the OOTB LogonCmdImpl, you should not try and set the forwarding URL, or that will interfere with the OOTB navigation.
I think you should perform your custom logoff functionality and then call super.performExecute() to allow the OOTB navigation logic to take over.
Note: You can retrieve the URL you were originally on via a call to getReferrerURL() and the ReLogonFormView should be returned from getURL().
Related
In our JAVA web application we maintain users' session in a database table active_sessions. And we do not allow multiple sessions per user. what it means is, if you are already logged in with a particular user account, you cannot open a new session with the same account. In case somebody does, we display error 'User already has an active session'. When user clicks on Logout his entry from table active_sessions is removed. But in case where user closes the window without logging out his entry remains in the table active_sessions. So any attempt to login in future results in an error 'User already has an active session'. Any tips on how to destroy user session in database in case he closes the browser window without logging out.
Edit: After reading all the posts it seems there is no clean way to restrict single session per user.
Use the 'onbeforeonload' JavaScript event which can perform an AJAX call to your server to delete the entry. This event will however be executed each time the page is unloaded so if you don't have a SPA then you'll need to ignore the event for href and such.
Agree with Almas however that your approach is dangerous in the sense that it is not possible to enforce this 100%. E.g. if the user kills the browser process then even this JS event would not be published.
Furthermore, a user can simply use another browser to bypass your 'protection'.
In the server side users HTTP session is normally invalided after a certain period of idle time. You can implement http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionListener.html and register it in web.xml to receive notifications about session create/destroy etc. In your listener implementation you could delete the table entry on session destroy event.
The basic thing about HTTP is that it is request/response protocol.
i.e. Things are changed/accessed only by making a request to the server. This 'limitation' makes your requirement interesting. There can be two workarounds for this:-
Poll the server at a repeated interval through an AJAX call. As long as you application keeps getting the polling AJAX request you can assume that the window is open.
Use javascript (window.onunload ) to fire an event to destroy user session when the browser is closed.
Using onuload
I am using timestamp till nano second as a user session, say tab A has session1 and user opens tab B say this session is session2 and now session1 gets only inactivated after some file upload activity is done at this point of time I want the session2 be still active.
How do I do this without using cookies?
have you looked into html5 sessionStorage/localStorage ?
these apis sport a client-side storage facility pretty similar to cookies which you can employ to manage sessions. the lifetime of the database is either the lifetime of the respective tab/window (ssessionStorage) or the interval between two consecutive deletions the pertaining browser data; the latter may depend on the browser preferences (eg. automatically after closing the tab/window in privacy mode or upon express user request).
for a start, mdn has something to say about it. there also is a full-fledged tutorial on html5rocks.
the gritty in-depth w3c standard details all about the programmatic (javascript) interface.
the api do not provide facilities to exchange information between client and server. one option to handle this part would be encoding the information into urls (client -> server) or http headers (server -> client) being called/received through ajax.
a final word of warning: for security reasons, do not store authenticating data this way.
say tab A has session1 and user opens tab B say this session is session2
This is already impossible. Both tabs will be in the same session. If tab B created a new session due to a login for example, tab A will now be in the new session.
and now session1 gets only inactivated after some file upload activity
It won't happen.
is done at this point of time I want the session2 be still active.
It still is. Session 1 will have been destroyed if it's different from session 2.
i wanted to throw an alert when session expires and when you press ok button in the alert box then it will take you to login page. For this i thought to create a timer and timertask and in the run method of the later class i will check if the session exists or not. So for this i tried to create a class in jsp page but it is showing error. i can create in servlet but all my pages are in jsp and so this idea is not useful.Now i created a sessionlistner and in the session destroyed method i want to link to login page but i have a problem here too.I can not use response method in the sessiondestroyed method.Please tell me are there any other ways
You can use JavaScript like:
var sessionTimeout = "<%= Session.Timeout %>";
function DisplaySessionTimeout()
{
//assigning minutes left to session timeout to Label
document.getElementById("<%= lblSessionTime.ClientID %>").innerText =
sessionTimeout;
sessionTimeout = sessionTimeout - 1;
//if session is not less than 0
if (sessionTimeout >= 0)
//call the function again after 1 minute delay
window.setTimeout("DisplaySessionTimeout()", 60000);
else
{
//show message box
alert("Your current Session is over.");
}
}
For more details visit here
First, you can creates totally client side solution: use setTimout() when page is loaded first time. Use either hard-coded or arrived from server value of timeout. When timer is triggered use document.location = login.html (or something like this) to arrive to login page.
This solution is "fast and dirty."
Better solution should be based on real session expiration. You can create AJAX call that tries from time to time special URL. This URL should return true/false that means that session is expired or not. When session is expired you should redirect the page to login screen. The problem with this solution is that the fact that you request the session state refreshes it. To solve this problem you can either perform the request to different server or (probably) remove session cookie from the polling request, so it will be performed in session different from the main session.
With Tomcat you can create a JS timer that make a simple AJAX call.
If the call return without errors the session is valid, if the call fails you can consider the session expired. On default behavior Tomcat deosn't renew sessions if you don't explicitly call it.
I had the opposit case: link
This problem is already solved by the Java EE Spec. You should consider using web.xml configurations to handle session timeout issues. It has specific tags for handling all of this. Some of the tags are:
<login-config> ... </login-config>
The above tag lets you used FORM based authentication where you can specify your login HTML resource.
<security-constraint> ... </security-constraint>
The above tag lets you specify the URLs you would like to secure. And finally the session timeout tag itself, which allows you to specify the session timeout in millis.
Once you do the above, the container would automatically take the user to the login page when he requests a secure URL.
Here is the web.xml reference.
From a messaging standpoint, there are multiple ways of seeing the problem:
The fact that system is taking the user back to the login page and forcing him to login, is indicator enough for him/her.
You could provide a generic message on the login page itself.
Device some tricky flag based or querystring logic to show the message on the login page.
Came across this link in StackOverflow itself which provides a strategy you can implement in the login page itself. Have not tried this though.
This in my mind is a trivial problem compared to the whole session timeout strategy itself.
Scenario:
User logs into website.com using firefox. Login credentials are valid, user is directed to member's page.
User tries to log in to website.com using chrome. Login credentials are valid, because use is already logged in using firefox, system will throw error, asks user to close other session to login through chrome.
How can I detect that? Right now I am able to detect it if user only use one browser, but seems to break when user uses two different browsers to log in at different times.
EDIT* I want to say it's more than just using different browsers, the website should not allow multiple people to log in with the same login credentials.
I am assuming your application is j2EE/servlet based. If it is the case, two browsers are independent of each other, hence they have their own sessionId and can function independently, as long as your application does not interfere.
To prevent this scenario, one way to implement is, keep a hashmap of SessionID and UserID in your servlet. You populate this on every successful login, for example via a filter or a valve. When you are populating the hashmap, make a check, to see if any other sessionID is already using this userID. If it is used, check if the corresponding sessionID is still active. If it is not active, allow the login, and delete the stale sessionID. If it is active, terminate the other session and allow the login.
If you're using Spring Security - it may be specified by parameter in the configuration file.
If just plain java - during log-in put user's session id to some storage; when he tries to log-in again you should prohibit it.
But you need to avoid situation when the user will be in storage very long time after closing the browser (one possible solution is short session timeout + keep-alive requests)
In your application, keep a timeout of the user that's updated after each call to the app. You can define the user as 'locked' into a session (for example your firefox session) until either the timeout expires, or the user requests a logout. When you log in on another browse (for example, chrome) it checks to see if there's an active session and, if there is, denies the login attempt.
I'm going to make up a quick example. This isn't even close to production ready and is for illustrative purposes only.
class User {
long lastCheckin;
int userId;
String username;
}
Now, when someone does anything in the app, like viewing a page, you do this
user.lastCheckin = System.currentTimeMillis();
Now, when someone specifically requests a logout, you do this
user.lastCheckin = 0L;
Now, when someone tries to log in, you do this
if(user.lastCheckin + PREDEFINED_TIMEOUT > System.currentTimeMillis()) {
return new LoginResponse(false,"User is active in another session.");
}
You can store a map of logged-in users on an application scope variable like a ServletContext. For example, on your auth servlet, you can probably do something like:
Map<String,String> activeUsers = request.getSession().getServletContext().getAttribute("__ONLINE_AUTHENTICATED_USERS");
//if null, context hasn't been prepared yet, create and attach a new one?2
You have to be careful though. Being an application scope variable, you need to ensure some thread safety and this is something which the servletContext.setAttribute/getAttribute is providing(e.g. those operations are not thread safe). You may be able to handle this by using some sort of application lifecycle listener to 'initialize' the servletContext to have the user map. This way you won't need to worry about the set/getAttribute. You still need to think about the map operations themselves(e.g. use j.u.c.ConcurrentHashMap maybe?).
You also have to take care of cleaning up(e.g. removing from the map) when a user logs out or session times out.
You also have to consider that a user might lock himself out for a long time by this approach(e.g. close browser but do not logout properly, session needs to timeout before the mapping is cleared).
Edit:
You also need to think about scalability and this depends on your application. Are you expecting a million online users? Or only a couple of thousands?
We have a spring security application with a pretty standard setup. Currently we only allow 1 session per principal, rejecting additional logins by the same principal until the first session is logged out or expired (maximumSessions=1, excpeptionIfMaximumExceeded=true).
I'd like to change this so that when a principal logs in a second time with a currently active login on another session the first session is invalidated/replaced. This is easily accomplished using the provided spring security concurrent session control strategy but I am having trouble figuring out how to alert the user. When a user's session is replaced the session is invalidated by the logout handler. The next request will get a redirect to the login page with a error code on the query string. However, if the request which gets this redirect is an image or other non-programatic call I'm unable to handle this.
It seems like I need to put the user into an inbetween state, where they have a session but it is expired and they need to log back in if they didn't mean to replace their original session. However I don't see a good way to do this.
Is there an example of a setup like this somewhere?
Have you thought of working out a polling mechanism in javascript to alert the user when their session is about to be invalidated? This way they will know that their session isnt valid and possibly have a chance to refresh it in case they have partially filled out forms or text areas.
This can also work from the login side. You can add a step after login if they have another session active and have them verify they want to invalidate it.
It seems that an in between step isnt necessary because, generally,authentication should be boolean. Either they are authenticated or they arent. The inbetween zone might be tougher to handle all cases for.