Reputation: 28611
After detailed investigation and consultation with some experts, it occurred to me, that idea of destroying sessions is an incorrect one. The better question would be — «How to force all users to log out».
And this problem should be solved not from the session perspective, which is a pretty low-level mechanism, but from the Security Component one. Even if you delete all session data, it will be re-created by means of remember me
cookies with the next user requests.
I will try to present the valid solution to this problem later on.
I need to implement a feature of so-called application «lockdown», so I need a way to log all users out of Symfony 2 application (close all active sessions).
What is the best way to achieve this functionality?
Ideally, the solution should be fully compatible with all possible save-handlers.
It looks like SessionHandlerInterface
doesn't provide a method to do so.
Upvotes: 3
Views: 6227
Reputation: 39380
A Programmatic approach should be to use a session listener and invalidate the session if a particular event exist, something like a flag/timestamp alive in a database table or some similar.
As described in this article
Invalidate the Session Based on its Age
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class SessionListener
{
/**
* @var \Acme\DemoBundle\Service\SessionInvalidator
*/
protected $sessionInvalidator;
function __construct($sessionInvalidator)
{
$this->sessionInvalidator=$sessionInvalidator;
}
public function onKernelRequest(GetResponseEvent $event)
{
if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
return;
}
$session = $event->getRequest()->getSession();
$metadataBag = $session->getMetadataBag();
$lastUsed = $metadataBag->getLastUsed();
if ($lastUsed === null) {
// the session was created just now
return;
}
// "last used" is a Unix timestamp
if (! $this->sessionInvalidator->checkTimestampIsValid($lastUsed))
$session->invalidate();
}
}
And the configuration:
<service id="amce_security.verify_session_listener"
class="Acme\DemoBundle\EventListener\SessionListener">
<argument type="service" id="acme.session_invalidator"/>
<tag name="kernel.event_listener"
event="kernel.request"
priority="100"
method="onKernelRequest" />
</service>
Hope this help
Upvotes: 5
Reputation: 96250
Ideally, the solution should be fully compatible with all possible save-handlers.
To be fully independent of the session save handler, I think it might be best if you implemented this “inside” of the sessions yourself.
When a user logs in, you store the current timestamp in their session (user-specific login timestamp).
When you want to apply your “lockdown”, then you store that current timestamp (lockdown timestamp) somewhere else, so that every script instance has access to it. That might be something like memcached/shared memory, a simple file (maybe using touch
and filemtime
), or something else.
Then on every page request, you check if the user login timestamp stored in the user session is greater than your lockdown timestamp. If not, the user logged in before the lockdown happened – then it is time to delete their session.
And of course you deny new logins while the lockdown is in place.
That way, you could even allow users to continue their existing sessions after the lockdown ends (if you want) – if you chose not to destroy their session, but simple deny access while in lockdown. For that, you either remove the lockdown timestamp completely (remove memcached/shmop entry, delete file), or set it to a value far in the past (f.e. 0).
You might want to implement an exception to the lockdown based on user level – an admin user should probably be able to still use the site (if only to disable the lockdown, if nothing else – and at least for that they need to be able to login regardless of the lockdown).
Upvotes: 4
Reputation: 4766
You could store the sessions into the database following this Symfony 2 Doc.
Basically you need to do the following in your config:
framework:
session:
# ...
handler_id: session.handler.pdo
services:
session.handler.pdo:
class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
public: false
arguments:
- "mysql:dbname=mydatabase"
- { db_username: myuser, db_password: mypassword }
Then you could delete all sessions from the database!
Upvotes: 4