-
Notifications
You must be signed in to change notification settings - Fork 111
Added ability to set multiple assertions and their condition for permissions #320
base: master
Are you sure you want to change the base?
Changes from all commits
7d5795e
9b5d507
01e35ba
b06275f
0a3e9a7
d2a7e27
8c6a9c3
311b942
d9a86ad
1a30f06
c695e41
47e17f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
namespace ZfcRbac\Assertion; | ||
|
||
use ZfcRbac\Exception\InvalidArgumentException; | ||
use ZfcRbac\Service\AuthorizationService; | ||
|
||
/** | ||
* Assertion set to hold and process multiple assertions | ||
* | ||
* @author David Havl | ||
* @licence MIT | ||
*/ | ||
class AssertionSet implements AssertionInterface | ||
{ | ||
/** | ||
* Condition constants | ||
*/ | ||
const CONDITION_OR = 'OR'; | ||
const CONDITION_AND = 'AND'; | ||
|
||
/** | ||
* @var $assertions array | ||
*/ | ||
protected $assertions = []; | ||
|
||
/** | ||
* @var $condition string | ||
*/ | ||
protected $condition = AssertionSet::CONDITION_AND; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param array|AssertionInterface[] $assertions An array of assertions. | ||
*/ | ||
public function __construct(array $assertions = array()) | ||
{ | ||
$this->assertions = []; | ||
|
||
// if definition contains condition, set it. | ||
if (isset($assertions['condition'])) { | ||
if ($assertions['condition'] != AssertionSet::CONDITION_AND | ||
&& $assertions['condition'] != AssertionSet::CONDITION_OR) { | ||
throw new InvalidArgumentException('Invalid assertion condition given.'); | ||
} | ||
$this->condition = $assertions['condition']; | ||
} | ||
// if there are multiple assertions under a key 'assertions', get them. | ||
if (isset($assertions['assertions']) && is_array($assertions['assertions'])) { | ||
$assertions = $assertions['assertions']; | ||
} | ||
// set each assertion | ||
foreach ($assertions as $name => $assertion) { | ||
if (is_int($name)) { | ||
$this->assertions[] = $assertion; | ||
} else { | ||
$this->assertions[$name] = $assertion; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Check if assertions are successful | ||
* | ||
* @param AuthorizationService $authorizationService | ||
* @param mixed $context | ||
* @return bool | ||
*/ | ||
public function assert(AuthorizationService $authorizationService, $context = null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe not logical but it's possible to have zero assertions here then maybe return true by default or throw exception? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An empty assertion is not logical indeed and should either return FALSE or an exception. Better to have defensive defaults. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Thanx. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
if (empty($this->assertions)) { | ||
return true; | ||
} | ||
|
||
if (AssertionSet::CONDITION_AND === $this->condition) { | ||
foreach ($this->assertions as $assertion) { | ||
if (!$assertion->assert($authorizationService, $context)) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
if (AssertionSet::CONDITION_OR === $this->condition) { | ||
foreach ($this->assertions as $assertion) { | ||
if ($assertion->assert($authorizationService, $context)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
use Rbac\Permission\PermissionInterface; | ||
use ZfcRbac\Assertion\AssertionPluginManager; | ||
use ZfcRbac\Assertion\AssertionInterface; | ||
use ZfcRbac\Assertion\AssertionSet; | ||
use ZfcRbac\Exception; | ||
use ZfcRbac\Identity\IdentityInterface; | ||
|
||
|
@@ -72,7 +73,7 @@ public function __construct(Rbac $rbac, RoleService $roleService, AssertionPlugi | |
* Set an assertion | ||
* | ||
* @param string|PermissionInterface $permission | ||
* @param string|callable|AssertionInterface $assertion | ||
* @param string|callable|array|AssertionInterface $assertion | ||
* @return void | ||
*/ | ||
public function setAssertion($permission, $assertion) | ||
|
@@ -139,8 +140,8 @@ public function isGranted($permission, $context = null) | |
} | ||
|
||
/** | ||
* @param string|callable|AssertionInterface $assertion | ||
* @param mixed $context | ||
* @param string|callable|array|AssertionInterface $assertion | ||
* @param mixed $context | ||
* @return bool | ||
* @throws Exception\InvalidArgumentException If an invalid assertion is passed | ||
*/ | ||
|
@@ -150,9 +151,26 @@ protected function assert($assertion, $context = null) | |
return $assertion($this, $context); | ||
} elseif ($assertion instanceof AssertionInterface) { | ||
return $assertion->assert($this, $context); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why remove this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now back, you are right, it makes it more performant to have the retrieval only when it's called/needed. |
||
} elseif (is_string($assertion)) { | ||
} elseif (is_string($assertion)) { // retrieve an actual instance from assertion plugin manager | ||
$assertion = $this->assertionPluginManager->get($assertion); | ||
|
||
return $assertion->assert($this, $context); | ||
} elseif (is_array($assertion)) { // else if multiple assertion definition, create assertion set. | ||
// move assertion definition under a key 'assertions'. | ||
if (!isset($assertion['assertions'])) { | ||
$assertion['assertions'] = (array)$assertion; | ||
} | ||
// convert to an array | ||
if (!is_array($assertion['assertions'])) { | ||
$assertion['assertions'] = (array)$assertion['assertions']; | ||
} | ||
// retrieve an actual instance from assertion plugin manager if necessary | ||
foreach ($assertion['assertions'] as $key => $value) { | ||
if (is_string($value)) { | ||
$assertion['assertions'][$key] = $this->assertionPluginManager->get($value); | ||
} | ||
} | ||
// create assertion set | ||
$assertion = new AssertionSet($assertion); | ||
return $assertion->assert($this, $context); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe add this: elseif (is_array($assertion)) {
$assertionSet = new AssertionSet($assertion, $this->assertionPluginManager);
return $assertionSet->assert($this, $context);
} see my above comments why |
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's mark final