Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/docs/Guides/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Guides",
"position": 7
}
4 changes: 4 additions & 0 deletions docs/docs/Upgrading/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Upgrading",
"position": 8
}
10 changes: 9 additions & 1 deletion docs/docs/authorization-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ title: Authorization Service

### Usage

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

```php
Expand Down Expand Up @@ -163,4 +163,12 @@ class Module
}
```

## Authorization Exception

LmcRbac provides a `Lmc\Rbac\Exception\UnauthorizedException` exception class that can be thrown by a service
when authorization is denied.

This is for convenience as LmcRbac does not provide any handler for this exception
and it is expected that applications will implement the exception handler.


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

Expand All @@ -14,6 +14,6 @@ a `config/autoload/lmcrbac.global.php` file. A sample configuration file is prov
| Key | Description |
|--|------------------------------------------------------------------------------------------------------------------------------------------------|
| `guest_role` | Defines the name of the `guest` role when no identity exists. <br/>Defaults to `'guest'`. |
| `role_provider` | Defines the role provider.<br/>Defaults to `[]`<br/>See the [Role Providers](role-providers) section. |
| `role_provider` | Defines the role provider.<br/>Defaults to `[]`<br/>See the [Role Providers](roles) section. |
| `assertion_map` | Defines the dynamic assertions that are associated to permissions.<br/>Defaults to `[]`.<br/>See the [Dynamic Assertions](assertions) section. |
| `assertion_manager` | Provides a configuration for the Assertion Plugin Manager.<br/> Defaults to `[]`.<br/>See the [Dynamic Assertion](assertions.md) section. |
| `assertion_manager` | Provides a configuration for the Assertion Plugin Manager.<br/> Defaults to `[]`.<br/>See the [Dynamic Assertion](assertions.md) section. |
9 changes: 5 additions & 4 deletions docs/docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LmcRbac extends the components provided by [laminas-permissions-rbac](https://gi
LmcRbac can be used in Laminas MVC and in Mezzio applications.

:::tip
If you are upgrading from LmcRbac v1 or from zfc-rbac v3, please read the [Upgrading section](Upgrading/to-v2.md)
If you are upgrading from LmcRbac v1 or from zfc-rbac v3, please read the [Upgrading section](upgrading/to-v2)
:::

## Concepts
Expand Down Expand Up @@ -63,7 +63,8 @@ Install the module:
$ composer require lm-commons/lmc-rbac
```

You will be prompted by the Laminas Component Installer plugin to inject LM-Commons\LmcRbac.
You will be prompted by the Laminas Component Installer plugin to inject the package
into the application's configuration.

:::note
**Manual installation:**
Expand All @@ -82,7 +83,7 @@ By default, no roles and no permissions are defined.

Roles and permissions are defined by a Role Provider. `LmcRbac` ships with two roles providers:
- a simple `InMemoryRoleProvider` that uses an associative array to define roles and their permission. This is the default.
- a `ObjectRepositoyRoleProvider` that is based on Doctrine ORM.
- a `ObjectRepositoyRoleProvider` that is based on Doctrine ORM. (*Deprecated since v2.3*)

To quickly get started, let's use the `InMemoryRoleProvider` role provider.

Expand Down Expand Up @@ -118,7 +119,7 @@ a child and with its own permission. If the hierarchy is flattened:

## Basic authorization

The authorization service can get retrieved from the service manager container and used to check if a permission
The authorization service can get retrieved from the container and used to check if a permission
is granted to an identity:

```php
Expand Down
87 changes: 87 additions & 0 deletions docs/docs/roles/custom-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: Building Custom Providers
sidebar_position: 4
---

To create a custom role provider, you first need to create a class that implements the
`Lmc\Rbac\Role\RoleProviderInterface` interface.

Then, you need to add it to the role provider manager:

```php
return [
'lmc_rbac' => [
'role_provider' => [
MyCustomRoleProvider::class => [
// Options
],
],
],
];
```
And the role provider is created using the service manager:
```php
return [
'service_manager' => [
'factories' => [
MyCustomRoleProvider::class => MyCustomRoleProviderFactory::class,
],
],
];
```
### Role Factory

A Role Factory is a factory that can be used to create basic role instances for a role returned by the role provider.

LmcRbac provide a convenience interface `RoleFactoryInterface` that can be used by a role provider to create roles.

```php
namespace Lmc\Rbac\Role;

use Laminas\Permissions\Rbac\RoleInterface;

interface RoleFactoryInterface
{
public function createRole(string $roleName): RoleInterface;
}
```

LmcRbac does not provide an implementation for this interface and it is left to the custom role provider to implement
the factory.

Therefore, in your application, you need to define a factory that returns a factory
in your container config. For example:

```php title="src/MyRoleFactory.php"
<?php

namespace MyApp;

use Lmc\Rbac\Role\RoleFactoryInterface;
use Laminas\Permissions\Rbac\Role;
use Laminas\Permissions\Rbac\RoleInterface;

class MyRoleFactory implements RoleFactoryInterface
{
public function createRole(string $roleName): RoleInterface {
{
return new Role($roleName)
}
}
```

```php title="/config/autoload/config.php"
return [
'dependencies' => [
'factories' => [
Lmc\Rbac\Role\RoleProviderInterface::class => function (ContainerInterface $container) {
return new MyApp\MyRoleFactory();
}
],
],
];
```




75 changes: 75 additions & 0 deletions docs/docs/roles/in-memory-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: Lmc\Rbac\Role\InMemoryRoleProvider
sidebar_position: 1
---

### `Lmc\Rbac\Role\InMemoryRoleProvider` (built-in)

This built-in provider is ideal for small/medium sites with few roles/permissions. All the data is specified in a simple associative array in a
PHP file.

Here is an example of the format you need to use:

```php
return [
'lmc_rbac' => [
'role_provider' => [
Lmc\Rbac\Role\InMemoryRoleProvider::class => [
'admin' => [
'children' => ['member'],
'permissions' => ['article.delete']
],
'member' => [
'children' => ['guest'],
'permissions' => ['article.edit', 'article.archive']
],
'guest' => [
'permissions' => ['article.read']
],
],
],
],
];
```

The `children` and `permissions` subkeys are entirely optional. Internally, the `Lmc\Rbac\Role\InMemoryRoleProvider` creates
`Laminas\Permissions\Rbac\Role` objects with children, if any.

If you are more confident with flat RBAC, the previous config can be re-written to remove any inheritence between roles:

```php
return [
'lmc_rbac' => [
'role_provider' => [
Lmc\Rbac\Role\InMemoryRoleProvider::class => [
'admin' => [
'permissions' => [
'article.delete',
'article.edit',
'article.archive',
'article.read'
]
],
'member' => [
'permissions' => [
'article.edit',
'article.archive',
'article.read'
]
],
'guest' => [
'permissions' => ['article.read']
]
]
]
]
];
```

### Handling non existent roles

If the list of roles names to retrieve using this provider includes roles that are
not defined in the provider's configuration, the role provider will create `Laminas\Permissions\Role\Role` objects
for them with no permissions.


106 changes: 106 additions & 0 deletions docs/docs/roles/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
sidebar_label: Roles, permissions and Role providers
title: Roles, Permissions and Role providers
sidebar_position: 4
---

## Roles

A role is an object that returns a list of permissions that the role has.

LmcRbac uses the Role class defined by [laminas-permissions-rbac](https://github.com/laminas/laminas-permissions-rbac). Roles
are defined using the `\Laminas\Permissions\Rbac\Role` class or by a class
implementing `\Laminas\Permissions\Rbac\RoleInterface`.

Roles can have child roles and therefore provides a hierarchy of roles where a role inherit the permissions of all its
child roles.

For example, a 'user' role may have the 'read' and 'write' permissions, and a 'admin' role
may inherit the permissions of the 'user' role plus an additional 'delete' role. In this structure,
the 'admin' role will have 'user' as its child role.


:::tip[Flat roles]
Previous version of LmcRbac used to make a distinction between flat roles and hierarchical roles.
A flat role is just a simplification of a hierarchical role, i.e. a hierarchical role without children.

In `laminas-permissions-rbac`, roles are hierarchical.
:::

## Permissions

A permission in `laminas-permissions-rbac` is simply a string that represents the permission such as 'read', 'write' or 'delete'.
But it can also be more precise like 'article.read' or 'article.write'.

A permission can also be an object as long as it can be cast to a string. This could be the
case, for example, when permissions are stored in a database where they could
also have a identifier and a description.

:::tip
An object can be cast to a string by implementing the `__toString()` method.
:::

## Role Service

LmcRbac provides a role service that will use a role providers to fetch the
roles and their permissions associated with a given identity.

It can be retrieved from the container be requesting the `Lmc\Rbac\Service\RoleServiceInterface` service.

`Lmc\Rbac\Service\RoleServiceInterface` defines the following method:

- `getIdentityRoles(object|null $identity = null): iterable`

| Parameter | Description |
|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `$identity` | The identity whose roles to retrieve. <br/>If `$identity` is null, then the `guest` is used. <br/>The `guest` role is definable via configuration and defaults to `'guest'`. |

:::warning
The `$identity` parameter must be an object that either implements the `Lmc\Rbac\Identity\IdentityInterface`
interface or has a `getRoles()` method that returns an array of strings or an array of objects
implementing the `Laminas\Permissions\Rbac\RoleInterface` interface.


:::


## Role Providers
A role provider is an object that returns a list of roles. A role provider must implement the
`Lmc\Rbac\Role\RoleProviderInterface` interface. The only required method is `getRoles`, and must return an array
of `Laminas\Permissions\Rbac\RoleInterface` objects.

```php
use Laminas\Permissions\Rbac\RoleInterface;

interface RoleProviderInterface
{
/**
* Get the roles from the provider
*
* @param string[] $roleNames
* @return RoleInterface[]
*/
public function getRoles(iterable $roleNames): iterable;
}
```

Roles can come from one of many sources: in memory, from a file, from a database, etc. However, you can specify only one role provider per application.

LmcRbac comes with two built-in role providers:
- [`Lmc\Rbac\Role\InMemoryRoleProvider`](/docs/roles/in-memory-provider)
- [`Lmc\Rbac\Role\ObjectRepositoryRoleProvider`](/docs/roles/object-repository-role-provider). **(deprecated as of v2.3)**

A role provider must be added to the `role_provider` subkey in the
configuration file. For example:

```php
return [
'lmc_rbac' => [
'role_provider' => [
Lmc\Rbac\Role\InMemoryRoleProvider::class => [
// configuration
],
]
]
];
```
Loading