"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "roundup/security.py" between
roundup-1.6.1.tar.gz and roundup-2.0.0.tar.gz

About: Roundup is an highly customisable issue-tracking system with command-line, web and e-mail interfaces (written in Python).

security.py  (roundup-1.6.1):security.py  (roundup-2.0.0)
skipping to change at line 46 skipping to change at line 46
function will be run. By making the permission valid only for function will be run. By making the permission valid only for
properties using props_only=True the permission will be properties using props_only=True the permission will be
skipped. You can set the default value for props_only for all skipped. You can set the default value for props_only for all
properties by calling: properties by calling:
db.security.set_props_only_default() db.security.set_props_only_default()
with a True or False value. with a True or False value.
''' '''
limit_perm_to_props_only=False limit_perm_to_props_only = False
def __init__(self, name='', description='', klass=None, def __init__(self, name='', description='', klass=None,
properties=None, check=None, props_only=None): properties=None, check=None, props_only=None):
from roundup.anypy import findargspec from roundup.anypy import findargspec
self.name = name self.name = name
self.description = description self.description = description
self.klass = klass self.klass = klass
self.properties = properties self.properties = properties
self._properties_dict = support.TruthDict(properties) self._properties_dict = support.TruthDict(properties)
self.check = check self.check = check
if properties is not None: if properties is not None:
# Set to None unless properties are defined. # Set to None unless properties are defined.
# This means that: # This means that:
skipping to change at line 77 skipping to change at line 77
Permission.limit_perm_to_props_only Permission.limit_perm_to_props_only
else: else:
# see note on use of bool() in set_props_only_default() # see note on use of bool() in set_props_only_default()
self.limit_perm_to_props_only = bool(props_only) self.limit_perm_to_props_only = bool(props_only)
else: else:
self.limit_perm_to_props_only = None self.limit_perm_to_props_only = None
if check is None: if check is None:
self.check_version = 0 self.check_version = 0
else: else:
args=findargspec.findargspec(check) args = findargspec.findargspec(check)
# args[2] is the keywords argument. Leave it as a subscript and # args[2] is the keywords argument. Leave it as a subscript and
# do not use named tuple reference as names change in python 3. # do not use named tuple reference as names change in python 3.
# If there is a **parameter defined in the function spec, the # If there is a **parameter defined in the function spec, the
# value of the 3rd argument (2nd index) in the tuple is not None. # value of the 3rd argument (2nd index) in the tuple is not None.
if args[2] is None: if args[2] is None:
# function definition is function(db, userid, itemid) # function definition is function(db, userid, itemid)
self.check_version = 1 self.check_version = 1
else: else:
# function definition is function(db, userid, itemid, **other) # function definition is function(db, userid, itemid, **other)
self.check_version = 2 self.check_version = 2
skipping to change at line 123 skipping to change at line 123
if property is None and self.properties is not None and \ if property is None and self.properties is not None and \
self.limit_perm_to_props_only: self.limit_perm_to_props_only:
return 0 return 0
# check code # check code
if itemid is not None and self.check is not None: if itemid is not None and self.check is not None:
if self.check_version == 1: if self.check_version == 1:
if not self.check(db, userid, itemid): if not self.check(db, userid, itemid):
return 0 return 0
elif self.check_version == 2: elif self.check_version == 2:
if not self.check(db, userid, itemid, property=property, \ if not self.check(db, userid, itemid, property=property,
permission=permission, classname=classname): permission=permission, classname=classname):
return 0 return 0
# we have a winner # we have a winner
return 1 return 1
def searchable(self, classname, property): def searchable(self, classname, property):
""" A Permission is searchable for the given permission if it """ A Permission is searchable for the given permission if it
doesn't include a check method and otherwise matches the doesn't include a check method and otherwise matches the
given parameters. given parameters.
""" """
skipping to change at line 152 skipping to change at line 152
# what about property? # what about property?
if not self._properties_dict[property]: if not self._properties_dict[property]:
return 0 return 0
if self.check: if self.check:
return 0 return 0
return 1 return 1
def __repr__(self): def __repr__(self):
return '<Permission 0x%x %r,%r,%r,%r,%r>'%(id(self), self.name, return '<Permission 0x%x %r,%r,%r,%r,%r>' % (id(self), self.name,
self.klass, self.properties, self.check, self.klass, self.properties, self.check,
self.limit_perm_to_props_only) self.limit_perm_to_props_only)
def __cmp__(self, other): def __eq__(self, other):
if self.name != other.name: if self.name != other.name:
return cmp(self.name, other.name) return False
if self.klass != other.klass: return 1 if self.klass != other.klass: return False
if self.properties != other.properties: return 1 if self.properties != other.properties: return False
if self.check != other.check: return 1 if self.check != other.check: return False
if self.limit_perm_to_props_only != \ if self.limit_perm_to_props_only != \
other.limit_perm_to_props_only: return 1 other.limit_perm_to_props_only: return False
# match # match
return 0 return True
def __ne__(self, other):
return not self.__eq__(other)
def __getitem__(self,index): def __getitem__(self, index):
return (self.name, self.klass, self.properties, self.check, return (self.name, self.klass, self.properties, self.check,
self.limit_perm_to_props_only)[index] self.limit_perm_to_props_only)[index]
class Role: class Role:
''' Defines a Role with the attributes ''' Defines a Role with the attributes
- name - name
- description - description
- permissions - permissions
''' '''
def __init__(self, name='', description='', permissions=None): def __init__(self, name='', description='', permissions=None):
self.name = name.lower() self.name = name.lower()
self.description = description self.description = description
if permissions is None: if permissions is None:
permissions = [] permissions = []
self.permissions = permissions self.permissions = permissions
def __repr__(self): def __repr__(self):
return '<Role 0x%x %r,%r>'%(id(self), self.name, self.permissions) return '<Role 0x%x %r,%r>' % (id(self), self.name, self.permissions)
class Security: class Security:
def __init__(self, db): def __init__(self, db):
''' Initialise the permission and role classes, and add in the ''' Initialise the permission and role classes, and add in the
base roles (for admin user). base roles (for admin user).
''' '''
self.db = weakref.proxy(db) # use a weak ref to avoid circularity self.db = weakref.proxy(db) # use a weak ref to avoid circularity
# permssions are mapped by name to a list of Permissions by class # permssions are mapped by name to a list of Permissions by class
self.permission = {} self.permission = {}
skipping to change at line 210 skipping to change at line 213
self.role = {} self.role = {}
# the default Roles # the default Roles
self.addRole(name="User", description="A regular user, no privs") self.addRole(name="User", description="A regular user, no privs")
self.addRole(name="Admin", description="An admin user, full privs") self.addRole(name="Admin", description="An admin user, full privs")
self.addRole(name="Anonymous", description="An anonymous user") self.addRole(name="Anonymous", description="An anonymous user")
# default permissions - Admin may do anything # default permissions - Admin may do anything
for p in 'create edit restore retire view'.split(): for p in 'create edit restore retire view'.split():
p = self.addPermission(name=p.title(), p = self.addPermission(name=p.title(),
description="User may %s everything"%p) description="User may %s everything" % p)
self.addPermissionToRole('Admin', p) self.addPermissionToRole('Admin', p)
# initialise the permissions and roles needed for the UIs # initialise the permissions and roles needed for the UIs
from roundup.cgi import client from roundup.cgi import client
client.initialiseSecurity(self) client.initialiseSecurity(self)
from roundup import mailgw from roundup import mailgw
mailgw.initialiseSecurity(self) mailgw.initialiseSecurity(self)
def getPermission(self, permission, classname=None, properties=None, def getPermission(self, permission, classname=None, properties=None,
check=None, props_only=None): check=None, props_only=None):
''' Find the Permission matching the name and for the class, if the ''' Find the Permission matching the name and for the class, if the
classname is specified. classname is specified.
Raise ValueError if there is no exact match. Raise ValueError if there is no exact match.
''' '''
if permission not in self.permission: if permission not in self.permission:
raise ValueError, 'No permission "%s" defined'%permission raise ValueError('No permission "%s" defined' % permission)
if classname: if classname:
try: try:
self.db.getclass(classname) self.db.getclass(classname)
except KeyError: except KeyError:
raise ValueError, 'No class "%s" defined'%classname raise ValueError('No class "%s" defined' % classname)
# look through all the permissions of the given name # look through all the permissions of the given name
tester = Permission(permission, klass=classname, properties=properties, tester = Permission(permission, klass=classname, properties=properties,
check=check, check=check,
props_only=props_only) props_only=props_only)
for perm in self.permission[permission]: for perm in self.permission[permission]:
if perm == tester: if perm == tester:
return perm return perm
raise ValueError, 'No permission "%s" defined for "%s"'%(permission, raise ValueError('No permission "%s" defined for "%s"' % (permission,
classname) classname))
def hasPermission(self, permission, userid, classname=None, def hasPermission(self, permission, userid, classname=None,
property=None, itemid=None): property=None, itemid=None):
'''Look through all the Roles, and hence Permissions, and '''Look through all the Roles, and hence Permissions, and
see if "permission" exists given the constraints of see if "permission" exists given the constraints of
classname, property, itemid, and props_only. classname, property, itemid, and props_only.
If classname is specified (and only classname) the If classname is specified (and only classname) the
search will match: search will match:
if there is *any* Permission for that classname, and if there is *any* Permission for that classname, and
that Permission was not created with props_only = True that Permission was not created with props_only = True
skipping to change at line 276 skipping to change at line 279
If itemid is specified, the Permission matched must have If itemid is specified, the Permission matched must have
either no check function defined or the check function, either no check function defined or the check function,
when invoked, must return a True value. when invoked, must return a True value.
Note that this functionality is actually implemented by the Note that this functionality is actually implemented by the
Permission.test() method. Permission.test() method.
''' '''
if itemid and classname is None: if itemid and classname is None:
raise ValueError, 'classname must accompany itemid' raise ValueError('classname must accompany itemid')
for rolename in self.db.user.get_roles(userid): for rolename in self.db.user.get_roles(userid):
if not rolename or (rolename not in self.role): if not rolename or (rolename not in self.role):
continue continue
# for each of the user's Roles, check the permissions # for each of the user's Roles, check the permissions
for perm in self.role[rolename].permissions: for perm in self.role[rolename].permissions:
# permission match? # permission match?
if perm.test(self.db, permission, classname, property, if perm.test(self.db, permission, classname, property,
userid, itemid): userid, itemid):
return 1 return 1
return 0 return 0
def roleHasSearchPermission(self, classname, property, *rolenames): def roleHasSearchPermission(self, classname, property, *rolenames):
""" For each of the given roles, check the permissions. """ For each of the given roles, check the permissions.
Property can be a transitive property. Property can be a transitive property.
""" """
perms = [] perms = []
# pre-compute permissions # pre-compute permissions
for rn in rolenames : for rn in rolenames:
for perm in self.role[rn].permissions: for perm in self.role[rn].permissions:
perms.append(perm) perms.append(perm)
# Note: break from inner loop means "found" # Note: break from inner loop means "found"
# break from outer loop means "not found" # break from outer loop means "not found"
cn = classname cn = classname
prev = None prev = None
prop = None prop = None
Link = hyperdb.Link Link = hyperdb.Link
Multilink = hyperdb.Multilink Multilink = hyperdb.Multilink
for propname in property.split('.'): for propname in property.split('.'):
skipping to change at line 330 skipping to change at line 333
break break
else: else:
# for Link and Multilink require search permission on label- # for Link and Multilink require search permission on label-
# and order-properties and on ID # and order-properties and on ID
if isinstance(prop, Multilink) or isinstance(prop, Link): if isinstance(prop, Multilink) or isinstance(prop, Link):
try: try:
cls = self.db.getclass(prop.classname) cls = self.db.getclass(prop.classname)
except KeyError: except KeyError:
return 0 return 0
props = dict.fromkeys(('id', cls.labelprop(), cls.orderprop())) props = dict.fromkeys(('id', cls.labelprop(), cls.orderprop()))
for p in props.iterkeys(): for p in props.keys():
for perm in perms: for perm in perms:
if perm.searchable(prop.classname, p): if perm.searchable(prop.classname, p):
break break
else: else:
return 0 return 0
return 1 return 1
return 0 return 0
def hasSearchPermission(self, userid, classname, property): def hasSearchPermission(self, userid, classname, property):
'''Look through all the Roles, and hence Permissions, and '''Look through all the Roles, and hence Permissions, and
skipping to change at line 361 skipping to change at line 364
Contrary to hasPermission, the search will *not* match if Contrary to hasPermission, the search will *not* match if
there are additional constraints (namely a search function) there are additional constraints (namely a search function)
on a Permission found. on a Permission found.
Concerning property, the Permission matched must have Concerning property, the Permission matched must have
either no properties listed or the property must appear in either no properties listed or the property must appear in
the list. the list.
''' '''
roles = [r for r in self.db.user.get_roles(userid) roles = [r for r in self.db.user.get_roles(userid)
if r and (r in self.role)] if r and (r in self.role)]
return self.roleHasSearchPermission (classname, property, *roles) return self.roleHasSearchPermission(classname, property, *roles)
def addPermission(self, **propspec): def addPermission(self, **propspec):
''' Create a new Permission with the properties defined in ''' Create a new Permission with the properties defined in
'propspec'. See the Permission class for the possible 'propspec'. See the Permission class for the possible
keyword args. keyword args.
''' '''
perm = Permission(**propspec) perm = Permission(**propspec)
self.permission.setdefault(perm.name, []).append(perm) self.permission.setdefault(perm.name, []).append(perm)
return perm return perm
skipping to change at line 392 skipping to change at line 395
# will be compared as part of tuple == tuple and # will be compared as part of tuple == tuple and
# (3,) == (True,) is False even though 3 is a True value # (3,) == (True,) is False even though 3 is a True value
# in a boolean context. So use bool() to coerce value. # in a boolean context. So use bool() to coerce value.
Permission.limit_perm_to_props_only = \ Permission.limit_perm_to_props_only = \
bool(props_only) bool(props_only)
def get_props_only_default(self): def get_props_only_default(self):
return Permission.limit_perm_to_props_only return Permission.limit_perm_to_props_only
def addPermissionToRole(self, rolename, permission, classname=None, def addPermissionToRole(self, rolename, permission, classname=None,
properties=None, check=None, props_only=None): properties=None, check=None, props_only=None):
''' Add the permission to the role's permission list. ''' Add the permission to the role's permission list.
'rolename' is the name of the role to add the permission to. 'rolename' is the name of the role to add the permission to.
'permission' is either a Permission *or* a permission name 'permission' is either a Permission *or* a permission name
accompanied by 'classname' (thus in the second case a Permission accompanied by 'classname' (thus in the second case a Permission
is obtained by passing 'permission' and 'classname' to is obtained by passing 'permission' and 'classname' to
self.getPermission) self.getPermission)
''' '''
if not isinstance(permission, Permission): if not isinstance(permission, Permission):
permission = self.getPermission(permission, classname, permission = self.getPermission(permission, classname,
properties, check, props_only) properties, check, props_only)
role = self.role[rolename.lower()] role = self.role[rolename.lower()]
role.permissions.append(permission) role.permissions.append(permission)
# Convenience methods for removing non-allowed properties from a # Convenience methods for removing non-allowed properties from a
# filterspec or sort/group list # filterspec or sort/group list
def filterFilterspec(self, userid, classname, filterspec): def filterFilterspec(self, userid, classname, filterspec):
""" Return a filterspec that has all non-allowed properties removed. """ Return a filterspec that has all non-allowed properties removed.
""" """
return dict ([(k, v) for k, v in filterspec.iteritems() return dict([(k, v) for k, v in filterspec.items()
if self.hasSearchPermission(userid,classname,k)]) if self.hasSearchPermission(userid, classname, k)])
def filterSortspec(self, userid, classname, sort): def filterSortspec(self, userid, classname, sort):
""" Return a sort- or group-list that has all non-allowed properties """ Return a sort- or group-list that has all non-allowed properties
removed. removed.
""" """
if isinstance(sort, tuple) and sort[0] in '+-': if isinstance(sort, tuple) and sort[0] in '+-':
sort = [sort] sort = [sort]
return [(d, p) for d, p in sort return [(d, p) for d, p in sort
if self.hasSearchPermission(userid,classname,p)] if self.hasSearchPermission(userid, classname, p)]
# vim: set filetype=python sts=4 sw=4 et si : # vim: set filetype=python sts=4 sw=4 et si :
 End of changes. 28 change blocks. 
33 lines changed or deleted 36 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)