4.4 RBAC and Security Architecture
KMP uses CakePHP Authentication to establish an identity and CakePHP Authorization policies to decide what that identity may do. Roles and permissions are tenant data; policies remain the final authority for every controller action and query.
Evaluation model
request host → tenant context → authenticated identity
→ role/permission and active-window data
→ resource policy + branch scope
→ allowed entity or scoped query
The host-to-tenant step happens before tenant-domain authentication data is loaded. An unknown, inactive, or schema-incompatible tenant fails closed. The platform administration host uses separate platform authentication and services.
Building blocks
| Component | Role |
|---|---|
KmpIdentityInterface |
Stable identity contract for members/service principals |
PermissionsLoader |
Loads effective roles, permissions, and policy metadata |
AuthorizationService |
Project extension of CakePHP’s authorization service |
BasePolicy |
Common entity/table policy behavior |
| Entity policies | Authorize operations on one resource |
| Table policies/scopes | Authorize collection actions and constrain queries |
ActiveWindow |
Applies start/end windows to roles and warrants |
| Warrants | Satisfy formal authorization requirements for eligible grants |
Controller rules
- Web controllers extend
AppController; API controllers extendApiController. - Call
$this->Authorization->authorize($entity, $action)for entity actions. - Use
authorizeModel()for table/controller actions. - Use
applyScope()before pagination, grids, counts, or exports. - Pass the scoped query forward; do not rebuild an unscoped query later.
- Never authorize by checking role names, super-user flags, or request parameters directly in templates.
Policies commonly implement canIndex, canView, canAdd, canEdit, canDelete, canGridData, and scopeIndex, with additional domain actions where required. Follow the nearest existing policy rather than assuming every action maps to CRUD.
Defense-in-depth invariants
- Validation and mass-assignment rules protect persistence but do not grant access.
- Hidden buttons are usability aids, not security boundaries.
- CSRF/security-token handling must remain enabled for state-changing browser requests.
- Restore locks, soft-delete semantics, footprint fields, and impersonation audit hooks inherited from project base classes must be preserved.
- Sensitive reads require authorization too, including autocomplete endpoints, CSV exports, JSON cells, previews, and counts.
- Secrets come from the configured secret stores, never source, logs, cache keys, or workflow context visible to users.
Multi-tenant implications
Database-per-tenant isolation is the first boundary; policy scope is the second. Both are required. A valid permission in tenant A has no meaning in tenant B. Never cache effective permissions without tenant namespacing, and never reuse a loaded entity after switching context.
Platform administration code must use platform services and the platform database explicitly. Tenant controllers must not read the tenant registry or platform secrets.
Testing authorization
For each protected feature, cover an allowed identity, denied identity, and a branch-scope edge. For collection endpoints, assert that out-of-scope rows are absent—not merely that the page returned 200. For worker flows, add a test showing that the correct tenant is entered and context is cleaned up.
Primary code
app/src/KMP/KmpIdentityInterface.phpapp/src/KMP/PermissionsLoader.phpapp/src/Services/AuthorizationService.phpapp/src/Policy/BasePolicy.phpapp/src/Middleware/TenantResolutionMiddleware.phpapp/src/Services/TenantConnectionManager.phpapp/src/Services/Security/