Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Add RBAC support for navigation helper. #3693

Merged
merged 13 commits into from
Mar 25, 2013

Conversation

francisdaigle
Copy link
Contributor

Permissions-based navigation support for RBAC component.

@bakura10
Copy link
Contributor

bakura10 commented Feb 7, 2013

Mixing the two permissions systems into the same objects is... strange :/. As I told it on another issue, Zend\Navigation should be agnostic to any permission system. Check @spiffyjr implementation (this should have been the Zend\Navigation of ZF 2 but because of lack of time it wasn't integrated, but it shoudl for ZF 3): https://github.com/spiffyjr/spiffy-navigation

And modules like ZfcRbac or BjyAuthorize will integrate the navigation to Rbac or Acl. I think this is a better idea than mixing. But as Zend\Navigation is a bit broken, may be we can afford this for ZF 2.

@froschdesign
Copy link
Member

@bakura10
I am on your side. It is a bad idea to add extra methods for any permission system.

@francisdaigle
Copy link
Contributor Author

The problem is is that there needs to be an "integrated" solution for the RBAC component. Otherwise, I would argue that the RBAC component should not have been included in the "core" of the framework. It's unreasonable to expect that users not assume that there be some level of integration between the RBAC component and navigation. It's not the cleanest solution to be sure but it is one that works. Is there a better alternative maybe?

@bakura10
Copy link
Contributor

bakura10 commented Feb 7, 2013

The Rbac component is pretty "useless" on its own, you should at least use ZfcRbac. Starting from here, it makes sense that all this integration work to be included into ZfcRbac instead than Zend\Navigation itself. Anyway, given the current state of Navigation, one more bad thing, maybe we can afford it...

Let's wait for @weierophinney point of ivew.

@francisdaigle
Copy link
Contributor Author

I use the ZfcRbac module myself. I don't know that there would be a way to provide any integration from the ZfcRbac component itself - unless you are proposing that the module include an alternative to the current implementation of the ZF2 Navigation component. This is the most flexible solution I have found so far but I am absolutely 100% open to a better alternative.

This is how I go about things in my own application:

$this->navigation('primary_navigation')
        ->menu()
        ->setUseAcl(false)
        ->setUseRbac(true)
        ->setPartial('partial/primary-menu.phtml')
        ->setRbac($this->rbacHelper()->getRbac())
        ->setRole($this->rbacHelper()->getIdentity()->getRoles());

(where "rbacHelper" is "ZfcRbac\Service\Rbac")

This way, you're not coupling Navigation directly to the ZfcRbac module while still being able to leverage the power of the ZfcRbac module.

@danizord
Copy link
Contributor

danizord commented Feb 8, 2013

Assuming that Acl has IsAllowed() and Rbac has IsGranted(), I think a good alternative would be to inject into the Page a "permission callable" that simply must return a boolean telling if the user has access to the Page.
This is a generic way that will work with all permission systems.

Thoughts?

@weierophinney
Copy link
Member

I don't think this is an appropriate solution; what happens if we add more permissions systems, each with their own APIs and requirements for determining validation?

A better approach is to trigger an event -- let's call it "isAllowed" -- passing the page to the event; a listener can then return a boolean value indicating this status. This allows keeping the actual mechanism for determining rights separate from the navigation itself, while still providing the ability to provide access-specific navigation to users.

@francisdaigle do you want to revise this PR to do that? or would you like somebody else to tackle it?

@spiffyjr
Copy link
Contributor

spiffyjr commented Feb 8, 2013

+1 to the listener. We have events - let's use them where appropriate. :)

@danizord
Copy link
Contributor

danizord commented Feb 8, 2013

The listener is a great idea 👍

@francisdaigle
Copy link
Contributor Author

Sounds great :)

I'd be happy to put something together unless there is someone more appropriate for the task.

@weierophinney
Copy link
Member

Go for it, @francisdaigle!

@francisdaigle
Copy link
Contributor Author

10-4

@francisdaigle
Copy link
Contributor Author

Alright. PR has been amended. Previous changes have been removed. Trigger for event listener ("isAllowed") has been added.

Simple use case would be:

...
echo $this->navigation('primary_navigation')
               ->menu()
               ->setUseAcl(false)
               ->setPartial('partial/primary-menu.phtml');
...
$eventManager->getSharedManager()->attach('Zend\View\Helper\Navigation\AbstractHelper', 'isAllowed', array('\Access\Listener\RbacListener', 'accept'));
namespace Access\Listener;

class RbacListener
{

    public function accept($event)
    {
        $serviceLocator = $event->getTarget()->getServiceLocator()->getServiceLocator();
        $rbac           = $serviceLocator->get('ZfcRbac\Service\Rbac');

        $params = $event->getParams();
        $page   = $params['page'];

        $permission = (string) $page->__get('permission');

        $isGranted = $rbac->isGranted($permission);

        return $isGranted;
    }

}

Does this work for everyone? @weierophinney?

@ghost ghost assigned weierophinney Feb 15, 2013
@weierophinney
Copy link
Member

@francisdaigle This is looking good!

Two comments:

  • I need some tests. :)
  • I'm wondering if we could move the existing ACL checks into a listener as well. In this case, it would check if there is an ACL attached to the target; if not, it returns immediately with a null value, but if so, it does the ACL check and returns a boolean. That way, a user could attach their own listener at a higher priority, and the code could do a short-circuit test to determine if a boolean has been returned.

Thoughts?

@francisdaigle
Copy link
Contributor Author

Sounds good to me :)

I'll put something together.

@weierophinney
Copy link
Member

@francisdaigle Any progress on tests? If you need help, jump into #zftalk.dev on Freenode IRC, and ask! Would love to see this in 2.2.0, as many folks are wanting RBAC support in navigation. :)

@francisdaigle
Copy link
Contributor Author

Yeah, sorry - I'll try to get to this as soon as I can. Not enough hours in the day :)

@francisdaigle
Copy link
Contributor Author

@weierophinney: Forthcoming :)

@danizord
Copy link
Contributor

@francisdaigle Why remove README-GIT.md?

@francisdaigle
Copy link
Contributor Author

Thanks @danizord :)

@francisdaigle
Copy link
Contributor Author

OK. ACL has been refactored (checks moved into listener).

So, for the RBAC component, a simple use case would be:

Setup the RBAC...

namespace Application\Service;

use Zend\Permissions\Rbac\Rbac;
use Zend\Permissions\Rbac\Role;

class RbacService
{
    protected  $rbac;

    public function getRbac() {
        return $this->rbac;
    }

    public function setRbac($rbac) {
        $this->rbac = $rbac;
    }

    public function __construct() {

        $rbac = new Rbac();
        $this->setRbac($rbac);

        $member = new Role('member');

        $member->addPermission('foo');

        $this->getRbac()->addRole($member);
    }

}

Add the RBAC listener...

namespace Application\Listener\Rbac;

use Application\Service\RbacService;
use Zend\EventManager\Event;

class AcListener
{

    public function accept(Event $event)
    { 
        $event->stopPropagation();

        $accepted = true;

        $rbacService = new RbacService();
        $rbac = $rbacService->getRbac();

        $params = $event->getParams();
        $page = $params['page'];

        $permission = $page->getPermission();

        if ($permission) {
            $accepted = $rbac->isGranted('member', $permission);
        }

        return $accepted;
    }

}

Attach the listener...

...
class Module
{
    public function onBootstrap()
    {
        $eventManager->getSharedManager()->attach('Zend\View\Helper\Navigation\AbstractHelper', 'isAllowed', array('Application\Listener\Rbac\AcListener', 'accept'));
    }
}
...

And lastly...

...
echo $this->navigation('navigation')->menu();
...

That's it. Because "$setUseAcl = true" by default there is no need for any additional flags. Just override the default listener and stop the event from propagating like in the example above (ie. $event->stopPropagation()).

Does this work for everyone? @weierophinney?

@@ -886,4 +916,18 @@ public static function setDefaultRole($role = null)
));
}
}
}

protected function setDefaultListeners()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a docblock (I'll supply this when I merge)

weierophinney added a commit that referenced this pull request Mar 25, 2013
[WIP] Add RBAC support for navigation helper.
weierophinney added a commit that referenced this pull request Mar 25, 2013
- Docblock additions/edits
- Logic workflow
weierophinney added a commit that referenced this pull request Mar 25, 2013
- trailing whitespace
- EOF endings
weierophinney added a commit that referenced this pull request Mar 25, 2013
@weierophinney weierophinney merged commit 09e2a44 into zendframework:develop Mar 25, 2013
weierophinney added a commit to zendframework/zend-filter that referenced this pull request May 15, 2015
…e/develop

[WIP] Add RBAC support for navigation helper.
weierophinney added a commit to zendframework/zend-filter that referenced this pull request May 15, 2015
- trailing whitespace
- EOF endings
weierophinney added a commit to zendframework/zend-filter that referenced this pull request May 15, 2015
weierophinney added a commit to zendframework/zend-view that referenced this pull request May 15, 2015
…e/develop

[WIP] Add RBAC support for navigation helper.
weierophinney added a commit to zendframework/zend-view that referenced this pull request May 15, 2015
- Docblock additions/edits
- Logic workflow
weierophinney added a commit to zendframework/zend-view that referenced this pull request May 15, 2015
- trailing whitespace
- EOF endings
weierophinney added a commit to zendframework/zend-view that referenced this pull request May 15, 2015
weierophinney added a commit to zendframework/zend-navigation that referenced this pull request May 15, 2015
…e/develop

[WIP] Add RBAC support for navigation helper.
weierophinney added a commit to zendframework/zend-navigation that referenced this pull request May 15, 2015
- trailing whitespace
- EOF endings
weierophinney added a commit to zendframework/zend-navigation that referenced this pull request May 15, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants