ZF-5369: Zend_Acl::allow($role) does not behave as expected

Issue Type: Bug Created: 2008-12-29T01:55:48.000+0000 Last Updated: 2009-09-08T19:11:00.000+0000 Status: Postponed Fix version(s): Reporter: Christian Ascheberg (asche) Assignee: Ralph Schindler (ralph) Tags: - Zend_Acl

Related issues: - ZF-7119

Attachments: - ZF-5379.patch


The following code does not behave as I do expect:

<pre class="highlight">
$acl = new Zend_Acl();

$acl->addRole(new Zend_Acl_Role('user'));
$acl->addRole(new Zend_Acl_Role('admin'), 'user');

$acl->add(new Zend_Acl_Resource('resource'));

$acl->deny('user', 'resource');

echo "user -> resource = ".(($acl->isAllowed('user', 'resource')) ? 'yes' : 'no')."\n";
echo "admin -> resource = ".(($acl->isAllowed('admin', 'resource')) ? 'yes' : 'no')."\n";

outputs: {quote} user -> resource = no admin -> resource = no {quote} I would expect that 'admin' is allowed to access 'resource'. Is there a bug?

Same thing with a modified code from… :

<pre class="highlight">
$acl->add(new Zend_Acl_Resource('home'));
$acl->add(new Zend_Acl_Resource('news'));
$acl->add(new Zend_Acl_Resource('tutorials'));
$acl->add(new Zend_Acl_Resource('forum'));
$acl->add(new Zend_Acl_Resource('support'));
$acl->add(new Zend_Acl_Resource('admin'));

$acl->addRole(new Zend_Acl_Role('guest'));
$acl->addRole(new Zend_Acl_Role('member'), 'guest');
$acl->addRole(new Zend_Acl_Role('admin'), 'member');

// Guest may only view content
$acl->allow('guest', 'home');
$acl->allow('guest', 'news');
$acl->allow('guest', 'tutorials');
$acl->allow('member', 'forum');
$acl->deny('member', 'forum', 'update'); // Remove specific privilege
$acl->allow('member', 'support');
$acl->allow('admin'); // unrestricted access

echo "member -> forum : read = ".(($acl->isAllowed('member', 'forum', 'read')) ? 'yes' : 'no')."\n";
echo "admin -> forum : read = ".(($acl->isAllowed('admin', 'forum', 'read')) ? 'yes' : 'no')."\n";
echo "member -> forum : update = ".(($acl->isAllowed('member', 'forum', 'update')) ? 'yes' : 'no')."\n";
echo "admin -> forum : update = ".(($acl->isAllowed('admin', 'forum', 'update')) ? 'yes' : 'no')."\n";

{quote} member -> forum : read = yes admin -> forum : read = yes member -> forum : update = no admin -> forum : update = no {quote}

After a closer look, to me it seems as if the 'allResources'-part of the rules is only checked when $resource is explicitly null instead of - for example - checking it whenever there is no explicit rule for the given resource (in Zend_Acl::_getRules).


Posted by Christian Ascheberg (asche) on 2009-01-05T01:37:53.000+0000

further investigations

Posted by Benjamin Eberlei (beberlei) on 2009-01-11T07:03:27.000+0000

This issue is a blocker, will investigate it, although i am not an expert at Zend_Acl

Posted by Benjamin Eberlei (beberlei) on 2009-01-11T07:16:05.000+0000

Confirmed the use-case as not working correctly.

Posted by Wil Sinclair (wil) on 2009-01-14T13:31:40.000+0000

Assigning to Ralph to get closure on this issues.

Posted by Dolf Schimmel (Freeaqingme) (freak) on 2009-07-01T21:12:38.000+0000

This issue cannot be changed without either changing the architecture drastically or breaking BC.

Given the original usecase: {php}$acl = new Zend_Acl();

$acl->addRole(new Zend_Acl_Role('user')); $acl->addRole(new Zend_Acl_Role('admin'), 'user');

$acl->add(new Zend_Acl_Resource('resource'));

$acl->deny('user', 'resource'); $acl->allow('admin');{php}

The point is that though you can allow role 'admin' to have access to everything, role 'user' is still the parent of user and by default this prevails. You can however change this behaviour by applying the attached patch. Point is then that you would break BC... see for that the current unittests, testCMSExample(), line 991: $this->assertFalse($this->_acl->isAllowed('administrator', 'announcement', 'archive')); (r16407)

What in that test basically is done is exactly the opposite: {php} $acl->addRole(new Zend_Acl_Role('user')); $acl->addRole(new Zend_Acl_Role('admin'), 'user');

$acl->add(new Zend_Acl_Resource('resource')); $acl->allow('admin'); $acl->deny(null, 'resource'); // Deny all access to 'resource'{php}

A solution would be with a future fix (reorganization of zend_acl, if any) would be to keep track of when which permission was added.

Posted by Dolf Schimmel (Freeaqingme) (freak) on 2009-07-01T21:15:33.000+0000

If not clear yet; I propose to either postpone this issue until zend_acl is drastically worked on (2.0?), or close it as a wont-fix.

Posted by Christian Ascheberg (asche) on 2009-07-19T10:26:38.000+0000

I think it would be better to "dratically" work on Zend_ACL (which surely means breaking BC) instead of just closing this issue.

My idea is (basically) that you should have tree of roles and resources (and maybe also privileges), each with a ROOT element. Furthermore you should have an explizit access matrix for every combination of roles and resources where the possible values are 'allow', 'deny' and 'inherit' while 'inherit' should be default and would not need to be set explizitly.

One more thing about the current implementation: to me, it is not logical why one role should inherit from multiple other roles. At least the way it is currently implemented is hard to follow / confusing to me. An expample is given on This is a modification of the given example with an additional level of inheritance:

<pre class="highlight">
$acl = new Zend_Acl();

$acl->addRole(new Zend_Acl_Role('a1'))
    ->addRole(new Zend_Acl_Role('a2'));

$acl->addRole(new Zend_Acl_Role('b1'), 'a1')
    ->addRole(new Zend_Acl_Role('b2'), 'a2');

$parents = array('b1', 'b2');
$acl->addRole(new Zend_Acl_Role('someUser'), $parents);

$acl->add(new Zend_Acl_Resource('someResource'));


$acl->allow('a2', 'someResource');

$acl->deny('b1', 'someResource');

echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';

The output is {quote} allowed {quote}

So you check 'b2' first, then 'b2's parent which is 'a2' (allowed). Given the case that there is no explizit rule for 'a2', then you would check 'b1' and its parent 'a1'... wouldn't it be more consequent then to completely walk up the tree to the ROOT with the result 'deny' (with no multiple inheritance possible) or check 'b1' first and then check the parents of 'b2' and 'b1'? I hope you understand what I mean (as I said, to me its is confusing...).

However, I really like Zend Framework and its really nice coding style. I would really like to get involved in this a bit!

Posted by Dolf Schimmel (Freeaqingme) (freak) on 2009-07-21T05:16:23.000+0000

This issue is certainly recognized. If the problem cannot be solved without major BC-breaks, probably a next version of an acl component will be added to ZF. There are already several proposals for this, I propose you keep an eye on those.

Have you found an issue?

See the Overview section for more details.


© 2006-2018 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.