Issues

ZF-7838: Null privilege tests incorrectly when explicit privileges are defined

Description

Assuming the following ACL

{{$acl=new Zend_Acl();}} {{$acl->add(new Zend_Acl_Resource('files'));}} {{$acl->addRole(new Zend_Acl_Role('user'));}}

{{$acl->allow('user', 'files');}} {{$acl->deny('user', 'files', 'create');}}

Then

{{isAllowed('user','files'); // returns false but should true because access was given to the entire resource and only revoked for the 'create' privilege.}}

Could not find a suitable workaround other than never checking the default access but explicitly checking each privilege. The trouble with that is that undefined default privileges will correctly reflect the explicit definition of the null privilege for the resource. However the as reported here the null privilege reports wrong if a specific privilege is denied.

Hope this makes sense.

Comments

Interesting, I'll have to dig around, I am not sure if this is a bug or not. Either way, the bigger question is if fixing this would cause a backwards-incompatibility for people consuming Zend_Acl.

Put another way:


$acl = new Zend_Acl();
$acl->addRole('some-role');
$acl->addResource('some-resource');
$acl->allow('some-role', 'some-resource');

echo ($acl->isAllowed('some-role','some-resource') ? 'true' : 'false') . PHP_EOL; // returns true

$acl->deny('some-role', 'some-resource', 'some-privilege');

echo ($acl->isAllowed('some-role','some-resource') ? 'true' : 'false') . PHP_EOL; // returns false

Consider this code in addendum to the above:


// give carte blanche access
$acl->allow('some-role', 'some-resource');

echo ($acl->isAllowed('some-role','some-resource') ? 'true' : 'false') . PHP_EOL; // returns true

// deny for a very specific priv, thus breaking carte blanche access
$acl->deny('some-role', 'some-resource', 'some-privilege');

echo ($acl->isAllowed('some-role','some-resource') ? 'true' : 'false') . PHP_EOL; // returns false
echo ($acl->isAllowed('some-role','some-resource', 'some-privildge') ? 'true' : 'false') . PHP_EOL; // returns false

By giving carte blanche access (no privilege), a user has full power over all privileges possible, thus it returns true. When you add a denied privilege to the tree, the user by definition can no longer have carte blanche access, thus when you ask if they have such access, it returns false, which is the correct behavior.

Ralph,

Thanks for looking into and explaining it. I don't agree with the logic as it works different than card blanche overrides for resources and roles alongside their support for inheritance. I.E. setting specific [card blanche] access lower in the inheritance tree doesn't alter the upstream [card blanche] definitions the same way.

So, following my logic would be more consistent across the board. Frankly, I have to assume backward compatibility would not be a problem, because apparently no-one has come across this yet. :-)

If it needs to stay as it is now, it would definitely be most useful for that to be explained in the reference guide.

Aside from that, I also want to point out that card-blanche privilege access does not work consistently when checking for non-existent privileges. My gut instinct tells me that non-existent privileges should be denied as they don't exist from the ACL's point of view and thus, can't be tested. Another case could be made for it to reflect the current state of the card blanche access. Currently it doesn't operate like either of the above:

// give card-blanche access
$acl->allow('some-role', 'some-resource');
// deny for a very specific priv, thus breaking carte blanche access
$acl->deny('some-role', 'some-resource', 'some-privilege');

// check card blanche access
echo ($acl->isAllowed('some-role','some-resource') ? 'true' : 'false') . PHP_EOL; // returns false

// check against a non-existing privilege
echo ($acl->isAllowed('some-role','some-resource', 'non-existent-privilige') ? 'true' : 'false') . PHP_EOL; // returns true even though card blanche is false - NOT GOOD

Compared to reversing the acl

// deny card-blanche access
$acl->deny('some-role', 'some-resource');
// allow for a very specific priv, thus breaking carte blanche access (not really, because it's already negative)
$acl->allow('some-role', 'some-resource', 'some-privilege');

// check card blanche access
echo ($acl->isAllowed('some-role','some-resource') ? 'true' : 'false') . PHP_EOL; // returns false reflecting card blanche on resource

// check specific privilege
echo ($acl->isAllowed('some-role','some-resource', 'some-privilege') ? 'true' : 'false') . PHP_EOL; // returns true, ok - expected

// check against a non-existing privilege
echo ($acl->isAllowed('some-role','some-resource', 'non-existent-privilige') ? 'true' : 'false') . PHP_EOL; // returns false reflecting card blanche on resource

I guess there's multiple ways to address it (if at all) - let acl be configured for assertions to respond as pessimistic vs. optimistic - let assertions return a mixed state rather than just true or false