- Notifications
You must be signed in to change notification settings - Fork9
sandstorm/NeosAcl
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
This package implements dynamic Access Control Lists for Neos Roles.
The development of this package was sponsored byujamii andqueo.
Main features:
- Switch
RestrictedEditor
to an allowlist-only permission approach. By installing this package, theRestrictedEditor
isno longer allowed to change any content. - Configure dynamic roles through a Neos backend module.
- Permissions on the node tree, workspaces and dimensions possible.
- Permissions work predictably with sane defaults and purely additive logic.
- Install the package:
composer require sandstorm/neosacl
- Run the migrations
./flow doctrine:migrate
- Log in with an admin account and visit the new menu entry 'Dynamic Roles'
Initial (Package) Setup
- Clone this package as
Sandstorm.NeosAcl
in the DistributionPackages of a Neos 4.3 or later installation - Add it to
composer.json
as"sandstorm/neosacl": "*"
- Run
composer update
Initial React Setup
cd Resources/Private/react-acl-editoryarnyarn dev
Then, log into the backend of Neos, and visit the module "Dynamic Roles".
The basic idea was the following: Hook intoPolicyService::emitConfigurationLoaded
, and modify the$configuration
array (introduce new rolesand privilegeTargets). This basically worksat runtime - however there is a problem with dynamic MethodPrivilege enforcement, which isexplained below and by the following diagram:
- Background: An implementation of
PointcutFilterInterface
can - during compile time of Flow - decide which classesand methods match for a certain aspect.- This is used in
PolicyEnforcementAspect
(which is the central point for enforcingMethodPrivileges). - There, the
MethodPrivilegePointcutFilter
is referenced. - The
MethodPrivilegePointcutFilter
asks thePolicyService
for all configuredMethodPrivilege
s - and ensuresAOP proxies are built for these methods.
- This is used in
- Side Effect: Now, during building up the pointcut filters, the
MethodPrivilegePointcutFilter
additionally builds upa data structuremethodPermissions
- which remembers whichMethodPrivileges
are registered for which method.- This data structure is storedpersistently in the
Flow_Security_Authorization_Privilege_Method
cache. - At runtime, for a class which is intercepted by
PolicyEnforcementAspect
, all configuredMethodPrivilege
s areinvoked - and they have to quickly decide if they matchthis particular call-site. - This is done using the
methodPermissions
data structure from theFlow_Security_Authorization_Privilege_Method
cache.
- This data structure is storedpersistently in the
- If a
MethodPrivilege
is defined dynamically at runtime, then themethodPermissions
data structure is missingthe information that this new privilege should be invoked for certain methods. - NOTE: You can only dynamically add
MethodPrivileges
for call-siteswhich are already instrumented by AOP;because otherwise the code will never get invoked (because of missing proxies).
We are mostly working withEditNodePrivilege
etc. - so why does this apply there?
EditNodePrivilege
has an internalMethodPrivilege
which takes care of the method call enforcement part;i.e. preventing you to call e.g.NodeInterface::setProperty()
if you do not have the permission to do so.
Furthermore, to make this idea work, thePolicy.yaml
of this package defines a catch-allSandstorm.NeosAcl:EditAllNodes
PrivilegeTarget - so AOP will instrument the corresponding methods ofNodeInterface
. This catch-all makes sensein any case, because this switches the security frameworkto an allowlist-only approach
- making it easier to grasp.
In order to make the dynamic policy enforcement work, we need to add custom stuff to themethodPermissions
- forthe dynamically added roles.
The post-processing of themethodPermissions
is done using a custom cache frontend (SecurityAuthorizationPrivilegeMethodCacheFrontend
).
Method privileges internally can use dynamic AOP Runtime Expressions (in case you check for method parameters). EspeciallytheMethodPrivilege
- which is attached to theRemoveNodePrivilege
- uses the following expression code:
return'within(' . NodeInterface::class .') && method(.*->setRemoved(removed == true))';
Theremoved == true
part is a so-calledAOP Runtime Expression.
This is internally implemented using theFlow_Aop_RuntimeExpressions
"cache", which is pre-filled again during the compiletime (which is a nasty side-effect).
Thus, in our case we need to again implement a custom cache frontend (AopRuntimeExpressionsCacheFrontend
),using the runtime expressions of the base configuration, which exists properly.
About
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors7
Uh oh!
There was an error while loading.Please reload this page.