In my Vaadin application I have an issue when Vaadin does not invalidate session after "Session timeout" message. After getting this message users sometimes are able to click the link or refresh the page and continue working as if they are still being logged in.
I use the following parameters:
closeIdleSessions=true
heartbeatInterval=60
session-timeout=15
Last parameter (session-timeout) is also set in context.xml (session-timeout=900) and web.xml (session-config/session-timeout=15) as I didn't get clear from vaadin documentation, is there such a parameter for vaadin servlet or not.
Did anybody face the titular problem?
UPDATE 1: Fixed parameters snippet.
UPDATE 2: SessionDestroyListener.sessionDestroy does not get triggered when Session expired message appears.
UPDATE 3: Previous error appeared because of code mistake. Now SessionDestroyListener.sessionDestroy gets called, but I have no access to HttpSession from given event.
Here is my SessionDestroyListener code (please note the comment in one of if branches):
private static class SynchronizerSessionDestroyListener implements SessionDestroyListener {
#Override
public void sessionDestroy(SessionDestroyEvent event) {
if (event.getSession() != null){
WrappedSession wrappedSession = event.getSession().getSession();
if (wrappedSession instanceof WrappedHttpSession){
WrappedHttpSession wrappedHttpSession = (WrappedHttpSession) wrappedSession;
HttpSession httpSession = wrappedHttpSession.getHttpSession();
if (httpSession != null){
try {
httpSession.invalidate();
logger.debug("Session '{}' was invalidated", httpSession.getId());
} catch (IllegalStateException e){
// do nothing, already invalidated
logger.debug("Session '{}' was already invalidated: {}", httpSession.getId(), e.getMessage());
}
} else {
logger.warn("Could not invalidate http session for vaadin session: http session is null"); // THIS IS THE BRANCH WHICH IS ACTUALLY GET EXECUTED ON 'SESSION EXPIRED' MESSAGE: event.getSession().getSession() is null!
}
} else {
logger.warn("Could not invalidate http session for vaadin session: event session is not an http session");
}
} else {
logger.warn("Could not invalidate http session for vaadin session: event session is null");
}
}
}
Here is how I attach the listener:
public class X extends VaadinServlet {
// different class members
#Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionDestroyListener(new SynchronizerSessionDestroyListener());
}
}
I will try to explain how the session invalidation basically works, maybe this helps (I can't read too much information out of your question):
Usually the session will timeout after the specified time inside the
session-timeout parameter.
BUT you have the take the heartbeat
interval into account. If your heartbeat interval is shorter
than the session timeout (it usually is), the heartbeat will keep the session alive
forever.
Thats where the parameter closeIdleSessions is relevant. Setting
this parameter to true the browser will not take the heartbeats as
a valid request for the timeout, but the last, non-heartbeat
request.
Second BUT: When will the timeout be recognized? The client-side engine can only recognize this at a heartbeat or if the user takes some action (as in both cases a request to the server is done). By consequence the actual timeout will not occur when the specified timeout has passed, but at the next heartbeat after the timeout.
Other situation: after 3 missing heartbeats, the server also closes the session. E.g. if the browser is closed this will cause the session to be invalidated as no heartbeats are sent.
Sample web.xml to explain better:
<context-param>
<!-- ATTENTION: This value is set in SECONDS -->
<param-name>heartbeatInterval</param-name>
<param-value>180</param-value>
</context-param>
<session-config>
<!-- ATTENTION: This value is set in MINUTES -->
<session-timeout>4</session-timeout>
</session-config>
<servlet>
<servlet-name>VaadinServlet</servlet-name>
<servlet-class>com.example.VaadinServlet</servlet-class>
<init-param>
<param-name>closeIdleSessions</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
Using the above web.xml the session will timeout after 6 minutes (without user interaction).
Explanation:
the session timeout is set to 4 minutes, but there is no heartbeat at 4 minutes. The next heartbeat will be at 6 minutes. Now the client side engine knows that the session actually timed out and will show the according message.
I am not sure if this is the same process when using Vaadin Push as there we have a continous channel from client to server.
Sources:
Book of Vaadin - 4.8.7. Session Expiration
Book of Vaadin - 4.9.6. Other Servlet Configuration Parameters, Session Timeout After User Inactivity
Additional information:
Upcoming Vaadin 7.6 seems to improve client-server connection stability: Blog Post
Related
In my RAP application I need to do some logout handling (forward do keycloak sso/logout).
Where would be a good hook to do that?
org.eclipse.ui.application.WorkbenchAdvisor.postShutdown() is executed also if I refresh my browser window (F5), I don't want the session to logout on-refresh. Rather if the session is expired or the browser window is closed.
Is there a hook for expired sessions or a session invalidation event?
Found UISessionListener.beforeDestroy() but it also is executed on browser-refresh:
RWT.getUISession().addUISessionListener(new UISessionListener() {
#Override
public void beforeDestroy(UISessionEvent event) {
System.out.println("UISessionListener.beforeDestroy" + event);
}
});
Code show that UISessionListener catch the event UISessionEvent that contains
UISession. This object is bound to HttpSession, if you don't wont to expire just configure session to endless(better to make it quit long but not endless depends on amount of users using application).
HttpSession has expiration time by default (for example for apache tomcat it is 30m). But it is configurable. Session expired when not single "touch" of session (request) in such timeout occurs.
Also by default session will "survive" during tab close/open, since cookie saved on client side (again this behaviour configurable).
Is it possible to manually reset the timeout interval of a specific session for a user that is currently logged in my web app?
I would like the ability to do something similar to this :
public void keepAliveForUser(long userID) {
Session session = this.userSessionManager.getUserSessionById(userID);
session.resetTimeOut();
}
P.S - keep in mind this function is not being called in a follow up to a user request. (i.e. It's called from a cron job, a scheduled task, etc...)
Thanks!
You can use HttpSession#setMaxInactiveInterval to change the session expiry time on the fly
Java Doc
Specifies the time, in seconds, between client requests before the
servlet container will invalidate this session. A negative time
indicates the session should never timeout.
Usage
//session will expire after 2 hours of inactivity
session.setMaxInactiveInterval(2 * 60 * 60);
Session timeout hierarchy:
$tomcat_home/conf/web.xml
$your_webapp/WEB-INF/web.xml
manual invocation of HttpSession.setMaxInactiveInterval(int)
I want to find the first request which is coming to jsp. Once a window is closed, again I want to find the first request coming to jsp, but I do not want to restart my server. I am trying this:
String name=session.getAttribute("val");
if(name!=null)
{
//something
}
else
{
//something
}
It is working only for the first request. After that, I have to restart the server again and again.
Moreover, I want to find the time spent on particular jsp.
You are storing the data in Server Session. It has invalidation period (configurable, let's say 10 min for example), so it is cleared only after this period. Closing the window doesn't affect this logic at all.
Handling of window behavior should be done on client side with Javascript. Take a look at window.onload and window.onbeforeunload events.
Time spent on the page can also be captured on client side. In general the logic could be:
When page loaded (onload event) you start the timer.
When page is unloaded (onbeforeunload event) you save timer value to some local storage of sending it to server with ajax call.
This is what you are looking for.
How to end sessions automatically if user closes the browser
Killing session when closing the browser
Try with below options:
web.xml
<session-config>
<session-timeout> 5 </session-timeout>
</session-config>
HttpSession.invalidate()
set the cache-control meta tag in the header to no cache to prevent session reuse.
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.
I've a web page, where user can extend the session using AJAX call to server. If the application configured session timeout is for 30 minutes, he can extend the session for 5 minutes by pressing a button. When this user submits the pages, I need to reset this session timeout value back to the global session-timeout value.
Is it possible in Java to reset it?
or
Is it possible to read the global session-timeout value which is configured in web.xml?
EDIT:
I'm using the following code to extend the session
request.getSession().setMaxInactiveInterval(300000);
How do the user extend the session. I mean do you give a javascript alert/confirm box regarding it.
Ideally, session should automatically be extended when the user submits a request to the server.
setMaxInactiveInterval() in code and <session-config> in web.xml should do the stuff in normal scenario.
Share the exact situation of your application
EDIT:
Sending a dummy request to a JSP should automatically extend the session as session time out is measured in terms of inactive interval and the dummy request should discard the inactive interval till now.
I solved it by setting the default session as a session variable on execution of an action class, then using it to reset when ever required.
I'm not sure this is the right way to solve this. but it solve my issue, at least for now.
The time out and rest function is here and it will work accordingly to the service response.
Time setting function:
$rootScope.SessionTime =localStorage.getItem('mint');
$rootScope.tickDuration=1000;
$rootScope.myInterval=setInterval(function(){
$rootScope.SessionTime=$rootScope.SessionTime-$rootScope.tickDuration
//console.log("secs:::::"+$rootScope.SessionTime);
if($rootScope.SessionTime<300000 && $rootScope.tickDuration >0){
$('#session').modal('show');
$rootScope.tickDuration =0;
}
},$rootScope.tickDuration);
Time out function:
$scope.myTimeout = function(){
var sessionId=getcokkies.getsessionId();
$http({
url: config.apiUrl + '/user/refreshsession?sessionId='+sessionId,
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: $.param({
'userId': parseInt(getcokkies.getUserId()),
})
}).then(function successCallback(response) {
//localStorage.setItem("mint", 600000);
//$rootScope.SessionTime = 600000;
clearInterval($rootScope.myInterval);
localStorage.setItem("mint", 600000);
$rootScope.SessionTime =localStorage.getItem('mint');
// console.log("after++++"+$rootScope.SessionTime);
$rootScope.tickDuration=1000;
}, function errorCallback(response) {});
}