Quantcast

Check ACL on routing

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Check ACL on routing

Ralf Eggert
Hi,

I wrote a listener that checks the ACL for the current user to forward
to a forbidden page when the rights are insufficient. This works
perfectly but now I have a problem.

If the routing matches a route but controller or action does not exist
these 404 errors are not shown. This is due to the ACL check which uses
controller as resource and action as privilege. This check fails because
the wrong controller is not set as a ACL resource or the wrong action is
not set as a ACL privilege. So I get a forward to the forbidden page.
Any dispatching errors for missing controller or action can not be
thrown any more.

But since these dispatching errors are only thrown while dispatching I
cannot add my ACL check there.

Can someone follow this problem and provide me with a solution?

Regards,

Ralf

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Check ACL on routing

Ralf Eggert
Hi Marc,

Marc Tempelmeier schrieb am 11.09.2012 08:56:
> in ZF1 I solved this with checking if the route is dispatchable and if not screw the whole ACL check. I didn´t check if there is something like that in ZF2 though.

I did not find any isDispatchable method yet though I think it is not there.

So I am still looking for a solution.

Regards,

Ralf

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Check ACL on routing

ralphschindler
You effectively have 2 options:

   First, and I am sure least favorite option from a framework
perspective: Put your acl check in an onDispatch() method inside of the
routed controller (that means at least a controller was dispatched).
Inside of this method, you could do whatever check you need.  At this
point, you'd make sure to call parent::onDispatch() as it is responsible
for calling the appropriate action.  This is all assuming you're
extending the AbstractActionController.

THE BETTER SOLUTION:

   Is to get familiar with Event system, write a listener and listen in
on a particular event.  I think this list is up to day and complete (but
I am not sure, best to check in IRC with Rob or Evan):

   http://akrabat.com/zend-framework-2/a-list-of-zf2-events/

   also:
   http://akrabat.com/zend-framework-2/an-introduction-to-zendeventmanager/

   the actual event manager:
 
http://framework.zend.com/manual/2.0/en/modules/zend.event-manager.event-manager.html

Hope this helps get you started,
Ralph


On 9/11/12 9:12 AM, Ralf Eggert wrote:

> Hi Marc,
>
> Marc Tempelmeier schrieb am 11.09.2012 08:56:
>> in ZF1 I solved this with checking if the route is dispatchable and if not screw the whole ACL check. I didn´t check if there is something like that in ZF2 though.
>
> I did not find any isDispatchable method yet though I think it is not there.
>
> So I am still looking for a solution.
>
> Regards,
>
> Ralf
>


--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Check ACL on routing

Ralf Eggert
Hi Ralph,

thanks for your reply. I am also working on the better solution you
suggested but with that solution I got stuck. This is my listener (a
little shortened):

--------------------------------------------------------------------
class RouteListener implements ListenerAggregateInterface
{
    public function attach(EventManagerInterface $events)
    {
        $this->listeners[] = $result = $events->attach(
            MvcEvent::EVENT_DISPATCH, array($this, 'checkAcl'), 100
        );
    }

    public function checkAcl(EventInterface $e)
    {
        $acl = $e->getApplication()->getServiceManager()
                 ->get('User\Acl\Service');

        $routeMatch = $e->getRouteMatch();
        $response   = $e->getResponse();

        if (!$acl->isAllowed(
            $routeMatch->getParam('controller'),
            $routeMatch->getParam('action')
        )) {
            $routeMatch->setParam('controller', 'user');
            $routeMatch->setParam('action', 'forbidden');
        }
    }
}
--------------------------------------------------------------------

So, the checkAcl() is processed before the dispatching. But at that
stage the dispatcher did not identify any missing controller or action.
So file not found errors are not thrown because the forbidden error
comes first. When I clear out the 100 or change it to any negative value
then the FnF error is thrown, but the ACL check does not work. Any user
with insufficient rights can access all other pages he isn't allowed to.

I looked into the code and I think the dispatching process is done
within the Zend\Mvc\DispatchListener::onDispatch() method. Correct my if
I am wrong. Since there is no isDispatchable() method any where to check
I don't see any chance to do an ACL check before the dispatching takes
place.

Do you have another idea?

Regards,

Ralf

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Check ACL on routing

Ralf Eggert
Hi again,

to clarify my last message. The ACL check does work for unknown actions.
It just doesn't work correctly for any unknown controllers.

Currently I am thinking about using the controller loader to try to load
the controller and only do the ACL check when the controller can be
loaded. But with this approach the controller loader would be used
twice. Once in my checkAcl() method and once again in the
Zend\Mvc\DispatchListener::onDispatch() method.

Regards,

Ralf

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Check ACL on routing

weierophinney
Administrator
-- Ralf Eggert <[hidden email]> wrote
(on Saturday, 15 September 2012, 11:17 AM +0200):
> to clarify my last message. The ACL check does work for unknown actions.
> It just doesn't work correctly for any unknown controllers.
>
> Currently I am thinking about using the controller loader to try to load
> the controller and only do the ACL check when the controller can be
> loaded. But with this approach the controller loader would be used
> twice. Once in my checkAcl() method and once again in the
> Zend\Mvc\DispatchListener::onDispatch() method.

I just had another idea. Use an initializer.

Initializers allow you to operate on instances when they are first
created by the service or plugin manager. As such, you could attach an
initializer to the ControllerManager, and run your ACL check then -- at
that point, you'll know you have a valid controller.

It would look something like this:
   
    'controllers' => array(
        'initializers' => function ($controller, $controllers)  {
            $services = $controllers->getServiceManager();
            $aclService = $services->get('WhateverYouNamedYourAclService');

            // At this point, you have your controller and acl service,
            // so you likely have the ability to do a check. If the
            // check fails, raise an exception here.
        }
    )

The above could be in a Module's getControllerConfig() method, or as a
standalone initializer class somewhere.

--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Check ACL on routing

Ralf Eggert
Hi Matthew,

thanks for this new idea.

> I just had another idea. Use an initializer.

I tried to build this but noticed that the initializer is only processed
for existing controllers. But the acl check problems I have have to do
with not existing controllers.

Currently I used this listener method:

-----------------------------------------------------------------
public function checkAcl(EventInterface $e)
{
    $routeMatch = $e->getRouteMatch();

    $controllerLoader = $e->getApplication()->getServiceManager()
                          ->get('ControllerLoader');

    try {
        $controller = $controllerLoader->get(
            $routeMatch->getParam('controller')
        );
    } catch (\Exception $exception) {
        return;
    }

    $acl = $e->getApplication()->getServiceManager()
             ->get('User\Acl\Service');

    if (!$acl->isAllowed(
        $routeMatch->getParam('controller'),
        $routeMatch->getParam('action'))
    ) {
        $routeMatch->setParam('controller', 'user');
        $routeMatch->setParam('action', 'forbidden');
    }
}

-----------------------------------------------------------------

Now the ACL check is not processed for not existing controllers. The
only issue with this is the double check with the controller loader.

The only other solution I currently see is adding another event trigger
within Zend\Mvc\DispatchListener::onDispatch() after the try-catch block
which checks existance of requested controller and before the dipatching.

Regards,

Ralf

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Loading...