Oihana PHP Arango

CasbinPolicySyncUserTrait

Casbin policy synchronization handlers for the `users` collection.

Handles the user branch of the live RBAC sync : direct user_has_permissions edges, user_has_roles groupings, the cascade- aware user vertex deletion which wipes every Casbin trace of the user (groupings + direct policies) in one shot, and the helper that maps an Arango user _key to its Zitadel identifier (the only string ever used as a user-keyed Casbin subject).

Subject convention : every Casbin row keyed on a user uses the user's Zitadel identifier (stable, never reassigned). The _key is never used as a Casbin subject, so a user vertex without an identifier never produced any Casbin row in the first place — nothing to clean on deletion.

The trait expects the consumer class to expose the following protected properties (already declared on CasbinPolicySync via constructor promotion) :

  • ?Enforcer $enforcer
  • string $domain
  • ?Documents $usersModel
  • ?Documents $permissionsModel
  • ?LoggerInterface $logger

Plus the cross-trait helper resolveRoleSubject() (provided by CasbinPolicySyncRoleTrait) and the standalone helper casbinSafeSubject().

Tags
author

Marc Alcaraz

Table of Contents

Methods

registerUserDelete()  : void
Registers cleanup of Casbin policies / groupings when a user vertex is deleted.
addUserPermissionPolicy()  : void
Adds: p, userId (identifier), domain, object, action, effect
addUserRoleGrouping()  : void
Adds: g, userIdentifier, roleIdentifier, domain
onUserDelete()  : void
Called when a user vertex is deleted — wipes every Casbin trace of that user.
removeUserPermissionPolicy()  : void
Removes: p, userId (identifier), domain, object, action, effect
removeUserRoleGrouping()  : void
Removes: g, userIdentifier, roleIdentifier, domain
resolveUserIdentifier()  : string|null
Resolves a user's identifier (Zitadel ID) from their ArangoDB _key.

Methods

registerUserDelete()

Registers cleanup of Casbin policies / groupings when a user vertex is deleted.

public registerUserDelete(Documents $usersModel) : void

Symmetric to CasbinPolicySyncRoleTrait::registerRoleDelete but for users. The cascade edge purge wired on the Users model (user_has_roles, user_has_permissions via UsersController::CASCADE_EDGES) removes the edges with a raw AQL query, which bypasses per-edge afterDelete signals — so the edge-level Casbin sync never fires and any g, <userIdentifier>, <roleIdentifier>, ... grouping or p, <userIdentifier>, ... direct policy would survive the deletion as orphaned data (silent security gap on M2M flows that rely on the user's identifier).

This listener subscribes to the users model's afterDelete signal and calls Enforcer::deleteUser($identifier) which purges both the user's groupings AND any direct user→permission policy in one shot.

Parameters
$usersModel : Documents

The users vertex model.

addUserPermissionPolicy()

Adds: p, userId (identifier), domain, object, action, effect

protected addUserPermissionPolicy(string $userKey, string $permissionKey) : void
Parameters
$userKey : string
$permissionKey : string
Tags
throws
BindException
ContainerExceptionInterface
ArangoException
NotFoundExceptionInterface
ReflectionException

addUserRoleGrouping()

Adds: g, userIdentifier, roleIdentifier, domain

protected addUserRoleGrouping(string $userKey, string $roleKey) : void
Parameters
$userKey : string
$roleKey : string
Tags
throws
BindException
ContainerExceptionInterface
ArangoException
NotFoundExceptionInterface
ReflectionException

onUserDelete()

Called when a user vertex is deleted — wipes every Casbin trace of that user.

protected onUserDelete(Payload $payload) : void

The payload data is the OLD document (or list of documents) returned by the ArangoDB REMOVE query, so the Zitadel identifier is still accessible even though the vertex is gone.

Enforcer::deleteUser($subject) purges in one shot:

  • every g, <subject>, *, * grouping (role assignments removed when the cascade-purged user_has_roles edges silently bypass per-edge afterDelete signals) ;
  • every p, <subject>, *, *, *, * direct user→permission policy (created via user_has_permissions, equally silent under cascade).
Parameters
$payload : Payload

removeUserPermissionPolicy()

Removes: p, userId (identifier), domain, object, action, effect

protected removeUserPermissionPolicy(string $userKey, string $permissionKey) : void
Parameters
$userKey : string
$permissionKey : string
Tags
throws
BindException
ContainerExceptionInterface
ArangoException
NotFoundExceptionInterface
ReflectionException

removeUserRoleGrouping()

Removes: g, userIdentifier, roleIdentifier, domain

protected removeUserRoleGrouping(string $userKey, string $roleKey) : void
Parameters
$userKey : string
$roleKey : string
Tags
throws
BindException
ContainerExceptionInterface
ArangoException
NotFoundExceptionInterface
ReflectionException

resolveUserIdentifier()

Resolves a user's identifier (Zitadel ID) from their ArangoDB _key.

protected resolveUserIdentifier(string $userKey) : string|null
Parameters
$userKey : string
Tags
throws
BindException
ContainerExceptionInterface
ArangoException
NotFoundExceptionInterface
ReflectionException
Return values
string|null

null if the user has no identifier set.

On this page

Search results