Wicket org.apache.wicket.authroles.authentication.AuthenticatedWebSession has 2 methods: signOut and invalidate. The javac says that signOut mark use not logged in while invalidate do the same (e.g. call signOut) but
remove the logon data from where ever they have been persisted
At first glace for logout action signOut should be called. But for security reasons session must be invalidated immediately after user logins or logouts. So from this point invalidate should be called.
So what to call for logout? Also when it is needed to call signOut and when invalidate?
If you want to logout only, use AuthenticatedWebSession#signOut().
AuthenticatedWebSession uses an internal boolean flag 'signedIn' to notice if a user has been signed in (true) or no body has been ever signed in or a user has been logged out.
WebSession#invalidate() is responsible for removing session from the Wicket session registry and its complete invalidation. The implementation of AuthenticatedWebSession#invalidate() invokes AuthenticatedWebSession#signOut() as well, so that the regular log out is done. That could be helpful if your logout process requires some other action, so you can override AuthenticatedWebSession#signOut() method.
In other words:
invalidate() calls signOut() and than removes the session from the session registry.
signOut() marks the session as 'not signed in', but it does NOT remove the session.
For logout you should use #invalidate()! In my opinion #signOut() should not be part of the API. At the best it should be an alias of #invalidate().
If you want to be really secure then you should use #replaceSession() after login.
Related
We have a web-application developed using struts2, spring & hibernate.
The application needs a functionality that one user can login from only one browser.
Say if user x, is logged in on pc-1 browser ff, then he cannot be logged in from any other place.
I tried it by implemention session map and store the sessions in global map, but this fails when user logs off and tries to login again.
Even it fails critically if the user does not logs off and session time-outs, but the map is not cleared.
Any better idea to implement this functionality.
We do not want to obstruct the user to login but do not want users to exploit the application by allowing him to share the creditionals and allow multiple users with same login to happen.
Since you are already using Spring, I would recommend you to integrate your application with Spring Security.
Spring security lets you define maximum sessions allowed per user concurrently.
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
If set when user having valid session tries to login again it will inform user that maximum concurrent access is set to 1.
Read more at the reference documentation of Spring Security: v3.2.x, v4.2.x or v5.1.x.
If spring security is not an option for you then:
Use a SessionInterceptor which will check for session validity, if session is valid it will check if user is already logged in to the application (for this you will have to maintain session somewhere for eg database for every successful login), if valid login is found, redirect user again to login page with custom message, or logout already valid session and then redirect him to login again. If you logout earlier session it would mean any successive action in that browser session will have to deal with invalid session.
If case you are also using Servlet in your application then Interceptor wont work for you, in this case you should use a Filter and follow the same steps as detailed above for Interceptor.
The best solution is to log-off user from other session when he logs in in new session. It is often that user would not logoff when closing browser and restricting him from logging in other window would be the pitfall.
Automaticly closing any previous user sessions is good, because in normal usage, it is no problem, but when sharing login and password, no two persons can work simultanously with your application.
At the login give the user a generated ID/cookie (sessionid suffices) stored with the user data. If a user does a request to the server with an old ID/cookie, say that he logged in elsewhere.
The other way round, forbidding the new login attempt, has its drawbacks - as you've experienced.
Create a map.
At the time of logging check that user id is present into that map or not.
If its not exist then put user id into map, at the time of logout remove that user id.
To be honest I would revisit the reasons why you have to restrict a user to a single login. Whilst preventing them from logging in from two different browsers is easy enough - any of the suggestions provided would work - with the Spring Security option being the easiest to implement if you can - they all break down when your user opens a second tab in the same browser. That is considered to be part of the same session.
Maintain user stack in servlet context,as it will be one for web container.perform a check before user getting logged in, if user name found in servlet context redirect him to login page.
All you should do is add a field in database userprofile table saying: alreadyLogin.
If user logins, make it Y. If user logs out, make it N. Now every time when user tries to login from new location, check this value and prevent login if Value is Y.
As many said, you can have a Map<String, User> (static Map or better an attribute in ServletContext) of (sessionId, user) of active users.
When a user tries to login, first check the existence in theMap.values(), and if it is okay add it to theMap.
Instead of removing from theMap on logout, implement a javax.servlet.http.HttpSessionListener, and on sessionDestroyed method, remove the item from it (the parameter of the method gives you the sessionId). This way if a user closes the browser, after session timeout period, it will be removed automatically.
On logout, invalidate the session, so it will be destroyed, and again this listener get executed.
Don't forget adding the listener to your web.xml.
Im working in a Web App with Java and JSF. I have a simple login, if it finds the user in the database it creates a session and stores some information on it. That works great.
The thing is, I want to avoid two different people using the same user name and password at the same time. Something like account sharing. Only one user logged at one time.
I have been thinking this but I can't find the correct approach.
Thanks in advance for all your help.
One way I can think of is to put a boolean field logged_in to the database and set it to true whenever someone log in and set it to false whenever someone log out or session expired. Set it to false when someone log out is easy. For the session expired part, I believe using JSF, you have a SessionScope managed bean storing information about the user after he log in. You can implement a #PreDestroy method for that managed bean and ask it to set the field to false before it is deleted on session expired event.
When someone send "username" and "password" to the server through the login panel, you just need to check if the logged_in field is true or not.
You can create an application scoped bean for keep track which users are currently login to the web application. When a bean is in the application scoped ,all the request/response cycles for all clients will use the same bean instance .
You may declare a HashSet in this application scoped bean to store all the currently login userID . When a user login , checks whether his userID is inside the HashSet. If yes , it means he login already . Otherwise , it means he does not login yet .
Whenever a user successfully login , put his userID into the HashSet.Whenever a user logout , remove his userID from the HashSet.For the expired of a user session , use HttpSessionListener or #PreDestroy to capture this event and remove the corresponding userID from the HashSet.
For how to use capture the session expired event , you can refer to this.
For how to force an application-scoped bean to instantiate when the webapps starts , you can refer to this
I'm refactoring an application which was doing its own session timeout management. I noted that the HttpSession supports setting a timeout value.
There is an event listener (HttpSessionListener I assume) that is redirecting to a 'timeout' page. "We're sorry your session expired, heres a link to the login page" kind of thing.
The problem is that when I first hit the app and am sitting on the login page, the session timeout event still fires. So I can be looking at the login page and get redirected to the timeout page.
What I want to happen is that if I am on the login page and only on the login page, that the session timeout does not occur. How do I do this?
I have already tried calling HttpSession.setMaxInactiveInterval(-1) in the default view resolution in the login's ActionBean, but that did not work.
I believe the session is being created, but not necessarily authenticated, whenever any page is accessed.
Where do you have the redirecting happening? If it's something declaratively set somewhere in a configuration file you could remove it and implement the HttpSessionListener interface.
In the sessionDestroyed method u would make the following:
Get the session from the sessionEvent
If the session contained an authentication flag then redirect
U could also keep the last page requested by the user and use that as a reference to determine whether to redirect or not but what do you do if a user is already authenticated and browses to the login page? I do not have a lot of information about your application.
Anyway the HttpSessionListener is the way to go I think.
How to get any http session by id or all currently active http sessions within web application (Java 2 EE) in an elegant way?
Currently I have a WebSessionListener and once session was created I put it in ConcurrentHashMap() (map.put(sessionId, sessionObj)), everything ok, I can retrieve HTTP session from that map in any time by session id, but it looks like the HttpSession objects will never finalize... Even session was invalidated the map still reference on invalidated session object... Also I have read this article and it looks like the WeakHashMap is not acceptable in my case...
In other words I need a possiblity to look in any HttpSession even get all currently active HttpSession and retrieve some attributes from there...
Please advice somebody :)
Update
I need to access HttpSession objects because of follwoing reason:
Sometimes user does some actions/requests that may impact the work of another concurrent user, for example admin should disable user account but this user currently working with the system, in this case I need to show a message to admin e.g. "user XXX is currently working with the system" hence I need to check if any HttpSession which holds credentials of user XXX already exists and active. So this is whay I need such possibility to get any http session or even all sessions.
My current implementation is: SessionManager which knows about all sessions (ConcurrentMap) and HttpSessionListener which put/remove session into SessionManager.
I was concerned about memory issues that may occure and I wanted to discusse this with someone, but currently I am clearly see that everything should works fine because all invalidated session will be removed from map when sessionDestroyed() method will be called...
Many thanks for your replays, but now I understood that problem was just imagination :)
As per your clarification:
Sometimes user does some actions/requests that may impact the work of another concurrent user, for example admin should disable user account but this user currently working with the system, in this case I need to show a message to admin e.g. "user XXX is currently working with the system" hence I need to check if any HttpSession which holds credentials of user XXX already exists and active. So this is whay I need such possibility to get any http session or even all sessions.
For this you actually don't need to know anything about the sessions. You just need to know which users are logged in. For that you can perfectly let the model object representing the logged in user implement HttpSessionBindingListener. I of course assume that you're following the normal idiom to login/logout user by setting/removing the User model as a session attribute.
public class User implements HttpSessionBindingListener {
#Override
public void valueBound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.add(this);
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.remove(this);
}
// #Override equals() and hashCode() as well!
}
Then somewhere in your admin app, just obtain the logins from ServletContext:
Set<User> logins = (Set<User>) servletContext.getAttribute("logins");
Generally speaking, your servlet container will have its own session manager, which is responsible both for maintaining the lifecycle of the sessions, and associating incoming requests with the appropriate session (via cookies, anchor parameters, whatever strategy it wants).
The elegant way to do this would be to hook into this session manager in whatever way it allows. You could subclass the default one, for example, to allow you to get access to arbitrary sessions.
However, it sounds like what you're doing belies an underlying problem with your architecture. The data contained within a session should be specific to that session, so in general you shouldn't need to look up an arbitrary one in order to provide the standard logic of your web application. And administrative/housekeeping tasks are usually handled for you by the container - so again, you shouldn't need to interfere with this.
If you gave an indication of why you want access to arbitrary sessions, chances are that an alternative approach is more suited to your goals.
Andrzej Doyle is very right. But if you really, really want to manage your own list of sessions, then the way to connect to your container is via the HttpSessionListener - example code.
The listener is called whenever a new session is created, and importantly, it's also called when a session is destroyed; this will allow you to mimic the container's session bookkeeping.
You use your web.xml to register your session listener as a lifecycle listener for your your app.
You can communicate your session list with other processes in the container using the ServletContext, or you can cook up a more dirty scheme using e.g. static class fields.
I have a series signup pages that build on each other. When the users session expires I have a Listener that cleans everything up on the server and that works great. But, if the user attempts to do anything else I just want to redirect them back to the first page of the series. However, my filter doesn't seem to work correctly. I keep getting javax.faces.application.ViewExpiredException
What is the best practice for handling this expcetion? I can't really just handle in web.xml because that's too global. Plus the Error page is being rendered from some JSF code - it seems like I need to catch that this is happening using a PhaseListener so the exception doesn't happen in the first place, but I haven't been able to find a good model for how to do this. Any ideas?
Richfaces has their own mechanism for handling ViewExpiredException, look at Richfaces docs.
I think you are the correct track with a phase listener. Essentially set something up in session on the first page. Then in phase listener look for the value in session. If it doesn't exit then do a redirect. The trick is to do it early in the phase listener process.
Not sure exactly where in the process your phase listener is throwing the exception.
The way I handle this is to add a filter to the web.xml only mapped to the urls you want to track. That filter checks if the session is expired, and then forwards to a login page if it is. It should work if the filter is run before any JSF code is run.
The way I have handled this in the past is to use a listener which checks a field in a managed session bean. If the users session times out a listener cleans up the mbean and marks the user as not logged in. Every request is sent through the listener and if the requirements are not met then the user is forced out of the site. I never get ViewExpiredException in my log. The only time this exception has occurred is if the server has been restarted and the user requests a page when having a previous active session.
You can check whether you session is invalidate or not
boolean sessionInValid = httpServletRequest.getRequestedSessionId()
!= null &&
!httpServletRequest.isRequestedSessionIdValid();
Here the boolean variable sessionInValid will return true if the session is invalidate by any means.
You can add this in a filter or a listener then configure this in your web.xml file.