From 5adacc8dd7c1cca2313f5e8b23bf2d841cdf60c3 Mon Sep 17 00:00:00 2001 From: bidi Date: Thu, 11 Apr 2024 16:13:45 +0300 Subject: [PATCH 1/2] updated docs, workflows, security --- .github/workflows/continuous-integration.yml | 11 +++ .github/workflows/cs-tests.yml | 47 ------------- .github/workflows/docs-build.yml | 16 +++++ .github/workflows/static-analysis.yml | 47 ------------- .github/workflows/unit-tests.yml | 47 ------------- README.md | 55 +++++++-------- SECURITY.md | 40 +++++++++++ docs/book/index.md | 1 + docs/book/v3/configuration.md | 74 ++++++++++++++++++++ docs/book/v3/customization.md | 25 +++++++ docs/book/v3/installation.md | 7 ++ docs/book/v3/usage.md | 19 +++++ mkdocs.yml | 19 +++++ 13 files changed, 237 insertions(+), 171 deletions(-) create mode 100644 .github/workflows/continuous-integration.yml delete mode 100644 .github/workflows/cs-tests.yml create mode 100644 .github/workflows/docs-build.yml delete mode 100644 .github/workflows/static-analysis.yml delete mode 100644 .github/workflows/unit-tests.yml create mode 100644 SECURITY.md create mode 100644 docs/book/index.md create mode 100644 docs/book/v3/configuration.md create mode 100644 docs/book/v3/customization.md create mode 100644 docs/book/v3/installation.md create mode 100644 docs/book/v3/usage.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..26c5802 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,11 @@ +name: "Continuous Integration" + +on: + pull_request: + push: + branches: + tags: + +jobs: + ci: + uses: laminas/workflow-continuous-integration/.github/workflows/continuous-integration.yml@1.x diff --git a/.github/workflows/cs-tests.yml b/.github/workflows/cs-tests.yml deleted file mode 100644 index e8bbade..0000000 --- a/.github/workflows/cs-tests.yml +++ /dev/null @@ -1,47 +0,0 @@ -on: - - push - -name: Run phpcs checks - -jobs: - mutation: - name: PHP ${{ matrix.php }}-${{ matrix.os }} - - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: - - ubuntu-latest - - php: - - "8.1" - - "8.2" - - "8.3" - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "${{ matrix.php }}" - tools: composer:v2, cs2pr - coverage: none - - - name: Determine composer cache directory - run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV - - - name: Cache dependencies installed with composer - uses: actions/cache@v3 - with: - path: ${{ env.COMPOSER_CACHE_DIR }} - key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: | - php${{ matrix.php }}-composer- - - name: Install dependencies with composer - run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - - name: Run phpcs checks - run: vendor/bin/phpcs diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml new file mode 100644 index 0000000..1a7aa24 --- /dev/null +++ b/.github/workflows/docs-build.yml @@ -0,0 +1,16 @@ +name: docs-build + +on: + release: + types: [published] + workflow_dispatch: + +jobs: + build-deploy: + runs-on: ubuntu-latest + steps: + - name: Build Docs + uses: dotkernel/documentation-theme/github-actions/docs@main + env: + DEPLOY_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml deleted file mode 100644 index 6f7452d..0000000 --- a/.github/workflows/static-analysis.yml +++ /dev/null @@ -1,47 +0,0 @@ -on: - - push - -name: Run static analysis - -jobs: - mutation: - name: PHP ${{ matrix.php }}-${{ matrix.os }} - - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: - - ubuntu-latest - - php: - - "8.1" - - "8.2" - - "8.3" - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "${{ matrix.php }}" - tools: composer:v2, cs2pr - coverage: none - - - name: Determine composer cache directory - run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV - - - name: Cache dependencies installed with composer - uses: actions/cache@v3 - with: - path: ${{ env.COMPOSER_CACHE_DIR }} - key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: | - php${{ matrix.php }}-composer- - - name: Install dependencies with composer - run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - - name: Run static analysis - run: vendor/bin/psalm --no-cache --output-format=github --show-info=false --threads=4 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml deleted file mode 100644 index 8f6f990..0000000 --- a/.github/workflows/unit-tests.yml +++ /dev/null @@ -1,47 +0,0 @@ -on: - - push - -name: Run PHPUnit tests - -jobs: - mutation: - name: PHP ${{ matrix.php }}-${{ matrix.os }} - - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: - - ubuntu-latest - - php: - - "8.1" - - "8.2" - - "8.3" - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "${{ matrix.php }}" - tools: composer:v2, cs2pr - coverage: none - - - name: Determine composer cache directory - run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV - - - name: Cache dependencies installed with composer - uses: actions/cache@v3 - with: - path: ${{ env.COMPOSER_CACHE_DIR }} - key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: | - php${{ matrix.php }}-composer- - - name: Install dependencies with composer - run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - - name: Run PHPUnit tests - run: vendor/bin/phpunit --colors=always diff --git a/README.md b/README.md index 93cd84b..fb782ad 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # 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. -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) @@ -12,7 +12,7 @@ Each role can have one or multiple permissions/privileges assigned. When decidin [![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) -[![Build Static](https://github.com/dotkernel/dot-rbac/actions/workflows/static-analysis.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/static-analysis.yml) +[![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) [![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) @@ -27,15 +27,14 @@ $ 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 some sane defaults config values for this module. +Create a configuration file in your `config/autoload` folder and change the module options as needed. -Create a configuration file in your `config/autoload` folder and change module options as desired +### authorization.global.php -##### authorization.global.php ```php 'dot_authorization' => [ //name of the guest role to use if no identity is provided @@ -102,42 +101,39 @@ Create a configuration file in your `config/autoload` folder and change module o ## Usage -Whenever you need to check if someone is authorized to take some actions, inject the `AuthorizationInterface::class` service into your class. -Using it is simple as calling the isGranted method with the correct parameters. There are 2 ways to call the isGranted method -```php +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, specifiy which roles do you want to check +### 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, this will check if the authenticated identity has permission -$isGranted = $this->authorizationService->isGranted($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); ``` ## Customize the IdentityProvider -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. +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. ## 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 is matching with 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. +An assertion has to implement the `AssertionInterface` and be registered in the `AssertionPluginManager`. This interface defines the following method @@ -145,5 +141,4 @@ 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. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..26ee1b7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,40 @@ +# Security Policy + +## 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: | | + + +## Reporting Potential Security Issues + +If you have encountered a potential security vulnerability in this project, +please report it to us at . We will work with you to +verify the vulnerability and patch it. + +When reporting issues, please provide the following information: + +- Component(s) affected +- A description indicating how to reproduce the issue +- A summary of the security vulnerability and impact + +We request that you contact us via the email address above and give the +project contributors a chance to resolve the vulnerability and issue a new +release prior to any public exposure; this helps protect the project's +users, and provides them with a chance to upgrade and/or update in order to +protect their applications. + + +## Policy + +If we verify a reported security vulnerability, our policy is: + +- We will patch the current release branch, as well as the immediate prior minor + release branch. + +- After patching the release branches, we will immediately issue new security + fix releases for each patched release branch. + diff --git a/docs/book/index.md b/docs/book/index.md new file mode 100644 index 0000000..ae42a26 --- /dev/null +++ b/docs/book/index.md @@ -0,0 +1 @@ +../../README.md diff --git a/docs/book/v3/configuration.md b/docs/book/v3/configuration.md new file mode 100644 index 0000000..d7a5918 --- /dev/null +++ b/docs/book/v3/configuration.md @@ -0,0 +1,74 @@ +# 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' => [] + ] + ] +] +``` diff --git a/docs/book/v3/customization.md b/docs/book/v3/customization.md new file mode 100644 index 0000000..6f9dee6 --- /dev/null +++ b/docs/book/v3/customization.md @@ -0,0 +1,25 @@ +# Customization + +## Customize the IdentityProvider + +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. + +## 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. + +## 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. + +An assertion has to implement the `AssertionInterface` and be registered in the `AssertionPluginManager`. + +This interface defines the following method + +```php +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. diff --git a/docs/book/v3/installation.md b/docs/book/v3/installation.md new file mode 100644 index 0000000..4e3e267 --- /dev/null +++ b/docs/book/v3/installation.md @@ -0,0 +1,7 @@ +# Installation + +Run the following command in your project root directory + +```bash +$ composer require dotkernel/dot-rbac +``` diff --git a/docs/book/v3/usage.md b/docs/book/v3/usage.md new file mode 100644 index 0000000..2717b52 --- /dev/null +++ b/docs/book/v3/usage.md @@ -0,0 +1,19 @@ +# 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. + +## First Method + +Specify which roles you want to check. + +```php +$isGranted = $this->authorizationService->isGranted($permission, $roles); +``` + +## 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. + +```php +$isGranted = $this->authorizationService->isGranted($permission); +``` diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..c089a6a --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,19 @@ +docs_dir: docs/book +site_dir: docs/html +extra: + project: Packages + current_version: v3 + versions: + - v3 +nav: + - Home: index.md + - v3: + - Installation: v3/installation.md + - Configuration: v3/configuration.md + - Usage: v3/usage.md + - Customization: v3/customization.md +site_name: dot-rbac +site_description: "The rbac authorization service decides if the authenticated identity or guest has access to certain parts of the application" +repo_url: "https://github.com/dotkernel/dot-rbac" +plugins: + - search From 9c59c58298c1f2b8e2b1c238a02d9cae5278d9d0 Mon Sep 17 00:00:00 2001 From: bidi47 Date: Thu, 11 Apr 2024 21:48:28 +0300 Subject: [PATCH 2/2] code review Co-authored-by: Alex Karajos --- docs/book/v3/installation.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/book/v3/installation.md b/docs/book/v3/installation.md index 4e3e267..cf86a41 100644 --- a/docs/book/v3/installation.md +++ b/docs/book/v3/installation.md @@ -2,6 +2,4 @@ Run the following command in your project root directory -```bash -$ composer require dotkernel/dot-rbac -``` + composer require dotkernel/dot-rbac