├── .coveralls.yml ├── .github └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── library └── SimpleAcl │ ├── Acl.php │ ├── BaseObject.php │ ├── Exception │ ├── ExceptionInterface.php │ ├── InvalidArgumentException.php │ └── RuntimeException.php │ ├── Object │ ├── ObjectAggregate.php │ └── RecursiveIterator.php │ ├── Resource.php │ ├── Resource │ ├── ResourceAggregate.php │ └── ResourceAggregateInterface.php │ ├── Role.php │ ├── Role │ ├── RoleAggregate.php │ └── RoleAggregateInterface.php │ ├── Rule.php │ ├── RuleResult.php │ ├── RuleResultCollection.php │ ├── RuleWide.php │ └── SplPriorityQueue.php ├── phpunit.xml.dist └── tests ├── SimpleAclStubs └── CustomRule.php ├── SimpleAclTest ├── AclRuleApplyTest.php ├── AclTest.php ├── Object │ └── RecursiveIteratorTest.php ├── ObjectTest.php ├── Resource │ └── ResourceAggregateTest.php ├── Role │ └── RoleAggregateTest.php ├── RuleResultCollectionTest.php ├── RuleResultTest.php └── RuleTest.php ├── bootstrap.php ├── bootstrap5.php └── bootstrap8.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | # for php-coveralls 2 | service_name: travis-ci 3 | coverage_clover: tmp/clover.xml 4 | json_path: tmp/coveralls-upload.json 5 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | branches: 8 | - master 9 | - develop 10 | paths-ignore: 11 | - '**/README.md' 12 | - '**/CHANGELOG.md' 13 | pull_request: 14 | branches: 15 | - master 16 | - develop 17 | paths-ignore: 18 | - '**/README.md' 19 | - '**/CHANGELOG.md' 20 | 21 | jobs: 22 | tests: 23 | runs-on: ubuntu-latest 24 | 25 | strategy: 26 | matrix: 27 | include: 28 | - php: 5.3 29 | php-unit: 4 30 | coveralls: 1 31 | coveralls-run: coveralls 32 | - php: 5.4 33 | php-unit: 4 34 | coveralls: 1 35 | coveralls-run: coveralls 36 | - php: 5.5 37 | php-unit: 4 38 | coveralls: 2 39 | coveralls-run: php-coveralls 40 | - php: 5.6 41 | php-unit: 5 42 | coveralls: 2 43 | coveralls-run: php-coveralls 44 | - php: 7.0 45 | php-unit: 5 46 | coveralls: 2 47 | coveralls-run: php-coveralls 48 | - php: 7.1 49 | php-unit: 5 50 | coveralls: 2 51 | coveralls-run: php-coveralls 52 | - php: 7.2 53 | php-unit: 5 54 | coveralls: 2 55 | coveralls-run: php-coveralls 56 | - php: 7.3 57 | php-unit: 5 58 | coveralls: 2 59 | coveralls-run: php-coveralls 60 | - php: 8.0 61 | php-unit: 9 62 | coveralls: 2.6 63 | coveralls-run: php-coveralls 64 | - php: 8.1 65 | php-unit: 9 66 | coveralls: 2.6 67 | coveralls-run: php-coveralls 68 | - php: 8.2 69 | php-unit: 9 70 | coveralls: 2.6 71 | coveralls-run: php-coveralls 72 | 73 | name: Tests PHP ${{ matrix.php }} PHPUnit ${{ matrix.php-unit }} 74 | 75 | steps: 76 | - uses: actions/checkout@v3 77 | 78 | - name: Setup PHP ${{ matrix.php }} PHPUnit ${{ matrix.php-unit }} 79 | uses: shivammathur/setup-php@v2 80 | with: 81 | php-version: ${{ matrix.php }} 82 | tools: composer, phpunit:${{ matrix.php-unit }} 83 | 84 | - run: composer install 85 | 86 | - run: phpunit --coverage-clover tmp/clover.xml 87 | 88 | - run: composer global require php-coveralls/php-coveralls:${{ matrix.coveralls }}.* 89 | 90 | - name: Coveralls 91 | env: 92 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 93 | COVERALLS_PARALLEL: true 94 | COVERALLS_FLAG_NAME: php-${{ matrix.php }}-${{ matrix.php-unit }} 95 | run: ${{ matrix.coveralls-run }} --coverage_clover=tmp/clover.xml -v 96 | 97 | coveralls: 98 | needs: tests 99 | 100 | runs-on: ubuntu-latest 101 | 102 | steps: 103 | - uses: coverallsapp/github-action@v2 104 | with: 105 | parallel-finished: true 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | vendor/ 3 | tmp 4 | composer.lock -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2.0.25 2 | 3 | - Fixed problems which cause warning for PHP 8.2 4 | - Migrate tests from Travis to GitHub Actions 5 | - Added tests for PHP 8.0, 8.1, 8.2 6 | 7 | 2.0.24 8 | 9 | - Rename Object to BaseObject (as Object is reserved keyword from PHP 7.2) 10 | 11 | 2.0.23 12 | 13 | - Made all string equality check strict 14 | - Remove coveralls.io from dev dependencies to travis 15 | 16 | 2.0.22 17 | 18 | - Add better random id function 19 | - Add coveralls.io and test on PHP 5.6 20 | 21 | 2.0.21 22 | 23 | - Fix issue with null in Acl isAllowed 24 | 25 | 2.0.20 26 | 27 | - Add priority for rule. 28 | 29 | 2.0.19 30 | 31 | - Add license. 32 | 33 | 2.0.18 34 | 35 | - Update README.md 36 | 37 | 2.0.17 38 | 39 | - Minor refactoring 40 | 41 | 2.0.16 42 | 43 | - Fix problem with resetting aggregates 44 | 45 | 2.0.15 46 | 47 | - Add ability get aggregate from rules and RuleResult 48 | 49 | 2.0.14-2.0.12 50 | 51 | - Start using recursive iterators for walking by objects 52 | 53 | 2.0.11-2.0.1 54 | 55 | - Last added Role (Resource) to RoleAggregate (or ResourceAggregate) wins 56 | 57 | 2.0.0 58 | 59 | - Last added rule now win 60 | - Child resources NOT grant access to their parents 61 | - Child resource inherit access from parents 62 | - Add priorities 63 | 64 | 1.0.0-1.0.2 65 | 66 | - First version 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | New BSD License 2 | =============== 3 | 4 | Copyright (c) 2012, Jurian Sluiman 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | * Neither the names of the copyright holders nor the names of its 16 | contributors may be used to endorse or promote products derived from this 17 | software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple Access Control List (ACL) for PHP. 2 | 3 | [![Test Status](https://github.com/alexshelkov/SimpleAcl/actions/workflows/test.yml/badge.svg)](https://github.com/alexshelkov/SimpleAcl/actions/workflows/test.yml) 4 | [![Coverage Status](https://coveralls.io/repos/alexshelkov/SimpleAcl/badge.svg?branch=master&service=github)](https://coveralls.io/github/alexshelkov/SimpleAcl?branch=master) 5 | _____________________________________________________________________________________________________________________ 6 | #### Install 7 | ##### Using composer 8 | Add following in your composer.json: 9 | ```json 10 | { 11 | "require": { 12 | "alexshelkov/simpleacl": "2.*" 13 | } 14 | } 15 | ``` 16 | ##### Manual 17 | Download library and register PSR-0 compatible autoloader. 18 | ________________________________________________________ 19 | #### Usage 20 | ##### Basic usage 21 | ###### Theory 22 | There is 4 kind of objects: *Rules*, *Roles*, *Resources* and *Acl* which holds list of *Rules*. Some *Rule* can grant access for some *Role* to some *Resource*. 23 | 24 | ###### Create rules 25 | Lets create "View" Rule, and with with it grant access for "User" to "Page" (note: all names are case sensitive): 26 | ```php 27 | $view = new Rule('View'); 28 | $view->setRole(new Role('User')); 29 | $view->setResource(new Resource('Page')); 30 | $view->setAction(true); // true means that we allow access 31 | 32 | var_dump((bool)$view->isAllowed('User', 'Page')); // true 33 | ``` 34 | 35 | ###### Add rules 36 | There is not much sense in rules without Acl. So we need to add rules in it. In next example we add few rules in Acl and see whats happens. 37 | ```php 38 | $acl = new Acl(); 39 | 40 | $user = new Role('User'); 41 | $admin = new Role('Admin'); 42 | 43 | $siteFrontend = new Resource('SiteFrontend'); 44 | $siteBackend = new Resource('SiteBackend'); 45 | 46 | $acl->addRule($user, $siteFrontend, new Rule('View'), true); 47 | $acl->addRule($admin, $siteFrontend, 'View', true); // you can use string as rule 48 | $acl->addRule($admin, $siteBackend, 'View', true); 49 | 50 | var_dump($acl->isAllowed('User', 'SiteFrontend', 'View')); // true 51 | var_dump($acl->isAllowed('User', 'SiteBackend', 'View')); // false 52 | var_dump($acl->isAllowed('Admin', 'SiteFrontend', 'View')); // true 53 | var_dump($acl->isAllowed('Admin', 'SiteBackend', 'View')); // true 54 | ``` 55 | They are various way to add rules to *Acl*, addRule method accepts from one to four arguments, so you can also add rules like this: 56 | ```php 57 | addRule($view); 60 | 61 | // where is true -- is action 62 | $acl->addRule($view, true); 63 | 64 | // in that case action must be set before adding rule 65 | $acl->addRule($user, $siteBackend, $view); 66 | ``` 67 | 68 | ###### Roles and resource inheritance 69 | As you maybe notice in previous example we have some duplication of code, because both "User" and "Admin" was allowed to "View" "SiteFrontend" we added 2 rules. But it is possible to avoid this using roles inheritance. 70 | ```php 71 | $acl = new Acl(); 72 | 73 | $user = new Role('User'); 74 | $admin = new Role('Admin'); 75 | $user->addChild($admin); // add user's child 76 | 77 | $siteFrontend = new Resource('SiteFrontend'); 78 | $siteBackend = new Resource('SiteBackend'); 79 | 80 | $acl->addRule($user, $siteFrontend, 'View', true); 81 | $acl->addRule($admin, $siteBackend, 'View', true); 82 | 83 | var_dump($acl->isAllowed('User', 'SiteFrontend', 'View')); // true 84 | var_dump($acl->isAllowed('User', 'SiteBackend', 'View')); // false 85 | var_dump($acl->isAllowed('Admin', 'SiteFrontend', 'View')); // true 86 | var_dump($acl->isAllowed('Admin', 'SiteBackend', 'View')); // true 87 | ``` 88 | Inheritance works for resources too. 89 | 90 | ##### Using callbacks 91 | You can create more complex rules using callbacks. 92 | ```php 93 | $acl = new Acl(); 94 | 95 | $user = new Role('User'); 96 | $siteFrontend = new Resource('SiteFrontend'); 97 | 98 | $acl->addRule($user, $siteFrontend, 'View', function (SimpleAcl\RuleResult $ruleResult) { 99 | echo $ruleResult->getNeedRoleName() . "\n"; 100 | echo $ruleResult->getNeedResourceName() . "\n"; 101 | echo $ruleResult->getPriority() . "\n"; 102 | echo $ruleResult->getRule()->getRole()->getName() . "\n"; 103 | echo $ruleResult->getRule()->getResource()->getName() . "\n"; 104 | 105 | return true; 106 | }); 107 | 108 | 109 | var_dump($acl->isAllowed('User', 'SiteFrontend', 'View')); // true 110 | 111 | // Outputs: 112 | // User 113 | // SiteFrontend 114 | // 0 115 | // User 116 | // SiteFrontend 117 | // bool(true) 118 | ``` 119 | 120 | ##### Using role and resource aggregates 121 | It is possible to check access not for particular Role or Resource, but for objects which aggregate them. These kind of objects must implement, respectively, SimpleAcl\Role\RoleAggregateInterface and SimpleAcl\Role\ResourceAggregateInterface. 122 | 123 | You can use SimpleAcl\Role\RoleAggregate and SimpleAcl\Role\ResourceAggregate as object which allow aggregation. 124 | ```php 125 | $acl = new Acl(); 126 | 127 | $user = new Role('User'); 128 | $admin = new Role('Admin'); 129 | 130 | $all = new RoleAggregate; 131 | $all->addRole($user); 132 | $all->addRole($admin); 133 | 134 | $siteFrontend = new Resource('SiteFrontend'); 135 | $siteBackend = new Resource('SiteBackend'); 136 | 137 | $acl->addRule($user, $siteFrontend, 'View', true); 138 | $acl->addRule($admin, $siteBackend, 'View', true); 139 | 140 | var_dump($acl->isAllowed($all, 'SiteFrontend', 'View')); // true 141 | var_dump($acl->isAllowed($all, 'SiteBackend', 'View')); // true 142 | ``` 143 | 144 | You can have access to role and resource aggregates in callbacks. 145 | ```php 146 | $acl->addRule($user, $siteFrontend, 'View', function (SimpleAcl\RuleResult $ruleResult) { 147 | var_dump($ruleResult->getRoleAggregate()); 148 | var_dump($ruleResult->getResourceAggregate()); 149 | }); 150 | 151 | var_dump($acl->isAllowed($all, 'SiteFrontend', 'View')); // true 152 | ``` 153 | 154 | __For more help check out wiki pages.__ 155 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alexshelkov/simpleacl", 3 | "license": "BSD-3-Clause", 4 | "type": "library", 5 | "description": "Simple Access Control List (ACL) for PHP.", 6 | "keywords": ["ACL", "authorization", "permission"], 7 | "homepage": "https://github.com/alexshelkov/SimpleAcl", 8 | "authors": [ 9 | { 10 | "name": "Alex Shelkovskiy", 11 | "email": "alexshelkov@gmail.com", 12 | "role": "Developer" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.3.0" 17 | }, 18 | "autoload": { 19 | "psr-0": { 20 | "SimpleAcl": "library/" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /library/SimpleAcl/Acl.php: -------------------------------------------------------------------------------- 1 | ruleClass = $ruleClass; 50 | } 51 | 52 | /** 53 | * Return rule class. 54 | * 55 | * @return string 56 | */ 57 | public function getRuleClass() 58 | { 59 | return $this->ruleClass; 60 | } 61 | 62 | /** 63 | * Return true if rule was already added. 64 | * 65 | * @param Rule | mixed $needRule Rule or rule's id 66 | * @return bool 67 | */ 68 | public function hasRule($needRule) 69 | { 70 | $needRuleId = ($needRule instanceof Rule) ? $needRule->getId() : $needRule; 71 | 72 | foreach ( $this->rules as $rule ) { 73 | if ( $rule->getId() === $needRuleId ) { 74 | return $rule; 75 | } 76 | } 77 | 78 | return false; 79 | } 80 | 81 | /** 82 | * Adds rule. 83 | * 84 | * Assign $role, $resource and $action to added rule. 85 | * If rule was already registered only change $role, $resource and $action for that rule. 86 | * 87 | * This method accept 1, 2, 3 or 4 arguments: 88 | * 89 | * addRule($rule) 90 | * addRule($rule, $action) 91 | * addRule($role, $resource, $rule) 92 | * addRule($role, $resource, $rule, $action) 93 | * 94 | * @param Role $role 95 | * @param Resource $resource 96 | * @param Rule|string $rule 97 | * @param mixed $action 98 | * 99 | * @throws InvalidArgumentException 100 | */ 101 | public function addRule() 102 | { 103 | $args = func_get_args(); 104 | $argsCount = count($args); 105 | 106 | $role = null; 107 | $resource = null; 108 | $action = null; 109 | 110 | if ( $argsCount == 4 || $argsCount == 3 ) { 111 | $role = $args[0]; 112 | $resource = $args[1]; 113 | $rule = $args[2]; 114 | if ( $argsCount == 4) { 115 | $action = $args[3]; 116 | } 117 | } elseif( $argsCount == 2 ) { 118 | $rule = $args[0]; 119 | $action = $args[1]; 120 | } elseif ( $argsCount == 1 ) { 121 | $rule = $args[0]; 122 | } else { 123 | throw new InvalidArgumentException(__METHOD__ . ' accepts only one, tow, three or four arguments'); 124 | } 125 | 126 | if ( ! is_null($role) && ! $role instanceof Role ) { 127 | throw new InvalidArgumentException('Role must be an instance of SimpleAcl\Role or null'); 128 | } 129 | 130 | if ( ! is_null($resource) && ! $resource instanceof Resource ) { 131 | throw new InvalidArgumentException('Resource must be an instance of SimpleAcl\Resource or null'); 132 | } 133 | 134 | if ( is_string($rule) ) { 135 | $ruleClass = $this->getRuleClass(); 136 | $rule = new $ruleClass($rule); 137 | } 138 | 139 | if ( ! $rule instanceof Rule ) { 140 | throw new InvalidArgumentException('Rule must be an instance of SimpleAcl\Rule or string'); 141 | } 142 | 143 | if ( $exchange = $this->hasRule($rule) ) { 144 | $rule = $exchange; 145 | } 146 | 147 | if ( ! $exchange ) { 148 | $this->rules[] = $rule; 149 | } 150 | 151 | if ( $argsCount == 3 || $argsCount == 4 ) { 152 | $rule->setRole($role); 153 | $rule->setResource($resource); 154 | } 155 | 156 | if ( $argsCount == 2 || $argsCount == 4 ) { 157 | $rule->setAction($action); 158 | } 159 | } 160 | 161 | /** 162 | * Get names. 163 | * 164 | * @param string|RoleAggregateInterface|ResourceAggregateInterface $object 165 | * @return array 166 | */ 167 | protected function getNames($object) 168 | { 169 | if ( is_string($object) || is_null($object) ) { 170 | return array($object); 171 | } elseif ( $object instanceof RoleAggregateInterface ) { 172 | return $object->getRolesNames(); 173 | } elseif ( $object instanceof ResourceAggregateInterface ) { 174 | return $object->getResourcesNames(); 175 | } 176 | 177 | return array(); 178 | } 179 | 180 | /** 181 | * Check is access allowed by some rule. 182 | * Returns null if rule don't match any role or resource. 183 | * 184 | * @param string $roleName 185 | * @param string $resourceName 186 | * @param $ruleName 187 | * @param RuleResultCollection $ruleResultCollection 188 | * @param string|RoleAggregateInterface $roleAggregate 189 | * @param string|ResourceAggregateInterface $resourceAggregate 190 | */ 191 | protected function isRuleAllow($roleName, $resourceName, $ruleName, RuleResultCollection $ruleResultCollection, $roleAggregate, $resourceAggregate) 192 | { 193 | foreach ($this->rules as $rule) { 194 | $rule->resetAggregate($roleAggregate, $resourceAggregate); 195 | 196 | $result = $rule->isAllowed($ruleName, $roleName, $resourceName); 197 | $ruleResultCollection->add($result); 198 | } 199 | } 200 | 201 | /** 202 | * Checks is access allowed. 203 | * 204 | * @param string|RoleAggregateInterface $roleName 205 | * @param string|ResourceAggregateInterface $resourceName 206 | * @param string $ruleName 207 | * @return bool 208 | */ 209 | public function isAllowed($roleName, $resourceName, $ruleName) 210 | { 211 | return $this->isAllowedReturnResult($roleName, $resourceName, $ruleName)->get(); 212 | } 213 | 214 | /** 215 | * Checks is access allowed. 216 | * 217 | * @param string|RoleAggregateInterface $roleAggregate 218 | * @param string|ResourceAggregateInterface $resourceAggregate 219 | * @param string $ruleName 220 | * 221 | * @return RuleResultCollection 222 | */ 223 | public function isAllowedReturnResult($roleAggregate, $resourceAggregate, $ruleName) 224 | { 225 | $ruleResultCollection = new RuleResultCollection(); 226 | 227 | $roles = $this->getNames($roleAggregate); 228 | $resources = $this->getNames($resourceAggregate); 229 | 230 | foreach ($roles as $roleName) { 231 | foreach ($resources as $resourceName) { 232 | $this->isRuleAllow($roleName, $resourceName, $ruleName, $ruleResultCollection, $roleAggregate, $resourceAggregate); 233 | } 234 | } 235 | 236 | return $ruleResultCollection; 237 | } 238 | 239 | /** 240 | * Remove all rules. 241 | * 242 | */ 243 | public function removeAllRules() 244 | { 245 | $this->rules = array(); 246 | } 247 | 248 | /** 249 | * Remove rules by rule name and (or) role and resource. 250 | * 251 | * @param null|string $roleName 252 | * @param null|string $resourceName 253 | * @param null|string $ruleName 254 | * @param bool $all 255 | */ 256 | public function removeRule($roleName = null, $resourceName = null, $ruleName = null, $all = true) 257 | { 258 | if ( is_null($roleName) && is_null($resourceName) && is_null($ruleName) ) { 259 | $this->removeAllRules(); 260 | return; 261 | } 262 | 263 | foreach ( $this->rules as $ruleIndex => $rule ) { 264 | if ( $ruleName === null || ($ruleName !== null && $ruleName === $rule->getName()) ) { 265 | if ( $roleName === null || ($roleName !== null && $rule->getRole() && $rule->getRole()->getName() === $roleName) ) { 266 | if ( $resourceName === null || ($resourceName !== null && $rule->getResource() && $rule->getResource()->getName() === $resourceName) ) { 267 | unset($this->rules[$ruleIndex]); 268 | if ( ! $all ) { 269 | return; 270 | } 271 | } 272 | } 273 | } 274 | } 275 | } 276 | 277 | /** 278 | * Removes rule by its id. 279 | * 280 | * @param mixed $ruleId 281 | */ 282 | public function removeRuleById($ruleId) 283 | { 284 | foreach ($this->rules as $ruleIndex => $rule) { 285 | if ( $rule->getId() === $ruleId ) { 286 | unset($this->rules[$ruleIndex]); 287 | return; 288 | } 289 | } 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /library/SimpleAcl/BaseObject.php: -------------------------------------------------------------------------------- 1 | setName($name); 43 | } 44 | 45 | /** 46 | * @param string $name 47 | */ 48 | public function setName($name) 49 | { 50 | $this->name = $name; 51 | } 52 | 53 | /** 54 | * @return string 55 | */ 56 | public function getName() 57 | { 58 | return $this->name; 59 | } 60 | 61 | /** 62 | * Adds child if it not added. 63 | * 64 | * @param Object $child 65 | */ 66 | public function addChild(BaseObject $child) 67 | { 68 | if ( $this->hasChild($child) ) { 69 | return; 70 | } 71 | $this->children[] = $child; 72 | } 73 | 74 | /** 75 | * Remove child, return true if child was removed. 76 | * 77 | * @param Object|string $needChild 78 | * 79 | * @return bool 80 | */ 81 | public function removeChild($needChild) 82 | { 83 | if ($needChild instanceof BaseObject ) { 84 | $needChild = $needChild->getName(); 85 | } 86 | 87 | foreach ($this->children as $childIndex => $child) { 88 | if ( $child->getName() === $needChild ) { 89 | unset($this->children[$childIndex]); 90 | return true; 91 | } 92 | } 93 | 94 | return false; 95 | } 96 | 97 | /** 98 | * Checks if object have child. 99 | * 100 | * @param Object|string $childName 101 | * 102 | * @return null|Object 103 | */ 104 | public function hasChild($childName) 105 | { 106 | if ($childName instanceof BaseObject ) { 107 | $childName = $childName->getName(); 108 | } 109 | 110 | foreach ( $this->children as $child ) { 111 | if ( $child->getName() === $childName ) { 112 | return $child; 113 | } 114 | } 115 | 116 | return null; 117 | } 118 | 119 | /** 120 | * Returns children. 121 | * 122 | * @return Object[] 123 | */ 124 | public function getChildren() 125 | { 126 | return $this->children; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /library/SimpleAcl/Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | getObject($object) ) { 23 | return; 24 | } 25 | $this->objects[] = $object; 26 | } 27 | 28 | protected function removeObjects() 29 | { 30 | $this->objects = array(); 31 | } 32 | 33 | /** 34 | * @param Object|string $objectName 35 | * 36 | * @return bool 37 | */ 38 | protected function removeObject($objectName) 39 | { 40 | if ($objectName instanceof BaseObject ) { 41 | $objectName = $objectName->getName(); 42 | } 43 | 44 | foreach ($this->objects as $objectIndex => $object) { 45 | if ( $object->getName() === $objectName ) { 46 | unset($this->objects[$objectIndex]); 47 | return true; 48 | } 49 | } 50 | 51 | return false; 52 | } 53 | 54 | /** 55 | * @param array $objects 56 | */ 57 | protected function setObjects($objects) 58 | { 59 | /** @var Object $object */ 60 | foreach ($objects as $object) { 61 | $this->addObject($object); 62 | } 63 | } 64 | 65 | /** 66 | * @return array|Object[] 67 | */ 68 | protected function getObjects() 69 | { 70 | return $this->objects; 71 | } 72 | 73 | /** 74 | * @param Object|string $objectName 75 | * 76 | * @return null|Object 77 | */ 78 | protected function getObject($objectName) 79 | { 80 | if ($objectName instanceof BaseObject ) { 81 | $objectName = $objectName->getName(); 82 | } 83 | 84 | foreach ($this->objects as $object) { 85 | if ( $object->getName() === $objectName ) { 86 | return $object; 87 | } 88 | } 89 | 90 | return null; 91 | } 92 | 93 | /** 94 | * @return array 95 | */ 96 | protected function getObjectNames() 97 | { 98 | $names = array(); 99 | 100 | foreach ($this->objects as $object) { 101 | $names[] = $object->getName(); 102 | } 103 | 104 | return $names; 105 | } 106 | } -------------------------------------------------------------------------------- /library/SimpleAcl/Object/RecursiveIterator.php: -------------------------------------------------------------------------------- 1 | objects); 21 | } 22 | 23 | #[\ReturnTypeWillChange] 24 | public function next() 25 | { 26 | return next($this->objects); 27 | } 28 | 29 | #[\ReturnTypeWillChange] 30 | public function key() 31 | { 32 | if ( is_null(key($this->objects)) ) { 33 | return null; 34 | } 35 | 36 | return $this->current()->getName(); 37 | } 38 | 39 | #[\ReturnTypeWillChange] 40 | public function valid() 41 | { 42 | return $this->key() !== null; 43 | } 44 | 45 | #[\ReturnTypeWillChange] 46 | public function rewind() 47 | { 48 | reset($this->objects); 49 | } 50 | 51 | #[\ReturnTypeWillChange] 52 | public function hasChildren() 53 | { 54 | if ( is_null($this->key()) ) { 55 | return false; 56 | } 57 | 58 | $object = $this->current(); 59 | 60 | return count($object->getChildren()) > 0; 61 | } 62 | 63 | #[\ReturnTypeWillChange] 64 | public function getChildren() 65 | { 66 | $object = $this->current(); 67 | $children = $object->getChildren(); 68 | 69 | return new RecursiveIterator($children); 70 | } 71 | 72 | public function __construct($objects) 73 | { 74 | $this->objects = $objects; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /library/SimpleAcl/Resource.php: -------------------------------------------------------------------------------- 1 | setId(); 74 | $this->setName($name); 75 | } 76 | 77 | /** 78 | * Set aggregate objects. 79 | * 80 | * @param $roleAggregate 81 | * @param $resourceAggregate 82 | */ 83 | public function resetAggregate($roleAggregate, $resourceAggregate) 84 | { 85 | if ( $roleAggregate instanceof RoleAggregateInterface ) { 86 | $this->setRoleAggregate($roleAggregate); 87 | } else { 88 | $this->roleAggregate = null; 89 | } 90 | 91 | if ( $resourceAggregate instanceof ResourceAggregateInterface ) { 92 | $this->setResourceAggregate($resourceAggregate); 93 | } else { 94 | $this->resourceAggregate = null; 95 | } 96 | } 97 | 98 | /** 99 | * @param ResourceAggregateInterface $resourceAggregate 100 | */ 101 | public function setResourceAggregate(ResourceAggregateInterface $resourceAggregate) 102 | { 103 | $this->resourceAggregate = $resourceAggregate; 104 | } 105 | 106 | /** 107 | * @return ResourceAggregateInterface 108 | */ 109 | public function getResourceAggregate() 110 | { 111 | return $this->resourceAggregate; 112 | } 113 | 114 | /** 115 | * @param RoleAggregateInterface $roleAggregate 116 | */ 117 | public function setRoleAggregate(RoleAggregateInterface $roleAggregate) 118 | { 119 | $this->roleAggregate = $roleAggregate; 120 | } 121 | 122 | /** 123 | * @return RoleAggregateInterface 124 | */ 125 | public function getRoleAggregate() 126 | { 127 | return $this->roleAggregate; 128 | } 129 | 130 | /** 131 | * Creates an id for rule. 132 | * 133 | * @return string 134 | */ 135 | protected function generateId() 136 | { 137 | return bin2hex(openssl_random_pseudo_bytes(10)); 138 | } 139 | 140 | /** 141 | * @param mixed $id 142 | */ 143 | public function setId($id = null) 144 | { 145 | if ( is_null($id) ) { 146 | $id = $this->generateId(); 147 | } 148 | 149 | $this->id = $id; 150 | } 151 | 152 | /** 153 | * @return mixed 154 | */ 155 | public function getId() 156 | { 157 | return $this->id; 158 | } 159 | 160 | /** 161 | * @param string $name 162 | */ 163 | public function setName($name) 164 | { 165 | $this->name = $name; 166 | } 167 | 168 | /** 169 | * @return string 170 | */ 171 | public function getName() 172 | { 173 | return $this->name; 174 | } 175 | 176 | /** 177 | * @param mixed $action 178 | */ 179 | public function setAction($action) 180 | { 181 | $this->action = $action; 182 | } 183 | 184 | /** 185 | * @param RuleResult|null $ruleResult 186 | * 187 | * @return bool|null 188 | */ 189 | public function getAction(RuleResult $ruleResult = null) 190 | { 191 | $actionResult = $this->action; 192 | if ( ! is_callable($actionResult) || is_null($ruleResult) ) { 193 | return is_null($actionResult) ? $actionResult : (bool)$actionResult; 194 | } 195 | 196 | $actionResult = call_user_func($this->action, $ruleResult); 197 | $actionResult = is_null($actionResult) ? $actionResult : (bool)$actionResult; 198 | 199 | return $actionResult; 200 | } 201 | 202 | /** 203 | * Check if $role and $resource match to need role and resource. 204 | * 205 | * @param Role|null $role 206 | * @param Resource|null $resource 207 | * @param string $needRoleName 208 | * @param string $needResourceName 209 | * @param $priority 210 | * 211 | * @return RuleResult|null 212 | */ 213 | protected function match(Role $role = null, Resource $resource = null, $needRoleName, $needResourceName, $priority) 214 | { 215 | if ( (is_null($role) || ($role && $role->getName() === $needRoleName)) && 216 | (is_null($resource) || ($resource && $resource->getName() === $needResourceName)) ) { 217 | return new RuleResult($this, $priority, $needRoleName, $needResourceName); 218 | } 219 | 220 | return null; 221 | } 222 | 223 | /** 224 | * Check if rule can be used. 225 | * 226 | * @param $neeRuleName 227 | * @return bool 228 | */ 229 | protected function isRuleMatched($neeRuleName) 230 | { 231 | return $this->getName() === $neeRuleName; 232 | } 233 | 234 | /** 235 | * Check owing Role & Resource (and their children) and match its with $roleName & $resourceName; 236 | * if match was found depending on action allow or deny access to $resourceName for $roleName. 237 | * 238 | * @param $needRuleName 239 | * @param string $needRoleName 240 | * @param string $needResourceName 241 | * 242 | * @return RuleResult|null null is returned if there is no matched Role & Resource in this rule. 243 | * RuleResult otherwise. 244 | */ 245 | public function isAllowed($needRuleName, $needRoleName, $needResourceName) 246 | { 247 | if ( $this->isRuleMatched($needRuleName) ) { 248 | if ( ! is_null($this->getRole()) ) { 249 | $roles = new RecursiveIteratorIterator($this->getRole(), RecursiveIteratorIterator::SELF_FIRST); 250 | } else { 251 | $roles = array(null); 252 | } 253 | 254 | if ( ! is_null($this->getResource()) ) { 255 | $resources = new RecursiveIteratorIterator($this->getResource(), RecursiveIteratorIterator::SELF_FIRST); 256 | } else { 257 | $resources = array(null); 258 | } 259 | 260 | foreach ($roles as $role) { 261 | foreach ($resources as $resource) { 262 | $roleDepth = $role ? $roles->getDepth() : 0; 263 | $resourceDepth = $resource ? $resources->getDepth() : 0; 264 | 265 | $depth = $roleDepth + $resourceDepth; 266 | $result = $this->match($role, $resource, $needRoleName, $needResourceName, -$depth); 267 | 268 | if ( $result ) { 269 | return $result; 270 | } 271 | } 272 | } 273 | } 274 | 275 | return null; 276 | } 277 | 278 | /** 279 | * @param Role|null $role 280 | */ 281 | public function setRole(Role $role = null) 282 | { 283 | $this->role = $role; 284 | } 285 | 286 | /** 287 | * @return Role 288 | */ 289 | public function getRole() 290 | { 291 | return $this->role; 292 | } 293 | 294 | /** 295 | * @param Resource|null $resource 296 | */ 297 | public function setResource(Resource $resource = null) 298 | { 299 | $this->resource = $resource; 300 | } 301 | 302 | /** 303 | * @return Resource 304 | */ 305 | public function getResource() 306 | { 307 | return $this->resource; 308 | } 309 | 310 | /** 311 | * @param int $priority 312 | */ 313 | public function setPriority($priority) 314 | { 315 | $this->priority = $priority; 316 | } 317 | 318 | /** 319 | * @return int 320 | */ 321 | public function getPriority() 322 | { 323 | return $this->priority; 324 | } 325 | } -------------------------------------------------------------------------------- /library/SimpleAcl/RuleResult.php: -------------------------------------------------------------------------------- 1 | id = bin2hex(openssl_random_pseudo_bytes(10));; 59 | $this->rule = $rule; 60 | $this->priority = $priority; 61 | $this->needRoleName = $needRoleName; 62 | $this->needResourceName = $needResourceName; 63 | } 64 | 65 | /** 66 | * @param int $priority 67 | */ 68 | public function setPriority($priority) 69 | { 70 | $this->priority = $priority; 71 | } 72 | 73 | /** 74 | * @return string 75 | */ 76 | public function getNeedResourceName() 77 | { 78 | return $this->needResourceName; 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function getNeedRoleName() 85 | { 86 | return $this->needRoleName; 87 | } 88 | 89 | /** 90 | * @return Rule 91 | */ 92 | public function getRule() 93 | { 94 | return $this->rule; 95 | } 96 | 97 | /** 98 | * @return bool 99 | */ 100 | public function getAction() 101 | { 102 | if ( ! $this->isInit ) { 103 | $this->action = $this->getRule()->getAction($this); 104 | $this->isInit = true; 105 | } 106 | 107 | return $this->action; 108 | } 109 | 110 | /** 111 | * @return int 112 | */ 113 | public function getPriority() 114 | { 115 | return $this->priority; 116 | } 117 | 118 | /** 119 | * @return int 120 | */ 121 | public function getRulePriority() 122 | { 123 | return $this->getRule()->getPriority(); 124 | } 125 | 126 | /** 127 | * @return string 128 | */ 129 | public function getId() 130 | { 131 | return $this->id; 132 | } 133 | 134 | /** 135 | * @return ResourceAggregateInterface 136 | */ 137 | public function getResourceAggregate() 138 | { 139 | return $this->getRule()->getResourceAggregate(); 140 | } 141 | 142 | /** 143 | * @return RoleAggregateInterface 144 | */ 145 | public function getRoleAggregate() 146 | { 147 | return $this->getRule()->getRoleAggregate(); 148 | } 149 | } -------------------------------------------------------------------------------- /library/SimpleAcl/RuleResultCollection.php: -------------------------------------------------------------------------------- 1 | collection = new SplPriorityQueue(); 22 | } 23 | 24 | /** 25 | * @return SplPriorityQueue 26 | */ 27 | #[\ReturnTypeWillChange] 28 | public function getIterator() 29 | { 30 | return clone $this->collection; 31 | } 32 | 33 | /** 34 | * @param RuleResult $result 35 | */ 36 | public function add(RuleResult $result = null) 37 | { 38 | if ( ! $result ) { 39 | return; 40 | } 41 | 42 | if ( is_null($result->getAction()) ) { 43 | return; 44 | } 45 | 46 | $this->collection->insert($result, $result->getPriority(), $result->getRulePriority()); 47 | } 48 | 49 | /** 50 | * @return bool 51 | */ 52 | public function get() 53 | { 54 | if ( ! $this->any() ) { 55 | return false; 56 | } 57 | 58 | /** @var RuleResult $result */ 59 | $result = $this->collection->top(); 60 | 61 | return $result->getAction(); 62 | } 63 | 64 | /** 65 | * @return bool 66 | */ 67 | public function any() 68 | { 69 | return $this->collection->count() > 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /library/SimpleAcl/RuleWide.php: -------------------------------------------------------------------------------- 1 | queueOrder++); 14 | } 15 | parent::insert($datum, $priority); 16 | } 17 | } -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | ./tests/SimpleAclTest/ 16 | 17 | 18 | 19 | 20 | 21 | ./library/SimpleAcl/ 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/SimpleAclStubs/CustomRule.php: -------------------------------------------------------------------------------- 1 | getName() === $needResourceName) ) { 14 | return new RuleResult($this, $priority, $needRoleName, $needResourceName); 15 | } 16 | 17 | return null; 18 | } 19 | 20 | protected function isRuleMatched($neeRuleName) 21 | { 22 | return true; 23 | } 24 | } 25 | 26 | class MathAnyResourceAndActAsWide extends Rule 27 | { 28 | protected function match(Role $role = null, Resource $resource = null, $needRoleName, $needResourceName, $priority) 29 | { 30 | if ( is_null($role) || ($role && $role->getName() === $needRoleName) ) { 31 | return new RuleResult($this, $priority, $needRoleName, $needResourceName); 32 | } 33 | 34 | return null; 35 | } 36 | 37 | protected function isRuleMatched($neeRuleName) 38 | { 39 | return true; 40 | } 41 | } 42 | 43 | class MatchAnything extends Rule 44 | { 45 | protected function match(Role $role = null, Resource $resource = null, $needRoleName, $needResourceName, $priority) 46 | { 47 | return new RuleResult($this, $priority, $needRoleName, $needResourceName); 48 | } 49 | 50 | protected function isRuleMatched($neeRuleName) 51 | { 52 | return true; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/AclRuleApplyTest.php: -------------------------------------------------------------------------------- 1 | assertFalse($acl->isAllowed('User', 'Page', 'View')); 25 | } 26 | 27 | public function testUnDefinedRule() 28 | { 29 | $acl = new Acl; 30 | $acl->addRule(new Role('User'), new Resource('Page'), new Rule('View'), true); 31 | 32 | $this->assertFalse($acl->isAllowed('User', 'Page', 'UnDefinedRule')); 33 | } 34 | 35 | public function testUnDefinedRoleOrResource() 36 | { 37 | $acl = new Acl; 38 | $acl->addRule(new Role('User'), new Resource('Page'), new Rule('View'), true); 39 | 40 | $this->assertFalse($acl->isAllowed('NotDefinedRole', 'Page', 'View')); 41 | $this->assertFalse($acl->isAllowed('User', 'NotDefinedResource', 'View')); 42 | $this->assertFalse($acl->isAllowed('NotDefinedRole', 'NotDefinedResource', 'View')); 43 | } 44 | 45 | public function testOneRoleOneResourceOneRule() 46 | { 47 | $acl = new Acl; 48 | $acl->addRule(new Role('User'), new Resource('Page'), new Rule('View'), true); 49 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 50 | 51 | $acl = new Acl; 52 | $acl->addRule(new Role('User'), new Resource('Page'), new Rule('View'), false); 53 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 54 | } 55 | 56 | public function testOneRoleOneResourceMultipleRule() 57 | { 58 | $acl = new Acl; 59 | 60 | $user = new Role('User'); 61 | $resource = new Resource('Page'); 62 | 63 | $acl->addRule($user, $resource, new Rule('View'), true); 64 | $acl->addRule($user, $resource, new Rule('Edit'), true); 65 | $acl->addRule($user, $resource, new Rule('Remove'), true); 66 | 67 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 68 | $this->assertTrue($acl->isAllowed('User', 'Page', 'Edit')); 69 | $this->assertTrue($acl->isAllowed('User', 'Page', 'Remove')); 70 | 71 | $acl = new Acl; 72 | 73 | $user = new Role('User'); 74 | $resource = new Resource('Page'); 75 | 76 | $acl->addRule($user, $resource, new Rule('View'), false); 77 | $acl->addRule($user, $resource, new Rule('Edit'), false); 78 | $acl->addRule($user, $resource, new Rule('Remove'), false); 79 | 80 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 81 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Edit')); 82 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Remove')); 83 | } 84 | 85 | public function testMultipleRolesMultipleResourcesMultipleRules() 86 | { 87 | $runChecks = function(TestCase $phpUnit, Acl $acl, $allowed) { 88 | // Checks for page 89 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Page', 'View')); 90 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Page', 'Edit')); 91 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Page', 'Remove')); 92 | 93 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Page', 'View')); 94 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Page', 'Edit')); 95 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Page', 'Remove')); 96 | 97 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Page', 'View')); 98 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Page', 'Edit')); 99 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Page', 'Remove')); 100 | 101 | // Checks for blog 102 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Blog', 'View')); 103 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Blog', 'Edit')); 104 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Blog', 'Remove')); 105 | 106 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Blog', 'View')); 107 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Blog', 'Edit')); 108 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Blog', 'Remove')); 109 | 110 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Blog', 'View')); 111 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Blog', 'Edit')); 112 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Blog', 'Remove')); 113 | 114 | // Checks for site 115 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Site', 'View')); 116 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Site', 'Edit')); 117 | $phpUnit->assertEquals($allowed, $acl->isAllowed('User', 'Site', 'Remove')); 118 | 119 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Site', 'View')); 120 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Site', 'Edit')); 121 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Moderator', 'Site', 'Remove')); 122 | 123 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Site', 'View')); 124 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Site', 'Edit')); 125 | $phpUnit->assertEquals($allowed, $acl->isAllowed('Admin', 'Site', 'Remove')); 126 | }; 127 | 128 | $acl = new Acl; 129 | 130 | $user = new Role('User'); 131 | $moderator = new Role('Moderator'); 132 | $admin = new Role('Admin'); 133 | 134 | $page = new Resource('Page'); 135 | $blog = new Resource('Blog'); 136 | $site = new Resource('Site'); 137 | 138 | $runChecks($this, $acl, false); 139 | 140 | // Rules for page 141 | $acl->addRule($user, $page, new Rule('View'), true); 142 | $acl->addRule($user, $page, new Rule('Edit'), true); 143 | $acl->addRule($user, $page, new Rule('Remove'), true); 144 | 145 | $acl->addRule($moderator, $page, new Rule('View'), true); 146 | $acl->addRule($moderator, $page, new Rule('Edit'), true); 147 | $acl->addRule($moderator, $page, new Rule('Remove'), true); 148 | 149 | $acl->addRule($admin, $page, new Rule('View'), true); 150 | $acl->addRule($admin, $page, new Rule('Edit'), true); 151 | $acl->addRule($admin, $page, new Rule('Remove'), true); 152 | 153 | // Rules for blog 154 | $acl->addRule($user, $blog, new Rule('View'), true); 155 | $acl->addRule($user, $blog, new Rule('Edit'), true); 156 | $acl->addRule($user, $blog, new Rule('Remove'), true); 157 | 158 | $acl->addRule($moderator, $blog, new Rule('View'), true); 159 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 160 | $acl->addRule($moderator, $blog, new Rule('Remove'), true); 161 | 162 | $acl->addRule($admin, $blog, new Rule('View'), true); 163 | $acl->addRule($admin, $blog, new Rule('Edit'), true); 164 | $acl->addRule($admin, $blog, new Rule('Remove'), true); 165 | 166 | // Rules for site 167 | $acl->addRule($user, $site, new Rule('View'), true); 168 | $acl->addRule($user, $site, new Rule('Edit'), true); 169 | $acl->addRule($user, $site, new Rule('Remove'), true); 170 | 171 | $acl->addRule($moderator, $site, new Rule('View'), true); 172 | $acl->addRule($moderator, $site, new Rule('Edit'), true); 173 | $acl->addRule($moderator, $site, new Rule('Remove'), true); 174 | 175 | $acl->addRule($admin, $site, new Rule('View'), true); 176 | $acl->addRule($admin, $site, new Rule('Edit'), true); 177 | $acl->addRule($admin, $site, new Rule('Remove'), true); 178 | 179 | $runChecks($this, $acl, true); 180 | 181 | } 182 | 183 | public function testParentRoles() 184 | { 185 | $acl = new Acl; 186 | 187 | $user = new Role('User'); 188 | $moderator = new Role('Moderator'); 189 | $admin = new Role('Admin'); 190 | 191 | $admin->addChild($moderator); 192 | $moderator->addChild($user); 193 | 194 | $page = new Resource('Page'); 195 | 196 | // Parent elements must NOT grant access 197 | $acl->addRule($user, $page, new Rule('View'), true); 198 | 199 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 200 | $this->assertFalse($acl->isAllowed('Moderator', 'Page', 'View')); 201 | $this->assertFalse($acl->isAllowed('Admin', 'Page', 'View')); 202 | 203 | $acl = new Acl; 204 | 205 | // Child elements must inherit access 206 | $acl->addRule($admin, $page, new Rule('View'), true); 207 | 208 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 209 | $this->assertTrue($acl->isAllowed('Moderator', 'Page', 'View')); 210 | $this->assertTrue($acl->isAllowed('Admin', 'Page', 'View')); 211 | 212 | // but last added rules wins 213 | $acl->addRule($user, $page, new Rule('View'), false); 214 | $acl->addRule($moderator, $page, new Rule('View'), false); 215 | 216 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 217 | $this->assertFalse($acl->isAllowed('Moderator', 'Page', 'View')); 218 | $this->assertTrue($acl->isAllowed('Admin', 'Page', 'View')); 219 | } 220 | 221 | public function testParentResources() 222 | { 223 | $acl = new Acl; 224 | 225 | $user = new Role('User'); 226 | 227 | $page = new Resource('Page'); 228 | $blog = new Resource('Blog'); 229 | $site = new Resource('Site'); 230 | 231 | $site->addChild($blog); 232 | $blog->addChild($page); 233 | 234 | // Parent elements must NOT have access 235 | $acl->addRule($user, $page, new Rule('View'), true); 236 | 237 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 238 | $this->assertFalse($acl->isAllowed('User', 'Blog', 'View')); 239 | $this->assertFalse($acl->isAllowed('User', 'Site', 'View')); 240 | 241 | $acl = new Acl; 242 | 243 | // Child elements must inherit access 244 | $acl->addRule($user, $site, new Rule('View'), true); 245 | 246 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 247 | $this->assertTrue($acl->isAllowed('User', 'Blog', 'View')); 248 | $this->assertTrue($acl->isAllowed('User', 'Site', 'View')); 249 | 250 | // but last added rules wins 251 | $acl->addRule($user, $page, new Rule('View'), false); 252 | $acl->addRule($user, $blog, new Rule('View'), false); 253 | 254 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 255 | $this->assertFalse($acl->isAllowed('User', 'Blog', 'View')); 256 | $this->assertTrue($acl->isAllowed('User', 'Site', 'View')); 257 | } 258 | 259 | public function testParentRolesAndResources() 260 | { 261 | $user = new Role('User'); 262 | $moderator = new Role('Moderator'); 263 | $admin = new Role('Admin'); 264 | 265 | $admin->addChild($moderator); 266 | $moderator->addChild($user); 267 | 268 | $page = new Resource('Page'); 269 | $blog = new Resource('Blog'); 270 | $site = new Resource('Site'); 271 | 272 | $site->addChild($blog); 273 | $blog->addChild($page); 274 | 275 | $acl = new Acl; 276 | 277 | $acl->addRule($user, $page, new Rule('View'), true); 278 | 279 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 280 | $this->assertFalse($acl->isAllowed('Moderator', 'Page', 'View')); 281 | $this->assertFalse($acl->isAllowed('Admin', 'Page', 'View')); 282 | 283 | $this->assertFalse($acl->isAllowed('User', 'Blog', 'View')); 284 | $this->assertFalse($acl->isAllowed('Moderator', 'Blog', 'View')); 285 | $this->assertFalse($acl->isAllowed('Admin', 'Blog', 'View')); 286 | 287 | $this->assertFalse($acl->isAllowed('User', 'Site', 'View')); 288 | $this->assertFalse($acl->isAllowed('Moderator', 'Site', 'View')); 289 | $this->assertFalse($acl->isAllowed('Admin', 'Site', 'View')); 290 | 291 | $acl = new Acl; 292 | 293 | $acl->addRule($admin, $page, new Rule('View'), true); 294 | 295 | $this->assertTrue($acl->isAllowed('Admin', 'Page', 'View')); 296 | $this->assertFalse($acl->isAllowed('Admin', 'Blog', 'View')); 297 | $this->assertFalse($acl->isAllowed('Admin', 'Site', 'View')); 298 | 299 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 300 | $this->assertFalse($acl->isAllowed('User', 'Blog', 'View')); 301 | $this->assertFalse($acl->isAllowed('User', 'Site', 'View')); 302 | 303 | $this->assertTrue($acl->isAllowed('Moderator', 'Page', 'View')); 304 | $this->assertFalse($acl->isAllowed('Moderator', 'Blog', 'View')); 305 | $this->assertFalse($acl->isAllowed('Moderator', 'Site', 'View')); 306 | 307 | $acl = new Acl; 308 | 309 | $acl->addRule($user, $site, new Rule('View'), true); 310 | 311 | $this->assertTrue($acl->isAllowed('User', 'Site', 'View')); 312 | $this->assertFalse($acl->isAllowed('Moderator', 'Site', 'View')); 313 | $this->assertFalse($acl->isAllowed('Admin', 'Site', 'View')); 314 | 315 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 316 | $this->assertFalse($acl->isAllowed('Moderator', 'Page', 'View')); 317 | $this->assertFalse($acl->isAllowed('Admin', 'Page', 'View')); 318 | 319 | $this->assertTrue($acl->isAllowed('User', 'Blog', 'View')); 320 | $this->assertFalse($acl->isAllowed('Moderator', 'Blog', 'View')); 321 | $this->assertFalse($acl->isAllowed('Admin', 'Blog', 'View')); 322 | 323 | // test add rule in the middle 324 | $acl = new Acl; 325 | 326 | $acl->addRule($moderator, $blog, new Rule('View'), true); 327 | 328 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 329 | $this->assertTrue($acl->isAllowed('User', 'Blog', 'View')); 330 | $this->assertFalse($acl->isAllowed('User', 'Site', 'View')); 331 | 332 | $this->assertTrue($acl->isAllowed('Moderator', 'Page', 'View')); 333 | $this->assertTrue($acl->isAllowed('Moderator', 'Blog', 'View')); 334 | $this->assertFalse($acl->isAllowed('Moderator', 'Site', 'View')); 335 | 336 | $this->assertFalse($acl->isAllowed('Admin', 'Page', 'View')); 337 | $this->assertFalse($acl->isAllowed('Admin', 'Blog', 'View')); 338 | $this->assertFalse($acl->isAllowed('Admin', 'Site', 'View')); 339 | 340 | // test add rule on the top 341 | $acl = new Acl; 342 | 343 | $acl->addRule($admin, $site, new Rule('View'), true); 344 | 345 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 346 | $this->assertTrue($acl->isAllowed('User', 'Blog', 'View')); 347 | $this->assertTrue($acl->isAllowed('User', 'Site', 'View')); 348 | 349 | $this->assertTrue($acl->isAllowed('Admin', 'Page', 'View')); 350 | $this->assertTrue($acl->isAllowed('Admin', 'Blog', 'View')); 351 | $this->assertTrue($acl->isAllowed('Admin', 'Site', 'View')); 352 | 353 | $this->assertTrue($acl->isAllowed('Moderator', 'Page', 'View')); 354 | $this->assertTrue($acl->isAllowed('Moderator', 'Blog', 'View')); 355 | $this->assertTrue($acl->isAllowed('Moderator', 'Site', 'View')); 356 | } 357 | 358 | public function testAggregateBadRolesAndResources() 359 | { 360 | $acl = new Acl; 361 | 362 | $user = new Role('User'); 363 | 364 | $page = new Resource('Page'); 365 | 366 | $acl->addRule($user, $page, new Rule('View'), true); 367 | 368 | $this->assertFalse($acl->isAllowed('User', new \stdClass(), 'View')); 369 | $this->assertFalse($acl->isAllowed(new \stdClass(), 'Page', 'Edit')); 370 | } 371 | 372 | public function testAggregateEmptyRolesAndResources() 373 | { 374 | $acl = new Acl; 375 | 376 | $user = new Role('User'); 377 | $moderator = new Role('Moderator'); 378 | $admin = new Role('Admin'); 379 | 380 | $page = new Resource('Page'); 381 | $blog = new Resource('Blog'); 382 | $site = new Resource('Site'); 383 | 384 | $userGroup = new RoleAggregate(); 385 | $siteGroup = new ResourceAggregate(); 386 | 387 | $acl->addRule($user, $page, new Rule('View'), true); 388 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 389 | $acl->addRule($admin, $site, new Rule('Remove'), true); 390 | 391 | $this->assertFalse($acl->isAllowed($userGroup, $siteGroup, 'View')); 392 | $this->assertFalse($acl->isAllowed($userGroup, $siteGroup, 'Edit')); 393 | $this->assertFalse($acl->isAllowed($userGroup, $siteGroup, 'Remove')); 394 | } 395 | 396 | public function testAggregateRoles() 397 | { 398 | $acl = new Acl; 399 | 400 | $user = new Role('User'); 401 | $moderator = new Role('Moderator'); 402 | $admin = new Role('Admin'); 403 | 404 | $page = new Resource('Page'); 405 | $blog = new Resource('Blog'); 406 | $site = new Resource('Site'); 407 | 408 | $userGroup = new RoleAggregate(); 409 | 410 | $userGroup->addRole($user); 411 | $userGroup->addRole($moderator); 412 | $userGroup->addRole($admin); 413 | 414 | $acl->addRule($user, $page, new Rule('View'), true); 415 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 416 | $acl->addRule($admin, $site, new Rule('Remove'), true); 417 | 418 | $this->assertTrue($acl->isAllowed($userGroup, 'Page', 'View')); 419 | $this->assertTrue($acl->isAllowed($userGroup, 'Blog', 'Edit')); 420 | $this->assertTrue($acl->isAllowed($userGroup, 'Site', 'Remove')); 421 | } 422 | 423 | public function testAggregateResources() 424 | { 425 | $acl = new Acl; 426 | 427 | $user = new Role('User'); 428 | $moderator = new Role('Moderator'); 429 | $admin = new Role('Admin'); 430 | 431 | $page = new Resource('Page'); 432 | $blog = new Resource('Blog'); 433 | $site = new Resource('Site'); 434 | 435 | $siteGroup = new ResourceAggregate(); 436 | 437 | $siteGroup->addResource($page); 438 | $siteGroup->addResource($blog); 439 | $siteGroup->addResource($site); 440 | 441 | $acl->addRule($user, $page, new Rule('View'), true); 442 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 443 | $acl->addRule($admin, $site, new Rule('Remove'), true); 444 | 445 | $this->assertTrue($acl->isAllowed('User', $siteGroup, 'View')); 446 | $this->assertTrue($acl->isAllowed('Moderator', $siteGroup, 'Edit')); 447 | $this->assertTrue($acl->isAllowed('Admin', $siteGroup, 'Remove')); 448 | } 449 | 450 | public function testAggregateRolesAndResources() 451 | { 452 | $acl = new Acl; 453 | 454 | $user = new Role('User'); 455 | $moderator = new Role('Moderator'); 456 | $admin = new Role('Admin'); 457 | 458 | $page = new Resource('Page'); 459 | $blog = new Resource('Blog'); 460 | $site = new Resource('Site'); 461 | 462 | $userGroup = new RoleAggregate(); 463 | $userGroup->addRole($user); 464 | $userGroup->addRole($moderator); 465 | $userGroup->addRole($admin); 466 | 467 | $siteGroup = new ResourceAggregate(); 468 | $siteGroup->addResource($page); 469 | $siteGroup->addResource($blog); 470 | $siteGroup->addResource($site); 471 | 472 | $acl->addRule($user, $page, new Rule('View'), true); 473 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 474 | $acl->addRule($admin, $site, new Rule('Remove'), true); 475 | 476 | $this->assertTrue($acl->isAllowed($userGroup, $siteGroup, 'View')); 477 | $this->assertTrue($acl->isAllowed($userGroup, $siteGroup, 'Edit')); 478 | $this->assertTrue($acl->isAllowed($userGroup, $siteGroup, 'Remove')); 479 | } 480 | 481 | public function testStringAsRule() 482 | { 483 | $acl = new Acl; 484 | 485 | $user = new Role('User'); 486 | $resource = new Resource('Page'); 487 | 488 | $acl->addRule($user, $resource, 'View', true); 489 | $acl->addRule($user, $resource, 'Edit', true); 490 | $acl->addRule($user, $resource, 'Remove', true); 491 | 492 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 493 | $this->assertTrue($acl->isAllowed('User', 'Page', 'Edit')); 494 | $this->assertTrue($acl->isAllowed('User', 'Page', 'Remove')); 495 | 496 | $acl = new Acl; 497 | 498 | $acl->setRuleClass('SimpleAcl\Rule'); 499 | 500 | $user = new Role('User'); 501 | $resource = new Resource('Page'); 502 | 503 | $acl->addRule($user, $resource, 'View', false); 504 | $acl->addRule($user, $resource, 'Edit', false); 505 | $acl->addRule($user, $resource, 'Remove', false); 506 | 507 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 508 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Edit')); 509 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Remove')); 510 | } 511 | 512 | public function testGetResult() 513 | { 514 | $self = $this; 515 | 516 | $testReturnResult = function ($result, $expected) use ($self) { 517 | $index = 0; 518 | foreach ($result as $r) { 519 | $self->assertSame($expected[$index], $r->getRule()); 520 | $index++; 521 | } 522 | $self->assertEquals(count($expected), $index); 523 | }; 524 | 525 | $acl = new Acl; 526 | 527 | $user = new Role('User'); 528 | $resource = new Resource('Page'); 529 | 530 | $view = new Rule('View'); 531 | $edit = new Rule('Edit'); 532 | $remove = new Rule('Remove'); 533 | 534 | $acl->addRule($user, $resource, $view, true); 535 | $acl->addRule($user, $resource, $edit, true); 536 | $acl->addRule($user, $resource, $remove, true); 537 | 538 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 539 | $this->assertTrue($acl->isAllowed('User', 'Page', 'Edit')); 540 | $this->assertTrue($acl->isAllowed('User', 'Page', 'Remove')); 541 | 542 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'View'), array($view)); 543 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'Edit'), array($edit)); 544 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'Remove'), array($remove)); 545 | 546 | $acl = new Acl; 547 | 548 | $acl->addRule($user, $resource, $view, false); 549 | $acl->addRule($user, $resource, $edit, false); 550 | $acl->addRule($user, $resource, $remove, false); 551 | 552 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 553 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Edit')); 554 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Remove')); 555 | 556 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'View'), array($view)); 557 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'Edit'), array($edit)); 558 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'Remove'), array($remove)); 559 | 560 | // test RuleResult order 561 | $acl = new Acl; 562 | 563 | $view1 = new Rule('View'); 564 | $view2 = new Rule('View'); 565 | $view3 = new Rule('View'); 566 | $view4 = new Rule('View'); 567 | 568 | $acl->addRule($user, $resource, $view, false); 569 | $acl->addRule($user, $resource, $view1, true); 570 | $acl->addRule($user, $resource, $view2, false); 571 | $acl->addRule($user, $resource, $view3, true); 572 | $acl->addRule($user, $resource, $view4, false); 573 | 574 | $testReturnResult($acl->isAllowedReturnResult('User', 'Page', 'View'), array($view4, $view3, $view2, $view1, $view)); 575 | } 576 | 577 | public function testRuleWithNullActionNotCounts() 578 | { 579 | $acl = new Acl; 580 | 581 | $user = new Role('User'); 582 | $resource = new Resource('Resource'); 583 | 584 | $nullAction = new Rule('View'); 585 | 586 | $acl->addRule($user, $resource, 'View', true); 587 | $acl->addRule($user, $resource, $nullAction, null); 588 | 589 | $this->assertTrue($acl->isAllowed('User', 'Resource', 'View')); 590 | } 591 | 592 | public function testActionCallable() 593 | { 594 | $acl = new Acl; 595 | 596 | $user = new Role('User'); 597 | $resource = new Resource('Resource'); 598 | 599 | $acl->addRule($user, $resource, 'View', function () { 600 | return true; 601 | }); 602 | 603 | $this->assertTrue($acl->isAllowed('User', 'Resource', 'View')); 604 | } 605 | 606 | public function testChangePriorityViaActionCallable() 607 | { 608 | $getResults = function($resultCollection) { 609 | $rs = array(); 610 | foreach ( $resultCollection as $r ) { 611 | $rs[] = $r; 612 | } 613 | return $rs; 614 | }; 615 | 616 | $acl = new Acl; 617 | 618 | $user = new Role('User'); 619 | $resource = new Resource('Resource'); 620 | 621 | $acl->addRule($user, $resource, 'View', function(RuleResult $r){ 622 | $r->setPriority(10); 623 | return true; 624 | }); 625 | 626 | $acl->addRule($user, $resource, 'View', false); 627 | 628 | $this->assertTrue($acl->isAllowed('User', 'Resource', 'View')); 629 | 630 | $acl = new Acl(); 631 | 632 | $p = new Role('P'); 633 | $c1 = new Role('C1'); 634 | $c2 = new Role('C2'); 635 | $c3 = new Role('C3'); 636 | 637 | $p->addChild($c1); 638 | $p->addChild($c2); 639 | $p->addChild($c3); 640 | 641 | $view = new Rule('View'); 642 | $acl->addRule($p, $resource, $view, function (RuleResult $r) { 643 | $role = $r->getNeedRoleName(); 644 | 645 | if ( $role == 'C3' || $role == 'P' ) { 646 | return true; 647 | } 648 | 649 | $r->setPriority(10); 650 | 651 | return $role == 'C1'; 652 | }); 653 | 654 | $view1 = new Rule('View'); 655 | $acl->addRule($c1, $resource, $view1, false); 656 | $view2 = new Rule('View'); 657 | $acl->addRule($c2, $resource, $view2, true); 658 | $view3 = new Rule('View'); 659 | $acl->addRule($c3, $resource, $view3, false); 660 | 661 | $this->assertTrue($acl->isAllowed('P', 'Resource', 'View')); 662 | $this->assertTrue($acl->isAllowed('C1', 'Resource', 'View')); 663 | $this->assertFalse($acl->isAllowed('C2', 'Resource', 'View')); 664 | $this->assertFalse($acl->isAllowed('C3', 'Resource', 'View')); 665 | 666 | $rs = $getResults($acl->isAllowedReturnResult('P', 'Resource', 'View')); 667 | $this->assertCount(1, $rs); 668 | $this->assertEquals(0, $rs[0]->getPriority()); 669 | $this->assertTrue($rs[0]->getAction()); 670 | $this->assertSame($view, $rs[0]->getRule()); 671 | $this->assertSame('P', $rs[0]->getNeedRoleName()); 672 | $this->assertSame('Resource', $rs[0]->getNeedResourceName()); 673 | 674 | $rs = $getResults($acl->isAllowedReturnResult('C1', 'Resource', 'View')); 675 | $this->assertCount(2, $rs); 676 | $this->assertEquals(10, $rs[0]->getPriority()); 677 | $this->assertSame($view, $rs[0]->getRule()); 678 | $this->assertTrue($rs[0]->getAction()); 679 | $this->assertSame('C1', $rs[0]->getNeedRoleName()); 680 | $this->assertSame('Resource', $rs[0]->getNeedResourceName()); 681 | $this->assertEquals(0, $rs[1]->getPriority()); 682 | $this->assertFalse($rs[1]->getAction()); 683 | $this->assertSame($view1, $rs[1]->getRule()); 684 | $this->assertSame('C1', $rs[1]->getNeedRoleName()); 685 | $this->assertSame('Resource', $rs[1]->getNeedResourceName()); 686 | 687 | $rs = $getResults($acl->isAllowedReturnResult('C2', 'Resource', 'View')); 688 | $this->assertCount(2, $rs); 689 | $this->assertEquals(10, $rs[0]->getPriority()); 690 | $this->assertSame($view, $rs[0]->getRule()); 691 | $this->assertFalse($rs[0]->getAction()); 692 | $this->assertSame('C2', $rs[0]->getNeedRoleName()); 693 | $this->assertSame('Resource', $rs[0]->getNeedResourceName()); 694 | $this->assertEquals(0, $rs[1]->getPriority()); 695 | $this->assertTrue($rs[1]->getAction()); 696 | $this->assertSame($view2, $rs[1]->getRule()); 697 | $this->assertSame('C2', $rs[1]->getNeedRoleName()); 698 | $this->assertSame('Resource', $rs[1]->getNeedResourceName()); 699 | 700 | $rs = $getResults($acl->isAllowedReturnResult('C3', 'Resource', 'View')); 701 | $this->assertCount(2, $rs); 702 | $this->assertEquals(-1, $rs[1]->getPriority()); 703 | $this->assertSame($view, $rs[1]->getRule()); 704 | $this->assertTrue($rs[1]->getAction()); 705 | $this->assertSame('C3', $rs[1]->getNeedRoleName()); 706 | $this->assertSame('Resource', $rs[1]->getNeedResourceName()); 707 | $this->assertEquals(0, $rs[0]->getPriority()); 708 | $this->assertFalse($rs[0]->getAction()); 709 | $this->assertSame($view3, $rs[0]->getRule()); 710 | $this->assertSame('C3', $rs[0]->getNeedRoleName()); 711 | $this->assertSame('Resource', $rs[0]->getNeedResourceName()); 712 | } 713 | 714 | public function testSetAggregates() 715 | { 716 | $acl = new Acl(); 717 | 718 | $u = new Role('U'); 719 | $r = new Resource('R'); 720 | 721 | $roleAgr = new RoleAggregate(); 722 | $roleAgr->addRole($u); 723 | 724 | $resourceAgr = new ResourceAggregate(); 725 | $resourceAgr->addResource($r); 726 | 727 | $self = $this; 728 | 729 | $rule = new Rule('View'); 730 | 731 | $acl->addRule($u, $r, $rule, function (RuleResult $r) use ($roleAgr, $resourceAgr, $self) { 732 | $self->assertSame($roleAgr, $r->getRoleAggregate()); 733 | $self->assertSame($resourceAgr, $r->getResourceAggregate()); 734 | 735 | return true; 736 | }); 737 | 738 | $this->assertTrue($acl->isAllowed($roleAgr, $resourceAgr, 'View')); 739 | 740 | $rule->setAction(function (RuleResult $r) use ($self) { 741 | $self->assertNull($r->getRoleAggregate()); 742 | $self->assertNull($r->getResourceAggregate()); 743 | 744 | return true; 745 | }); 746 | 747 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 748 | } 749 | 750 | public function testAddRuleOneArgument() 751 | { 752 | $acl = new Acl(); 753 | 754 | $rule = new Rule('View'); 755 | 756 | $acl->addRule($rule); 757 | 758 | // only action determines is access allowd or not for rule with null role and resource 759 | $this->assertFalse($acl->isAllowed('U', 'R', 'View')); 760 | 761 | $rule->setAction(true); 762 | 763 | // rule matched any role or resource as it have null for both 764 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 765 | 766 | // nothing is change if only one argument use, action is not overwritten to null 767 | $acl->addRule($rule); 768 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 769 | 770 | // rule not matched if wrong rule name used 771 | $this->assertFalse($acl->isAllowed('U', 'R', 'NotMatchedView')); 772 | 773 | $u = new Role('U1'); 774 | $rule->setRole($u); 775 | 776 | $r = new Resource('R1'); 777 | $rule->setResource($r); 778 | 779 | $acl->addRule($rule); 780 | 781 | $this->assertFalse($acl->isAllowed('U', 'R', 'View')); 782 | // role and resource not overwritten 783 | $this->assertTrue($acl->isAllowed('U1', 'R1', 'View')); 784 | $this->assertSame($u, $rule->getRole()); 785 | $this->assertSame($r, $rule->getResource()); 786 | } 787 | 788 | public function testAddRuleTowArguments() 789 | { 790 | $acl = new Acl(); 791 | 792 | $rule = new Rule('View'); 793 | 794 | $rule->setAction(false); 795 | 796 | // rule overwrite action 797 | $acl->addRule($rule, true); 798 | 799 | // rule matched any role or resource as it have null for both 800 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 801 | 802 | // rule not matched if wrong rule name used 803 | $this->assertFalse($acl->isAllowed('U', 'R', 'NotMatchedView')); 804 | 805 | $u = new Role('U1'); 806 | $rule->setRole($u); 807 | 808 | $r = new Resource('R1'); 809 | $rule->setResource($r); 810 | 811 | $acl->addRule($rule, true); 812 | 813 | $this->assertFalse($acl->isAllowed('U', 'R', 'View')); 814 | // role and resource not overwritten 815 | $this->assertTrue($acl->isAllowed('U1', 'R1', 'View')); 816 | 817 | $acl->addRule($rule, null); 818 | 819 | $this->assertNull($rule->getAction()); 820 | } 821 | 822 | public function testAddRuleThreeArguments() 823 | { 824 | $acl = new Acl(); 825 | 826 | $rule = new Rule('View'); 827 | 828 | $rule->setAction(false); 829 | 830 | $u = new Role('U'); 831 | $r = new Resource('R'); 832 | 833 | $acl->addRule($u, $r, $rule); 834 | 835 | $this->assertFalse($acl->isAllowed('U', 'R', 'View')); 836 | $rule->setAction(true); 837 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 838 | 839 | $u1 = new Role('U1'); 840 | $r1 = new Resource('R1'); 841 | 842 | // role and resource changed 843 | $acl->addRule($u1, $r1, $rule); 844 | 845 | $this->assertSame($u1, $rule->getRole()); 846 | $this->assertSame($r1, $rule->getResource()); 847 | 848 | $this->assertFalse($acl->isAllowed('U', 'R', 'View')); 849 | $this->assertTrue($acl->isAllowed('U1', 'R1', 'View')); 850 | } 851 | 852 | public function testRuleOrResourceNull() 853 | { 854 | $acl = new Acl(); 855 | 856 | $rule = new Rule('View'); 857 | 858 | $rule->setAction(false); 859 | 860 | $u = new Role('U'); 861 | $r = new Resource('R'); 862 | 863 | $acl->addRule(null, $r, $rule, true); 864 | 865 | $this->assertTrue($acl->isAllowed('Any', 'R', 'View')); 866 | $this->assertFalse($acl->isAllowed('Any', 'R1', 'View')); 867 | $this->assertNull($rule->getRole()); 868 | $this->assertSame($r, $rule->getResource()); 869 | 870 | $acl->addRule($u, null, $rule, true); 871 | $this->assertTrue($acl->isAllowed('U', 'Any', 'View')); 872 | $this->assertFalse($acl->isAllowed('U1', 'Any', 'View')); 873 | $this->assertNull($rule->getResource()); 874 | $this->assertSame($u, $rule->getRole()); 875 | } 876 | 877 | public function testRuleWide() 878 | { 879 | $acl = new Acl(); 880 | 881 | $rule = new RuleWide('RuleWide'); 882 | 883 | $u = new Role('U'); 884 | $r = new Resource('R'); 885 | 886 | $acl->addRule($u, $r, $rule, true); 887 | 888 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 889 | $this->assertTrue($acl->isAllowed('U', 'R', null)); 890 | $this->assertFalse($acl->isAllowed('NotExist', 'R', null)); 891 | $this->assertFalse($acl->isAllowed('U', 'NotExist', null)); 892 | 893 | // null role and resource 894 | $acl = new Acl(); 895 | 896 | $acl->addRule(null, null, $rule, true); 897 | 898 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 899 | $this->assertTrue($acl->isAllowed('U', 'R', null)); 900 | 901 | $this->assertTrue($acl->isAllowed(null, null, null)); 902 | $acl->removeRuleById($rule->getId()); 903 | $this->assertFalse($acl->isAllowed(null, null, null)); 904 | 905 | // null resource 906 | $acl = new Acl(); 907 | 908 | $u = new Role('U'); 909 | 910 | $acl->addRule($u, null, $rule, true); 911 | 912 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 913 | $this->assertTrue($acl->isAllowed('U', 'R', null)); 914 | $this->assertTrue($acl->isAllowed('U', null, 'View')); 915 | $this->assertFalse($acl->isAllowed('NotExist', 'R', 'View')); 916 | $this->assertFalse($acl->isAllowed(null, 'R', 'View')); 917 | 918 | // null role 919 | $acl = new Acl(); 920 | 921 | $r = new Resource('R'); 922 | 923 | $acl->addRule(null, $r, $rule, true); 924 | 925 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 926 | $this->assertTrue($acl->isAllowed('U', 'R', null)); 927 | $this->assertTrue($acl->isAllowed(null, 'R', 'View')); 928 | $this->assertFalse($acl->isAllowed('U', 'NotExist', 'View')); 929 | $this->assertFalse($acl->isAllowed('U', null, 'View')); 930 | } 931 | 932 | public function testRuleApplyPriority() 933 | { 934 | $acl = new Acl(); 935 | 936 | $rule = new Rule('View'); 937 | $rule->setPriority(1); 938 | 939 | $u = new Role('U'); 940 | $r = new Resource('R'); 941 | 942 | $acl->addRule($u, $r, $rule, false); 943 | 944 | $acl->addRule($u, $r, 'View', true); 945 | 946 | $this->assertFalse($acl->isAllowed('U', 'R', 'View')); 947 | 948 | $rule->setPriority(0); 949 | 950 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 951 | } 952 | 953 | /** 954 | * Testing edge conditions. 955 | */ 956 | 957 | public function testEdgeConditionLastAddedRuleWins() 958 | { 959 | $acl = new Acl; 960 | 961 | $user = new Role('User'); 962 | 963 | $page = new Resource('Page'); 964 | 965 | $acl->addRule($user, $page, new Rule('View'), false); 966 | $acl->addRule($user, $page, new Rule('View'), true); 967 | 968 | $this->assertAttributeCount(2, 'rules', $acl); 969 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 970 | 971 | $acl->removeRule(null, null, 'View', false); 972 | 973 | $this->assertAttributeCount(1, 'rules', $acl); 974 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 975 | 976 | $acl->addRule($user, $page, new Rule('View'), false); 977 | 978 | $this->assertAttributeCount(2, 'rules', $acl); 979 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 980 | 981 | $acl->addRule($user, $page, new Rule('View'), true); 982 | $this->assertAttributeCount(3, 'rules', $acl); 983 | $this->assertTrue($acl->isAllowed('User', 'Page', 'View')); 984 | } 985 | 986 | public function testEdgeConditionParentRolesAndResourcesWithMultipleRules() 987 | { 988 | $user = new Role('User'); 989 | $moderator = new Role('Moderator'); 990 | $admin = new Role('Admin'); 991 | 992 | $admin->addChild($moderator); 993 | $moderator->addChild($user); 994 | 995 | $page = new Resource('Page'); 996 | $blog = new Resource('Blog'); 997 | $site = new Resource('Site'); 998 | 999 | $site->addChild($blog); 1000 | $blog->addChild($page); 1001 | 1002 | $acl = new Acl; 1003 | 1004 | $acl->addRule($moderator, $blog, new Rule('View'), true); 1005 | $acl->addRule($user, $page, new Rule('View'), false); 1006 | 1007 | $this->assertFalse($acl->isAllowed('User', 'Page', 'View')); 1008 | $this->assertTrue($acl->isAllowed('User', 'Blog', 'View')); 1009 | $this->assertFalse($acl->isAllowed('User', 'Site', 'View')); 1010 | 1011 | $this->assertTrue($acl->isAllowed('Moderator', 'Page', 'View')); 1012 | $this->assertTrue($acl->isAllowed('Moderator', 'Blog', 'View')); 1013 | $this->assertFalse($acl->isAllowed('Moderator', 'Site', 'View')); 1014 | 1015 | $this->assertFalse($acl->isAllowed('Admin', 'Page', 'View')); 1016 | $this->assertFalse($acl->isAllowed('Admin', 'Blog', 'View')); 1017 | $this->assertFalse($acl->isAllowed('Admin', 'Site', 'View')); 1018 | } 1019 | 1020 | public function testEdgeConditionAggregateLastAddedWins() 1021 | { 1022 | $acl = new Acl; 1023 | 1024 | $user = new Role('User'); 1025 | $moderator = new Role('Moderator'); 1026 | 1027 | $page = new Resource('Page'); 1028 | 1029 | $userGroup = new RoleAggregate(); 1030 | 1031 | $userGroup->addRole($moderator); 1032 | $userGroup->addRole($user); 1033 | 1034 | $acl->addRule($user, $page, new Rule('View'), true); 1035 | $acl->addRule($moderator, $page, new Rule('View'), false); 1036 | 1037 | $this->assertTrue($acl->isAllowed($userGroup, 'Page', 'View')); 1038 | 1039 | $userGroup->removeRole('User'); 1040 | $this->assertFalse($acl->isAllowed($userGroup, 'Page', 'View')); 1041 | $userGroup->addRole($user); 1042 | $this->assertTrue($acl->isAllowed($userGroup, 'Page', 'View')); 1043 | 1044 | $acl = new Acl; 1045 | 1046 | $userGroup = new RoleAggregate(); 1047 | 1048 | $userGroup->addRole($moderator); 1049 | $userGroup->addRole($user); 1050 | 1051 | // changing rule orders don't change result 1052 | $acl->addRule($moderator, $page, new Rule('View'), false); 1053 | $acl->addRule($user, $page, new Rule('View'), true); 1054 | 1055 | $this->assertTrue($acl->isAllowed($userGroup, 'Page', 'View')); 1056 | 1057 | $userGroup->removeRole('User'); 1058 | $this->assertFalse($acl->isAllowed($userGroup, 'Page', 'View')); 1059 | $userGroup->addRole($user); 1060 | $this->assertTrue($acl->isAllowed($userGroup, 'Page', 'View')); 1061 | 1062 | // test case when priority matter 1063 | $acl = new Acl; 1064 | 1065 | $userGroup = new RoleAggregate(); 1066 | 1067 | $userGroup->addRole($moderator); 1068 | $userGroup->addRole($user); 1069 | 1070 | $contact = new Resource('Contact'); 1071 | $page->addChild($contact); 1072 | 1073 | $acl->addRule($moderator, $contact, new Rule('View'), true); 1074 | $acl->addRule($user, $page, new Rule('View'), false); 1075 | 1076 | // user rule match first but moderator has higher priority 1077 | $this->assertTrue($acl->isAllowed($userGroup, 'Contact', 'View')); 1078 | 1079 | $acl->addRule($user, $contact, new Rule('View'), false); 1080 | 1081 | // now priorities are equal 1082 | $this->assertFalse($acl->isAllowed($userGroup, 'Contact', 'View')); 1083 | } 1084 | 1085 | public function testComplexGraph() 1086 | { 1087 | $acl = new Acl(); 1088 | 1089 | $u = new Role('U'); 1090 | $u1 = new Role('U1'); 1091 | $u2 = new Role('U2'); 1092 | $u3 = new Role('U3'); 1093 | 1094 | $u->addChild($u1); 1095 | $u->addChild($u2); 1096 | $u->addChild($u3); 1097 | 1098 | $r = new Resource('R'); 1099 | $r1 = new Resource('R1'); 1100 | $r2 = new Resource('R2'); 1101 | $r3 = new Resource('R3'); 1102 | $r4 = new Resource('R4'); 1103 | $r5 = new Resource('R5'); 1104 | 1105 | $r->addChild($r1); 1106 | $r->addChild($r2); 1107 | $r->addChild($r3); 1108 | 1109 | $r3->addChild($r4); 1110 | $r3->addChild($r5); 1111 | 1112 | $a = new Rule('View'); 1113 | 1114 | $acl->addRule($u, $r, $a, true); 1115 | 1116 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 1117 | $this->assertTrue($acl->isAllowed('U', 'R1', 'View')); 1118 | $this->assertTrue($acl->isAllowed('U', 'R2', 'View')); 1119 | $this->assertTrue($acl->isAllowed('U', 'R3', 'View')); 1120 | $this->assertTrue($acl->isAllowed('U', 'R4', 'View')); 1121 | $this->assertTrue($acl->isAllowed('U', 'R5', 'View')); 1122 | $this->assertTrue($acl->isAllowed('U1', 'R', 'View')); 1123 | $this->assertTrue($acl->isAllowed('U1', 'R1', 'View')); 1124 | $this->assertTrue($acl->isAllowed('U1', 'R2', 'View')); 1125 | $this->assertTrue($acl->isAllowed('U1', 'R3', 'View')); 1126 | $this->assertTrue($acl->isAllowed('U1', 'R4', 'View')); 1127 | $this->assertTrue($acl->isAllowed('U1', 'R5', 'View')); 1128 | $this->assertTrue($acl->isAllowed('U2', 'R', 'View')); 1129 | $this->assertTrue($acl->isAllowed('U2', 'R1', 'View')); 1130 | $this->assertTrue($acl->isAllowed('U2', 'R2', 'View')); 1131 | $this->assertTrue($acl->isAllowed('U2', 'R3', 'View')); 1132 | $this->assertTrue($acl->isAllowed('U2', 'R4', 'View')); 1133 | $this->assertTrue($acl->isAllowed('U2', 'R5', 'View')); 1134 | $this->assertTrue($acl->isAllowed('U3', 'R', 'View')); 1135 | $this->assertTrue($acl->isAllowed('U3', 'R1', 'View')); 1136 | $this->assertTrue($acl->isAllowed('U3', 'R2', 'View')); 1137 | $this->assertTrue($acl->isAllowed('U3', 'R3', 'View')); 1138 | $this->assertTrue($acl->isAllowed('U3', 'R4', 'View')); 1139 | $this->assertTrue($acl->isAllowed('U3', 'R5', 'View')); 1140 | 1141 | $a2 = new Rule('View'); 1142 | 1143 | $acl->addRule($u, $r3, $a2, false); 1144 | 1145 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 1146 | $this->assertTrue($acl->isAllowed('U', 'R1', 'View')); 1147 | $this->assertTrue($acl->isAllowed('U', 'R2', 'View')); 1148 | $this->assertFalse($acl->isAllowed('U', 'R3', 'View')); 1149 | $this->assertFalse($acl->isAllowed('U', 'R4', 'View')); 1150 | $this->assertFalse($acl->isAllowed('U', 'R5', 'View')); 1151 | $this->assertTrue($acl->isAllowed('U1', 'R', 'View')); 1152 | $this->assertTrue($acl->isAllowed('U1', 'R1', 'View')); 1153 | $this->assertTrue($acl->isAllowed('U1', 'R2', 'View')); 1154 | $this->assertFalse($acl->isAllowed('U1', 'R3', 'View')); 1155 | $this->assertFalse($acl->isAllowed('U1', 'R4', 'View')); 1156 | $this->assertFalse($acl->isAllowed('U1', 'R5', 'View')); 1157 | $this->assertTrue($acl->isAllowed('U2', 'R', 'View')); 1158 | $this->assertTrue($acl->isAllowed('U2', 'R1', 'View')); 1159 | $this->assertTrue($acl->isAllowed('U2', 'R2', 'View')); 1160 | $this->assertFalse($acl->isAllowed('U2', 'R3', 'View')); 1161 | $this->assertFalse($acl->isAllowed('U2', 'R4', 'View')); 1162 | $this->assertFalse($acl->isAllowed('U2', 'R5', 'View')); 1163 | $this->assertTrue($acl->isAllowed('U3', 'R', 'View')); 1164 | $this->assertTrue($acl->isAllowed('U3', 'R1', 'View')); 1165 | $this->assertTrue($acl->isAllowed('U3', 'R2', 'View')); 1166 | $this->assertFalse($acl->isAllowed('U3', 'R3', 'View')); 1167 | $this->assertFalse($acl->isAllowed('U3', 'R4', 'View')); 1168 | $this->assertFalse($acl->isAllowed('U3', 'R5', 'View')); 1169 | 1170 | $a3 = new Rule('View'); 1171 | $a4 = new Rule('View'); 1172 | $acl->addRule($u2, $r4, $a3, true); 1173 | $acl->addRule($u2, $r5, $a4, true); 1174 | 1175 | $this->assertTrue($acl->isAllowed('U', 'R', 'View')); 1176 | $this->assertTrue($acl->isAllowed('U', 'R1', 'View')); 1177 | $this->assertTrue($acl->isAllowed('U', 'R2', 'View')); 1178 | $this->assertFalse($acl->isAllowed('U', 'R3', 'View')); 1179 | $this->assertFalse($acl->isAllowed('U', 'R4', 'View')); 1180 | $this->assertFalse($acl->isAllowed('U', 'R5', 'View')); 1181 | $this->assertTrue($acl->isAllowed('U1', 'R', 'View')); 1182 | $this->assertTrue($acl->isAllowed('U1', 'R1', 'View')); 1183 | $this->assertTrue($acl->isAllowed('U1', 'R2', 'View')); 1184 | $this->assertFalse($acl->isAllowed('U1', 'R3', 'View')); 1185 | $this->assertFalse($acl->isAllowed('U1', 'R4', 'View')); 1186 | $this->assertFalse($acl->isAllowed('U1', 'R5', 'View')); 1187 | $this->assertTrue($acl->isAllowed('U2', 'R', 'View')); 1188 | $this->assertTrue($acl->isAllowed('U2', 'R1', 'View')); 1189 | $this->assertTrue($acl->isAllowed('U2', 'R2', 'View')); 1190 | $this->assertFalse($acl->isAllowed('U2', 'R3', 'View')); 1191 | $this->assertTrue($acl->isAllowed('U2', 'R4', 'View')); 1192 | $this->assertTrue($acl->isAllowed('U2', 'R5', 'View')); 1193 | $this->assertTrue($acl->isAllowed('U3', 'R', 'View')); 1194 | $this->assertTrue($acl->isAllowed('U3', 'R1', 'View')); 1195 | $this->assertTrue($acl->isAllowed('U3', 'R2', 'View')); 1196 | $this->assertFalse($acl->isAllowed('U3', 'R3', 'View')); 1197 | $this->assertFalse($acl->isAllowed('U3', 'R4', 'View')); 1198 | $this->assertFalse($acl->isAllowed('U3', 'R5', 'View')); 1199 | } 1200 | 1201 | public function testCustomRule() 1202 | { 1203 | require_once __DIR__ . '/../SimpleAclStubs/CustomRule.php'; 1204 | 1205 | // must match any role and act as wide 1206 | $acl = new Acl(); 1207 | 1208 | $rule = new MathAnyRoleAndActAsWide('MathAnyRoleAndActAsWide'); 1209 | 1210 | $u = new Role('U'); 1211 | $r = new Resource('R'); 1212 | 1213 | $acl->addRule($u, $r, $rule, true); 1214 | 1215 | $this->assertTrue($acl->isAllowed('U', 'R', 'ShouldActAsWide')); 1216 | $this->assertTrue($acl->isAllowed('U1', 'R', 'ShouldActAsWide'), 'Must work with any role'); 1217 | $this->assertFalse($acl->isAllowed('U', 'R1', 'ShouldActAsWide')); 1218 | $this->assertFalse($acl->isAllowed('U1', 'R1', 'MathAnyRoleAndActAsWide')); 1219 | 1220 | // must match any resource and act as wide 1221 | $acl = new Acl(); 1222 | 1223 | $rule = new MathAnyResourceAndActAsWide('MathAnyResourceAndActAsWide'); 1224 | 1225 | $u = new Role('U'); 1226 | $r = new Resource('R'); 1227 | 1228 | $acl->addRule($u, $r, $rule, true); 1229 | 1230 | $this->assertTrue($acl->isAllowed('U', 'R', 'ShouldActAsWide')); 1231 | $this->assertTrue($acl->isAllowed('U', 'R1', 'ShouldActAsWide'), 'Must work with any resource'); 1232 | $this->assertFalse($acl->isAllowed('U1', 'R', 'ShouldActAsWide')); 1233 | $this->assertFalse($acl->isAllowed('U1', 'R1', 'MathAnyResourceAndActAsWide')); 1234 | 1235 | // must match anything 1236 | $acl = new Acl(); 1237 | $rule = new MatchAnything('MathAnything'); 1238 | 1239 | $u = new Role('U'); 1240 | $r = new Resource('R'); 1241 | 1242 | $acl->addRule($u, $r, $rule, true); 1243 | $this->assertTrue($acl->isAllowed('anything', 'anything', 'anything')); 1244 | } 1245 | } 1246 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/AclTest.php: -------------------------------------------------------------------------------- 1 | setExpectedException('SimpleAcl\Exception\InvalidArgumentException', 'SimpleAcl\Rule or string'); 19 | 20 | $acl->addRule(new Role('User'), new Resource('Page'), new \stdClass(), true); 21 | } 22 | 23 | public function testThrowsExceptionWhenBadArgumentsCount() 24 | { 25 | $this->setExpectedException('SimpleAcl\Exception\InvalidArgumentException', 'accepts only one, tow, three or four arguments'); 26 | 27 | $acl = new Acl; 28 | $acl->addRule(new Role(1), new Resource(1), new Rule(1), true, 'test'); 29 | } 30 | 31 | public function testThrowsExceptionWhenBadRole() 32 | { 33 | $this->setExpectedException('SimpleAcl\Exception\InvalidArgumentException', 'Role must be an instance of SimpleAcl\Role or null'); 34 | 35 | $acl = new Acl; 36 | $acl->addRule(new \StdClass(1), new Resource('test'), new Rule('test'), true); 37 | } 38 | 39 | public function testThrowsExceptionWhenBadResource() 40 | { 41 | $this->setExpectedException('SimpleAcl\Exception\InvalidArgumentException', 'Resource must be an instance of SimpleAcl\Resource or null'); 42 | 43 | $acl = new Acl; 44 | $acl->addRule(new Role('test'), new \StdClass(1), new Rule('test'), true); 45 | } 46 | 47 | public function testSetRuleClassOriginal() 48 | { 49 | $acl = new Acl; 50 | $acl->setRuleClass('SimpleAcl\Rule'); 51 | 52 | $this->assertEquals('SimpleAcl\Rule', $acl->getRuleClass()); 53 | } 54 | 55 | public function testSetRuleNotExistingClass() 56 | { 57 | $this->setExpectedException('SimpleAcl\Exception\RuntimeException', 'Rule class not exist'); 58 | 59 | $acl = new Acl; 60 | $acl->setRuleClass('BadClassTest'); 61 | 62 | $this->assertEquals('SimpleAcl\Rule', $acl->getRuleClass()); 63 | } 64 | 65 | public function testSetRuleNotInstanceOfRuleClass() 66 | { 67 | $this->setExpectedException('SimpleAcl\Exception\RuntimeException', 'Rule class must be instance of SimpleAcl\Rule'); 68 | 69 | eval('class NotInstanceOfRuleClass {}'); 70 | 71 | $acl = new Acl; 72 | $acl->setRuleClass('NotInstanceOfRuleClass'); 73 | 74 | $this->assertEquals('SimpleAcl\Rule', $acl->getRuleClass()); 75 | } 76 | 77 | public function testSetRuleClass() 78 | { 79 | eval('class GoodRuleClass extends \SimpleAcl\Rule {}'); 80 | 81 | $acl = new Acl; 82 | $acl->setRuleClass('GoodRuleClass'); 83 | 84 | $this->assertEquals('GoodRuleClass', $acl->getRuleClass()); 85 | } 86 | 87 | public function testAddSameRules() 88 | { 89 | $acl = new Acl; 90 | 91 | $rule = new Rule('Edit'); 92 | 93 | $user = new Role('User'); 94 | $page = new Resource('Page'); 95 | 96 | $superUser = new Role('SuperUser'); 97 | $superPage = new Resource('SuperPage'); 98 | 99 | $acl->addRule($user, $page, $rule, true); 100 | 101 | $this->assertSame($rule->getRole(), $user); 102 | $this->assertSame($rule->getResource(), $page); 103 | 104 | // If rule already exist don't add it in Acl, but change Role, Resource and Action 105 | $acl->addRule($superUser, $superPage, $rule, true); 106 | 107 | $this->assertNotSame($rule->getRole(), $user); 108 | $this->assertNotSame($rule->getResource(), $page); 109 | 110 | $this->assertSame($rule->getRole(), $superUser); 111 | $this->assertSame($rule->getResource(), $superPage); 112 | 113 | $this->assertFalse($acl->isAllowed('User', 'Page', 'Edit')); 114 | $this->assertTrue($acl->isAllowed('SuperUser', 'SuperPage', 'Edit')); 115 | 116 | $acl->addRule($superUser, $superPage, $rule, false); 117 | 118 | $this->assertFalse($acl->isAllowed('SuperUser', 'SuperPage', 'Edit')); 119 | 120 | $this->assertAttributeCount(1, 'rules', $acl); 121 | 122 | // rule should overwrite $role, $resource and $action when they actually used in addRule 123 | 124 | $acl->addRule($superUser, $superPage, $rule); 125 | $this->assertFalse($acl->isAllowed('SuperUser', 'SuperPage', 'Edit')); 126 | $this->assertAttributeCount(1, 'rules', $acl); 127 | 128 | $acl->addRule($rule); 129 | $this->assertFalse($acl->isAllowed('SuperUser', 'SuperPage', 'Edit')); 130 | $this->assertSame($rule->getRole(), $superUser); 131 | $this->assertSame($rule->getResource(), $superPage); 132 | 133 | $acl->addRule($rule, true); 134 | $this->assertTrue($acl->isAllowed('SuperUser', 'SuperPage', 'Edit')); 135 | $this->assertSame($rule->getRole(), $superUser); 136 | $this->assertSame($rule->getResource(), $superPage); 137 | } 138 | 139 | public function testRemoveAllRules() 140 | { 141 | $acl = new Acl; 142 | 143 | $user = new Role('User'); 144 | $resource = new Resource('Page'); 145 | 146 | $acl->addRule($user, $resource, new Rule('View'), true); 147 | $acl->addRule($user, $resource, new Rule('Edit'), true); 148 | $acl->addRule($user, $resource, new Rule('Remove'), true); 149 | 150 | $this->assertAttributeCount(3, 'rules', $acl); 151 | 152 | $acl->removeAllRules(); 153 | 154 | $this->assertAttributeCount(0, 'rules', $acl); 155 | } 156 | 157 | public function testRemoveRuleActAsRemoveAllRules() 158 | { 159 | $acl = new Acl; 160 | 161 | $user = new Role('User'); 162 | $resource = new Resource('Page'); 163 | 164 | $acl->addRule($user, $resource, new Rule('View'), true); 165 | $acl->addRule($user, $resource, new Rule('Edit'), true); 166 | $acl->addRule($user, $resource, new Rule('Remove'), true); 167 | 168 | $this->assertAttributeCount(3, 'rules', $acl); 169 | 170 | $acl->removeRule(); 171 | 172 | $this->assertAttributeCount(0, 'rules', $acl); 173 | } 174 | 175 | public function testRemoveRuleNotMatch() 176 | { 177 | $acl = new Acl; 178 | 179 | $user = new Role('User'); 180 | $moderator = new Role('Moderator'); 181 | $admin = new Role('Admin'); 182 | 183 | $page = new Resource('Page'); 184 | $blog = new Resource('Blog'); 185 | $site = new Resource('Site'); 186 | 187 | $acl->addRule($user, $page, new Rule('View'), true); 188 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 189 | $acl->addRule($admin, $site, new Rule('Remove'), true); 190 | 191 | $this->assertAttributeCount(3, 'rules', $acl); 192 | $acl->removeRule('RoleNotMatch'); 193 | $this->assertAttributeCount(3, 'rules', $acl); 194 | 195 | $this->assertAttributeCount(3, 'rules', $acl); 196 | $acl->removeRule(null, 'ResourceNotMatch'); 197 | $this->assertAttributeCount(3, 'rules', $acl); 198 | 199 | $this->assertAttributeCount(3, 'rules', $acl); 200 | $acl->removeRule(null, 'ResourceNotMatch'); 201 | $this->assertAttributeCount(3, 'rules', $acl); 202 | 203 | $this->assertAttributeCount(3, 'rules', $acl); 204 | $acl->removeRule(null, null, 'RuleNotMatch'); 205 | $this->assertAttributeCount(3, 'rules', $acl); 206 | 207 | $this->assertAttributeCount(3, 'rules', $acl); 208 | $acl->removeRule('RoleNotMatch', 'ResourceNotMatch', 'RuleNotMatch'); 209 | $this->assertAttributeCount(3, 'rules', $acl); 210 | } 211 | 212 | public function testRemoveRule() 213 | { 214 | $acl = new Acl; 215 | 216 | $user = new Role('User'); 217 | $moderator = new Role('Moderator'); 218 | $admin = new Role('Admin'); 219 | 220 | $page = new Resource('Page'); 221 | $blog = new Resource('Blog'); 222 | $site = new Resource('Site'); 223 | 224 | // Remove rules by Role 225 | $acl->addRule($user, $page, new Rule('View'), true); 226 | $acl->addRule($user, $blog, new Rule('Edit'), true); 227 | $acl->addRule($user, $site, new Rule('Remove'), true); 228 | 229 | $this->assertAttributeCount(3, 'rules', $acl); 230 | $acl->removeRule('User'); 231 | $this->assertAttributeCount(0, 'rules', $acl); 232 | 233 | $acl->addRule($user, $page, new Rule('View'), true); 234 | $acl->addRule($user, $blog, new Rule('Edit'), true); 235 | $acl->addRule($moderator, $site, new Rule('Remove'), true); 236 | 237 | $acl->removeRule('User'); 238 | $this->assertAttributeCount(1, 'rules', $acl); 239 | 240 | $acl->removeRule(); 241 | 242 | // Remove rules by Resource 243 | $acl->addRule($user, $page, new Rule('View'), true); 244 | $acl->addRule($moderator, $page, new Rule('Edit'), true); 245 | $acl->addRule($admin, $page, new Rule('Remove'), true); 246 | 247 | $this->assertAttributeCount(3, 'rules', $acl); 248 | $acl->removeRule(null, 'Page'); 249 | $this->assertAttributeCount(0, 'rules', $acl); 250 | 251 | $acl->addRule($user, $page, new Rule('View'), true); 252 | $acl->addRule($moderator, $page, new Rule('Edit'), true); 253 | $acl->addRule($admin, $blog, new Rule('Remove'), true); 254 | 255 | $this->assertAttributeCount(3, 'rules', $acl); 256 | $acl->removeRule(null, 'Page'); 257 | $this->assertAttributeCount(1, 'rules', $acl); 258 | 259 | $acl->removeRule(); 260 | 261 | // Remove rules by Rule 262 | $acl->addRule($user, $page, new Rule('View'), true); 263 | $acl->addRule($moderator, $blog, new Rule('View'), true); 264 | $acl->addRule($admin, $site, new Rule('View'), true); 265 | 266 | $this->assertAttributeCount(3, 'rules', $acl); 267 | $acl->removeRule(null, null, 'View'); 268 | $this->assertAttributeCount(0, 'rules', $acl); 269 | 270 | $acl->addRule($user, $page, new Rule('View'), true); 271 | $acl->addRule($moderator, $blog, new Rule('View'), true); 272 | $acl->addRule($admin, $site, new Rule('Edit'), true); 273 | 274 | $this->assertAttributeCount(3, 'rules', $acl); 275 | $acl->removeRule(null, null, 'View'); 276 | $this->assertAttributeCount(1, 'rules', $acl); 277 | 278 | $acl->removeRule(); 279 | 280 | // Remove rules by Role & Resource & Rule 281 | $acl->addRule($user, $page, new Rule('View'), true); 282 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 283 | $acl->addRule($admin, $site, new Rule('Remove'), true); 284 | 285 | $this->assertAttributeCount(3, 'rules', $acl); 286 | $acl->removeRule('User', 'Page', 'View'); 287 | $this->assertAttributeCount(2, 'rules', $acl); 288 | $acl->removeRule('Moderator', 'Blog', 'Edit'); 289 | $this->assertAttributeCount(1, 'rules', $acl); 290 | $acl->removeRule('Admin', 'Site', 'Remove'); 291 | $this->assertAttributeCount(0, 'rules', $acl); 292 | 293 | // Remove rules by pairs 294 | $acl->addRule($user, $page, new Rule('View'), true); 295 | $acl->addRule($moderator, $blog, new Rule('Edit'), true); 296 | $acl->addRule($admin, $site, new Rule('Remove'), true); 297 | 298 | $this->assertAttributeCount(3, 'rules', $acl); 299 | $acl->removeRule('User', 'Page'); 300 | $this->assertAttributeCount(2, 'rules', $acl); 301 | $acl->removeRule('Moderator', null, 'Edit'); 302 | $this->assertAttributeCount(1, 'rules', $acl); 303 | $acl->removeRule(null, 'Site', 'Remove'); 304 | $this->assertAttributeCount(0, 'rules', $acl); 305 | 306 | $acl->removeRule(); 307 | } 308 | 309 | public function testRemoveRuleById() 310 | { 311 | $acl = new Acl; 312 | 313 | $user = new Role('User'); 314 | 315 | $page = new Resource('Page'); 316 | 317 | $rule1 = new Rule('View'); 318 | $rule2 = new Rule('View'); 319 | $rule3 = new Rule('View'); 320 | 321 | $acl->addRule($user, $page, $rule1, true); 322 | $acl->addRule($user, $page, $rule2, true); 323 | $acl->addRule($user, $page, $rule3, true); 324 | 325 | $acl->removeRuleById('bad_id_test'); 326 | 327 | $this->assertAttributeCount(3, 'rules', $acl); 328 | 329 | $acl->removeRuleById($rule1->getId()); 330 | 331 | $this->assertAttributeCount(2, 'rules', $acl); 332 | 333 | $acl->removeRuleById($rule2->getId()); 334 | $acl->removeRuleById($rule3->getId()); 335 | 336 | $this->assertAttributeCount(0, 'rules', $acl); 337 | } 338 | 339 | public function testHasRule() 340 | { 341 | $acl = new Acl; 342 | 343 | $user = new Role('User'); 344 | 345 | $page = new Resource('Page'); 346 | 347 | $rule1 = new Rule('View'); 348 | $rule2 = new Rule('View'); 349 | $rule3 = new Rule('View'); 350 | 351 | $acl->addRule($user, $page, $rule1, true); 352 | $acl->addRule($user, $page, $rule2, true); 353 | 354 | $this->assertSame($rule1, $acl->hasRule($rule1)); 355 | $this->assertSame($rule2, $acl->hasRule($rule2->getId())); 356 | $this->assertFalse($acl->hasRule($rule3)); 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/Object/RecursiveIteratorTest.php: -------------------------------------------------------------------------------- 1 | getMockForAbstractClass('SimpleAcl\BaseObject', array($name)); 20 | } 21 | 22 | public function testKey() 23 | { 24 | $iterator = new RecursiveIterator(array()); 25 | $this->assertNull($iterator->key()); 26 | 27 | $iterator = new RecursiveIterator(array($this->getObject('Test'))); 28 | $this->assertEquals('Test', $iterator->key()); 29 | } 30 | 31 | public function testCurrent() 32 | { 33 | $iterator = new RecursiveIterator(array()); 34 | $this->assertFalse($iterator->current()); 35 | 36 | $test = $this->getObject('Test'); 37 | $iterator = new RecursiveIterator(array($test)); 38 | $this->assertSame($test, $iterator->current()); 39 | } 40 | 41 | public function testValidNextRewind() 42 | { 43 | $iterator = new RecursiveIterator(array()); 44 | $this->assertFalse($iterator->valid()); 45 | 46 | $test1 = $this->getObject('Test1'); 47 | $test2 = $this->getObject('Test2'); 48 | 49 | $iterator = new RecursiveIterator(array($test1, $test2)); 50 | $this->assertTrue($iterator->valid()); 51 | $this->assertSame($test1, $iterator->current()); 52 | $this->assertEquals('Test1', $iterator->key()); 53 | 54 | $iterator->next(); 55 | $this->assertTrue($iterator->valid()); 56 | $this->assertSame($test2, $iterator->current()); 57 | $this->assertEquals('Test2', $iterator->key()); 58 | } 59 | 60 | public function testHasChildren() 61 | { 62 | $iterator = new RecursiveIterator(array()); 63 | $this->assertFalse($iterator->hasChildren()); 64 | 65 | $parent = $this->getObject('Test1'); 66 | 67 | $child = $this->getObject('Test2'); 68 | $parent->addChild($child); 69 | 70 | $iterator = new RecursiveIterator(array($parent)); 71 | 72 | $this->assertTrue($iterator->hasChildren()); 73 | } 74 | 75 | public function testIterate() 76 | { 77 | $parent = $this->getObject('parent'); 78 | 79 | $oc00 = $this->getObject('child0.0'); 80 | $oc01 = $this->getObject('child0.1'); 81 | 82 | $parent->addChild($oc00); 83 | $parent->addChild($oc01); 84 | 85 | $oc10 = $this->getObject('child1.0'); 86 | 87 | $oc00->addChild($oc10); 88 | 89 | $oc20 = $this->getObject('child2.0'); 90 | $oc10->addChild($oc20); 91 | 92 | $oc21 = $this->getObject('child2.1'); 93 | $oc10->addChild($oc21); 94 | 95 | $actual = array(); 96 | $i = new RecursiveIteratorIterator($parent, RecursiveIteratorIterator::SELF_FIRST); 97 | foreach ($i as $k => $o) { 98 | $actual[$k] = $o; 99 | } 100 | 101 | $expected = array('parent' => $parent, 'child0.0' => $oc00, 'child1.0' => $oc10, 102 | 'child2.0' => $oc20, 'child2.1' => $oc21, 'child0.1' => $oc01); 103 | $this->assertSame($expected, $actual); 104 | 105 | $actual = array(); 106 | foreach (new RecursiveIteratorIterator($oc10, RecursiveIteratorIterator::SELF_FIRST) as $k => $o) { 107 | $actual[$k] = $o; 108 | } 109 | 110 | $expected = array('child1.0' => $oc10, 'child2.0' => $oc20, 'child2.1' => $oc21); 111 | $this->assertSame($expected, $actual); 112 | 113 | $actual = array(); 114 | foreach (new RecursiveIteratorIterator($oc20, RecursiveIteratorIterator::SELF_FIRST) as $k => $o) { 115 | $actual[$k] = $o; 116 | } 117 | 118 | $expected = array('child2.0' => $oc20); 119 | $this->assertSame($expected, $actual); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/ObjectTest.php: -------------------------------------------------------------------------------- 1 | getMockForAbstractClass('SimpleAcl\BaseObject', array('TestName')); 14 | 15 | $this->assertEquals($object->getName(), 'TestName'); 16 | $object->setName('NewName'); 17 | $this->assertEquals($object->getName(), 'NewName'); 18 | } 19 | 20 | public function testAddChild() 21 | { 22 | /** @var Object $parent */ 23 | $parent = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Parent')); 24 | 25 | $child = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Child')); 26 | 27 | $parent->addChild($child); 28 | 29 | $this->assertEquals(1, count($parent->getChildren())); 30 | $this->assertSame($child, $parent->hasChild($child)); 31 | $this->assertSame($child, $parent->hasChild('Child')); 32 | } 33 | 34 | public function testRemoveChild() 35 | { 36 | /** @var Object $parent */ 37 | $parent = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Parent')); 38 | 39 | $child = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Child')); 40 | 41 | $this->assertFalse($parent->removeChild($child)); 42 | 43 | $parent->addChild($child); 44 | 45 | $this->assertEquals(1, count($parent->getChildren())); 46 | $this->assertSame($child, $parent->hasChild($child)); 47 | $this->assertSame($child, $parent->hasChild('Child')); 48 | 49 | $this->assertTrue($parent->removeChild($child)); 50 | 51 | $this->assertNull($parent->hasChild($child)); 52 | $this->assertEquals(0, count($parent->getChildren())); 53 | } 54 | 55 | public function testAddSameChild() 56 | { 57 | /** @var Object $parent */ 58 | $parent = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Parent')); 59 | 60 | $child = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Child')); 61 | 62 | $parent->addChild($child); 63 | 64 | $this->assertEquals(1, count($parent->getChildren())); 65 | $this->assertSame($child, $parent->hasChild($child)); 66 | 67 | $parent->addChild($child); 68 | $this->assertEquals(1, count($parent->getChildren())); 69 | 70 | $child2 = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('Child')); 71 | 72 | $parent->addChild($child2); 73 | 74 | $this->assertEquals(1, count($parent->getChildren())); 75 | $this->assertSame($child, $parent->hasChild('Child')); 76 | $this->assertSame($child, $parent->hasChild($child)); 77 | $this->assertSame($child, $parent->hasChild($child2)); 78 | 79 | $this->assertNotSame($child2, $parent->hasChild($child2)); 80 | } 81 | 82 | public function testGetChildren() 83 | { 84 | $parent = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('TestName')); 85 | 86 | $child1 = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('TestNameChild1')); 87 | $parent->addChild($child1); 88 | 89 | $child2 = $this->getMockForAbstractClass('SimpleAcl\BaseObject', array('TestNameChild2')); 90 | $parent->addChild($child2); 91 | 92 | $this->assertSame(array($child1, $child2), $parent->getChildren()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/Resource/ResourceAggregateTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(0, count($site->getResources())); 19 | 20 | $site->setResources($resources); 21 | 22 | $this->assertEquals($resources, $site->getResources()); 23 | 24 | $this->assertEquals(2, count($site->getResources())); 25 | } 26 | 27 | public function testResourceAdd() 28 | { 29 | $site = new ResourceAggregate(); 30 | 31 | $resource1 = new Resource('One'); 32 | $resource2 = new Resource('Tow'); 33 | 34 | $this->assertEquals(0, count($site->getResources())); 35 | 36 | $site->addResource($resource1); 37 | $site->addResource($resource2); 38 | 39 | $this->assertEquals(2, count($site->getResources())); 40 | 41 | $this->assertEquals(array($resource1, $resource2), $site->getResources()); 42 | } 43 | 44 | public function testGetResourcesNames() 45 | { 46 | $site = new ResourceAggregate(); 47 | 48 | $resource1 = new Resource('One'); 49 | $resource2 = new Resource('Tow'); 50 | 51 | $this->assertEquals(0, count($site->getResources())); 52 | 53 | $site->addResource($resource1); 54 | $site->addResource($resource2); 55 | 56 | $this->assertEquals(2, count($site->getResources())); 57 | 58 | $this->assertSame(array('One', 'Tow'), $site->getResourcesNames()); 59 | } 60 | 61 | public function testRemoveResources() 62 | { 63 | $site = new ResourceAggregate(); 64 | 65 | $resource1 = new Resource('One'); 66 | $resource2 = new Resource('Tow'); 67 | 68 | $this->assertEquals(0, count($site->getResources())); 69 | 70 | $site->addResource($resource1); 71 | $site->addResource($resource2); 72 | 73 | $this->assertEquals(2, count($site->getResources())); 74 | 75 | $site->removeResources(); 76 | 77 | $this->assertEquals(0, count($site->getResources())); 78 | 79 | $this->assertNull($site->getResource('One')); 80 | $this->assertNull($site->getResource('Tow')); 81 | } 82 | 83 | public function testRemoveResource() 84 | { 85 | $site = new ResourceAggregate(); 86 | 87 | $resource1 = new Resource('One'); 88 | $resource2 = new Resource('Tow'); 89 | 90 | $this->assertEquals(0, count($site->getResources())); 91 | 92 | $site->addResource($resource1); 93 | $site->addResource($resource2); 94 | 95 | $this->assertEquals(2, count($site->getResources())); 96 | 97 | $site->removeResource('One'); 98 | $this->assertEquals(1, count($site->getResources())); 99 | $this->assertEquals($resource2, $site->getResource('Tow')); 100 | 101 | $site->removeResource('UnDefinedTow'); 102 | $this->assertEquals(1, count($site->getResources())); 103 | 104 | $site->removeResource($resource2); 105 | $this->assertEquals(0, count($site->getResources())); 106 | } 107 | 108 | public function testAddResourceWithSameName() 109 | { 110 | $site = new ResourceAggregate(); 111 | 112 | $resource1 = new Resource('One'); 113 | $resource2 = new Resource('One'); 114 | 115 | $site->addResource($resource1); 116 | $site->addResource($resource2); 117 | 118 | $this->assertEquals(1, count($site->getResources())); 119 | $this->assertSame($resource1, $site->getResource('One')); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/Role/RoleAggregateTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(0, count($user->getRoles())); 19 | 20 | $user->setRoles($roles); 21 | 22 | $this->assertEquals($roles, $user->getRoles()); 23 | 24 | $this->assertEquals(2, count($user->getRoles())); 25 | } 26 | 27 | public function testRoleAdd() 28 | { 29 | $user = new RoleAggregate(); 30 | 31 | $role1 = new Role('One'); 32 | $role2 = new Role('Tow'); 33 | 34 | $this->assertEquals(0, count($user->getRoles())); 35 | 36 | $user->addRole($role1); 37 | $user->addRole($role2); 38 | 39 | $this->assertEquals(2, count($user->getRoles())); 40 | 41 | $this->assertEquals(array($role1, $role2), $user->getRoles()); 42 | } 43 | 44 | public function testGetRolesNames() 45 | { 46 | $user = new RoleAggregate(); 47 | 48 | $role1 = new Role('One'); 49 | $role2 = new Role('Tow'); 50 | 51 | $this->assertEquals(0, count($user->getRoles())); 52 | 53 | $user->addRole($role1); 54 | $user->addRole($role2); 55 | 56 | $this->assertEquals(2, count($user->getRoles())); 57 | 58 | $this->assertSame(array('One', 'Tow'), $user->getRolesNames()); 59 | } 60 | 61 | public function testRemoveRoles() 62 | { 63 | $user = new RoleAggregate(); 64 | 65 | $role1 = new Role('One'); 66 | $role2 = new Role('Tow'); 67 | 68 | $this->assertEquals(0, count($user->getRoles())); 69 | 70 | $user->addRole($role1); 71 | $user->addRole($role2); 72 | 73 | $this->assertEquals(2, count($user->getRoles())); 74 | 75 | $user->removeRoles(); 76 | 77 | $this->assertEquals(0, count($user->getRoles())); 78 | 79 | $this->assertNull($user->getRole('One')); 80 | $this->assertNull($user->getRole('Tow')); 81 | } 82 | 83 | public function testRemoveRole() 84 | { 85 | $user = new RoleAggregate(); 86 | 87 | $role1 = new Role('One'); 88 | $role2 = new Role('Tow'); 89 | 90 | $this->assertEquals(0, count($user->getRoles())); 91 | 92 | $user->addRole($role1); 93 | $user->addRole($role2); 94 | 95 | $this->assertEquals(2, count($user->getRoles())); 96 | 97 | $user->removeRole('One'); 98 | $this->assertEquals(1, count($user->getRoles())); 99 | $this->assertEquals($role2, $user->getRole('Tow')); 100 | 101 | $user->removeRole('UnDefinedTow'); 102 | $this->assertEquals(1, count($user->getRoles())); 103 | 104 | $user->removeRole($role2); 105 | $this->assertEquals(0, count($user->getRoles())); 106 | } 107 | 108 | public function testAddRoleWithSameName() 109 | { 110 | $user = new RoleAggregate(); 111 | 112 | $role1 = new Role('One'); 113 | $role2 = new Role('One'); 114 | 115 | $user->addRole($role1); 116 | $user->addRole($role2); 117 | 118 | $this->assertEquals(1, count($user->getRoles())); 119 | $this->assertSame($role1, $user->getRole('One')); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/RuleResultCollectionTest.php: -------------------------------------------------------------------------------- 1 | assertFalse($collection->any()); 16 | $this->assertFalse($collection->get()); 17 | } 18 | 19 | public function testAddNull() 20 | { 21 | $collection = new RuleResultCollection(); 22 | 23 | $collection->add(null); 24 | 25 | $this->assertFalse($collection->any()); 26 | $this->assertFalse($collection->get()); 27 | } 28 | 29 | public function testAdd() 30 | { 31 | $collection = new RuleResultCollection(); 32 | 33 | $rule = new Rule('Test'); 34 | $result = new RuleResult($rule, 0, 'testNeedRole', 'testNeedResource'); 35 | 36 | $collection->add($result); 37 | 38 | $this->assertTrue($collection->any()); 39 | $this->assertSame($result->getAction(), $collection->get()); 40 | 41 | $index = 0; 42 | foreach ( $collection as $r ) { 43 | $this->assertSame($result, $r); 44 | $index++; 45 | } 46 | $this->assertEquals(1, $index); 47 | } 48 | 49 | public function testMultipleAdd() 50 | { 51 | $collection = new RuleResultCollection(); 52 | 53 | $rule = new Rule('Test'); 54 | $result = new RuleResult($rule, 0, 'testNeedRole', 'testNeedResource'); 55 | 56 | $rule2 = new Rule('Test2'); 57 | $result2 = new RuleResult($rule2, 0, 'testNeedRole', 'testNeedResource'); 58 | 59 | $collection->add($result); 60 | $collection->add($result2); 61 | 62 | $this->assertTrue($collection->any()); 63 | 64 | $results = array($result2, $result); 65 | 66 | $index = 0; 67 | foreach ( $collection as $r ) { 68 | $this->assertSame($results[$index], $r); 69 | $index++; 70 | } 71 | $this->assertEquals(2, $index); 72 | } 73 | 74 | public function testResultWithNullAction() 75 | { 76 | $collection = new RuleResultCollection(); 77 | 78 | $rule = new Rule('Test'); 79 | $rule->setAction(null); 80 | $result = new RuleResult($rule, 0, 'testNeedRole', 'testNeedResource'); 81 | 82 | $rule2 = new Rule('Test2'); 83 | $rule2->setAction(true); 84 | $result2 = new RuleResult($rule2, 0, 'testNeedRole', 'testNeedResource'); 85 | 86 | $collection->add($result); 87 | $this->assertFalse($collection->get()); 88 | 89 | $collection->add($result2); 90 | $this->assertTrue($collection->get()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/RuleResultTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('SimpleAcl\Role\RoleAggregateInterface')->getMock(); 14 | $resourceAggregate = $this->getMockBuilder('SimpleAcl\Resource\ResourceAggregateInterface')->getMock(); 15 | 16 | $rule = new Rule('Test'); 17 | 18 | $rule->setRoleAggregate($roleAggregate); 19 | $rule->setResourceAggregate($resourceAggregate); 20 | $rule->setAction(true); 21 | $result = new RuleResult($rule, 0, 'testNeedRole', 'testNeedResource'); 22 | 23 | $this->assertSame($rule, $result->getRule()); 24 | $this->assertEquals('testNeedRole', $result->getNeedRoleName()); 25 | $this->assertEquals('testNeedResource', $result->getNeedResourceName()); 26 | $this->assertEquals(0, $result->getPriority()); 27 | $this->assertEquals($rule->getAction($result), $result->getAction()); 28 | 29 | $result->setPriority(10); 30 | $this->assertEquals(10, $result->getPriority()); 31 | 32 | $this->assertSame($roleAggregate, $result->getRoleAggregate()); 33 | $this->assertSame($resourceAggregate, $result->getResourceAggregate()); 34 | 35 | $this->assertNotEmpty($result->getId()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/SimpleAclTest/RuleTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($rule->getName(), 'Rule'); 17 | $rule->setName('NewRuleName'); 18 | $this->assertEquals($rule->getName(), 'NewRuleName'); 19 | } 20 | 21 | public function testAction() 22 | { 23 | $rule = new Rule('Rule'); 24 | $ruleResult = new RuleResult($rule, 0, 'testNeedRoleName', 'testNeedResourceName'); 25 | 26 | $rule->setAction(true); 27 | $this->assertTrue($rule->getAction($ruleResult)); 28 | $this->assertTrue($rule->getAction()); 29 | 30 | $rule->setAction(false); 31 | $this->assertFalse($rule->getAction($ruleResult)); 32 | $this->assertFalse($rule->getAction()); 33 | 34 | // Action can be mixed, but getAction must return bool 35 | $a = array(); 36 | $rule->setAction($a); 37 | $this->assertFalse($rule->getAction($ruleResult)); 38 | $this->assertFalse($rule->getAction()); 39 | $this->assertAttributeEquals($a, 'action', $rule); 40 | 41 | $a = array(1, 2, 3); 42 | $rule->setAction($a); 43 | $this->assertTrue($rule->getAction($ruleResult)); 44 | $this->assertTrue($rule->getAction()); 45 | $this->assertAttributeEquals($a, 'action', $rule); 46 | } 47 | 48 | public function testRolesAndResources() 49 | { 50 | $rule = new Rule('Rule'); 51 | 52 | $role = new Role('Role'); 53 | $rule->setRole($role); 54 | $this->assertSame($rule->getRole(), $role); 55 | 56 | $resource = new Resource('Resource'); 57 | $rule->setResource($resource); 58 | $this->assertSame($rule->getResource(), $resource); 59 | } 60 | 61 | public function testId() 62 | { 63 | $rule = new Rule('Rule'); 64 | 65 | $this->assertNotNull($rule->getId()); 66 | } 67 | 68 | public function testActionCallableWithNullRuleResult() 69 | { 70 | $rule = new Rule('Rule'); 71 | $ruleResult = new RuleResult($rule, 0, 'testNeedRoleName', 'testNeedResourceName'); 72 | 73 | $self = $this; 74 | $isCalled = false; 75 | 76 | $rule->setAction(function() use (&$isCalled, $self) { 77 | $isCalled = true; 78 | return false; 79 | }); 80 | 81 | $this->assertTrue($rule->getAction()); 82 | $this->assertFalse($isCalled); 83 | 84 | $this->assertFalse($rule->getAction($ruleResult)); 85 | $this->assertTrue($isCalled); 86 | } 87 | 88 | public function testActionCallable() 89 | { 90 | $rule = new Rule('Rule'); 91 | $ruleResult = new RuleResult($rule, 0, 'testNeedRoleName', 'testNeedResourceName'); 92 | 93 | $self = $this; 94 | $isCalled = false; 95 | 96 | $rule->setAction(function(RuleResult $r) use (&$isCalled, $self) { 97 | $isCalled = true; 98 | $self->assertEquals('testNeedRoleName', $r->getNeedRoleName()); 99 | $self->assertEquals('testNeedResourceName', $r->getNeedResourceName()); 100 | $self->assertEquals(0, $r->getPriority()); 101 | 102 | return true; 103 | }); 104 | 105 | $this->assertTrue($rule->getAction($ruleResult)); 106 | 107 | $this->assertTrue($isCalled); 108 | } 109 | 110 | public function testNullRoleOrResource() 111 | { 112 | $rule = new Rule('Rule'); 113 | 114 | $this->assertNull($rule->isAllowed('NotMatchedRule', 'Role', 'Resource')); 115 | $this->assertInstanceOf('SimpleAcl\RuleResult', $rule->isAllowed('Rule', 'Role', 'Resource')); 116 | 117 | $rule = new Rule('Rule'); 118 | $rule->setRole(new Role('Role')); 119 | 120 | $this->assertNull($rule->isAllowed('Rule', 'NotMatchedRole', 'Resource')); 121 | $this->assertInstanceOf('SimpleAcl\RuleResult', $rule->isAllowed('Rule', 'Role', 'Resource')); 122 | 123 | $rule = new Rule('Rule'); 124 | $rule->setResource(new Resource('Resource')); 125 | 126 | $this->assertNull($rule->isAllowed('Rule', 'Role', 'NotMatchedResource')); 127 | $this->assertInstanceOf('SimpleAcl\RuleResult', $rule->isAllowed('Rule', 'Role', 'Resource')); 128 | 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | = 8) { 9 | require_once __DIR__ . '/bootstrap8.php'; 10 | } else { 11 | require_once __DIR__ . '/bootstrap5.php'; 12 | } 13 | -------------------------------------------------------------------------------- /tests/bootstrap5.php: -------------------------------------------------------------------------------- 1 | expectException($class); 9 | $this->expectExceptionMessage($message); 10 | } 11 | 12 | public static function assertAttributeCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void { 13 | 14 | $reflectionProperty = new \ReflectionProperty($haystackClassOrObject, $haystackAttributeName); 15 | $reflectionProperty->setAccessible(true); 16 | 17 | static::assertSame($expectedCount, count($reflectionProperty->getValue($haystackClassOrObject)), $message); 18 | } 19 | 20 | public static function assertAttributeEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void { 21 | $reflectionProperty = new \ReflectionProperty($actualClassOrObject, $actualAttributeName); 22 | $reflectionProperty->setAccessible(true); 23 | 24 | static::assertSame($expected, $reflectionProperty->getValue($actualClassOrObject), $message); 25 | } 26 | } 27 | --------------------------------------------------------------------------------