Authorization And Access Control

Document created by resplin Employee on Jun 6, 2015Last modified by alfresco-archivist on Aug 31, 2016
Version 2Show Document
  • View in full screen mode

Obsolete Pages{{Obsolete}}

The official documentation is at: http://docs.alfresco.com



Authorization


Authorities – User, Group or Role Name


An authority is a string representation of a user name, group name, or role name.  Authorities can be assigned permissions to perform actions in the repository.   This way, a certain user, or a certain group, or a certain role can be granted or denied permissions to do something


  • Well-Known Authorities - Specific strings are used to identify well known authorities such as the administrator, everyone, owner and guest.
  • Prefixed strings are used to identify groups and roles.
    • Groups are identified by strings starting with the GROUP_ prefix, which should be hidden from end users in the client. Groups can include users and other groups and users.  It is thus possible to construct group hierarchies.
    • Similarly, roles start with the ROLE_ prefix.
    • Strings that do not match these patterns may be used for usernames.
  • The username are strings that do not match the above patterns.

Some authorities are dynamic, such as the owner of a node and the owner of a lock held on a node.
These authorities are evaluated in the context of a node.
For some nodes you may be the 'owner' of that node. You will then have the permissions granted to the owner authority available to you.
Dynamic authorities are similar to an access policy. You can evaluate any condition knowing the node to be accessed and the current user and decide if the user should
have an authority in the given context. An access policy would be a dynamic permission assignment. 



Groups can include both other groups and users so it is possible to construct hierarchies.



When any call is made to the repository through the public service API, the caller must first be authenticated.
This can be done by logging in using a username and password or using a ticket.
A ticket can be requested after logging in and can be used, under certain conditions, to revalidate a user. 
Some applications and authentication mechanisms may support single sign on.



By default, the owner of a node is the person who created it. Ownership may be transferred to another user.
Only one user can own a node. However, other users may be able to take ownership of a node if they have suitable permission.



Permissions are identified by a string. A particular permission, for example 'ReadChildren', may be granted or denied to an authority; a user, group, administrator, owner, etc. The children of a node will inherit permissions from their parents if inheritance is set. So by default, the files in a folder will inherit their permissions from the folder. Permissions set on a node are additive with the inherited permissions from the parent nodes. If for example the parent is set to consumer, but the child is set for collaborator for the user, the user will have the sum of both permissions. The inheritance of permissions may be turned off for any node. A permission group is a convenient grouping of permissions such as 'Read' made up of 'ReadProperties' and 'ReadChildren'.



As the username is used as the key to find personal information, group membership and against which to assign permission, it is key to know if this is case sensitive or not.
The security framework as a whole may be case sensitive, or not.
Configuration of this key behaviour is set in repository.properties. It is quite unusual to have case sensitive user ids.



An ACL is a permission or permission group assigned to an authority for a particular node. An ACL can deny or allow. An 'allow' permission will be inherited by any children unless the permission is denied by an ACL on a child or inheritance of ACLs is disabled on a child. Allow takes precedence. If 'bob' is a member of the group 'rats' and 'bob' is allowed 'read' and 'rats' is denied 'read' then 'bob' will be allowed read. Any allow allows access, as opposed to a single deny denies all.

Global Permission - a permission or permission group assigned to an authority regardless of the node. A global permission takes precedence over node specific ACLS. If 'bob' were granted the global permission 'read' then 'bob' would have the 'read' permission for everything, regardless of any ACLs set on any nodes.




What is a role?


We think of role is an idea in the UI that refers to a set of permissions that can be applied to a folder. If you have role based permissions, this is not usually the same thing; it is really just another authority, like groups, with global permissions.

How are you using roles?


  • If you are assigning a permission like read/write/delete to a role, you are using role as an authority. Groups could probably be used to do the same thing.
  • If you are assigning roles to people and groups you are using roles as a convenient name for a bundle of permissions and other roles. This is what we do in the UI.

A Simple Permissions Example


The diagram below shows some simple permissions that have applied to a basic directory structure. There are two users, Andy and Dave, to which permissions have been assigned. Permissions are also assigned to two special authorities: one that applies to all users and one that applies to the owner of a node. In this example, we are only interested in read, create and all permissions.

800px



A summary of the permissions shown in the above diagram:




/

All users can read the properties and children of this folder.

No one can alter properties or children.




/app:company_home

Permissions are inherited from the parent nodes.

All users can read the properties and children of this folder (inherited from /).




/app:company_home/app:andy

Permissions are not inherited from the parent nodes.

All permissions are granted to andy.

All users can read the properties and children of this folder.




/app:company_home/app:dave

Permissions are not inherited from the parent nodes.

All permissions are granted to dave.

There are no permissions granted to other users.




/app:company_home/app:public

Permissions are inherited from the parent nodes.

All users can read the properties and children of this folder (inherited from /).

/app:company_home/app:andy/app:private

Permissions are not inherited from the parent nodes.

All permissions are granted to andy.

There are no permissions granted to other users.




/app:company_home/app:andy/app:public

Permissions are inherited from the parent nodes.

All users can read the properties and children of this folder. This permission takes precedence over the permission set on the parent node. If the permission on the parent node is altered it will have no effect on this permission.

/app:company_home/app:andy/app:collab

Permissions are inherited from the parent nodes.

Andy inherits all permissions.

Dave can read the properties and children of this folder, regardless of the permissions set on any parent nodes.

Dave can create children in this folder, regardless of the permissions set on any parent nodes.

The owner of a node has all permissions on their content. If Dave creates a file he will have full control over it. Andy could take ownership of this file, as he has all permissions; Dave would then only have read access to this file, as he would no longer be the owner.

All users are denied read permission; this takes precedence over the allow read permissions to all users set on the parent node.




Access Control Implementation


Authorization Enforcement Overview


Authorization is enforced when methods are called on public services.
Access control is defined in meta-data and not in code.
The meta-data is used to 'inject' security in an aspect oriented way.
Security settings can therefore be changed without affecting the implementation code.

Security could be based on:


  • the method accessed;
  • the objects provided as arguments to the called method; and
  • the objects returned by the invoked method.





Security is enforced around public services. Web services, the UI, CIFS, WebDav, FTP etc all use public services and so include security enforcement. Public services are defined in public-services-context.xml.

Access control allows or prevents people from executing service methods on a particular object by checking if the current user, or any of the authorities granted to the current user, has a particular permission or permission group.

For example, on the NodeService bean, the readProperties method checks that the current user has read access to the properties of the node before invoking the method. On the SearchService, the results from queries are restricted to return only the nodes for which a user has read permission.


Configuring Authorization Enforcement


Authorization is enforced by defining proxies for each internal service implementation and adding. A method interceptor to enforce security is included in each proxy. When a method is called on a public service, the security interceptor is called before it returns execution to the internal implementation. At this stage, the interceptor can examine the function arguments to the method and check that the user has the appropriate rights for each in order to invoke the method.

For example, a method delete(NodeRef nodeRef) exists on the node service. The security interceptor can see the nodeRef argument before the underlying delete(...) method is called.
If configured correctly, the interceptor could check that the current user has 'Delete' permission for the node. If not, a security exception is raised. If permission allows the method goes ahead.

In a similar manner, after a method has executed the interceptor can examine the returned object and decided if it should return it the caller. For example, a search method could return a list of nodes. The security interceptor could filter this list for only those nodes that the current user can 'Read'.

It is possible you may want to configure a method so that it can only be called by an admin user, specific users, groups of users etc. This can also be enforced by the security method interceptor.

Access control for public services is defined in public-services-context.xml. The public services are the only Spring beans to have access restrictions.

Each service defines a method interceptor bean that enforces any security requirements for method calls. By convention, these are defined in public-services-security-context.xml, along with any other supporting beans. This file also defines the location from which the permission model is loaded.

Here is the v1.0 public services security context as an example PublicServicesSecurityContext




Defining method level security


In public-services-security-context.xml the beans required to support Acegi based security around method invocation are defined.
This configures two alfresco specific beans: a voter that can veto method execution based on the permissions granted to the current user for specific arguments to the method, and an after invocation provider to apply security to objects returned by methods. Method access defined in the normal acegi way with a few additions.

In the following: ? represents an authority (user name or group), # a method argument index and * a string representation of a permission.

Pre-conditions take one of the following forms:


ACL_METHOD.?
Access to the method is restricted to those with the given authority in alfresco.
This could be a user name or group. Dynamic authorities are not supported

ACL_NODE.#.*
Access control is restricted to users who have the the specified permission for the node on the identified argument.
If the argument is a NodeRef it will be used; if it is a StoreRef then the root node for the store will be used; if it is a ChildAssociationRef then the child node will be used.

ACL_PARENT.#.*
Access control is restricted to users who have the the specified permission for the parent of the node on the identified argument.
If the argument is a NodeRef the parent of the node will be used; if it is a ChildAssociationRef then the parent node will be used.




ROLE_...
Check for an Acegi authority starting with ROLE_

GROUP_...
Check for an Acegi authority starting with GROUP_

If more than one ACL_NODE.#.* or  ACL_PARENT.#.* entry is present then all the permissions must be available for the method to execute.

Post-conditions take the forms:


AFTER_ACL_NODE.*
Similar to ACL_NODE.#.* but the restriction applies to the return argument.
The supported return types are ChildAssociationRef, FileInfo, NodeRef, StoreRef, ResultSet; Collections and arrays of StoreRef, NodeRef, ChildAssociationRef, and FileInfo.

AFTER_ACL_PARENT.*
Similar to ACL_PARENT.#.* but the restriction applies to the return argument.
The supported return types are ChildAssociationRef, FileInfo, NodeRef, StoreRef, ResultSet; Collections and arrays of StoreRef, NodeRef, ChildAssociationRef, and FileInfo.

The post-conditions will create access denied exceptions for return types like NodeRef's, StoreRef's, ChildAssociationRef's. For collections and arrays members will be filtered based on the access conditions.

Some examples and explanations taken from the method security interceptor for the NodeService public service bean.
Refer to the NodeService interface for the method documentation and methos parameters etc.

org.alfresco.service.cmr.repository.NodeService.getStores=AFTER_ACL_NODE.sys:base.Read

If the returned object is a collection or array then filter its members to contain only those that can be read by the current user.
If it is a single reference to a node of some form, throw an AccessDeniedException.

org.alfresco.service.cmr.repository.NodeService.createStore=ACL_METHOD.ROLE_ADMINISTRATOR

Allow access to users who are members of the administrator group.
(This does not use an acegi ROLE_... as we do not bind groups and roles to the Acegi authentication object.

org.alfresco.service.cmr.repository.NodeService.exists=ACL_NODE.0.sys:base.Read

Only allow for users who have read permission for the node specified by the first parameter of the method.

org.alfresco.service.cmr.repository.NodeService.createNode=ACL_NODE.0.sys:base.CreateChildren

Only allow for users who have create children permission for the node specified by the first parameter of the method.



org.alfresco.service.cmr.repository.NodeService.moveNode=ACL_NODE.0.sys:base.WriteProperties,ACL_PARENT.0.sys:base.DeleteChildren,ACL_NODE.1.sys:base.CreateChildren

Only users who can write the properties of the moving node, remove the node from its parent, and ann children to the destination node can perform a move node. 

org.alfresco.service.cmr.repository.NodeService.setChildAssociationIndex=ACL_PARENT.0.sys:base.WriteProperties

Setting the index of an association requires the write properties permissions

org.alfresco.service.cmr.repository.NodeService.getType=ACL_NODE.0.sys:base.ReadProperties

Getting the type of a node required read permission for properties.

org.alfresco.service.cmr.repository.NodeService.addAspect=ACL_NODE.0.sys:base.Write

Adding an aspect to a node requires the write permission set.

org.alfresco.service.cmr.repository.NodeService.removeAspect=ACL_NODE.0.sys:base.Write

Remoing an aspect from a node requires the write permission set.

org.alfresco.service.cmr.repository.NodeService.hasAspect=ACL_NODE.0.sys:base.ReadProperties

Querying if a node has an aspect requires the read properties permission on the node.

org.alfresco.service.cmr.repository.NodeService.getAspects=ACL_NODE.0.sys:base.ReadProperties

Getting a list of all aspects for a node requires the read properties permission on the node.

org.alfresco.service.cmr.repository.NodeService.deleteNode=ACL_NODE.0.sys:base.Delete

Deleting a node requires the delete permission. Testing for delete on the children is not possible for performance reasons.
The node service should retest this for each node that it tries to delete.

org.alfresco.service.cmr.repository.NodeService.addChild=ACL_NODE.0.sys:base.CreateChildren,ACL_NODE.1.sys:base.ReadProperties

Adding children to a node requires the create children property on the parent and read properties on the node (this ensures that you can see the child node)

org.alfresco.service.cmr.repository.NodeService.removeChild=ACL_NODE.1.sys:base.Delete

To remove a child node you need delete permission for the child (this includes the test to see if it is deletable from the parent.)

org.alfresco.service.cmr.repository.NodeService.getProperties=ACL_NODE.0.sys:base.ReadProperties

Accessing the properties of a node requires the permission to read properties.

org.alfresco.service.cmr.repository.NodeService.getProperty=ACL_NODE.0.sys:base.ReadProperties
Accessing a particular property on a node requires the permission to read properties.

org.alfresco.service.cmr.repository.NodeService.setProperties=ACL_NODE.0.sys:base.WriteProperties

Setting all properties on a node required the permission to write properties.

org.alfresco.service.cmr.repository.NodeService.setProperty=ACL_NODE.0.sys:base.WriteProperties

Setting a specific property on a node required the permission to write properties.

org.alfresco.service.cmr.repository.NodeService.getParentAssocs=ACL_NODE.0.sys:base.ReadProperties,AFTER_ACL_PARENT.sys:base.Read

Getting the parent associations on a node requires read access to the node. The method only reports the parents that are visible.
There may be mutiple parents some of which are not visible. You must have access via the primary parent to read a node.

org.alfresco.service.cmr.repository.NodeService.getChildAssocs=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.Read

Reading child associations requires read access to the node and filters for only the children that are visible.

org.alfresco.service.cmr.repository.NodeService.getPrimaryParent=ACL_NODE.0.sys:base.ReadProperties,AFTER_ACL_PARENT.sys:base.Read

Accessing the primary parent requires that the node and its primary parent are accessible. In future, we may allow access along a link and not just the primary parent, in which case it is possible that the primary parent is not visible.

org.alfresco.service.cmr.repository.NodeService.createAssociation=ROLE_AUTHENTICATED

org.alfresco.service.cmr.repository.NodeService.removeAssociation=ROLE_AUTHENTICATED
org.alfresco.service.cmr.repository.NodeService.getTargetAssocs=ROLE_AUTHENTICATED
org.alfresco.service.cmr.repository.NodeService.getSourceAssocs=ROLE_AUTHENTICATED

Currently, there are no retrictions on the creation of associations between nodes.

org.alfresco.service.cmr.repository.NodeService.getPath=ACL_NODE.0.sys:base.ReadProperties
Getting the primary path to a node requires read access to the node.

org.alfresco.service.cmr.repository.NodeService.getPaths=ACL_NODE.0.sys:base.ReadProperties

Getting all the paths to a node requires read access to the node.

Outcomes