Set Liferay Hook on session timeout - java

I want to write a Hook in Java that is executed if the session of my Liferay 5.2.3 Portal times out.
I managed to write a Hook that is executed whenever the user clicks the logout link with the following setup in the liferay-hook.xml:
<hook>
<event>
<event-class>com.extensions.hooks.LogoutHook</event-class>
<event-type>logout.events.pre</event-type>
</event>
</hook>
However the Logout Hook does not get called if the session times out, but I need to execute the same method on a timeout. I did not find an event-type for a session timeout.
Is there a way to execute a Java-Method when the session times out and identify the User-ID of the ended session?

There is an event which will be triggered upon Session Expiry/TimeOut event of User Session,
# Servlet session destroy event
servlet.session.destroy.events = com.extensions.hooks.CustomPreSessionExpireAction
You can either add this property in liferay-hook.xml or portal.properties [Written in Hook] or portal-ext.properties.
And can be used as ,
public class CustomPreSessionExpireAction extends SessionAction {
#Override
public void run(HttpSession session) throws ActionException {
//Code
}
}
However, We can only use HttpSession here. So, you need to figure out the way to get userId here.
Thanks

Related

Spring boot session timeout event listener

I want to perform a custom event when a user is logged out from a session timeout. The user is successfully logged out after exactly the length of time specified by my application.properties:
server.servlet.session.timeout=10
server.servlet.session.cookie.max-age=10
I have found a few similar solutions which involve a SessionDestroyedEvent, for example:
#Slf4j
#Component
public class SessionExpiredListener implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
for (SecurityContext securityContext : event.getSecurityContexts()) {
Authentication authentication = securityContext.getAuthentication();
UserPrincipal user = (UserPrincipal) authentication.getPrincipal(); // UserPrincipal is my custom Principal class
log.debug("Session expired!" + user.getUsername());
// do custom event handling
}
}
}
The problem is the SessionDestroyedEvent is not triggered at the same time as the session timeout, in my tests it has triggered up to 5 minutes after the session has expired.
I have also tried using sessionDestroyed in HttpSessionListener but with similar results.
Is there an event that will trigger exactly when the session expires, or is there some way to achieve this?
The sessionDestroyed() method is called when the web container expires the session.
In Tomcat, session expirations happens every minute, and I think it is the case with other servlet containers.
So, even after the session times out there could be a delay until the next detection of expirations.
Session management is done by servlet container, and your application is getting notification from it.
And there is no way to be notified at the exact time of session expiration.
I also had handle the event when the user is logged out by session timeout. For me, this solution was helpfull: https://stackoverflow.com/a/18128496/4074871
Additionally I had to register the HttpSessionEventPublisher as mentioned in https://stackoverflow.com/a/24957247/4074871 because I had no web.xml for listener registration.

Refresh session time when user confirm's to stay online

I am working on JSF framework. In Web.xml session time out time is 5 min. After 4 min i am showing confirm dialog for the user whether to stay active or not. After clicking on Yes I tried sessionObject.setMaxInactiveInterval(5). But session gets invalidated after 5th min. Is there a way to extend user session time dynamically without changing time in web.xml.
public void refreshSession(){
//code to refresh the session
System.out.println("want to stay alive");
HttpSession currentSession = ServerUtility.getSession();
currentSession.setMaxInactiveInterval(2*60);
}
Web.xml sets timeout setting is global, it's applicable for the whole application.
But if you want to extend the session time, you need to create method containing following code:
HttpSession session = request.getSession();
session.setMaxInactiveInterval(5*60);
What you can do is create an endpoint which executes above-mentioned code
public void extendSession(){
HttpSession session = request.getSession();
session.setMaxInactiveInterval(5*60);
}
If User doesn't want to continue then below code will end session immediately:
session.setMaxInactiveInterval(0); // inactive immediately

How to call a method before the session object is destroyed?

When developing a JSP application it's possible to define a session timeout value, say 30 minutes.
After that timeout, the session object is destroyed.
Moreover I can programmatically invalidate a session calling session.invalidate() .
Since I'm saving a complex Java object inside the HTTP session, before invalidate the session or let it expire by the tomcat app server, I need to call a saved object method to release some memory. Of course I can do it programmatically when the user click a logout button.
What I would like to do is intercepting the Tomcat app server when it is going to destroy all expired sessions (30 minutes or custom), so that I can pre-process Java objects saved in the session calling a specific method to release memory.
Is it possible?
Yes, that's possible. You could use HttpSessionListener and do the job in sessionDestroyed() method,
#WebListener
public class MyHttpSessionListener implements HttpSessionListener {
#Override
public void sessionDestroyed(HttpSessionEvent event) {
// Do here the job.
}
// ...
}
Or you could let the complex object which is been stored as a session attribute implement the HttpSessionBindingListener and do the job in valueUnbound() method.
public class YourComplexObject implements HttpSessionBindingListener {
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
// Do here the job.
}
// ...
}
It will be called whenever the object is to be removed from the session (either explicitly by HttpSession#removeAttribute() or by an invalidation/expire of the session).

How to access HTTP sessions in 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.

Java:Why http session is not destroyed when tab or browser is closed?

I have the following implementation of HttpSessionlistener
public class SessionListener implements HttpSessionAttributeListener, HttpSessionListener {
public void attributeAdded(HttpSessionBindingEvent event) {
...
}
public void attributeRemoved(HttpSessionBindingEvent event) {
...
}
public void attributeReplaced(HttpSessionBindingEvent event) {
}
//HttpSesion creation & destruction
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
//log created time
}
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
long destroyedTime = System.currentTimeMillis();
//log destroyed time
}
}
Basically i log the session creation and destruction time.
But if the session is long (default to 30 minutes), and user closes browser meanwhile, the
sessionDestroyed
is not called ?
Why is that ?
Is there a workaround to log exactly the when the session was destroyed (when user closes the browser)? Should'nt be this be the browser's problem, to kill the session when it is closed ?
Is there any interface that i have to implement for this to work ?
Thank you !
How would the server know when the browser is closed or the tab closed? At that point the browser doesn't send anything to the server.
This is a fundamental part of HTTP - it's a request/response protocol, not a "permanently open conversation" where you can tell if one party leaves the conversation. Think of it as a series of telegrams rather than a phone call - and you can't tell when you've received the last telegram you're going to get.
You'll need to design your way round this - to avoid needing to know when the browser has been closed. There are some ugly hacks to work around it - making AJAX poll the server with a heartbeat message, for example - but changing the design is a better solution.
NOTE: As jwenting commented below, this it's not 100% safe at all. If the the onunload event does not get triggered by a closing event of the browser tab or window, then this would fail.
I had the same problem, and solve it using an intrusive JavaScript event:
window.onunload
Let me briefly explain, lets say you have a JavaScript function that post, using jQuery, the current Session ID to that Servlet to invalidate it, like this:
function safeexit(){
$.post("/SessionKillServlet", { SID = <%=session.getId()%> }, function(data){});
}
To call that function, you just need to bind it like these:
window.onunload = safeexit; //without the ()
Now, safeexit method will be called when the TAB or BROWSER WINDOW gets closed (or in a redirection).
Session objects live in the server and are controlled by the server. Only the server can create or destroy sessions. So if the client is closed the session lives until it expires. The client can only suggest to the server that it can destroy some session. This request must be explicit somehow. Hence, when you close a browser window, there's no implicit request to the server informing that it must destroy a given session.
With out a lot of work the browser does not inform the server that the window is closed, therefore Java can not know when to destroy the session. Hence the time out is in place and is the first the server knows that this session can be distroyed.
You could try and play an ajax call on the javascript event document.onunload
https://developer.mozilla.org/en/DOM/window.onunload but you will need to be sure that the user is not still within your site when you do this.
If you need the session to be destroyed when a browser window/tab is closed you might attach a JavaScript handler to the onunload event that makes some sort of AJAX call to a resource that call kill the session.
Note that the onunload event does not always fire so it's not totally trustworthy. One trusty way might be to use a "heartbeat" system.
there is some hacks for knows
following code for destroy session when user closes browser
client side:
<script src="jquery path"></script>
<script>
window.onunload = function(){ $.get("${request.contextPath}/logout"); }
</script>
server side: create request mapping for "/logout"
public void doGet(HttpServletRequest request, HttpServletResponse) {
request.getSession().invalidate();
System.out.println('destroy from logout on unload browser');
}
Following code is optional
use session listener when want to know when session destroyed
// in class
import javax.servlet.*;
import javax.servlet.http.*;
public class SesListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
System.out.println("Session created...");
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("Session destroyed...");
}
}
//-----------------------------------------
// in web.xml
<listener>
<listener-class>SesListener</listener-class>
</listener>
As Eric mentioned the unload event on the browser can call a javascript function, which in turn can access an url through a servlet that logs you out. You need not wait for the actual response from the servlet.
The web browser interacts with the server through the http protocol and that is stateless.
you can just verify if your session user , aren't null like :
if (session.getAttribute("user") != null )
sessionsetAttribute("user","null");

Categories

Resources