ZF-Commons / ZfcUser

A generic user registration and authentication module for ZF2. Supports Zend\Db and Doctrine2. (Formerly EdpUser)
BSD 3-Clause "New" or "Revised" License
497 stars 343 forks source link

AdapterChain->resetAdapters broken #689

Open lon9man opened 2 years ago

lon9man commented 2 years ago
  1. ZfcUser attaches authentication adapters to EventManager using event authenticate
  2. BUT resets this adapters using SharedEventManager

in result this doesn't work and information in $_SESSION is alive during all session lifetime

NOTE: in version for ZF2 it worked as expected using EventManager in both cases. for ZF3 method resetAdapters was refactored using broken logic.

ZF3:

AdapterChainServiceFactory.php

class AdapterChainServiceFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $serviceLocator, $requestedName, array $options = null)
    {
        $chain = new AdapterChain();
        $chain->setEventManager($serviceLocator->get('EventManager'));

        $options = $this->getOptions($serviceLocator);

        //iterate and attach multiple adapters and events if offered
        foreach ($options->getAuthAdapters() as $priority => $adapterName) {
            $adapter = $serviceLocator->get($adapterName);

            if (is_callable(array($adapter, 'authenticate'))) {
                $chain->getEventManager()->attach('authenticate', array($adapter, 'authenticate'), $priority);
            }

            if (is_callable(array($adapter, 'logout'))) {
                $chain->getEventManager()->attach('logout', array($adapter, 'logout'), $priority);
            }
        }

        return $chain;
    }
...

AdapterChain.php

    public function resetAdapters()
    {
        $sharedManager = $this->getEventManager()->getSharedManager();

        if ($sharedManager) {
            $listeners = $sharedManager->getListeners(['authenticate'], 'authenticate');
            foreach ($listeners as $listener) {
                if (is_array($listener) && $listener[0] instanceof ChainableAdapter) {
                    $listener[0]->getStorage()->clear();
                }
            }
        }

        return $this;
    }

ZF2:

AdapterChainServiceFactory.php

class AdapterChainServiceFactory implements FactoryInterface
{

    /**
     * @var ModuleOptions
     */
    protected $options;

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $chain = new AdapterChain();

        $options = $this->getOptions($serviceLocator);

        //iterate and attach multiple adapters and events if offered
        foreach ($options->getAuthAdapters() as $priority => $adapterName) {
            $adapter = $serviceLocator->get($adapterName);

            if (is_callable(array($adapter, 'authenticate'))) {
                $chain->getEventManager()->attach('authenticate', array($adapter, 'authenticate'), $priority);
            }

            if (is_callable(array($adapter, 'logout'))) {
                $chain->getEventManager()->attach('logout', array($adapter, 'logout'), $priority);
            }
        }

        return $chain;
    }
...

AdapterChain.php

    public function resetAdapters()
    {
        $listeners = $this->getEventManager()->getListeners('authenticate');
        foreach ($listeners as $listener) {
            $listener = $listener->getCallback();
            if (is_array($listener) && $listener[0] instanceof ChainableAdapter) {
                $listener[0]->getStorage()->clear();
            }
        }
        return $this;
    }