How to access HTTP sessions in Java - java

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.

Related

User Session in Rest

i'm working a webapp with REST services in java using Spring and AngularJs.
When user authenticates some session data is mantained in the server session (userid, user structure code).
When i do some user request (a product search for example) i need these data (i.e. user structure code).
I can proceed in 2 ways:
send the structure code from client
get the structure code in server, accessing the user session
In case 1 my REST API should have the structure code in its parameters, but i need to develop some safety check on server, otherwise, theoretically, a 'smart' user can ask for data for other structure codes.
In case 2 my REST API doesn't need the structure code in its parameters, as it can be taken from the session. And i don't need to implement a safety check procedure either, so server can process the requests in a quicker way.
I know REST calls should be stateless, but as i understood, the 'stateless' mean not maintaining session state (i.e. subsequent states changes following requests). In my case i don't maintain session state, but some static user informations.
Is this correct in terms of REST paradigm or i need to pass the structure code in the request, make the safety check procedure etc ?
EDIT
To Clarify, here is an example session object
public class userData {
private String userId;
private String structureCode;
...getters and setters
}

How to initialise a session in Play

Well, this is from a developer newly using Play. When it came to using session, I found its not at all like I have been doing in servlets or jsps.
I have tried reading documentation and found session in Play are stored in HTTP cookies rather. I have tried importing HTTP class of play.
My problem however is I am unable to initialise a new session to set values in it.
I have obviously tried using 'new' session as in Java and that obviosly didnt work out.
Session session = new session();
Also after looking somewhere I have used:
Session session = Http.Context.current().session();
which shows me error in identifying context and current
I have tried looking at sample codes and codes on net. each of them however is different and I don't get the basic way of using sessions in Play, so that after that I can use put and get to keep and retrieve.
I know the question seems too basic but believe me there is no exact answer available anywhere to what I need. So please help me regarding this.
Any answer, any piece of code, or any Link on this will be highly appreciated.
Forget everything about the sessions from the jsp and servlets world while working with the Play's session. Play doesn't store anything on the server side and by design it's completely stateless. The Play session is just a cookie attached to every http request and it's stored on the client side. Word 'session' may be misleading in your case.
Working with the session is pretty straight forward. All you need is inherited from play.mvc.Controller which you have to extend when creating your own controller. To put a value in it you simply call the session(String key, String value) method from within a controller. For example:
public class Application extends Controller {
public static Result login() {
session("key", "example value");
return ok("Welcome!");
}
}
If there is no session cookie stored on client side this method will create new one and attach it to the HTTP response. Otherwise it will modify the existing one.
To read stored value use:
String value = session("key");
You can also remove value from the session:
session().remove("key");
or completely destroy it:
session().clear();
These are helper methods to work with the particular cookie witch in Play's terminology is called session. Nothing stops you from creating another cookie with similar purpose. But it'll require more writing. These helper methods saves your time and in many cases are more than enough.
You can specify session cookie name in your application.conf by setting session.cookieName property.
In play 2.8 the Http.Context was deprecated. This means, among other things, that the method "session()" is no longer available in a controller.
This is the updated way of doing it:
public Result info(Http.Request request) {
//This is the equivalent to the old session()
request.session() ...
}
The Http.Request needs to be passed down through the route defined in routes. More information here.

How do you cache data only for the duration of the http request using apache shiro in a servlet container?

More specifically, I find that I'm implementing a custom AuthorizingRealm, which declares template methods doGetAuthenticationInfo() and doGetAuthorizationInfo() for returning AuthenticationInfo and AuthorizationInfo objects, respectively.
However, when I retrieve the data for the AuthenticationInfo (a JPA entity) in doGetAuthenticationInfo(), I find that I already have the necessary AuthorizationInfo. Alas, there's no apparantly good way to hang onto this data, so I have to throw it out only to perform another JPA lookup when the authorization filter ultimately gets its turn in the filter chain.
Behold:
public class CustomRealm extends AuthorizingRealm {
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
String username = userPassToken.getUsername()
User user; // Contains username, password, and roles
// Perform JPA lookup by username...
return constructSimpleAuthenticationInfoFromUser(user);
}
#Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// Look up user again? :(
...
}
}
I've considered a number of possibilities:
Use realm caching. The application will run in a distributed environment so there could be any arbitrary number of JVMs running. The default realm cache manager implementations don't solve all of the inherent problems and setting up an enterprise implementations seems out of scope for this project.
Use the subject's session. There is no server-side state and I'd like to keep it that way if possible. Perhaps you can force the session to behave like request scope, but I wouldn't know how to do so and that risks being obfuscated.
Implement my own Subject. There appears to typically be one Subject instance per request, but it's unclear how to bootstrap this and I would risk losing a lot of potential functionality.
Use the Shiro ThreadContext object. I could attach the data to the ThreadContext as a threadlocal property. Servlet containers generally follow a thread-per-request model, and the Subject instance itself seems to chill out here, awaiting its inevitable garbage collection. Shiro also appears to build up and tear down the context automatically. However, there's not much documentation on this and the source code is hard for me to follow.
Finally, the default WebSecurityManager keeps singleton instances of the CustomRealm around, one per JVM it seems. Simply setting some local instance property is not thread-safe.
This seems like a common data retrieval option and a typical deployment scenario. So, what am I missing?
Thanks!
I would go with option 4 - Using ThreadLocal object as your requirement clearly says that the object lifetime must be of http request.
Have a look at this discussion: When and how should I use a ThreadLocal variable?
ThreadLocal doc: http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

Allow only one session per user

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.

How to manually kill a specific HttpSession by ID

We need a functionality of killing a specific session (by session ID) from some kind of an admin panel.
I attempted using the following approach:
public static void killSession(String sid) {
HttpSessionContext sc = FacesUtil.getSession().getSessionContext();
HttpSession session=sc.getSession(sid);
session.invalidate();
}
However
HttpSessionContext, and getSessionContext() and
getSession(sessionId) methods of a session are all deprecated (for seemingly paranoid security reasons)
The above code also gets a null session when invoked in an ApplicationScoped JSF managed bean
I'm seeking an alternative way of achieving the functionality.
Yes, you can't invalidate session from another session due to security reasons. What you can do is to manually store all sessions in some static attribute available to admin. So user logs in, you add him and his session to this attribute (usually a Map/HashMap with user as a key and session as value).
Look at my older answer here and you will get an idea.

Categories

Resources