ZF-Commons / zfc-rbac

Role-based access control module to provide additional features on top of Zend\Permissions\Rbac
BSD 3-Clause "New" or "Revised" License
181 stars 111 forks source link

How to disable ZfcRbac for ConsoleRequest #265

Closed chateaux closed 10 years ago

chateaux commented 10 years ago

Hi,

I need to write some crons for my app and am unsure how to set ZfcRbac to ignore ConsoleRequests.

Please advise,

bakura10 commented 10 years ago

Hi,

This was a problem I had, and this is indeed annoying. That's one of the reason why I don't actually protect my services but rather the controller.

You just need to create new routes, that are not protected (neither by guards or by authorization service).

guliano commented 10 years ago

I had the same problem, and i resolved this by using special user called SYSTEM, who inherites privileges from other roles (something like root access). In console aware controllers, I implemented SystemUserAwareInterface which is needed by controller initializer:

class SystemUserInitializer implements \Zend\ServiceManager\InitializerInterface
{

    public function initialize($instance, ServiceLocatorInterface $serviceLocator)
    {
        if ($instance instanceof SystemUserAwareInterface) {
            $userService = $serviceLocator->getServiceLocator()->get('UserService');
            $authenticationService = $serviceLocator->getServiceLocator()->get('Zend\Authentication\AuthenticationService');
            $instance->logAsSystemUser($userService, $authenticationService);
        }
    }
}

logAsSystemUser is as following (used Doctrine):

public function logAsSystemUser(UserService $userService, AuthenticationService $authenticationService)
{
    $systemUser = $userService->getUser(UserEntity::SYSTEM_USER_ID, true); // getting User Entity from database..
    $authenticationService->getStorage()->write($systemUser);
}

UserEntity::SYSTEM_USER_ID is constant holding my System User ID from database. This function can be in Trait and can be used in controllers.

And finally initializer configuration in module config:

'controllers' => array(
    'initializers' => array(
        'systemUser' => 'SystemUserInitializer',
    ),
    //more controller configs...
),

I'm not sure it is good practice, but is working for me.

bakura10 commented 10 years ago

I'm closing, as those are the two best ways to deal with this issue currently :).

chateaux commented 10 years ago

Thank you,

I like the idea of having a route with no guards in it. If I am using a POLICY_DENY strategy I can not get it to work... I am guessing for DENY I need to follow gulcoder example?

'zfc_rbac' => [ 'protection_policy' => \ZfcRbac\Guard\GuardInterface::POLICY_DENY, 'guards' => [ 'ZfcRbac\Guard\RouteGuard' => [ //Cronjob access 'cpanel/hello' => ['guest'], ] ]

I have tried: 'cpanel/hello' => [''], 'cpanel/hello' => [*], 'cpanel/hello' => [],

chateaux commented 10 years ago

Hi Guys,

Thank you for your respective input, I got this to work perfectly. Where I was struggling was the assumption of the actual route name, what I would suggest other people do when implementing console routes is to first dump the actual route they are on:

In any bootstrap Module.php event you can do the following:

$e->getApplication()->getEventManager()->attach( MvcEvent::EVENT_ROUTE, function(MvcEvent $e) { $routeMatch = $e->getRouteMatch()->getMatchedRouteName(); die(var_dump($routeMatch)); }) .. ;

Once you know the route add this to your guards as per my previous comment. If the Console is open to the guest Role for either Policy DENY or ALLOW, the route will work fine. On the other hand if you would like a degree of security then I would suggest following what guicoder suggested.

This is my final Module.php functions:

public function onBootstrap(EventInterface $e) { $app = $e->getApplication(); $em = $app->getEventManager(); $sm = $app->getServiceManager();

    //Mail listener crashes the cron due to the viewRenderer
    if ( Console::isConsole()) {
        //CONSOLE
        $this->logAsSystemUser(
            $sm->get(UserServiceInterface::class),
            $sm->get(AuthenticationService::class)
        );
    } else
    {
        //HTTP
        $em->attachAggregate(
            $sm->get(UserRegisteredListener::class)
        );
    }
}

/**
 *
 * @param UserService $userService
 * @param AuthenticationService $authenticationService
 */
public function logAsSystemUser(UserService $userService, AuthenticationService $authenticationService)
{
    $systemUser = $userService->find(29); // getting User Entity from database..
    $authenticationService->getStorage()->write($systemUser);
}