Why code igniter session time expiration not calculating from last user activity? - codeigniter

I am wondering why codeigniter session time expiration is not calculating from last user activity.This way i can retain active users. Right now even user performing activities, the session gets expired due to the limitation.

I think you are facing a bug.
Codeigniter's session stores the timestamp of your user's last activity.
The framework use this information to calculate the expiration time.
Also, I've read multiple times that Ajax calls may broke CI sessions. I've also been struggling with CI's sessions and i've been forced to pass $config['sess_use_database'] to false as a workaround.
https://degreesofzero.com/article/fixing-the-expiring-session-problem-in-codeigniter.html
https://ellislab.com/codeigniter/user-guide/libraries/sessions.html
https://ellislab.com/forums/viewthread/182755/#900523

You can check whether user is performing activity or not. If not you can ask the process to sleep for 1 sec. This way the session will never expire.
sleep(1);
In PHP this will work. This way you can make the process sleep when user is idle.

Related

Community-auth Codeigniter 3 - randomly seems to lose session variable

I am using Community-Auth with Codeingniter V3 to do authentication and to store authorization levels, etc.
The problem I am having is that my users are sometimes being redirected to the login page, even though they have not been inactive. I cannot seem to isolate a particular behavior or pattern to duplicate the problem.
The problem occurs when a controller calls the verify_min_level routine which should just verify that they are logged on. But it returns FALSE, which means Community-Auth believes they are not logged in, and the code redirects to the login screen.
Since it seems to happen randomly and for no apparent reason (the user was not inactive for a while, etc) it is driving my users crazy.
Has anyone else seen this kind of behavior?
I seem to have identified the problem. This particular client wanted sessions that would only end when they logged out or closed their browser window. So I set the session expiration to zero (0).
I thought that the garbage collection would only delete sessions occasionally (given that in codeigniter I understand that 0 means the session ends in two years) and that I would catch up with it with my own garbage collection. However I started noticing that the ci_sessions table (I moved session data to database from file system to help debug this issue) would have multiple sessions removed frequently, even though none of the sessions were anywhere near two years old.
What seems to have solved the problem is to turn off the garbage collection completely by setting the PHP parameter sessions.gc_probability to 0.
No garbage collection, no premature deletion of session variables.
I am implementing a nightly CRON job to do garbage collection of the ci_sessions table.

Check availability of resource used by another user

Building a web application.
User have access trough their browser to shared resources host on a server, however if UserA is already using Resource1, Resource1 should not be available to UserB until UserA release Resource1 or until a given amount of time.
For this part : I chose to use a MySQL table with a list of tuples (resource,currentuser) and run a cron task to delete expired tuples.
Now I want to be able to notify UserA that UserB wants to access Resource1 and if get not answer from UserA, then UserA lost his lock on Resource1 and then the Resource is then available to UserB.
For this part, I guess I have to use AJAX. I have thought about the following solution :
User's browser make periodic AJAX call (let's say each minute) to prove he is still alive and upon a call, if another User has requested the same resource, he has to challenge a server request in a given amount of time(for example a captcha). If the challenge fails, it means the user is not here anymore (maybe he left his browser opened or the webpage unfocused).
The tricky part is : "he has to challenge a server request in a given amount of time (for example a captcha)". How to do that?
Am I following the best path ?
Yes, what you've outlined is fine. Using ajax is also completely fine, especially if you're simply polling every minute.
For example, let's say you have the following:
setInterval(function() {
$.get('/resource/status', function(response) {
if (response.data.newRequest) {
//This would signal a new request to the resource
}
})
}, 60000)
When handling the new request to access the resource, you could use something like reCaptcha and display that however appropriate (overlay or inline). When you do this, you could also start a timer to determine if it's exceeded the amount of time allocated or not. If it has, then you can do another ajax request and revoke this person's access to the resource, or however you want to handle that.
i would use web sockets to control all the users that need to get the resource.
this way you will know who is connected and using the resource and when he finish using it you can let the next user the resource and so on ,
(this way can tell each user an estimation of how much time it will take him to get the resource and do some progress bar)
I think there're two problems here.
How to notify users that resource becomes available?
Periodic AJAX requests might be okay, but you can also consider long-polling or websockets to get close to notifying waiting users in real time.
How to find out that resource is still used by user?
If you want to catch the moment when human user is not doing anything on page, you can track mouse movement/clicking or keyboard button pressing. If nothing is done for last n minutes, the page might be considered as not active.
If you want to make sure that page is not exploited by automated software, you can ask to fill in captcha once in n minutes when resource is being used.

how to handle session expire basing redis?

I want to implement a session store based on Redis. I would like to put session data into Redis. But I don't know how to handle session-expire. I can loop through all the redis keys (sessionid) and evaluate the last access time and max idle time, thus I need to load all the keys into the client, and there may be 1000m session keys and may lead to very poor I/O performances.
I want to let Redis manage the expire, but there are no listener or callback when the key expire, so it is impossible to trigger HttpSessionListener. Any advice?
So you need your application to be notified when a session expires in Redis.
While Redis does not support this feature, there are a number of tricks you can use to implement it.
Update: From version 2.8.0, Redis does support this http://redis.io/topics/notifications
First, people are thinking about it: this is still under discussion, but it might be added to a future version of Redis. See the following issues:
https://github.com/antirez/redis/issues/83
https://github.com/antirez/redis/issues/594
Now, here are some solutions you can use with the current Redis versions.
Solution 1: patching Redis
Actually, adding a simple notification when Redis performs key expiration is not that hard. It can be implemented by adding 10 lines to the db.c file of Redis source code. Here is an example:
https://gist.github.com/3258233
This short patch posts a key to the #expired list if the key has expired and starts with a '#' character (arbitrary choice). It can easily be adapted to your needs.
It is then trivial to use the EXPIRE or SETEX commands to set an expiration time for your session objects, and write a small daemon which loops on BRPOP to dequeue from the "#expired" list, and propagate the notification in your application.
An important point is to understand how the expiration mechanism works in Redis. There are actually two different paths for expiration, both active at the same time:
Lazy (passive) mechanism. The expiration may occur each time a key is accessed.
Active mechanism. An internal job regularly (randomly) samples a number of keys with expiration set, trying to find the ones to expire.
Note that the above patch works fine with both paths.
The consequence is Redis expiration time is not accurate. If all the keys have expiration, but only one is about to be expired, and it is not accessed, the active expiration job may take several minutes to find the key and expired it. If you need some accuracy in the notification, this is not the way to go.
Solution 2: simulating expiration with zsets
The idea here is to not rely on the Redis key expiration mechanism, but simulate it by using an additional index plus a polling daemon. It can work with an unmodified Redis 2.6 version.
Each time a session is added to Redis, you can run:
MULTI
SET <session id> <session content>
ZADD to_be_expired <current timestamp + session timeout> <session id>
EXEC
The to_be_expired sorted set is just an efficient way to access the first keys that should be expired. A daemon can poll on to_be_expired using the following Lua server-side script:
local res = redis.call('ZRANGEBYSCORE',KEYS[1], 0, ARGV[1], 'LIMIT', 0, 10 )
if #res > 0 then
redis.call( 'ZREMRANGEBYRANK', KEYS[1], 0, #res-1 )
return res
else
return false
end
The command to launch the script would be:
EVAL <script> 1 to_be_expired <current timestamp>
The daemon will get at most 10 items. For each of them, it has to use the DEL command to remove the sessions, and notify the application. If one item was actually processed (i.e. the return of the Lua script is not empty), the daemon should loop immediately, otherwise a 1 second wait state can be introduced.
Thanks to the Lua script, it is possible to launch several polling daemons in parallel (the script guarantees that a given session will only be processed once, since the keys are removed from to_be_expired by the Lua script itself).
Solution 3: use an external distributed timer
Another solution is to rely on an external distributed timer. The beanstalk lightweight queuing system is a good possibility for this
Each time a session is added in the system, the application posts the session ID to a beanstalk queue with a delay corresponding to the session time out. A daemon is listening to the queue. When it can dequeue an item, it means a session has expired. It just has to clean the session in Redis, and notify the application.

dynamic session timeout

Can I change the session timeout dynamically? The timeout must be set according to the user role. I tried to use configure::write to change the timeout dynamically but it doesn't work. it seems that for the new session timeout to take efect, you have to reset the session, but resetting the session will loss the login info.
I think using something like the following after you check role membership will get you what you want.
HttpContext.Current.Session.Timeout = 1200;
I think you are right when saying you can't change the session timeout after it has been created, maybe you could look at regenerating one with a new timeout.
But maybe a more easy solution would be to use javascript, you could set a timeout value and when it runs out send an ajax request logging the user out.
This obviously won't work if a user disables javascript but it depends on how secure you want this to be.
Rather than changing the session timeout, have you considered using a variable in the session to store the date/time of the last pageload, so that you can check it on the next pageload?
You could add some code to the beforeFilter() method in AppController to calculate the amount of time elapsed between the last pageload (stored in the session) and now, and if this is greater than the session length for your specified user role, destroy the session. If not, store the current date/time in the session, so that it can be used next time.

will session expire in my scenario?

I am designing a top level page which is designed by implementing a frameset. In one frame of the frameset, I will invoke JavaScript to refresh the page to post to some URL regularly (every 10 minutes). In the other frame of the frameset, I will let user do the major work -- let end user enter input for a time-consuming form (e.g., to have a written essay test).
My question is, in my scenario, I think the frame which does the major user input work will never session expire, because the other frame will refresh? Is that understanding correct? My confusion is, I am not sure whether in another frame posting to some other URL in the same web site will block the other frame from session expire?
thanks in advance,
George
You are correct, that will keep the session alive.
The server keeps track of when you last fetched a page and passed your session identifier as a cookie. When it has been longer than the session timeout interval, it will no longer accept the session identifier and considers your session expired.
By hitting the server in the background, you are maintaining the session. Note, you do not have to do a POST. A simple GET will suffice.
Note, I am assuming your session timeout is longer than ten minutes.

Resources