Skip to content

Commit

Permalink
Merge pull request #27 from dotkernel/issue-26
Browse files Browse the repository at this point in the history
Issue #26: Added support for `laminas/laminas-servicemanager:4.x`
  • Loading branch information
alexmerlin authored Jan 23, 2025
2 parents 1bf7e94 + 208bc4b commit 4eb9be2
Show file tree
Hide file tree
Showing 21 changed files with 320 additions and 58 deletions.
6 changes: 6 additions & 0 deletions .laminas-ci.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"ignore_php_platform_requirements": {
"8.4": true
},
"backwardCompatibilityCheck": true
}
53 changes: 33 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,40 @@
# dot-rbac

Rbac authorization model implements [dot-authorization](https://github.com/dotkernel/dot-authorization)'s `AuthorizationInterface`. An authorization service is responsible for deciding if the authenticated identity or guest has access to certain parts of the application.
Rbac authorization model implements [dot-authorization](https://github.com/dotkernel/dot-authorization)'s `AuthorizationInterface`.
An authorization service is responsible for deciding if the authenticated identity or guest has access to certain parts of the application.

The RBAC model defines roles that can be assigned to users. The authorization is done on a role basis, not user basis as in ACL. Each role can have one or multiple permissions/privileges assigned. When deciding if a user is authorized, the requested permission is checked in all user roles and if at least one role has that permission, access is granted.
The RBAC model defines roles that can be assigned to users.
The authorization is done on a role basis, not user basis as in ACL.
Each role can have one or multiple permissions/privileges assigned.
When deciding if a user is authorized, the requested permission is checked in all user roles and if at least one role has that permission, access is granted.

![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-rbac)
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.5.2)
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/4.0.0)

[![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/issues)
[![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/network)
[![GitHub stars](https://img.shields.io/github/stars/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/stargazers)
[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/blob/3.0/LICENSE.md)
[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/blob/4.0/LICENSE.md)

[![Build Static](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml)
[![Build Static](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml)
[![codecov](https://codecov.io/gh/dotkernel/dot-rbac/graph/badge.svg?token=GCK6C92N83)](https://codecov.io/gh/dotkernel/dot-rbac)

[![SymfonyInsight](https://insight.symfony.com/projects/ce0cfbb2-7e97-427b-b394-531ff5be13d6/big.svg)](https://insight.symfony.com/projects/ce0cfbb2-7e97-427b-b394-531ff5be13d6)

## Installation

Run the following command in your project root directory
Run the following command in your project root directory:

```bash
$ composer require dotkernel/dot-rbac
```shell
composer require dotkernel/dot-rbac
```

## Configuration

Even if the authorization service can be programmatically configured, we recommend using the configuration based approach. We further describe how to configure the module, using configuration file.
Even if the authorization service can be programmatically configured, we recommend using the configuration based approach.
We further describe how to configure the module, using configuration file.

First of all, you should enable the module in your application by merging this package's `ConfigProvider` with your application's config. This ensures that all dependencies required by this module are registered in the service manager. It also defines default config values for this module.
First of all, you should enable the module in your application by merging this package's `ConfigProvider` with your application's config.
This ensures that all dependencies required by this module are registered in the service manager.
It also defines default config values for this module.

Create a configuration file in your `config/autoload` folder and change the module options as needed.

Expand Down Expand Up @@ -101,19 +106,21 @@ Create a configuration file in your `config/autoload` folder and change the modu

## Usage

Whenever you need to check if someone is authorized to take some actions, inject the `AuthorizationInterface::class` service into your class, then call the `isGranted` method with the correct parameters. There are 2 ways to call the isGranted method.
Whenever you need to check if someone is authorized to take some actions, inject the `AuthorizationInterface::class` service into your class, then call the `isGranted` method with the correct parameters.
There are 2 ways to call the isGranted method.

### First Method
### First method

Specify which roles you want to check.

```php
$isGranted = $this->authorizationService->isGranted($permission, $roles);
```

### Second Method
### Second method

Do not specify the roles or send an empty array as the second parameter. This will check if the authenticated identity has permission.
Do not specify the roles or send an empty array as the second parameter.
This will check if the authenticated identity has permission.

```php
$isGranted = $this->authorizationService->isGranted($permission);
Expand All @@ -123,15 +130,20 @@ $isGranted = $this->authorizationService->isGranted($permission);

Whenever you request an authorization check on the authenticated identity, the identity will be provided to the `AuthorizationService` through a registered `IdentityProviderInterface` service.

This is because identity is authentication dependent, so the module lets you overwrite this service, depending on your needs. If you want to get the identity from other sources instead of the dot-authentication service, just overwrite the `IdentityProviderInterface::class` service in the service manager with your own implementation of this interface.
This is because identity is authentication dependent, so the module lets you overwrite this service, depending on your needs.
If you want to get the identity from other sources instead of the dot-authentication service, just overwrite the `IdentityProviderInterface::class` service in the service manager with your own implementation of this interface.

## Custom role providers

Write your own role provider by implementing the `RoleProviderInterface` and register it in the `RoleProviderPluginManager`. After that, you can use them in the configuration file, as described above.
Write your own role provider by implementing the `RoleProviderInterface` and register it in the `RoleProviderPluginManager`.
After that, you can use them in the configuration file, as described above.

## Creating assertions

Assertions are checked after permission granting, right before returning the authorization result. Assertions can have a last word in deciding if someone is authorized for the requested action. A good assertion example could be an edit permission, but with the restriction that it should be able to edit the item just if the `user id` matches the item's `owner id`. It is up to you to write the logic inside an assertion.
Assertions are checked after permission granting, right before returning the authorization result.
Assertions can have a last word in deciding if someone is authorized for the requested action.
A good assertion example could be an edit permission, but with the restriction that it should be able to edit the item just if the `user id` matches the item's `owner id`.
It is up to you to write the logic inside an assertion.

An assertion has to implement the `AssertionInterface` and be registered in the `AssertionPluginManager`.

Expand All @@ -141,4 +153,5 @@ This interface defines the following method
public function assert(AuthorizationInterface $authorization, $context = null);
```

The context variable can be any external data that an assertion needs in order to decide the authorization status. The assertion must return a boolean value, reflecting the assertion pass or failure status.
The context variable can be any external data that an assertion needs in order to decide the authorization status.
The assertion must return a boolean value, reflecting the assertion pass or failure status.
9 changes: 5 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
## Supported Versions


| Version | Supported | PHP Version |
|---------|--------------------|------------------------------------------------------------------------------------------------------------------|
| 3.x | :white_check_mark: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.5.2) |
| <= 2.x | :x: | |
| Version | Supported | PHP Version |
|---------|--------------------|----------------------------------------------------------------------------------------------------------|
| 4.x | :white_check_mark: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/4.0.0) |
| 3.x | :x: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.5.2) |
| <= 2.x | :x: | |


## Reporting Potential Security Issues
Expand Down
2 changes: 2 additions & 0 deletions authorization.global.php.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

return [
'dot_authorization' => [
//name of the guest role to use if no identity is provided
Expand Down
23 changes: 12 additions & 11 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"name": "dotkernel/dot-rbac",
"type": "library",
"description": "DotKernel RBAC authorization component",
"description": "Dotkernel RBAC authorization component",
"license": "MIT",
"homepage": "https://github.com/dotkernel/dot-rbac",
"keywords": [
"authorization",
"laminas",
"mezzio",
"rbac"
],
"authors": [
{
"name": "DotKernel Team",
"name": "Dotkernel Team",
"email": "[email protected]"
}
],
Expand All @@ -22,16 +22,16 @@
}
},
"require": {
"php": "~8.1.0 || ~8.2.0 || ~8.3.0",
"laminas/laminas-servicemanager": "^3.11",
"dotkernel/dot-authorization": "^3.4.1",
"laminas/laminas-stdlib": "^3.7",
"laminas/laminas-authentication": "2.16.0"
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"dotkernel/dot-authorization": "^3.6.0",
"laminas/laminas-authentication": "^2.16.0",
"laminas/laminas-servicemanager": "^4.0",
"laminas/laminas-stdlib": "^3.7"
},
"require-dev": {
"laminas/laminas-coding-standard": "^3.0",
"phpunit/phpunit": "^10.2",
"vimeo/psalm": "^5.13",
"laminas/laminas-coding-standard": "^2.5"
"vimeo/psalm": "^5.13"
},
"autoload": {
"psr-4": {
Expand All @@ -46,7 +46,8 @@
"scripts": {
"check": [
"@cs-check",
"@test"
"@test",
"@static-analysis"
],
"cs-check": "phpcs",
"cs-fix": "phpcbf",
Expand Down
1 change: 0 additions & 1 deletion docs/book/index.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/book/index.md
4 changes: 3 additions & 1 deletion docs/book/v3/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
Even if the authorization service can be programmatically configured, we recommend using the configuration based approach.
We further describe how to configure the module, using the configuration file.

First of all, you should enable the module in your application by merging this package's `ConfigProvider` with your application's config. This ensures that all dependencies required by this module are registered in the service manager. It also defines default config values for this module.
First of all, you should enable the module in your application by merging this package's `ConfigProvider` with your application's config.
This ensures that all dependencies required by this module are registered in the service manager.
It also defines default config values for this module.

Create a configuration file in your `config/autoload` folder and change the module options as needed.

Expand Down
14 changes: 10 additions & 4 deletions docs/book/v3/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@

Whenever you request an authorization check on the authenticated identity, the identity will be provided to the `AuthorizationService` through a registered `IdentityProviderInterface` service.

This is because identity is authentication dependent, so the module lets you overwrite this service, depending on your needs. If you want to get the identity from other sources instead of the dot-authentication service, just overwrite the `IdentityProviderInterface::class` service in the service manager with your own implementation of this interface.
This is because identity is authentication dependent, so the module lets you overwrite this service, depending on your needs.
If you want to get the identity from other sources instead of the dot-authentication service, just overwrite the `IdentityProviderInterface::class` service in the service manager with your own implementation of this interface.

## Custom role providers

Write your own role provider by implementing the `RoleProviderInterface` and register it in the `RoleProviderPluginManager`. After that, you can use them in the configuration file, as described above.
Write your own role provider by implementing the `RoleProviderInterface` and register it in the `RoleProviderPluginManager`.
After that, you can use them in the configuration file, as described above.

## Creating assertions

Assertions are checked after permission granting, right before returning the authorization result. Assertions can have a last word in deciding if someone is authorized for the requested action. A good assertion example could be an edit permission, but with the restriction that it should be able to edit the item just if the `user id` matches the item's `owner id`. It is up to you to write the logic inside an assertion.
Assertions are checked after permission granting, right before returning the authorization result.
Assertions can have a last word in deciding if someone is authorized for the requested action.
A good assertion example could be an edit permission, but with the restriction that it should be able to edit the item just if the `user id` matches the item's `owner id`.
It is up to you to write the logic inside an assertion.

An assertion has to implement the `AssertionInterface` and be registered in the `AssertionPluginManager`.

Expand All @@ -22,4 +27,5 @@ This interface defines the following method
public function assert(AuthorizationInterface $authorization, $context = null);
```

The context variable can be any external data that an assertion needs in order to decide the authorization status. The assertion must return a boolean value, reflecting the assertion pass or failure status.
The context variable can be any external data that an assertion needs in order to decide the authorization status.
The assertion must return a boolean value, reflecting the assertion pass or failure status.
6 changes: 4 additions & 2 deletions docs/book/v3/installation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Installation

Run the following command in your project root directory
Run the following command in your project root directory:

composer require dotkernel/dot-rbac
```shell
composer require dotkernel/dot-rbac
```
7 changes: 4 additions & 3 deletions docs/book/v3/usage.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# Usage

Whenever you need to check if someone is authorized to take some actions, inject the `AuthorizationInterface::class` service into your class, then call the `isGranted` method with the correct parameters. There are 2 ways to call the isGranted method.
Whenever you need to check if someone is authorized to take some actions, inject the `AuthorizationInterface::class` service into your class, then call the `isGranted` method with the correct parameters.
There are 2 ways to call the isGranted method.

## First Method
## First method

Specify which roles you want to check.

```php
$isGranted = $this->authorizationService->isGranted($permission, $roles);
```

## Second Method
## Second method

Do not specify the roles or send an empty array as the second parameter. This will check if the authenticated identity has permission.

Expand Down
76 changes: 76 additions & 0 deletions docs/book/v4/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Configuration

Even if the authorization service can be programmatically configured, we recommend using the configuration based approach.
We further describe how to configure the module, using the configuration file.

First of all, you should enable the module in your application by merging this package's `ConfigProvider` with your application's config.
This ensures that all dependencies required by this module are registered in the service manager.
It also defines default config values for this module.

Create a configuration file in your `config/autoload` folder and change the module options as needed.

## authorization.global.php

```php
'dot_authorization' => [
//name of the guest role to use if no identity is provided
'guest_role' => 'guest',

'role_provider_manager' => [],

//example for a flat RBAC model using the InMemoryRoleProvider
'role_provider' => [
'type' => 'InMemory',
'options' => [
'roles' => [
'admin' => [
'permissions' => [
'edit',
'delete',
//etc..
]
],
'user' => [
'permissions' => [
//...
]
]
]
],
],

//example for a hierarchical model, less to write but it can be confusing sometimes
/*'role_provider' => [
'type' => 'InMemory',
'options' => [
'roles' => [
'admin' => [
'children' => ['user'],
'permissions' => ['create', 'delete']
],
'user' => [
'children' => ['guest']
'permissions' => ['edit']
]
'guest' => [
'permissions' => ['view']
]
]
]
],*/

'assertion_manager' => [
'factories' => [
//EditAssertion::class => InvokableFactory::class,
],
],

'assertions' => [
[
'type' => EditAssertion::class,
'permissions' => ['edit'],
'options' => []
]
]
]
```
Loading

0 comments on commit 4eb9be2

Please sign in to comment.