Skip to end of metadata
Go to start of metadata

<h2>What is RBAC?</h2>

<p>From Wikipedia:</p>

<p>"In computer systems security, role-based access control (RBAC) is an approach to restricting system access to authorized users. It is used by the majority of enterprises with more than 500 employees,<ac:link><ri:page ri:content-title="3" /></ac:link> and can implement mandatory access control (MAC) or discretionary access control (DAC). RBAC is sometimes referred to as role-based security."</p>

<h2>Proposal</h2>

<p>The primary goals for this RFC are:</p>

<ul>
<li>Implement role-based access control as an <strong>alternative</strong> to access control lists (Zend\Permission\Acl).</li>
<li>Utilize PHP 5.3 SPL datastructures (RecursiveIterator and RecursiveIteratorIterator).</li>
</ul>

<h3>Architecture</h3>

<p>The requirements are as follows:</p>

<ul>
<li>Many to many relationship between identities and roles.</li>
<li>Many to many relationship between roles and permissions.</li>
<li>A role can have a parent (inheritance must be supported).</li>
<li>Dynamic assertions <strong>must</strong> be supported.</li>
</ul>

<p>Given the requirements, RBAC is a perfect fit for a composite pattern (<a href="http://en.wikipedia.org/wiki/Composite_pattern">http://en.wikipedia.org/wiki/Composite_pattern</a>) combined with SPL RecursiveIterator.</p>

<h3>Class skeletons</h3>

<ac:macro ac:name="code"><ac:parameter ac:name="title">Zend\Permission\Rbac\AbstractIterator.php</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Permission\Rbac;

use RecursiveIterator;

abstract class AbstractIterator implements RecursiveIterator
{
public function current();

public function next();

public function key();

public function valid();

public function rewind();

public function hasChildren();

public function getChildren();
}
]]></ac:plain-text-body></ac:macro>

<ac:macro ac:name="code"><ac:parameter ac:name="title">Zend\Permission\Rbac\AbstractRole.php</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Permission\Rbac;

abstract class AbstractRole extends AbstractIterator
{
public function getName();

public function addPermission($permission);

public function hasPermission($permission);

public function addChild($child);
}
]]></ac:plain-text-body></ac:macro>

<ac:macro ac:name="code"><ac:parameter ac:name="title">Zend\Permission\Rbac\Rbac.php</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Permission\Rbac;

class Rbacextends AbstractIterator
{
public function addRole($role);

public function hasRole($role);

public function getRole($role);

public function isGranted($permission);
}
]]></ac:plain-text-body></ac:macro>

<ac:macro ac:name="code"><ac:parameter ac:name="title">Zend\Permission\Rbac\Role.php</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Permission\Rbac;

class Role extends AbstractRole
{
}
]]></ac:plain-text-body></ac:macro>

<h3>Setting up roles and permissions</h3>
<ac:macro ac:name="code"><ac:parameter ac:name="title">Roles</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[

// Creating roles manually
$foo = new \Zend\Permission\Rbac\Role('foo');
$bar = new \Zend\Permission\Rbac\Role('bar');

// Adding a child
$foo->addChild($bar);
$foo->addChild('baz'); // If a string is given creates default Role with name 'baz'

// Using Rbac container
$rbac = new \Zend\Permission\Rbac\Rbac;
$rbac->addRole($foo);
$rbac->addRole('baz');
$rbac->addRole($bar, array($foo)); // Add role bar with parents $foo, can also just give it a single object instead of array

// Adding permissions
$foo->addPermission('test');
var_dump($foo->hasPermission('test')); // true

// Using Rbac container
$rbac->getRole('foo')->addPermission('barperm');
]]></ac:plain-text-body></ac:macro>

<h3>Dynamic assertions</h3>

<p>Dynamic assertions can be provided via an AssertionInterface (Zend\Permission\Rbac\AssertionInterface) or by simply passing a closure. For example,</p>

<ac:macro ac:name="code"><ac:parameter ac:name="title">Zend\Permission\Rbac\AssertionInterface</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$event = new \My\Event;
$event->setUserId(1);

// Verify user has event.update permission and event user matches user.
$rbac->isGranted('event.update', function($rbac) use ($user, $event) {
return $user->getId() === $event->getUserId();
});
]]></ac:plain-text-body></ac:macro>

<h3>Working example</h3>

<p>The SpiffySecurity module currently implements the Rbac code and can be found at <a class="external-link" href="https://github.com/SpiffyJr/SpiffySecurity/tree/master/src/SpiffySecurity/Rbac">https://github.com/SpiffyJr/SpiffySecurity/tree/master/src/SpiffySecurity/Rbac</a>.</p>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Aug 21, 2012

    <p>Can you detail how you'd setup the permissions and roles, please?</p>

    1. Aug 30, 2012

      <p>Updated.</p>

      1. Aug 30, 2012

        <p>Awesome – much clearer now!</p>

  2. Aug 22, 2012

    <p>What is the reason RBAC is provided as an alternative to ACL? It might seem obvious, but I would like to see explicitly why RBAC in this RFC should be accepted: is it "better", faster, easier than ACL? Does it have things ACL can't? Why would you develop a new component (RBAC) and not update ACL if there is something "wrong" with ACL?</p>

    1. Aug 30, 2012

      <p>There are no technical advantages (assuming ACL is rewritten to use SPL data structures like my component). The only advantage relates to how you think about permissions. For me, it's easier to assign permissions to a meaningful or specific operation instead of some arbitrary object.</p>

  3. Sep 21, 2012

    <p>PR available @ <a class="external-link" href="https://github.com/zendframework/zf2/pull/2396/files">https://github.com/zendframework/zf2/pull/2396/files</a></p>