Peter
Peter

Reputation: 1211

ZF2, exception was raised while creating a listener & Session validation failed

Let's start with what's going wrong: I have an acl listener coupled to the "route" event which at first appears to work fine but that will throw a couple of errors after a while. These are the errors:

Fatal error: Uncaught exception 'Zend\Session\Exception\RuntimeException' with message 'Session validation failed'...

Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "authService"; no instance returned...

Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "MyAclListener"; no instance returned...

The listener is setup as follows:

class MyAclListener implements ListenerAggregateInterface
{
    /** @var  AuthenticationServiceInterface */
    protected $_authService;

    function __construct (
        AuthenticationServiceInterface $authService ,
    )
    {
        $this->_authService     = $authService;
    }

    public function attach ( EventManagerInterface $events )
    {

        $this->listeners[ ] = $events->attach( 'route' , array( $this , 'checkAcl' ) );
    }

    public function checkAcl( MvcEvent $e ) {
\\\Do Something for which the authService is needed
}

Then, in the module.config.php I have

$config = array(
    'service_manager' => array(
        'factories' => array(
            'MyAclListener' => 'MyAcl\Factory\MyAclListenerFactory'
        ) ,
    ) ,
    'listeners'       => array(
        'MyAclListener'
    ) ,
);

The factory for the listener:

<?php

namespace MyAcl\Factory;

use MyAcl\Listener\MyAclListener;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class AclListenerFactory implements FactoryInterface
{

    public function createService(ServiceLocatorInterface $serviceLocator)
    {

        // Finally create the service
        return new MyAclListener(
            $serviceLocator->get('authService') ,
        );
    }

}

The Session is setup in Module.php

   public function onBootstrap ( MvcEvent $e )
    {

        $serviceManager         = $e->getApplication()->getServiceManager();

        $config = $serviceManager->get('Configuration');
        $this->initSession( $config['session'] , $serviceManager->get('sessionCache')  );
}

public function initSession ( $config , $cache )
{

    $sessionConfig = new SessionConfig();
    $sessionConfig->setOptions( $config );
    $sessionManager = new SessionManager( $sessionConfig );

    $saveHandler = new Cache($cache);
    $sessionManager->setSaveHandler( $saveHandler );

    $sessionManager->getValidatorChain()->attach('session.validate', array(new HttpUserAgent(), 'isValid'));
    $sessionManager->getValidatorChain()->attach('session.validate', array(new RemoteAddr(), 'isValid'));

    $sessionManager->start();
    $sessionManager->regenerateId(true);

}

And these are the relevant configs for the session:

$config = array(
    'session'         => array(
        'cookie_lifetime' => 28800 ,
        'remember_me_seconds' => 28800 ,
        'use_cookies'         => true ,
        'cookie_httponly'     => true ,
    ) ,
    'caches'          => array(
        'sessionCache' => array(
            'adapter' => array(
                'name'     => 'memcached' ,
                'lifetime' => 604800 ,
                'options'  => array(
                    'servers'    => array(
                        array(
                            '127.0.0.1' , 11211
                        )
                    ) ,
                    'namespace'  => 'MySessionCache' ,
                    'liboptions' => array(
                        'COMPRESSION'     => true ,
                        'binary_protocol' => true ,
                        'no_block'        => true ,
                        'connect_timeout' => 100
                    )
                ) ,
                'plugins'  => array( 'serializer' )
            ) ,
        ) ,
    ) ,
)

It might also be useful to know that after the error my "identity" is lost and the logged in user was logged out.

So, what am I doing wrong? How do I get rid of these errors? Maybe even: are there better sollutions for setting up an ACL check and my sessions?

UPDATE
I changed the session setup:

In Module.php

    public function onBootstrap ( MvcEvent $e )
    {

        $serviceManager = $e->getApplication()->getServiceManager();

        /* session */
        $this->expandInitialSessionConfig( $serviceManager , $serviceManager->get( 'sessionCache' ) );
}

public function expandInitialSessionConfig ( $sm , $cache )
{

    /** @var \Zend\Session\SessionManager $sessionManager */
    $sessionManager = $sm->get( 'Zend\Session\SessionManager' );

    $saveHandler = new Cache( $cache );
    $sessionManager->setSaveHandler( $saveHandler );

    $sessionManager->getValidatorChain()->attach( 'session.validate' , array( new HttpUserAgent() , 'isValid' ) );
    $sessionManager->getValidatorChain()->attach( 'session.validate' , array( new RemoteAddr() , 'isValid' ) );

}

In module.config.php

return array(
    'session_config'  => array(
        'cookie_lifetime'     => 28800 ,
        'remember_me_seconds' => 28800 ,
        'use_cookies'         => true ,
        'cookie_httponly'     => true ,
        'gc_probability'      => 10 ,
        'gc_maxlifetime'      => 7200 ,
        'cookie_domain'       => 'mydomain.com' ,
    ) ,
    'service_manager' => array(
        'factories' => array(
            'Zend\Session\SessionManager'         => 'Zend\Session\Service\SessionManagerFactory' ,
            'Zend\Session\Config\ConfigInterface' => 'Zend\Session\Service\SessionConfigFactory' ,
        ) ,
);

And the $sessionManager->regenerateId( true ) was moved so it now only happends on login.

Upvotes: 0

Views: 2422

Answers (2)

Peter
Peter

Reputation: 1211

I seriously doubt this is "best practice", but removing from the constructor of my listener, those depencies (more were added since the original question) that on their turn are dependend on the session solved the issue. I know get them from the ServiceLocator at the first moment I need them in my code and store them in a protected param of my listener class for further use. However, like I said, this isn't proper dependency injection anymore, but at least it works.

function __construct (Logger $_myLog )
{
    $this->_myLog          = $_myLog;
    // removed here: $this->_authService     = $authService;

}

Then:

public function checkAcl ( MvcEvent $e )
{
   $sm = $e->getApplication()->getServiceManager();
   $this->_authService = $sm->get('authService');
   ....
}

Upvotes: 0

Wilt
Wilt

Reputation: 44373

Your ask the ServiceLocator in your AclListenerFactory for a authService but it cannot find anything named like this which causes the second exception. Because the authService is not found your factory doesn't return the listener. That is the last exception.

In your code you write:

$serviceLocator->get('authService') ,

The first exception is related to some session validation fail. The cause of all issues lies probably in there. No session validation results probably in no valid authService thus chaining the other two exceptions. Where is this authService registered or created? This is not visible in the code you share currently. And how does this service rely on the "validation" that is failing...

If you solve your session validation issue all will probably be fine.

Upvotes: 1

Related Questions