pax_global_header00006660000000000000000000000064110525222700014506gustar00rootroot0000000000000052 comment=5069d4751848725f30cf86afc19d218bdce219c3 trac-virtualticketpermissions-1.0.0+svn4153/000077500000000000000000000000001105252227000207405ustar00rootroot00000000000000trac-virtualticketpermissions-1.0.0+svn4153/README000066400000000000000000000044011105252227000216170ustar00rootroot00000000000000Notes ===== Creates a set of virtual permissions for tickets that the user is associated with. There are three main permissions for this plugin: ``TICKET_IS_REPORTER``, ``TICKET_IS_CC``, and ``TICKET_IS_OWNER``. ``TICKET_IS_SELF`` is an alias for all three of these. With each permission, users will be granted the permissions where they are the person mentioned in the permission. So if a user has ``TICKET_IS_REPORTER``, they can only get the permisson for ticket they reported. For ``TICKET_IS_CC``, they just have to be included in the CC list. There are also group-based permissions: ``TICKET_IS_REPORTER_GROUP``, ``TICKET_IS_CC_GROUP``, and ``TICKET_IS_OWNER_GROUP``. These work in a similar way to their non-group counterparts, except that you are granted the permission if you share a group with the target user. For example, if ticket 1 was reported by Allan, and Allan and Bob are both in the group company_foo, and Bob has ``TICKET_IS_REPORTER_GROUP``, then Bob will get the permission for ticket 1 since he shares a group with the reporter. Each group-based permission is also an alias for the normal one, so you do not have to grant both. ``TICKET_IS_GROUP`` is an alias for all the group-based permissions (and therefore all the normal ones as well). Finally, users with ``TRAC_ADMIN`` will automatically get all these permissions. The meta-user "anonymous" also cannot be restricted by this plugin, as their identity isn't known to be checked. Configuration ============= All configuration options go in the ``[virtualticketpermissions]`` section. ``group_blacklist`` Groups to ignore for the purposes of the ``*_GROUP`` permissions. Defaults to "``anonymous, authenticated``" You must also add ``VirtualTicketPermissionsPolicy`` to your ``permission_policies`` setting in trac.ini. See below for an example if you don't have any other policies. Example ======= An example configuration:: [virtualticketpermissions] group_blacklist = anonymous, authenticated, labusers [components] virtualticketpermissions.* = enabled [trac] permission_policies = DefaultPermissionPolicy, LegacyAttachmentPolicy, VirtualTicketPermissionsPolicy [ticket-workflow] accept = new,accepted -> accepted accept.permissions = TICKET_IS_OWNER trac-virtualticketpermissions-1.0.0+svn4153/setup.py000066400000000000000000000020101105252227000224430ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: iso-8859-1 -*- import os from setuptools import setup setup( name = 'TracVirtualTicketPermissions', version = '1.0.0', packages = ['virtualticketpermissions'], author = 'Norman Rasmussen', author_email = 'norman@rasmussen.co.za', description = 'Modified ticket permissions for Trac.', #long_description = 'Allow users to only see tickets they are involved with.', long_description = open(os.path.join(os.path.dirname(__file__), 'README')).read(), license = 'BSD', keywords = 'trac plugin ticket permissions security', url = 'http://trac-hacks.org/wiki/VirtualTicketPermissionsPlugin', download_url = 'http://trac-hacks.org/svn/virtualticketpermissionsplugin/0.11#egg=TracVirtualTicketPermissions-dev', classifiers = [ 'Framework :: Trac', ], install_requires = ['Trac'], entry_points = { 'trac.plugins': [ 'virtualticketpermissions.policy = virtualticketpermissions.policy', ], }, ) trac-virtualticketpermissions-1.0.0+svn4153/virtualticketpermissions/000077500000000000000000000000001105252227000261265ustar00rootroot00000000000000trac-virtualticketpermissions-1.0.0+svn4153/virtualticketpermissions/__init__.py000066400000000000000000000000001105252227000302250ustar00rootroot00000000000000trac-virtualticketpermissions-1.0.0+svn4153/virtualticketpermissions/policy.py000066400000000000000000000123111105252227000277750ustar00rootroot00000000000000# Created by Norman Rasmussen on 2008-08-19. # Copyright (c) 2008 Norman Rasmussen. All rights reserved. # Based on the PrivateTicketsPlugin by Noah Kantrowitz from trac.core import * from trac.perm import IPermissionRequestor, IPermissionGroupProvider, IPermissionPolicy, PermissionSystem from trac.ticket.model import Ticket from trac.config import IntOption, ListOption from trac.util.compat import set class VirtualTicketPermissionsPolicy(Component): """Central tasks for the VirtualTicketPermissions plugin.""" implements(IPermissionRequestor, IPermissionPolicy) group_providers = ExtensionPoint(IPermissionGroupProvider) blacklist = ListOption('virtualticketpermissions', 'group_blacklist', default='anonymous, authenticated', doc='Groups that do not affect the common membership check.') virtual_permissions = set([ 'TICKET_IS_REPORTER', 'TICKET_IS_OWNER', 'TICKET_IS_CC', 'TICKET_IS_REPORTER_GROUP', 'TICKET_IS_OWNER_GROUP', 'TICKET_IS_CC_GROUP', ]) # IPermissionPolicy(Interface) def check_permission(self, action, username, resource, perm): if username == 'anonymous' or \ not action in self.virtual_permissions: # In these two cases, checking makes no sense return None if 'TRAC_ADMIN' in perm: # In this case, checking makes no sense return True # Look up the resource parentage for a ticket. while resource: if resource.realm == 'ticket': break resource = resource.parent if resource and resource.realm == 'ticket' and resource.id is not None: return self.check_ticket_permissions(action, perm, resource) return None # IPermissionRequestor methods def get_permission_actions(self): actions = ['TICKET_IS_REPORTER', 'TICKET_IS_OWNER', 'TICKET_IS_CC'] group_actions = ['TICKET_IS_REPORTER_GROUP', 'TICKET_IS_OWNER_GROUP', 'TICKET_IS_CC_GROUP'] all_actions = actions + [(a+'_GROUP', [a]) for a in actions] return all_actions + [('TICKET_IS_SELF', actions), ('TICKET_IS_GROUP', group_actions)] # Public methods def check_ticket_permissions(self, action, perm, res): """Return if this req is generating permissions for the given ticket ID.""" try: tkt = Ticket(self.env, res.id) except TracError: return None # Ticket doesn't exist if action == 'TICKET_IS_SELF': return tkt['reporter'] == perm.username or \ perm.username == tkt['owner'] or \ perm.username in [x.strip() for x in tkt['cc'].split(',')] if action == 'TICKET_IS_REPORTER': return tkt['reporter'] == perm.username if action == 'TICKET_IS_CC': return perm.username in [x.strip() for x in tkt['cc'].split(',')] if action == 'TICKET_IS_OWNER': return perm.username == tkt['owner'] if action == 'TICKET_IS_GROUP': result = self._check_group(perm.username, tkt['reporter']) or \ self._check_group(perm.username, tkt['owner']) for user in tkt['cc'].split(','): #self.log.debug('Private: CC check: %s, %s', req.authname, user.strip()) if self._check_group(perm.username, user.strip()): result = True return result if action == 'TICKET_IS_REPORTER_GROUP': return self._check_group(perm.username, tkt['reporter']) if action == 'TICKET_IS_OWNER_GROUP': return self._check_group(perm.username, tkt['owner']) if action == 'TICKET_IS_CC_GROUP': result = False for user in tkt['cc'].split(','): #self.log.debug('Private: CC check: %s, %s', req.authname, user.strip()) if self._check_group(perm.username, user.strip()): result = True return result # We should never get here return None # Internal methods def _check_group(self, user1, user2): """Check if user1 and user2 share a common group.""" user1_groups = self._get_groups(user1) user2_groups = self._get_groups(user2) both = user1_groups.intersection(user2_groups) both -= set(self.blacklist) #self.log.debug('PrivateTicket: %s&%s = (%s)&(%s) = (%s)', user1, user2, ','.join(user1_groups), ','.join(user2_groups), ','.join(both)) return bool(both) def _get_groups(self, user): # Get initial subjects groups = set([user]) for provider in self.group_providers: for group in provider.get_permission_groups(user): groups.add(group) perms = PermissionSystem(self.env).get_all_permissions() repeat = True while repeat: repeat = False for subject, action in perms: if subject in groups and action.islower() and action not in groups: groups.add(action) repeat = True return groups