Zend permissions rbac - Inheritance permissions

Hi, I’m using right now the component zend-permissions-rbac to achieve the authorization process in my expressive application. I’m struggling to figure out how to solve the following problem that crossed my mind:

The component automatically allow to any role to inherit the permissions of their children which is a beautiful feature that go along with almost all my permissions.
I want to be able to avoid this feature only with some specific permissions, so that only the role associated with it can access it.

Example of a hierarchy structure of roles:

$role=$rbac->addRole('role');
$subRole = $rbac->addRole('subrole');
$role->addChild($subRole);

$role->addPermission('permission1');
$role->addPermission('permission2');

// This permission should be not accessible by the role parent
$subRole->addPermission('permission3');

// This permission must be accessibile by the role parent
$subRole->addPermission('permission4');




I want to maintain the hierarchy structure of the roles, this means that I don’t want to remove children for the role which can cause the explained problem and I don’t really like the first solution.

Solutions:

  1. Creating an assert associated with the right permissions which do the following check:
class AssertOnlyMyRole implements AssertionInterface
{
    public function assert(Rbac $rbac)
    {
        if($permission='permission3'){
           return $this->role=='subrole';
        }
    }
}
  1. Overwriting the hasPermission() of the AbstractRole class in this way:
class MyRole extends AbstractRole{

private $excludePermissionsCheckOnChildren=['permission3'];

 public function hasPermission($name)
    {
        if (isset($this->permissions[$name])) {
            return true;
        }
        if(!in_array($name, $excludePermissionsCheckOnChildren)){
           $it = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::CHILD_FIRST);
           foreach ($it as $leaf) {
            /** @var RoleInterface $leaf */
               if ($leaf->hasPermission($name)) {
                  return true;
               }
            }
            return false;
        }
    }
}

Can someone suggest improvements to my ideas or help me?

Thank you.

If $subRole is a child of $role all the permissions of $subRole are valid for $role, so you cannot have permission3 of $subRole that not accessible by parent role ($role). You need to change the hierarchy model.

UPDATE: we are changing the AssertionInterface::assert for v.3.0.0 with $role and $permission always required, as follows:

namespace Zend\Permissions\Rbac;

interface AssertionInterface
{
    /**
     * Assertion method - must return a boolean.
     */
    public function assert(Rbac $rbac, RoleInterface $role, string $permission) : bool;
}

More info here: https://github.com/zendframework/zend-permissions-rbac/pull/34

Sorry for my late feedback. At the end I will modify hierarchy structure of roles so I don’t need to make too custom logic. Thanks!

I never understood why the parent inherits from a child :thinking:
If using a nomenclature like role and subrole - okay.
But with using nomenclature like parent and child, it doesn’t make sense, as it’s usually vice versa.

@lowtower why it doesn’t make sense to define a child/parent hierarchy for a role? This is actually a very common scenario to map role level using a hierarchy tree model. Can you explain it better? Thanks.

@enrico In real world parent/child hierarchy, children inherit traits and attributes from their parents, not the other way around. I think that’s the issue @lowtower is referring to.

For ACL it makes sense, child roles inherit permissions from parent roles in the classical sense.

For RBAC each child adds something to its parent. It’s more akin to each sub role granting a new level of access to roles it’s a subordinate of.

Of course none of that helps in coming up with better names, but as it’s something I’ve observed and grappled with before, I thought I’d chime in.

@CrispCrumbs, exactly.

In the real world, usually the child inherits from the parent.
So, in my opinion, the allegory with parent/child doesn’t make sense or leads to confusion (as seen in the original Post).

@CrispCrumbs and @lowtower my references (see below) assert that a role inherits the permissions of the children roles.
I’ve implemented zend-permissions-rbac V.3.0.0-dev (still in development) following the NIST standard.

I also used as reference the RBAC model proposed by Ravi S. Sandhu et all (cited in the NIST standard) reported here:

In particular, in the Role-based Access Control paper, at page 247 we have an example of role hierarchies, in Figure 2.

Here we can see the model of Fig.2(a). At pag. 247 we can read:

“By convention more powerful (or senior) roles are shown toward the top of these diagrams, and less powerful (or junior) roles toward the bottom”

Moreover, at pag. 248, we can read:

“In Fig. 2(a) the junior-most role is health-care provider. The physician role is senior to health-care provider and thereby inherits all permissions from health-care provider. The physician role can have permissions in addition to those inherited from the health-care provider role. Inheritance of permissions is transitive so, for example, in Fig. 2(a), the primary-care physician role inherits permissions from the physician and health-care provider roles. Primary-care physician and specialist physician both inherit permissions from the physician role, but each one of these will have different permissions directly assigned to it.”

So, I think the actual implementation reported in develop branch is compliant with these references.

Note: I forgot to mention, I didn’t change the hierarchy model of zend-permission-rbac in v.3.0-dev, it still the same of v.2.x. I just changed some API and removed the Role::setParent() in favor of Role::addParent(), you can see the CHANGELOG for more details.

Hello @enrico,

nothing wrong with the implementation!
It’s just the wording “parent / child” that confuses the hierarchy in my opinion.
In the real world, the parents build a house and when they die, the child inherits the parent’s property.
Btw, I haven’t found the wording “parent / child” in the references You have given, except for zend-rbac. “Senior / junior” is used in one reference.

Nevertheless, i am okay with the implementation and wording, just don’t understand it.
Let’s close the discussion here.

Cheers,
Lowtower.

Hi @lowtower maybe now I see your point. We used parent/child naming because this is the usual way to refer nodes in a Tree data structure (see the previous diagram reported in Fig. 2). See https://en.wikipedia.org/wiki/Tree_(data_structure) for more details.
Maybe we need to clarify this naming in the documentation, using the Tree as data model.