Index: library/Zend/Acl.php =================================================================== --- library/Zend/Acl.php (revision 23318) +++ library/Zend/Acl.php (working copy) @@ -632,22 +632,30 @@ unset($rolesTemp); // ensure that all specified Resources exist; normalize input to array of Resource objects or null - if (!is_array($resources)) { - $resources = ($resources == null && count($this->_resources) > 0) ? array_keys($this->_resources) : array($resources); - } else if (0 === count($resources)) { - $resources = array(null); - } - $resourcesTemp = $resources; - $resources = array(); - foreach ($resourcesTemp as $resource) { - if (null !== $resource) { - $resources[] = $this->get($resource); - } else { - $resources[] = null; + if ($resources !== null) { + if (!is_array($resources)) { + $resources = array($resources); + } else if (0 === count($resources)) { + $resources = array(null); } + $resourcesTemp = $resources; + $resources = array(); + foreach ($resourcesTemp as $resource) { + if (null !== $resource) { + $resources[] = $this->get($resource); + } else { + $resources[] = null; + } + } + unset($resourcesTemp, $resource); + } else { + $allResources = array(); // this might be used later if resource iteration is required + foreach ($this->_resources as $rTarget) { + $allResources[] = $rTarget['instance']; + } + unset($rTarget); } - unset($resourcesTemp); - + // normalize privileges to array if (null === $privileges) { $privileges = array(); @@ -659,15 +667,32 @@ // add to the rules case self::OP_ADD: - foreach ($resources as $resource) { + if ($resources !== null) { + // this block will iterate the provided resources + foreach ($resources as $resource) { + foreach ($roles as $role) { + $rules =& $this->_getRules($resource, $role, true); + if (0 === count($privileges)) { + $rules['allPrivileges']['type'] = $type; + $rules['allPrivileges']['assert'] = $assert; + if (!isset($rules['byPrivilegeId'])) { + $rules['byPrivilegeId'] = array(); + } + } else { + foreach ($privileges as $privilege) { + $rules['byPrivilegeId'][$privilege]['type'] = $type; + $rules['byPrivilegeId'][$privilege]['assert'] = $assert; + } + } + } + } + } else { + // this block will apply to all resources in a global rule foreach ($roles as $role) { - $rules =& $this->_getRules($resource, $role, true); + $rules =& $this->_getRules(null, $role, true); if (0 === count($privileges)) { $rules['allPrivileges']['type'] = $type; $rules['allPrivileges']['assert'] = $assert; - if (!isset($rules['byPrivilegeId'])) { - $rules['byPrivilegeId'] = array(); - } } else { foreach ($privileges as $privilege) { $rules['byPrivilegeId'][$privilege]['type'] = $type; @@ -680,41 +705,85 @@ // remove from the rules case self::OP_REMOVE: - foreach ($resources as $resource) { - foreach ($roles as $role) { - $rules =& $this->_getRules($resource, $role); - if (null === $rules) { - continue; - } - if (0 === count($privileges)) { - if (null === $resource && null === $role) { - if ($type === $rules['allPrivileges']['type']) { - $rules = array( - 'allPrivileges' => array( - 'type' => self::TYPE_DENY, - 'assert' => null - ), - 'byPrivilegeId' => array() - ); - } + if ($resources !== null) { + // this block will iterate the provided resources + foreach ($resources as $resource) { + foreach ($roles as $role) { + $rules =& $this->_getRules($resource, $role); + if (null === $rules) { continue; } - - if (isset($rules['allPrivileges']['type']) && - $type === $rules['allPrivileges']['type']) - { - unset($rules['allPrivileges']); - } - } else { - foreach ($privileges as $privilege) { - if (isset($rules['byPrivilegeId'][$privilege]) && - $type === $rules['byPrivilegeId'][$privilege]['type']) + if (0 === count($privileges)) { + if (null === $resource && null === $role) { + if ($type === $rules['allPrivileges']['type']) { + $rules = array( + 'allPrivileges' => array( + 'type' => self::TYPE_DENY, + 'assert' => null + ), + 'byPrivilegeId' => array() + ); + } + continue; + } + + if (isset($rules['allPrivileges']['type']) && + $type === $rules['allPrivileges']['type']) { - unset($rules['byPrivilegeId'][$privilege]); + unset($rules['allPrivileges']); } + } else { + foreach ($privileges as $privilege) { + if (isset($rules['byPrivilegeId'][$privilege]) && + $type === $rules['byPrivilegeId'][$privilege]['type']) + { + unset($rules['byPrivilegeId'][$privilege]); + } + } } } } + } else { + // this block will apply to all resources in a global rule + foreach ($roles as $role) { + /** + * since null (all resources) was passed to this setRule() call, we need + * clean up all the rules for the global allResources, as well as the indivually + * set resources (per privilege as well) + */ + foreach (array_merge(array(null), $allResources) as $resource) { + $rules =& $this->_getRules($resource, $role, true); + if (null === $rules) { + continue; + } + if (0 === count($privileges)) { + if (null === $role) { + if ($type === $rules['allPrivileges']['type']) { + $rules = array( + 'allPrivileges' => array( + 'type' => self::TYPE_DENY, + 'assert' => null + ), + 'byPrivilegeId' => array() + ); + } + continue; + } + + if (isset($rules['allPrivileges']['type']) && $type === $rules['allPrivileges']['type']) { + unset($rules['allPrivileges']); + } + } else { + foreach ($privileges as $privilege) { + if (isset($rules['byPrivilegeId'][$privilege]) && + $type === $rules['byPrivilegeId'][$privilege]['type']) + { + unset($rules['byPrivilegeId'][$privilege]); + } + } + } + } + } } break; @@ -1129,6 +1198,7 @@ return $nullRef; } $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array(); + $visitor['byRoleId'][$roleId]['allPrivileges'] = array('type' => null, 'assert' => null); } return $visitor['byRoleId'][$roleId]; } Index: tests/Zend/Acl/AclTest.php =================================================================== --- tests/Zend/Acl/AclTest.php (revision 23318) +++ tests/Zend/Acl/AclTest.php (working copy) @@ -1304,7 +1304,7 @@ /** * @group ZF-9643 */ - public function testRemoveAllowWithNullResourceAppliesToAllResources() + public function testRemoveAllowWithNullResourceAfterResourceSpecificRulesAppliesToAllResources() { $this->_acl->addRole('guest'); $this->_acl->addResource('blogpost'); @@ -1331,7 +1331,7 @@ /** * @group ZF-9643 */ - public function testRemoveDenyWithNullResourceAppliesToAllResources() + public function testRemoveDenyWithNullResourceAfterResourceSpecificRulesAppliesToAllResources() { $this->_acl->addRole('guest'); $this->_acl->addResource('blogpost'); @@ -1357,4 +1357,22 @@ $this->assertFalse($this->_acl->isAllowed('guest', 'newsletter', 'read')); } + /** + * @group ZF-10649 + */ + public function testAllowAndDenyWithNullForResourcesWillApplyToAllResources() + { + $this->_acl->addRole('guest'); + $this->_acl->addResource('blogpost'); + + $this->_acl->allow('guest'); + $this->assertTrue($this->_acl->isAllowed('guest')); + $this->assertTrue($this->_acl->isAllowed('guest', 'blogpost')); + $this->assertTrue($this->_acl->isAllowed('guest', 'blogpost', 'read')); + + $this->_acl->deny('guest'); + $this->assertFalse($this->_acl->isAllowed('guest')); + $this->assertFalse($this->_acl->isAllowed('guest', 'blogpost')); + $this->assertFalse($this->_acl->isAllowed('guest', 'blogpost', 'read')); + } }