Scala and Lift and SessionVar that loses it contents - session

I have SessionVar like this in Lift:
object MyObject {
object myVar extends SessionVar[Box[MyObject]](Empty)
}
Then I set value once for myVar:
MyObject.myVar(Full(value))
My problem is that after some time (1-5 mins) myVar will lose its value, that is, it will have value Empty again. This is not due inactivity since I am clicking pages constantly. My code is not setting value to Empty. During this 1-5 mins the myVar will work correctly. The logs contain no related messages.
I tried to add shutdown method to myVar, but it is not getting called.
override protected def onShutdown(session: CleanUpParam): Unit = {
Log.error("shutdown executed")
}
I am running Lift in jetty via mvn jetty:run command. I am using 1.1-SNAPSHOT of Lift. I am not creating explicitly any kind of cookie or session.
Any ideas what is happening? It could be that session expires or invalidates somehow, but why and by whom?
I even tried to disable liftGC with (LiftRules.enableLiftGC = false) but that does not affect.

I imagine that the issue is that while clicking around, you are accidentally creating a new session. That would explain why you're not getting the session shutdown event: the old session still exists, but you're no longer using it. I suggest that you print out the session ID with each request and see if it changes.
You might be losing the session because the session cookie is expiring, or because you aren't URL-encoding some links (see HttpServletResponse.encodeURL), or because you are navigating outside your application's context path.

What's your session expiry time set in LiftRules?

Related

Only one User using entire web application at a time - Spring boot

In spring boot application only one user should be using the certain page at a time (let's call it home.jsp). Another users should be redirected to different page(let's call it another_home.jsp) if they appear when accessing that same url. User doesn't login and just uses the application as it is. Any policy can be used for home.jsp could be first-come-first-serve or any other.
If more than one users are using application at a time only one user should be using home.html and all rest of the others should be using another_home.jsp.
As no login is needed in the application I believe I need anonymous sessions. Also, session needs to be expired after some time of inactivity. I've searched spring security but couldn't find anything.
I think that you don't even need spring security. Simple http session will work too. As far as I can see you just want to allocate the stream to one user and for that you need first user's session id which you can compare against whenever the requests come again. So store session id and expire after some timeout with some Time object or Date object.
In properties
server.servlet.session.timeout = 600 // 10 minutes
Something like this
private String currSessionId = null;
private Date lastDate = new Date();
private Integer TIMEOUT = 600000; // 10 minutes
public String loadHomePage(Model model) {
if(currSessionId!=null && new Date().getTime()- lastDate.getTime()>TIMEOUT){
currSessionId = null;
}
if(currSessionId==null){
currSessionId = session.getId();
lastDate = new Date();
return "home";
}else{
if(session.getId().equals(currSessionId)){
return "home";
}else{
return "another_home";
}
}
}
This is as simple as it gets when you don't have logged in users to manage and also don't need to remember previous state where user left off. Let me know if it helps.
You need to create a serverside state that is either empty or stores the identifier of the visitor that is currently claiming /home.jsp.
This could be a field on a singleton Bean, or an entity in the database.
It has to expire automatically, or it will prevent new visitors forever to make a claim.
As long as the state is empty, the first visitors identifier will be stored in this state.
And from that moment on, you will redirect all other visitors to another_home.jsp
So the Controllers Code would be something like this
if(visitorHoldsTheClaim()) {
return "home.jsp"
} else if (noClaimActive()) {
createClaimForVisitor();
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Depending on your implementation, these methods will do different things.
I'd usually recommend against serverside session state (more about this in Roy Fieldings Dissertation),
but for your use case, you need a way to identify a visitor over many requests.
A session would certainly be a very simple way to achieve this.
You can at least minimize session usage by only creating one session at a time - the one for the visitor that holds the claim.
In this case you'd never have more than one open session, and the visitor that owns the session is the visitor that holds the claim.
So in this case, the implementation would be be something like this:
if(currentUserHasASession()) { // checks if the current user has a session, but !!!does not create a new session if it does not exist!!! careful, HttpServletRequest.getSession(true) would create it!
return "home.jsp"
} else if (serverHasNoSessions()) { // https://stackoverflow.com/questions/49539076/how-can-i-get-a-list-of-all-sessions-in-spring
createSessionForUser(); // HttpServletRequest.getSession(true)
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Keep in mind that this only works if you do not create Sessions in another place.
So you have to configure Spring Boot/Spring Security to not create Sessions. How to make spring boot never issue session cookie?
Also keep concurrency in mind. For example, if you had only one server instance, you could put this code into a synchronized method to avoid two visitors creating a claim at the same time.
So... first of all, this sounds like a bad idea. I would be curious why you would need such an unusual behavior. There might be more sensible approaches for it.
Like Gregor said, the redirect code part is rather straightforward:
if(pageLock.getUser() == null) {
pageLock.setUser(user);
}
if(user.equals(pageLock.getUser())) {
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
What is actually more tricky is the part when "expiring" the lock. It's likely the user will simply close the browser and not click on "logout" (or whatever), leaving the lock forever. On the other extreme, the user might be gone for a lunch break but its browser still has the page open for hours.
So that's the first thing you wanna add: some keep-alive mechanism on the page, regularly prolonging the lock, and some expiration checker, releasing the lock if nothing was received for a while.
...but like I said in the beginning, the whole thing sounds fishy.

Adobe Analytics - Force a session/userID refresh

We have a website that can be viwed from a kiosk in a shop.
When the inactivity is above 2 minutes, the site returns to the home.
Anyone knows how to refresh the session when this appens?
It could also serve make a refresh of the user id, but I don't know how it works.
I'm going to assume you are talking about Adobe Analytics javascript library and not the Android/iOS SDK, based on your tagging and lack of mention of it. If your kiosk is in fact using Android or iOS SDK, then please comment and I can update with instructions for that.
Adobe Analytics javascript library does not currently offer a direct method to force refresh an Adobe Analytics session/userID. However, you can effectively do it by explicitly setting s.visitorID yourself, which will override the default generated by the library.
So, when you want to start a new session, you can pop s.visitorID with for example the current timestamp:
s.visitorID = (new Date()).getTime().toString();
Or maybe you already have a "session" id you generate that you can use, instead.
Note: with this method, you must set s.visitorID (with the same value) for every hit for the duration of your session. So in practice, you would really do something more along the lines of generate the new value at start of session, put the value in a cookie, and put s.visitorID in s_doPlugin but it reads the cookie value.
Note: This will effectively make your visits and visitors metrics the same. Which is to be expected with a publicly shared device, but just mentioning it in case it comes up later.
pseudocode:
function startNewSession() {
// use whatever cookie writing utility you have to
// set a cookie named visitorID set to the generated
// value. In practice, the expiration doesn't really
// matter as long as it's something longer than
// your average session. Just setting it to default
// session expiration should be okay
var visitorID = (new Date()).getTime().toString();
setCookie('visitorID',visitorID);
}
// in your existing logic that times out returning
// home after 2 minutes of inactivity, call the function
// to generate a new id
startNewSession();
// this is AA's s_doPlugins callback function. This may look
// slightly different, maybe defined as s_doPlugins and then assigned
// to s.doPlugins, depending on what AA lib version you are using.
// This is AA's callback function that gets called whenever
// an s.t or s.tl call is made
s.usePlugins=true;
s.doPlugins=function(s) {
// make sure visitorID variable is addedto linkTrackVars
// so it gets 'registered' for s.tl calls.
s.linkTrackVars='visitorID';
// explicitly set the visitorID with the cookie, using
// whatever cookie reading utility you have.
s.visitorID=readCookie('visitorID');
}

how to delete a value from session with revel

Is there a way to delete the value from session witch revel the go web framework?
I have a function for validate captcha for user input, and I set the value of captcha in session, and delete the captcha from session if there nothing to do for client after 1 minute. The code is like:
time.AfterFunc(time.Minute, func() {
delete(this.Session, CSecurityCode)
})
But I can still get the old value of captcha , why, and how to fix this?
Anybody who can help me?
The Session value is valid only while processing a client request. i.e. between the time you get the request and the time you respond to that request. Its contents are kept in a cookie on the client side and you'll get a new Session every time the client connects to your server. Thus if you keep it for later use (like the name of your AfterFunc suggests, triggered by a timer?), anything you do with it will be lost on the next client connection.
In order to achieve what you want to do, you'll need to add a "lastSeen" timestamp to the Session. When a request comes in, check Session["lastSeen"], and if it's older than 1 minute, then you can discard CSecurityCode from it.

How to prevent AJAX polling keeping Asp.Net sessions alive

We have a ASP.Net application that has been given a 20 minute sliding expiry for the session (and cookie).
However, we have some AJAX that is polling the server for new information. The downside of this of course is that the session will continue indefinitely, as it is being kept alive by the polling calls causing the expiry time to be refreshed. Is there a way of preventing this - i.e. to only allow the session to be refreshed on non-ajax calls?
Turning off sliding expiry is not really an option as this is an application that business users will be using for most of their day between telephone calls.
Other Stackoverflow discussions on this talk about maintaining 2 separate application (one for authenticated calls, one for unauthenticated. I'm not sure this will be an option as all calls need to be authenticated.
Any ideas?
As this question is old I am assuming it has been resolved or a workaround implemented. However, I wanted to mention that instead of AJAX polling the server to perform an operation we have utilized SignalR which allows both the client to communicate with the server via JQuery and/or the server to notify the client.
Check it out: Learn About ASP.NET SignalR
add below code to your controller action that you are reference for polling.Convert this into an attribute so it can be used everywhere. This line will not extend session timeout
[HttpPost]
public ActionResult Run()
{
Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
return Json("");
}
There is no way to stop the ajax from keeping the session and cookies alive!
However, there is a way to achieve what you want to do. That is if the process I will describe will be ok to you.
I think what you really want to achieve is first to refresh your page with ajax so that some processes will be active and running. Also to know when the user has stopped operating the program.
If that is what you want then there is a simple process to achieve this
You will have your ajax running for the things you want to run.
You will remove the session you want to check if user has stopped operation on the page and manage the session as a variable instead.
The variable can be a global variable or a class variable that will be set to initial value whenever the user clicks an element on the page.
(You will select the click event of an element and set the variable to initial value)
You will increment the variable every given time (say every time your ajax runs)
You will also have a function/method run to check the value of that variable if it is greater than the value you set as limit. This can run every time your ajax runs or every time you want it to run (timed event).
If the value of your variable is greater than the limit set it should invalidate or clear session/log user out.
This way if user stops operating (clicking elements) the system on any page that this is running will eventually log out the current user and stop running the program.
I have done this by creating a hidden page in an i-Frame. Then using JavaScript it posts back every 18 minutes to keep the session alive. This works really well.
This example is from a ASP.NET Forms project but could be tweaked for MVC.
Create a page called KeepSessionAlive page and add a meta refresh tag
meta id="MetaRefresh" http-equiv="refresh" content="21600;url=KeepSessionAlive.aspx"
In the code behind
protected string WindowStatusText = "";
protected void Page_Load(object sender, EventArgs e)
{
//string RefreshValue = Convert.ToString((Session.Timeout * 60) - 60);
string RefreshValue = Convert.ToString((Session.Timeout * 60) - 90);
// Refresh this page 60 seconds before session timeout, effectively resetting the session timeout counter.
MetaRefresh.Attributes["content"] = RefreshValue + ";url=KeepSessionAlive.aspx?q=" + DateTime.Now.Ticks;
WindowStatusText = "Last refresh " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
}
Add the hidden iFrame in a master page
iframe ID="KeepAliveFrame" src="KeepSessionAlive.aspx" frameBorder="0" width="0" height="0"
Download example

How to set expiration time to session in the controller?

I need to set a session with expiration time of 5min in controller. How do i do it?
I need something like:
$this->container->get('session')->set('mysession', 'value', 'expiration');
in symfony2 way?
Thanks!
Assuming your session is already created, you can achive your goal with:
$this->container->get('session')->migrate($destroy = false, $lifetime = null);
$destroy: Whether to delete the old session or leave it to garbage collection.
$lifetime: Sets the cookie lifetime for the session cookie. A null value will leave the system settings unchanged, 0 sets the cookie to expire with browser session. Time is in seconds, and is not a Unix timestamp.
This feature is added recently. You can update to this commit or patch. From the code it seems you can set expiry time by following way,
$this->container->get('session')->getMetadataBag()->stampNew(300);
To control the time of the active session (and idle time too) you have to do it in the controller this way (extract from: session configuration in the official doc):
$session->start();
if (time() - $session->getMetadataBag()->getCreated() > $maxTime) {
$session->invalidate();
throw new SessionExpired(); // redirect to expired session page
}
When time reaches your $maxTime session is "closed". You can put this code in the backend of your app as a function to call from the different methods to control the time.

Resources