In our intranet application(s) we use SSO (single sign on) login while the sessions both on client and auth origin applications are stored in memcached.
The sessions are set to live for 12h before the garbage collector may consider them as for removal. Both applications are written using ZF2.
Unfortunately, the problem is, that after certain period of time (I don't have the exact value) the browser loses the session which causes the redirection to auth origin, where the session is still alive thus user is redirected back to client and the browser session is refreshed. This is not a big deal if the user has no unsaved work as these two redirects happen within 1 second and user even may not notice them.
But it really is a big deal when user has unsaved work and even an attempt to save it leads to redirects and the work is gone.
Here is the configuration of session in Bootstrap.php
:
class Module
{
public function onBootstrap(MvcEvent $e)
{
// ...
$serviceManager = $e->getApplication()->getServiceManager();
$sessionManager = $serviceManager->get('session_manager_memcached');
$sessionManager->start();
Container::setDefaultManager($sessionManager);
// ...
}
public function getServiceConfig()
{
return array(
'factories' => array(
// ...
'session_manager_memcached' => function ($sm) {
$systemConfig = $sm->get('config');
$config = new SessionConfig;
$config->setOptions(array(
'phpSaveHandler' => 'memcache',
'savePath' => 'tcp://localhost:11211?timeout=1&retry_interval=15&persistent=1',
'cookie_httponly' => true,
'use_only_cookies' => true,
'cookie_lifetime' => 0,
'gc_maxlifetime' => 43200, // 12h
'remember_me_seconds' => 43200 // 12h
));
return new SessionManager($config);
},
// ...
);
}
}
The authentication service is defined as
'authService' => function ($sm) {
$authService = new \Zend\Authentication\AuthenticationService;
$authService->setStorage(new \Zend\Authentication\Storage\Session('user_login'));
return $authService;
},
- the session storage uses the same memcached session manager.
Then anywhere within the application a session value needs to be retrieved or set I just use a \Zend\Session\Container
like this:
$sessionContainer = new \Zend\Session\Container('ClientXYZ');
$sessionContainer['key1'] = $val1;
// or
$val2 = $sessionContainer['key2'];
The SSO is requested for the active session at any action using the token from session which contains PHPSESSID from the auth origin. It's quite complicated to describe here within this question.
Additionally an authentication service stores a user identity (with roles for ACL) also in memcached session - using the same settings. Obviously this is now the place which causes confusion. Apparently the session storage of authentication service times out prematurely causing the ACL to retrieve no user identity to check leading into SSO logout sequence (but because user didn't really log out, SSO redirects the user back as described above).
I'm not sure how much code should I (and can I) share here, maybe you'll lead me to the solution straight away or just by asking me some questions. I am quite helpless right now after many hours of debugging and trying to identify the problem.
Somewhere I have read that memcached wipes out the memory once the session cookie gets 1MB in size - may this be the case? For the user identity we save just general user information and array of roles, I'd guess this could be max. up to few kb in size...
EDIT 1: To dismiss all guesses and to save your time, here few facts (to keep an eye on):
- only memcached is used
- cookies serve only to transport the
PHPSESSID
between the browser and server and it's value is the key for memory chunk in memcached where the data is stored - client and SSO auth apps are running on one server (be it integration, staging or live environment, still just one server)
- session on client app goes off randomly causing it to redirect to SSO auth app, but here the session is still alive thus user is redirected back to client app which gets new session and user stays logged in
- this should dismiss discussion about memcached being wiped off or restarted
- also observation on telneted memcached directly shows both data chunks (for client and auth apps) are established almost at the same time with the same ttl
I am going to implement some die
s in PHP and return
s in JS parts to catch the moment when the session is considered gone and further inspect the browser cookie, memcached data, etc. and will update you (unless somebody comes with explanation and solution).
Memcached & gc_maxlifetime
When using
memcached
assession.save_handler
, garbage collection of session will not be done.Because Memcached works with a TTL (time to live) value, garbage collection isn't needed. An entry that has not lived long enough to reach the TTL age will be considered "fresh" and will be used. After that it will be considered "stale" and will not be used any longer. Eventually Memcached will free the memory used by the entry, but this has nothing to do with session garbage collection of PHP.
In fact, the only
session.gc_
setting that's actually used in this case issession.gc_maxlifetime
, which will be passed as TTL to Memcached.In short: garbage collection is not an issue in your case.
Memcached & Cronjobs
As you are using Memcached as storage for your sessions, any cronjobs provided by the OS that will manually clean session folders on disk (like Ubuntu does) will have no effect. Memcached is memory storage, not disk storage.
In short: cronjobs like this are not an issue in your case.
Issue of app, not SSO
You state that the SSO server/authority is on the same machine as the SSO client (the application itself), is using the same webserver / PHP configuration, and is using the same instance of Memcached.
This leads me to believe we have to search in how session management is done in the application, as that is the only difference between the SSO authority and client. In other words: we need to dive into Zend\Session.
Disclaimer: I've professionally worked on several Zend Framework 1 applications, but not on any Zend Framework 2 applications. So I'm flying blind here :)
Configuration
One thing I notice in your configuration is that you've set
cookie_lifetime
to0
. This actually means "until the browser closes". This doesn't really make sense together withremember_me_seconds
set to 12 hours, because a lot of people will have closed their browser before that time.I suggest you set
cookie_lifetime
to 12 hours as well.Also note that
remember_me_seconds
is only used when the Remember Me functionality is actually used. In other words: ifZend\Session\SessionManager::rememberMe()
is called.Alternative implementation
Looking at the way you've implemented using Memcached as session storage, and what I can find on the subject, I'd say you've done something different than what seems to be "the preferred way".
Most resources on this subject advise to use
Zend\Session\SaveHandler\Cache
(doc, api) as save-handler, which gives you the ability to useZend\Cache\Storage\Adapter\Memcached
(doc, api). This gives you much more control over what's going on, because it doesn't rely on the limitedmemcached
session-save-handler.I suggest you try this implementation. If it won't immediately resolve your issue, there are at least a lot more resources to find on the subject. Your chances of finding a solution will be better IMHO.