Extension Point : IPermissionRequestor
The (somewhat confusingly named) IPermissionRequestor simply allows components to define permission actions (and meta permission actions and their relations to other permission actions).
Many of Trac's features are only available to users with certain permissions. By default these are the coarse permissions described in TracPermissions. More fine-grained per-resource permissions as described by TracFineGrainedPermissions are also possible.
While a component can check for any permissions already defined by other components, it might want to define its own permission types for its actions on resources.
Only one method has to be defined:
get_permission_actions(). This method should return a list of permission actions. Each action is either the name of the action (a simple string) or, for so called meta permissions a tuple, where the first tuple item is the name of the action, and the second tuple item is a list of subsumed action names. (The meta permission covers all listed permissions. If multiple implementations return the same meta permission, they are combined.)
Action names should be in ALL_CAPS_WITH_UNDERSCORES and usually consist of two parts:
- The resource type / module name.
- The action to perform on that resource.
The most common action is VIEW, to allow basic usage (viewing) of a resource. It is often required for components implementing IRequestHandler, where
process_request() would check for permissions categorically (
req.perm.require('RESOURCE_VIEW')) or selectively (
if 'RESOURCE_ACTION' in req.perm:). (Such an IRequestHandler - or any other kind of checked resource access - could also be implemented by any other Component.)
Anyone with access to a perm (
trac.perm.PermissionCache) can perform permission check. It is usually obtained from req (a trac.web.api.Request). More fine-grained per-resource permission checks can be performed by obtaining a specialized cache using
A slightly more complex pattern is to return multiple simple RESOURCE_ACTION permission actions and one RESOURCE_ADMIN meta permission action covering the others. Even more complex hierarchies of permissions are possible. (See #Ticket)
A minimal IPermissionRequestor in isolation is not very useful (but possible) and usually accompanied by implementations of other interfaces that require these permissions. Hence the following example is best understood in context of the ComponentModuleExamples.
In Trac, components have no associated permissions. The following example defines two new permissions to be checked elsewhere:
from trac.core import Component, implements from trac.perm import IPermissionRequestor class ComponentModule(Component): implements(IPermissionRequestor) def get_permission_actions(self): return ['COMPONENT_LIST', 'COMPONENT_VIEW']
If a new version of a component renames / merges / splits existing permissions of an older version, it might want to implement an environment upgrade (IEnvironmentSetupParticipant).
A real example would be TracPastePlugin, which changed from a single permission PASTEBIN_USE to multiple permissions PASTEBIN_VIEW and PASTEBIN_CREATE. In this changeset, (
_has_old_permission for any of the old permissions and
convert_use_permissions (via the
version_map if required) to convert them to the new permissions.
One of the simplest use cases is to define one permission to view the resources of that module:
The most complex example in Trac itself. Various meta permissions subsume certain / all other permissions for convenience.
return ['TICKET_APPEND', 'TICKET_CREATE', 'TICKET_CHGPROP', 'TICKET_VIEW', 'TICKET_EDIT_CC', 'TICKET_EDIT_DESCRIPTION', 'TICKET_EDIT_COMMENT', ('TICKET_MODIFY', ['TICKET_APPEND', 'TICKET_CHGPROP']), ('TICKET_ADMIN', ['TICKET_CREATE', 'TICKET_MODIFY', 'TICKET_VIEW', 'TICKET_EDIT_CC', 'TICKET_EDIT_DESCRIPTION', 'TICKET_EDIT_COMMENT'])]
actions = ['REPORT_CREATE', 'REPORT_DELETE', 'REPORT_MODIFY', 'REPORT_SQL_VIEW', 'REPORT_VIEW'] return actions + [('REPORT_ADMIN', actions)]
actions = ['MILESTONE_CREATE', 'MILESTONE_DELETE', 'MILESTONE_MODIFY', 'MILESTONE_VIEW', 'ROADMAP_VIEW'] return ['ROADMAP_VIEW'] + [('ROADMAP_ADMIN', actions)]
actions = ['MILESTONE_CREATE', 'MILESTONE_DELETE', 'MILESTONE_MODIFY', 'MILESTONE_VIEW'] return actions + [('MILESTONE_ADMIN', actions)]
actions = ['WIKI_CREATE', 'WIKI_DELETE', 'WIKI_MODIFY', 'WIKI_RENAME', 'WIKI_VIEW'] return actions + [('WIKI_ADMIN', actions)]
As an interesting peculiarity, permissions to manipulate permissions:
actions = ['PERMISSION_GRANT', 'PERMISSION_REVOKE'] return actions + [('PERMISSION_ADMIN', actions)]
An example of a component to combine permissions of other components into a meta permission.
return [('VERSIONCONTROL_ADMIN', ['BROWSER_VIEW', 'CHANGESET_VIEW', 'FILE_VIEW', 'LOG_VIEW'])]