- Pyramid ACL
In Pyramid, every traversal resource might have an Access Conrol List, which is a set of rules containing
- an action (Allow, Deny)
- a principal (an arbitrary string usually denoting a role, group or userid)
- a set of permissions to allow or deny
An example of a rule:
(Allow, 'some_group', 'some_permission')
Every view in pyramid might be protected by a permission.
The permission is tested against the principals of the current web user, when the view is entered (after traversal and view lookup).
In Portal we have two different levels of Access Roles:
- global web user roles
- instance level object roles
The names of the permissions should reflect the action of the web user (e.g. 'edit_artist') and should be unique, if possible.
The only exception is the permission 'authenticated', which is granted for web users after login and might be used for all views, which should be accessible for authenticated web users in general.
A web user has one or more roles corresponding to the portal plugins (e.g. licenser for portal.plugin.repertoire).
Each plugin should have it's own role to ensure that the web user is only able to use the corresponding parts of the application.
The web user roles are persisted in tryton:
- WebUserRole (web.user.role)
The web user roles are imported via
The imported standard roles are:
- licenser (for portal.plugin.repertoire)
- licensee (for portal.plugin.events)
The web user roles can be retrieved via the roles method of the WebUser Model:
For convenience, the list of roles are added as request property:
To set permissions on a resource to a principal:
class SomeResource(ResourceBase): __acl__ = [ (Allow, '<PRINCIPAL>', ( '<PERMISSION1>', '<PERMISSION2>', ... )), ]
To prevent inheritance of ACL from parent resources (e.g. for the main resource of a plugin), add DENY_ALL as the last rule:
class SomeResource(ResourceBase): __acl__ = [ ..., DENY_ALL ]
Every web user might take one or more access roles for each acl capable object (e.g. Artist, Release, Creation, Content) via an access control entry.
Every access role is associated with a set of permissions to be granted.
Additional to the permissions codes used in the pyramid views directly (e.g. view_artist, view_release, etc.), there are permissions to reflect transitive rights for objects down the hierarchy (e.g. view_arist_creations, view_arist_releases).
All access related objects are persisted in tryton and assigned to a model via the AccessControlList mixin, see also the database model:
- AccessControlEntry (ace)
- AccessRole (ace.role)
- AccessPermission (ace.permission)
The access permissions are imported via
collection_society.xml and readonly for the tryton client, as the codes of the permissions are hardcoded.
The access roles are free to edit and each role might be associated with any set of existing permissions.
The names of the access roles should be chosen according to the semantics of the role to be taken.
The imported standard roles are:
- Administrator (all permissions)
- Stakeholder (view related permissions only)
To retrieve permission related information, every acl capable model has two instance methods:
instance.permits(): asks the instance, if a web user has a certain permission:
instance.permissions(): asks the instance, what permissions a web_user has:
The returned permissions might be constrained to permissions in the list of valid codes to tighten security.
An example domain to include transitive permissions:
[ 'OR', [ ('acl.web_user', '=', web_user_id), ('acl.roles.permissions.code', '=', '<PERMISSION>') ], [ ('<FIELD>.acl.web_user', '=', web_user_id), ('<FIELD>.acl.roles.permissions.code', '=', '<PERMISSION>'), ] ]
The permissions are set within the
__acl__ method of a resource and bound to the authenticated userid:
class SomeResource(ResourceBase): _permit = ['only', 'allow', 'these', 'permissions'] def __acl__(self): return [ (Allow, self.request.authenticated_userid, <INSTANCE>.permissions(self.request.web_user, self._permit)) ]