Skip to main content
Version: 1.4

Dynamic Assertions

Dynamic Assertions provide the capability to perform extra validations when the authorization service's isGranted() method is called.

As described in Authorization Service, it is possible to pass a context to the isGranted() method. This context is then passed to dynamic assertion functions. This context can be any object type.

You can define dynamic assertion functions and assigned them to permission via configuration.

Defining a dynamic assertion function

A dynamic assertion must implement the LmcRbac\Assertion\AssertionInterace which defines only one method:

public function assert(
string $permission,
IdentityInterface $identity = null,
$context = null
): bool

The assertion returns true when the access is granted, false otherwise.

A simple assertion could be to check that user represented by $identity, for the permission represented by $permission owns the resource represented by $context.

<?php

class MyAssertion implements \LmcRbac\Assertion\AssertionInterface
{
public function assert(string $permission, IdentityInterface $identity = null, $context = null): bool
{
// for 'edit' permission
if ('edit' === $permission) {
/** @var MyObjectClass $context */
return $context->getOwnerId() === $identity->getId();
}
// This should not happen since this assertion should only be
// called when the 'edit' permission is checked
return true;
}
}

Configuring Assertions

Dynamic assertions are configured in LmcRbac via an assertion map defined in the LmcRbac configuration where assertions are associated with permissions.

The assertion_map key in the configuration is used to define the assertion map. If an assertion needs to be created via a factory, use the assertion_manager config key. The Assertion Manager is a standard plugin manager and its configuration should be a service manager configuration array.

<?php

return [
'lmc_rbac' => [
/* the rest of the file */
'assertion_map' => [
'edit' => \My\Namespace\MyAssertion::class,
],
'assertion_manager' => [
'factories' => [
\My\Namespace\MyAssertion::class => \Laminas\ServiceManager\Factory\InvokableFactory::class
],
],
],
];

It is also possible to configure an assertion using a callable instead of a class:

<?php

return [
'lmc_rbac' => [
/* the rest of the file */
'assertion_map' => [
'edit' => function assert(string $permission, IdentityInterface $identity = null, $context = null): bool
{
// for 'edit' permission
if ('edit' === $permission) {
/** @var MyObjectClass $context */
return $context->getOwnerId() === $identity->getId();
}
// This should not happen since this assertion should only be
// called when the 'edit' permission is checked
return true;
},
],
],
];

Dynamic Assertion sets

LmcRbac supports the creation of dynamic assertion sets where multiple assertions can be combined using 'and/or' logic. Assertion sets are configured by associating an array of assertions to a permission in the assertion map:

<?php

return [
'lmc_rbac' => [
/* the rest of the file */
'assertion_map' => [
'edit' => [
\My\Namespace\AssertionA::class,
\My\Namespace\AssertionB::class,
],
'read' => [
'condition' => \LmcRbac\Assertion\AssertionSet::CONDITION_OR,
\My\Namespace\AssertionC::class,
\My\Namespace\AssertionD::class,
],
'delete' => [
'condition' => \LmcRbac\Assertion\AssertionSet::CONDITION_OR,
\My\Namespace\AssertionE::class,
[
'condition' => \LmcRbac\Assertion\AssertionSet::CONDITION_AND,
\My\Namespace\AssertionF::class,
\My\Namespace\AssertionC::class,
],
],
/** the rest of the file */
],
];

By default, an assertion set combines assertions using a 'and' condition. This is demonstrated by the map associated with the 'edit' permission above.

It is possible to combine assertions using a 'or' condition by adding a condition equal to AssertionSet::CONDITION_OR to the assertion set as demonstrated by the map associated with the 'read' permission above.

Furthermore, it is possible to nest assertion sets in order to create more complex logic as demonstrated by the map associated with the 'delete' permission above.

The default logic is to combine assertions using 'and' logic but this can be explicitly set as shown above for 'delete' permission.