Flexible permissions
Provides a framework for gathering, calculating, and caching permissions from multiple sources, enabling Policy Based Access Control (PBAC) for Drupal sites.
flexible_permissions
Install
composer require 'drupal/flexible_permissions:^2.0'
composer require 'drupal/flexible_permissions:^1.1'
Overview
The Flexible Permissions module provides a centralized permission calculation and caching system that allows permissions to be gathered from multiple sources. By utilizing a chain of permission calculators, it enables sophisticated Policy Based Access Control (PBAC) where permissions can vary based on any criteria such as time, context, or membership status.
The module introduces the concept of "scopes" which determine where permissions should be checked. While standard Drupal permissions operate in the "default" scope, implementations can define custom scopes. For example, the Group module defines scopes like "group_outsider", "group_insider", and "group_individual" to handle permissions differently based on membership status.
The caching layer uses Drupal's VariationCache to intelligently handle cache variations, ensuring that dynamic permission changes (like those based on office hours) are properly cached and served. This makes it possible to have contextual permissions that automatically adapt to changing conditions while maintaining excellent performance.
Note: This module is now deprecated. Drupal 10.3+ includes the Access Policy API in core, which provides similar functionality. The module continues to function as a compatibility layer that converts Flexible Permissions policies into core Access Policy API policies.
Features
- Scope-based permission system allowing permissions to be defined for different contexts (e.g., per group, per domain, per store)
- Chain permission calculator that aggregates permissions from multiple calculator services
- Two-phase permission building: initial calculation followed by alter phase for modifications
- Intelligent caching using VariationCache that handles cache redirects and variations based on cache contexts
- Dual-layer caching with persistent cache and static memory cache for optimal performance
- Account switching support to correctly calculate and cache permissions for any user account
- Integration with Drupal core's Access Policy API (Drupal 10.3+) as a compatibility layer
- Permission items can be marked as admin to bypass individual permission checks within a scope
- Immutable value objects (CalculatedPermissions) and refinable building objects (RefinableCalculatedPermissions) for safe permission handling
- Build mode protection that prevents accidental removal of permissions during the initial calculation phase
Use Cases
Time-based access control
Create a permission calculator that grants editing permissions only during office hours. The calculator would check the current time and add edit permissions only between 9 AM and 5 PM on weekdays. The cache would automatically vary by time to serve the correct permissions throughout the day.
Group-based permissions
As implemented by the Group module, define different permission scopes for users based on their relationship to a group. Outsiders (non-members) get one set of permissions, insiders (members) get another, and specific individuals can have custom permissions based on their membership roles.
Multi-domain access control
For multi-site installations using Domain Access, create calculators that grant permissions based on the current domain. Content editors might have full access on their assigned domains but read-only access on others.
Conditional admin access
Grant admin privileges within a scope based on certain conditions. For example, senior editors could have admin access in content management scopes during quiet periods, automatically falling back to regular permissions during high-traffic times.
Layered permission system
Combine multiple permission calculators to build complex access control. One calculator might provide base permissions from roles, another might add permissions based on content ownership, and a third might grant temporary elevated access based on workflows.
Tips
- Always implement getPersistentCacheContexts() correctly - if permissions vary by any condition, that condition must be represented as a cache context
- Use PermissionCalculatorBase as your starting point rather than implementing the interface directly
- Prefer PermissionCalculatorAlterInterfaceV2 over the original alter interface as it provides account and scope context
- Remember that items are merged, not overwritten, during build mode - use the alter phase if you need to modify existing items
- When setting isAdmin to true on a CalculatedPermissionsItem, permissions array is ignored - admin items have all permissions
- For Drupal 10.3+, consider using native Access Policies instead. This module provides a compatibility layer but new code should use core APIs
- The module applies a 'flexible_permissions' cache tag to all calculated permissions, making bulk invalidation easy
Technical Details
Troubleshooting 5
Clear the 'flexible_permissions' cache bin. You can use Drush: drush cr, or invalidate the 'flexible_permissions' cache tag programmatically.
Ensure your calculator only returns permissions for the scope that was requested. Check that you're not accidentally adding items with different scope names in your calculatePermissions() method.
If your permissions vary by user, make sure to include 'user' or appropriate user-related cache contexts in your getPersistentCacheContexts() method. The chain calculator uses account switching to handle this correctly.
Item removal is only allowed after build mode is disabled. The chain calculator disables build mode automatically before the alter phase. If you need to remove items, implement PermissionCalculatorAlterInterface or PermissionCalculatorAlterInterfaceV2.
This module is deprecated in favor of Drupal core's Access Policy API (available in Drupal 10.3+). Consider migrating to native access policies. The module continues to work as a compatibility layer during the transition period.
Security Notes 4
- Never make getPersistentCacheContexts() conditional on anything other than the scope parameter. Conditional cache contexts can lead to privilege escalation vulnerabilities.
- Do not use cache contexts that rely on calculated permissions within your calculations, as this creates an infinite loop.
- Be careful when implementing alterPermissions() - incorrectly removing or modifying permissions can lead to unintended access.
- When extending the permission system, always consider the security implications of granting admin status within a scope, as admin items bypass all permission checks.