Skip to content

Commit

Permalink
Updated documentation
Browse files Browse the repository at this point in the history
Signed-off-by: Eric Richer [email protected] <[email protected]>
  • Loading branch information
visto9259 committed Jul 11, 2024
1 parent e146b1c commit d69a229
Show file tree
Hide file tree
Showing 15 changed files with 626 additions and 49 deletions.
4 changes: 2 additions & 2 deletions docs/blog/2024-04-11-New-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
slug: new-documentation
title: New documentation
authors: [ericr]
tags: [laminas, PHP, LmcUser, authentication, LM-Commons]
tags: [laminas, PHP, LmcRbac, authorization, LM-Commons]
---
This the new documentation site dedicated to the LmcUser module.
This the new documentation site dedicated to the LmcRbac module.

There are no changes to the code, just improvements in the documentation.
144 changes: 144 additions & 0 deletions docs/docs/assertions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
sidebar_label: Dynamic Assertions
sidebar_position: 6
title: 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](authorization-service#reference), 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:

```php
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
<?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
<?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
<?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
<?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.

33 changes: 33 additions & 0 deletions docs/docs/authorization-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
sidebar_label: Authorization service
sidebar_position: 5
title: Authorization Service
---

### Usage

The Authorization service can be retrieved from the service manager using the name
`LmcRbac\Service\AuthorizationServiceInterface` and injected into your code:

```php
<?php
/** @var \Psr\Container\ContainerInterface $container */
$authorizationService = $container->get(LmcRbac\Service\AuthorizationServiceInterface::class);

```
### Reference

`LmcRbac\Service\AuthorizationServiceInterface` defines the following method:

`isGranted(?IdentityInterface $identity, string $permission, $context = null): bool`

| Parameter | Description |
|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `$identity` | The identity whose roles to checks. <br/>If `$identity` is null, then the `guest` is used. <br/>The `guest` role is definable via configuration and defaults to `'guest'`. |
| `$permission` | The permission to check against |
| `$context` | A context that will be passed to dynamic assertions that are defined for the permission |

More on dynamic assertions can be found in the [Assertions](assertions.md) section.

More on the `guest` role can be found in the [Configuration](configuration.md) section.

44 changes: 44 additions & 0 deletions docs/docs/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
sidebar_label: Concepts
sidebar_position: 2
title: Concepts
---

[Role-Based Access Control (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control)
is an approach to restricting system access to authorized users by putting emphasis
on roles and their permissions.

In the RBAC model:

- an **identity** has one of more roles.
- a **role** has one of more permissions.
- a **permission** is typically an action like "read", "write", "delete".
- a **role** can have **child roles** thus providing a hierarchy of roles where a role will inherit the permissions of all its child roles.

## Authorization

An identity will be authorized to perform an action, such as accessing a resource, if it is granted
the permission that controls the execution of the action.

For example, deleting an item could be restricted to identities that have at least one role that has the
`item.delete` permission. This could be implemented by defining a `member` role that has the `item.delete` and assigning
this role of an authenticated user.

## Dynamic Assertions

In some cases, just checking if the identity has the `item.delete` permission is not enough.
It would also be necessary to check, for example, that the `item` belongs to the identity. Dynamic assertion allow
to specify some extra checks before granting access to perform an action such as, in this case, being the owner of the
resource.

## Identities

An identity is typically provided by an authentication process within the application.

Authentication is not in the scope of `LmcRbac` and it is assumed that an identity entity providing assigned roles
is available when using the authorization service. If no identity is available, as it would be the case when no user is "logged in",
then a guest role is assumed.




18 changes: 18 additions & 0 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
sidebar_label: Configuration
sidebar_position: 7
title: Configuring LmcRbac
---

LmcRbac is configured via the `lmc_rbac` key in the application config.

This is typically achieved by creating
a `config/autoload/lmcrbac.global.php` file. A sample configuration file is provided in the `config/` folder.

## Reference

| Key | Description |
|--|------------------------------------------------------------------------------------------------------------------------------------------------|
| `guest_role` | Defines the name of the `guest` role when no identity exists. <br/>Defaults to `'guest'`. |
| `assertion_map` | Defines the dynamic assertions that are associated to permissions.<br/>Defaults to `[]`.<br/>See the [Dynamic Assertions](assertions) section. |
| `role_provider` | Defines the role provider.<br/>Defaults to `[]`<br/>See the [Role Providers](role-providers) section. |
34 changes: 34 additions & 0 deletions docs/docs/gettingstarted.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
sidebar_label: Getting Started
sidebar_position: 1
title: Get started
---
## Requirements

- PHP 7.3 or higher

:::warning
The code is continuously tested against PHP 8.1 and higher only. There is no warranty that it will work for PHP 8.0 and lower.
:::

## Installation

LmcRbac only officially supports installation through Composer.

Install the module:

```sh
$ composer require lm-commons/lmc-rbac "~1.0"
```

You will be prompted by the `laminas-component-installer` plugin to inject LM-Commons\LmcRbac.

:::note
**Manual installation:**

Enable the module by adding `LmcRbac` key to your `application.config.php` or `modules.config.php` file for Laminas MVC
applications, or to the `config/config.php` file for Mezzio applications.
:::

Customize the module by copy-pasting
the `lmcrbac.global.php` file to your `config/autoload` folder.
26 changes: 0 additions & 26 deletions docs/docs/installation.md

This file was deleted.

15 changes: 0 additions & 15 deletions docs/docs/introduction.md

This file was deleted.

22 changes: 22 additions & 0 deletions docs/docs/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
sidebar_label: Migration Guide
sidebar_position: 8
title: Migration Guide
---

## Migrating from ZF-Commons RBAC v3

The ZF-Commons Rbac was created for the Zend Framework. When the Zend Framework was migrated to
the Laminas project, the LM-Commons organization was created to provide components formerly provided by ZF-Commons.

When ZfcRbac was moved to LM-Commons, it was split into two repositories:

- [LmcRbacMvc](https://github.com/LM-Commons/LmcRbacMvc) contains the old version 2 of ZfcRbac.
- LmcRbac contains the version 3 of ZfcRbac, which was only released as v3.alpha.1.

To upgrade

- Uninstall `zf-commons/zfc-rbac:3.0.0-alpha.1`.
- Install `lm-commons/lmc-rbac:~1.0`
- Change `zfc-rbac.global.php` to `lmcrbac.global.php` and update the key `zfc_rbac` to `lmc_rbac`.
- Review your code for usages of the `ZfcRbac/*` namespace to `LmcRbac/*` namespace.
Loading

0 comments on commit d69a229

Please sign in to comment.