Slava Fomin II
Slava Fomin II

Reputation: 28611

How to destroy all sessions in Symfony 2

Update

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.

The question

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

Answers (3)

Matteo
Matteo

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

C3roe
C3roe

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

KhorneHoly
KhorneHoly

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

Related Questions