The External Roles module integrates seamlessly with Drupal's core Access Policy API to extend role-based access control. This module allows you to assign permissions to users based on external roles, making it an ideal solution for projects that require integration with external systems or configurations.
Important Note
This module is intended for developers. It provides flexible interfaces for customization and extension through code, allowing you to define external roles and easily manage them within your business logic.
How to use?
Minimal setup
Installation
Start by installing the module via Composer and enable the module.
External roles definition
Add the following definition to the settings.php file. The array structure for this configuration is defined as follows.
$settings['external_roles'] = [
'{role}' => [
'name' => '...',
'permissions' => [
'...',
'...',
'...',
],
],
'{role}' => ...,
'{role}' => ...,
];
Assign external roles in business logic
Use the ExternalRolesUser wrapper to assign external roles to users in your business logic. The easiest way to do this is probably through hook_user_presave(). For example:
function my_module_user_presave(UserInterface $user): void {
$wrapped_user = new ExternalRolesUser($user);
$wrapped_user->addExternalRole('alpha');
$wrapped_user->addExternalRole('beta');
}
Rebuild cache
The cache requires a rebuild whenever the definition of the external roles is changed.
Advanced setup
External roles repository
The first point of extension is the external roles repository. It implements the simple ExternalRolesRepositoryInterface and can be easily replaced by a more advanced repository. Let's discuss an example where the external roles are defined in a file.
namespace Drupal\my_module;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Extension\ModuleExtensionList;
class ExternalRolesRepository implements ExternalRolesRepositoryInterface {
protected const ROLES_FILE_NAME = 'my_module.roles.yml';
protected array $definition;
public function __construct(protected ModuleExtensionList $extensions) {}
public function getPermissionsByRole(string $role): array {
return $this->loadDefinition()[$role]['permissions'] ?? [];
}
protected function loadDefinition(): array {
if (!isset($this->definition)) {
$file_contents = file_get_contents($this->extensions
->getPath('my_module') . '/'. static::ROLES_FILE_NAME) ?: '';
$this->definition = Yaml::decode($file_contents) ?? [];
}
return $this->definition;
}
}
The external roles file my_module.roles.yml could look like this.
alpha:
name: 'Alpha'
permissions: [
'access foo',
]
beta:
name: 'Beta'
permissions: [
'access foo',
'access bar',
]
Then, overwrite the external roles repository in your custom module service definition.
external_roles.repository:
class: Drupal\my_module\ExternalRolesRepository
arguments: [ '@extension.list.module']
OpenID Connect
If you are using OpenID Connect, the user info hook is a good point for assigning external roles.
function my_module_openid_connect_userinfo_save(UserInterface $account, array $context) {
// Get roles from the identity provider.
$roles = ...;
$wrapped_user = new ExternalRolesUser($account);
foreach ($roles as $role) {
// Optionally add some validation here.
if (!my_module_validate_role($role)) {
continue;
}
$wrapped_user->addExternalRole($role);
}
}
Further developer notes
- The Access Policy API heavily relies on caching to calculate the permissions efficiently. The relevant cache context is
user.external_roles, which is defined inExternalRolesCacheContext. For security reasons, a cache rebuild is required when the definition of external roles changes. - The
ExternalRolesUserwrapper can easily manage the external roles. - The external roles are saved in a user base field. The database table is
user__external_roles. - Please also consult the documentation for the Access Policy API.
Project information
Maintenance fixes only
Considered feature-complete by its maintainers.- Project categories: Access control
- Created by simonbaese on , updated
Stable releases for this project are covered by the security advisory policy.
Look for the shield icon below.
