Repository Authorization and Permissions
Concepts and definitions
The users configuration is stored at:
Users are stored in hipposys:userfolders. The user folders can also contain user folders. This can be useful if the number of users gets very large, like close to a thousand. Then the users can be split up in sub folder for example by using their first letter.
A user in the repository is represented by a single node. The node name is the username.
Users can be managed by the CMS or synced with an external source like LDAP. For users that are managed from the CMS the hipposys:user node type is used. For externally managed users the hipposys:externaluser type or a custom subtype of hipposys:externaluser can be used. The hipposys:securityprovider property specifies which security provider manages the user. For CMS managed users the provider is internal.
If a user is marked as a system user the user is not allowed to login to the CMS and the console. A user can be made a system user by setting the property hipposys:system to true. To disable a user the property hipposys:active can be set to false. A disabled user can not login to the repository. The hipposys:password property contains the password of the user. The password can be stored in plain text, which is discouraged, or prefixed with the encryption between two dollar signs. By default the CMS uses SHA-256, for example: $SHA-256$dGeytXwnqAU=$NqCe6sJcM4qAwV8166GdueUVA/TSyidpAI3Evn+y/hc=.
Node type definitions
[hipposys:user] > nt:base - hipposys:securityprovider (string) = 'internal' mandatory autocreated - hipposys:active (boolean) = true mandatory autocreated - hipposys:system (boolean) - hipposys:password (string) - hipposys:passkey (string) - hipposys:lastlogin (date) - hipposys:firstname (string) - hipposys:lastname (string) - hipposys:email (string)
[hipposys:externaluser] > hipposys:user - hipposys:lastsync (date) - * (string)
[hipposys:userfolder] > nt:base + * (hipposys:user) = hipposys:user + * (hipposys:userfolder) = hipposys:userfolder
The groups configuration is stored at:
The groups are stored in hipposys:groupfolders. The folders can be nested as with the user folders. A group in the repository is represented by a single node. The node name is the group name.
A group is a collection of users. The members of the group are stored in the hipposys:members property. The members are referenced just by their name which is equal to their node name.
Nested groups are not supported, but the node type does already have the hipposys:groups property to be able to support this in the future.
Node type definitions
[hipposys:group] > nt:base - hipposys:securityprovider (string) = 'internal' mandatory autocreated - hipposys:system (boolean) - hipposys:members (string) multiple - hipposys:groups (string) multiple - hipposys:description (string)
[hipposys:externalgroup] > hipposys:group - hipposys:syncdate (date) - * (string)
[hipposys:groupfolder] > nt:base + * (hipposys:group) = hipposys:group + * (hipposys:groupfolder) = hipposys:groupfolder
Roles and privileges
A role defines a set of privileges. The privileges are stored in the hipposys:privileges property. There are two kinds of privileges: the default JCR privileges and the workflow privileges.
The JCR privileges are specified in the JSR 283 spec in "16.2.3 Standard Privileges". The current implemented permissions are: jcr:read, jcr:write, jrc:all, jcr:addChildNodes, jcr:removeChildNodes, and jcr:setProperties.
The workflow privileges are used by the workflow engine to check if a user is allowed a certain step on the node (document). The current workflow permissions are: hippo:author, hippo:editor and hippo:admin.
Roles are hierarchical. A role will inherit all privileges from the roles specified in the the hipposys:roles property.
Node type definitions
[hipposys:role] > nt:base - hipposys:privileges (string) multiple - hipposys:roles (string) multiple
[hipposys:rolefolder] > nt:base + * (hipposys:role) = hipposys:role
The roles configuration is stored at:
A security domain defines a set of documents on which permissions can be set. The security domain is defined in a query-like manner based on facets (properties). This allows the repository to return the correct nodes in queries and faceted views, like facet select, without having to evaluate the access rules for all the nodes individually. This keeps query execution and virtual node creation very fast, even when the amount of nodes is in the millions and the user is only allowed to see (read) a few of them, because no filtering of the result set is needed afterwards.
A security domain consists of one or more domain rules. Each domain rule consists of one or more facet rules. The security domain can be seen as a query in the following manner: a document belongs to the security domain if it matches one or more of the domain rules and a document matches a domain rule if it matches all of the facet rules.
A domain rule is a container for one or more facet rules.
A facet rule defines the rules for which a document is tested whether it belongs to the security domain.
The facet rule is made up of a facet name and a value. The facet name, stored in the property hipposys:facet is the name of the property (facet) of the node (document) to do the matching on. The value of the facet to match on is stored in the hipposys:value property.
The facet rule can be negated by setting the hipposys:equals property to false. This means that the rule matches all documents that do have the facet but not that value.
A facet rule in filtering mode is only applied to documents that have the specific facet. All documents that don't have the specific facet will match the rule and all documents that have the facet and the specified value will match the rule. The facet rule can be set in filtering mode by setting the property hipposys:filter to true.
A facet rule must be one of the following types:
String : normal string matching
Name : a jcr Name used for node name and mixin types
Reference : a reference type looks up the uuid of a node specified with a path in the value. The matching is then done as a String type on the uuid of the node.
Special facet names
jcr:primaryType : match the exact node type
jcr:mixinTypes : match any of the mixin types
nodetype : match the exact node type of any subtypes
nodename : match the node name
Special facet values
* : match any value
__user__ : match the name of the current user
__group__: match any group the current user is a member of
__role__: match the current user's role (for the domain)
Node type definitions
[hipposys:domain] > nt:base + * (hipposys:domainrule) = hipposys:domainrule multiple + * (hipposys:authrole) = hipposys:authrole multiple - hipposys:description (string)
[hipposys:domainrule] > nt:base + * (hipposys:facetrule) = hipposys:facetrule multiple - hipposys:description (string)
[hipposys:facetrule] > nt:base - hipposys:facet (string) mandatory - hipposys:value (string) mandatory - hipposys:type (string) = 'String' mandatory < 'String', 'Name', 'Reference' - hipposys:equals (boolean) = 'true' mandatory autocreated - hipposys:filter (boolean) = 'false' mandatory autocreated - hipposys:description (string)
The security domains are stored at:
The permission settings define "who can do what where". Permissions are granted to a user by granting a role to a user or to a group the user is in for a specific security domain. A user can have one or more roles for each security domain.
The authrole node is the "glue" between the user or group, the role(s) and the security domain. A security domain can have multiple authrole nodes.
At login all the roles for the security domains the user has, either directly or through group memberships, are parsed. This makes evaluating the rules faster in the access manager. When the permissions for a user have changed the user has to logout and login back again to effectuate the new permissions.
Node type definitions
[hipposys:authrole] > nt:base - hipposys:users (string) multiple - hipposys:groups (string) multiple - hipposys:role (string) mandatory - hipposys:description (string)
Access Manager Configuration
The configuration of the access manager is stored in the repository. In the configuration are general path and cache settings and the extension points for custom Security Providers.
On the /hippo:configuration/hippo:security node the following paths can be configured: the users, groups, roles and domains path. The paths are configured with the following properties:
users: hipposys:userspath, default /hippo:configuration/hippo:users
groups: hipposys:groupspath, default /hippo:configuration/hippo:groups
roles: hipposys:rolespath, default /hippo:configuration/hippo:roles
domains: hipposys:domainspath, default /hippo:configuration/hippo:domains
The access manager has a user-based cache for read access. It caches which nodes a user is allowed to read or not to read. Write operations are always checked at run time. The cache is configured in the numbers of items per user. An item is a node or a property. The cache can be configured by setting the hipposys:permissioncachesize property in the /hippo:configuration/hippo:security/hipposys:accessmanager node.
The security provider configuration is the extension point of the access manager. A security provider can have a custom user provider and a custom group provider. Such a custom provider is the LDAP security provider which synchronizes users and groups with the repository.
Node type definitions
[hipposys:securityfolder] > nt:base - hipposys:userspath (string) mandatory - hipposys:groupspath (string) mandatory - hipposys:rolespath (string) mandatory - hipposys:domainspath (string) mandatory + hipposys:accessmanager (hipposys:accessmanager) = hipposys:accessmanager + * (hipposys:securityprovider) = hipposys:securityprovider
[hipposys:accessmanager] > nt:base - hipposys:permissioncachesize (long) = '20000' mandatory autocreated
[hipposys:securityprovider] > nt:base orderable - hipposys:classname (string) mandatory + hipposys:userprovider (hipposys:userprovider) = hipposys:userprovider + hipposys:groupprovider (hipposys:groupprovider) = hipposys:groupprovider
[hipposys:userprovider] > nt:base - hipposys:dirlevels (long) = '0' autocreated
[hipposys:groupprovider] > nt:base - hipposys:dirlevels (long) = '0' autocreated
The access manager configuration is stored at:
Default CMS Configuration
admin: the administrator, has all privileges
editor: the editor, is only allowed the edit and publish content
author: the author, is only allowed the edit content, but not publish
workflowuser: used internally by the CMS workflow (do not delete)
admin: members of this group have all privileges
editor: members of this group can edit and publish content
author: members of this group can edit content
webmaster: members of this group can edit the HST configuration and create channels
everybody: every logged in user is member of this group
Roles and privileges
admin: has the privileges of editor, all jcr privileges and the hippo:admin privilege
editor: has the privileges of author, jcr write privileges and the hippo:editor privilege
author: has jcr read privileges and the hippo:author privilege
readwrite: has jcr read and write privileges
readonly: has jcr read privileges
everywhere: all content of the repository
defaultread: nodes that need to be readable by all (CMS) users
defaultwrite: nodes that need to be readable and writeable by all (CMS) users
versioning: nodes related to versioning
workflow: workflow configuration related nodes
hippodocuments: all documents
hippofolders: all folders
frontendconfig: CMS configuration nodes
hippogallery: assets and images
htmlcleaner: html cleaner configuration
templates: template definitions
hippolog: log nodes for activity plugin
hipporequests: nodes related to scheduling
Note that this is a general overview, the exact implementation might differ slightly.
Tips when creating your own security domains
To get some information about what is going on in the repository w.r.t. security set the following two classes to log level INFO:
This can usually be done in your log4j.xml. Another way to configure the logging is by using the logging servlet. The servlet is configured by default at: http://localhost:8080/cms/logging/
The new permissions rules for a user are only re-evaluated by logging out and logging back in again. The repository browser is stateless and does this by default, so you can check your results by just pressing F5. The repository browser is by default configured at: http://localhost:8080/cms/repository/
It is possible to view which permissions a user has on a node in the console. To view the permissions login to the console as a certain user and browse to the node in the tree on the left side and select the node. In the top menu is an item which is called "View permissions" which shows a dialog with the permissions the logged in user has on the current node. Don't forget to logout and login again after you change the permissions. The console is by default configured at: http://localhost:8080/cms/console/
It is easier to use two browsers when configuring the security domains and permissions. Use one browser only for the admin and use the second browser as the user for which the permissions are configured.
Sensible names for security domains
Make sure you choose sensible names for the facet rules and domain rules in the security domains. It should be possible to "read" the rules without having to look at the properties. For example the security domain "everywhere" has the domain rule "all-nodes" which has the facet rule "match-all-types".
Start with minimal privileges
It's easier to add privileges to a user or group then to remove them. Try to start with a minimal set and add the privileges the user needs one by one. A CMS user should at least have the following privileges:
readwrite role on defaultwrite
author or editor role on hipporequests