This page is not yet fully completed - we are still working on the content here. Expect some rough edges 🙃
Neos CMS security
A common requirement, especially for larger websites with many editors, is the possibility to selectively control access to certain backend tools and parts of the content. For example so that editors can only edit certain pages or content types or that they are limited to specific workspaces. These access restrictions are used to enforce certain workflows and to reduce complexity for editors.
Neos provides a way to define Access Control Lists (ACL) in a very fine-grained manner, enabling the following use cases:
- hide parts of the node tree completely
- useful for multi-site websites and frontend-login
- show only specific Backend Modules
- allow to create/edit only specific Node Types
- allow to only edit parts of the Node Tree
- allow to only edit a specific dimension
Privilege targets define what is restricted, they are defined by combining privileges with matchers, to address specific parts of the node tree. A user is assigned to one or more specific roles, defining who the user is. For each role, a list of privileges is specified, defining the exact permissions of users assigned to each role.
In the Neos user interface, it is possible to assign a list of multiple roles to a user. This allows to define the permissions a user actually has on a fine-grained level. Additionally, the user management module has basic support for multiple accounts per user: a user may, for example, have one account for backend access and another one for access to a member-only area on the website.
As a quick example, a privilege target giving access to a specific part of the node tree looks as follows:
'Neos\ContentRepository\Security\Authorization\Privilege\NodeTreePrivilege': 'YourSite:EditWebsitePart': matcher: 'isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")'
Adjusting and defining roles
Neos comes with a number of predefined roles that can be assigned to users:
|Neos.ContentRepository:Administrator||A no-op role for future use|
|Neos.Neos:AbstractEditor||Neos.ContentRepository:Administrator||Grants the very basic things needed to use Neos at all|
|Neos.Neos:LivePublisher||A “helper role” to allow publishing to the live workspace|
|Neos.Neos:RestrictedEditor||Neos.Neos:AbstractEditor||Allows to edit content but not publish to the live workspace|
|Allows to edit and publish content|
|Neos.Neos:Administrator||Neos.Neos:Editor||Everything the Editor can do, plus admin things|
To adjust permissions for your editors, you can of course just adjust the existing roles (Neos.Neos:RestrictedEditor and Neos.Neos:Editor in most cases). If you need different sets of permissions, you will need to define your own custom roles, though.
Those custom roles should inherit from RestrictedEditor or Editor and then grant access to the additional privilege targets you define (see below).
Here is an example for a role, which limiting editing to a specific language
privilegeTargets: 'Neos\ContentRepository\Security\Authorization\Privilege\Node\EditNodePrivilege': # this privilegeTarget is defined to switch to a "whitelist" approach 'Vendor.Site:EditAllNodes': matcher: 'TRUE' 'Vendor.Site:EditFinnish': matcher: 'isInDimensionPreset("language", "fi")' roles: 'Neos.Neos:Editor': privileges: - privilegeTarget: 'Vendor.Site:EditAllNodes' permission: GRANT 'Vendor.Site:FinnishEditor': parentRoles: ['Neos.Neos:RestrictedEditor'] privileges: - privilegeTarget: 'Vendor.Site:EditFinnish' permission: GRANT
Node privileges define what can be restricted in relation to accessing and editing nodes. In combination with matchers (see the next section) they allow to define privilege targets that can be granted or denied for specific roles.
This is a blacklist by default, so the privilege won’t match if one of the conditions don’t match. So the example:
privilegeTargets: 'Neos\ContentRepository\Security\Authorization\Privilege\Node\CreateNodePrivilege': 'Some.Package:SomeIdentifier': matcher: >- isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287") && createdNodeIsOfType("Neos.NodeTypes:Text")
will actually only affect nodes of that type (and subtypes). All users will still be able to create other node types, unless you also add a more generic privilege target:
privilegeTargets: 'Neos\ContentRepository\Security\Authorization\Privilege\Node\CreateNodePrivilege': 'Some.Package:SomeIdentifier': matcher: isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")
That will be abstained by default. It’s the same with MethodPrivileges, but with those we abstain all actions by default (in Neos that is).
Asset privileges define what can be restricted in relation to accessing Assets (images, documents, videos, …), AssetCollections and Tags.
The privileges need to be applied to certain nodes to be useful. For this, matchers are used in the policy, written using Eel. Depending on the privilege, various methods to address nodes are available.
Global objects in matcher expressions
Since the matchers are written using Eel, anything in the Eel context during evaluation is usable for matching. This is done by using the context keyword, followed by dotted path to the value needed. E.g. to access the personal workspace name of the currently logged in user, this can be used:
privilegeTargets: 'Neos\ContentRepository\Security\Authorization\Privilege\Node\ReadNodePrivilege': 'Neos.ContentRepository:Workspace': matcher: 'isInWorkspace("context.userInformation.personalWorkspaceName“))’
These global objects available under context (by default the current SecurityContext imported as securityContext and the UserService imported as userInformation) are registered in the Settings.yaml file in section aop.globalObjects. That way you can add your own as well.
Flow security framework
As the Neos CMS is built on the Flow Framework - the underlying security features of Flow provide the following generic possibilities in addition:
- protect arbitrary method calls
- define the visibility of arbitrary elements depending on the authenticated user