comparison roundup/security.py @ 6012:06e6bc21b67e

flake8 changes whitepace and formatting
author John Rouillard <rouilj@ieee.org>
date Tue, 31 Dec 2019 21:34:24 -0500
parents 3fa026621f69
children c12377fb4144
comparison
equal deleted inserted replaced
6011:8bd93c8e98a6 6012:06e6bc21b67e
6 6
7 from roundup import hyperdb, support 7 from roundup import hyperdb, support
8 8
9 import logging 9 import logging
10 logger = logging.getLogger('roundup.security') 10 logger = logging.getLogger('roundup.security')
11
11 12
12 class Permission: 13 class Permission:
13 ''' Defines a Permission with the attributes 14 ''' Defines a Permission with the attributes
14 - name 15 - name
15 - description 16 - description
41 db.security.set_props_only_default() 42 db.security.set_props_only_default()
42 43
43 with a True or False value. 44 with a True or False value.
44 ''' 45 '''
45 46
46 limit_perm_to_props_only=False 47 limit_perm_to_props_only = False
47 48
48 def __init__(self, name='', description='', klass=None, 49 def __init__(self, name='', description='', klass=None,
49 properties=None, check=None, props_only=None): 50 properties=None, check=None, props_only=None):
50 from roundup.anypy import findargspec 51 from roundup.anypy import findargspec
51 self.name = name 52 self.name = name
52 self.description = description 53 self.description = description
53 self.klass = klass 54 self.klass = klass
54 self.properties = properties 55 self.properties = properties
69 # see note on use of bool() in set_props_only_default() 70 # see note on use of bool() in set_props_only_default()
70 self.limit_perm_to_props_only = bool(props_only) 71 self.limit_perm_to_props_only = bool(props_only)
71 else: 72 else:
72 self.limit_perm_to_props_only = None 73 self.limit_perm_to_props_only = None
73 74
74
75 if check is None: 75 if check is None:
76 self.check_version = 0 76 self.check_version = 0
77 else: 77 else:
78 args=findargspec.findargspec(check) 78 args = findargspec.findargspec(check)
79 # args[2] is the keywords argument. Leave it as a subscript and 79 # args[2] is the keywords argument. Leave it as a subscript and
80 # do not use named tuple reference as names change in python 3. 80 # do not use named tuple reference as names change in python 3.
81 # If there is a **parameter defined in the function spec, the 81 # If there is a **parameter defined in the function spec, the
82 # value of the 3rd argument (2nd index) in the tuple is not None. 82 # value of the 3rd argument (2nd index) in the tuple is not None.
83 if args[2] is None: 83 if args[2] is None:
119 if itemid is not None and self.check is not None: 119 if itemid is not None and self.check is not None:
120 if self.check_version == 1: 120 if self.check_version == 1:
121 if not self.check(db, userid, itemid): 121 if not self.check(db, userid, itemid):
122 return 0 122 return 0
123 elif self.check_version == 2: 123 elif self.check_version == 2:
124 if not self.check(db, userid, itemid, property=property, \ 124 if not self.check(db, userid, itemid, property=property,
125 permission=permission, classname=classname): 125 permission=permission, classname=classname):
126 return 0 126 return 0
127 127
128 # we have a winner 128 # we have a winner
129 return 1 129 return 1
130 130
147 if self.check: 147 if self.check:
148 return 0 148 return 0
149 149
150 return 1 150 return 1
151 151
152
153 def __repr__(self): 152 def __repr__(self):
154 return '<Permission 0x%x %r,%r,%r,%r,%r>'%(id(self), self.name, 153 return '<Permission 0x%x %r,%r,%r,%r,%r>' % (id(self), self.name,
155 self.klass, self.properties, self.check, 154 self.klass, self.properties, self.check,
156 self.limit_perm_to_props_only) 155 self.limit_perm_to_props_only)
157 156
158 def __eq__(self, other): 157 def __eq__(self, other):
159 if self.name != other.name: 158 if self.name != other.name:
161 160
162 if self.klass != other.klass: return False 161 if self.klass != other.klass: return False
163 if self.properties != other.properties: return False 162 if self.properties != other.properties: return False
164 if self.check != other.check: return False 163 if self.check != other.check: return False
165 if self.limit_perm_to_props_only != \ 164 if self.limit_perm_to_props_only != \
166 other.limit_perm_to_props_only: return False 165 other.limit_perm_to_props_only: return False
167 166
168 # match 167 # match
169 return True 168 return True
170 169
171 def __ne__(self, other): 170 def __ne__(self, other):
172 return not self.__eq__(other) 171 return not self.__eq__(other)
173 172
174 def __getitem__(self,index): 173 def __getitem__(self, index):
175 return (self.name, self.klass, self.properties, self.check, 174 return (self.name, self.klass, self.properties, self.check,
176 self.limit_perm_to_props_only)[index] 175 self.limit_perm_to_props_only)[index]
176
177 177
178 class Role: 178 class Role:
179 ''' Defines a Role with the attributes 179 ''' Defines a Role with the attributes
180 - name 180 - name
181 - description 181 - description
187 if permissions is None: 187 if permissions is None:
188 permissions = [] 188 permissions = []
189 self.permissions = permissions 189 self.permissions = permissions
190 190
191 def __repr__(self): 191 def __repr__(self):
192 return '<Role 0x%x %r,%r>'%(id(self), self.name, self.permissions) 192 return '<Role 0x%x %r,%r>' % (id(self), self.name, self.permissions)
193
193 194
194 class Security: 195 class Security:
195 def __init__(self, db): 196 def __init__(self, db):
196 ''' Initialise the permission and role classes, and add in the 197 ''' Initialise the permission and role classes, and add in the
197 base roles (for admin user). 198 base roles (for admin user).
210 self.addRole(name="Anonymous", description="An anonymous user") 211 self.addRole(name="Anonymous", description="An anonymous user")
211 212
212 # default permissions - Admin may do anything 213 # default permissions - Admin may do anything
213 for p in 'create edit restore retire view'.split(): 214 for p in 'create edit restore retire view'.split():
214 p = self.addPermission(name=p.title(), 215 p = self.addPermission(name=p.title(),
215 description="User may %s everything"%p) 216 description="User may %s everything" % p)
216 self.addPermissionToRole('Admin', p) 217 self.addPermissionToRole('Admin', p)
217 218
218 # initialise the permissions and roles needed for the UIs 219 # initialise the permissions and roles needed for the UIs
219 from roundup.cgi import client 220 from roundup.cgi import client
220 client.initialiseSecurity(self) 221 client.initialiseSecurity(self)
221 from roundup import mailgw 222 from roundup import mailgw
222 mailgw.initialiseSecurity(self) 223 mailgw.initialiseSecurity(self)
223 224
224 def getPermission(self, permission, classname=None, properties=None, 225 def getPermission(self, permission, classname=None, properties=None,
225 check=None, props_only=None): 226 check=None, props_only=None):
226 ''' Find the Permission matching the name and for the class, if the 227 ''' Find the Permission matching the name and for the class, if the
227 classname is specified. 228 classname is specified.
228 229
229 Raise ValueError if there is no exact match. 230 Raise ValueError if there is no exact match.
230 ''' 231 '''
231 if permission not in self.permission: 232 if permission not in self.permission:
232 raise ValueError('No permission "%s" defined'%permission) 233 raise ValueError('No permission "%s" defined' % permission)
233 234
234 if classname: 235 if classname:
235 try: 236 try:
236 self.db.getclass(classname) 237 self.db.getclass(classname)
237 except KeyError: 238 except KeyError:
238 raise ValueError('No class "%s" defined'%classname) 239 raise ValueError('No class "%s" defined' % classname)
239 240
240 # look through all the permissions of the given name 241 # look through all the permissions of the given name
241 tester = Permission(permission, klass=classname, properties=properties, 242 tester = Permission(permission, klass=classname, properties=properties,
242 check=check, 243 check=check,
243 props_only=props_only) 244 props_only=props_only)
244 for perm in self.permission[permission]: 245 for perm in self.permission[permission]:
245 if perm == tester: 246 if perm == tester:
246 return perm 247 return perm
247 raise ValueError('No permission "%s" defined for "%s"'%(permission, 248 raise ValueError('No permission "%s" defined for "%s"' % (permission,
248 classname)) 249 classname))
249 250
250 def hasPermission(self, permission, userid, classname=None, 251 def hasPermission(self, permission, userid, classname=None,
251 property=None, itemid=None): 252 property=None, itemid=None):
252 '''Look through all the Roles, and hence Permissions, and 253 '''Look through all the Roles, and hence Permissions, and
253 see if "permission" exists given the constraints of 254 see if "permission" exists given the constraints of
254 classname, property, itemid, and props_only. 255 classname, property, itemid, and props_only.
255 256
256 If classname is specified (and only classname) the 257 If classname is specified (and only classname) the
284 continue 285 continue
285 # for each of the user's Roles, check the permissions 286 # for each of the user's Roles, check the permissions
286 for perm in self.role[rolename].permissions: 287 for perm in self.role[rolename].permissions:
287 # permission match? 288 # permission match?
288 if perm.test(self.db, permission, classname, property, 289 if perm.test(self.db, permission, classname, property,
289 userid, itemid): 290 userid, itemid):
290 return 1 291 return 1
291 return 0 292 return 0
292 293
293 def roleHasSearchPermission(self, classname, property, *rolenames): 294 def roleHasSearchPermission(self, classname, property, *rolenames):
294 """ For each of the given roles, check the permissions. 295 """ For each of the given roles, check the permissions.
295 Property can be a transitive property. 296 Property can be a transitive property.
296 """ 297 """
297 perms = [] 298 perms = []
298 # pre-compute permissions 299 # pre-compute permissions
299 for rn in rolenames : 300 for rn in rolenames:
300 for perm in self.role[rn].permissions: 301 for perm in self.role[rn].permissions:
301 perms.append(perm) 302 perms.append(perm)
302 # Note: break from inner loop means "found" 303 # Note: break from inner loop means "found"
303 # break from outer loop means "not found" 304 # break from outer loop means "not found"
304 cn = classname 305 cn = classname
361 either no properties listed or the property must appear in 362 either no properties listed or the property must appear in
362 the list. 363 the list.
363 ''' 364 '''
364 roles = [r for r in self.db.user.get_roles(userid) 365 roles = [r for r in self.db.user.get_roles(userid)
365 if r and (r in self.role)] 366 if r and (r in self.role)]
366 return self.roleHasSearchPermission (classname, property, *roles) 367 return self.roleHasSearchPermission(classname, property, *roles)
367 368
368 def addPermission(self, **propspec): 369 def addPermission(self, **propspec):
369 ''' Create a new Permission with the properties defined in 370 ''' Create a new Permission with the properties defined in
370 'propspec'. See the Permission class for the possible 371 'propspec'. See the Permission class for the possible
371 keyword args. 372 keyword args.
392 393
393 def get_props_only_default(self): 394 def get_props_only_default(self):
394 return Permission.limit_perm_to_props_only 395 return Permission.limit_perm_to_props_only
395 396
396 def addPermissionToRole(self, rolename, permission, classname=None, 397 def addPermissionToRole(self, rolename, permission, classname=None,
397 properties=None, check=None, props_only=None): 398 properties=None, check=None, props_only=None):
398 ''' Add the permission to the role's permission list. 399 ''' Add the permission to the role's permission list.
399 400
400 'rolename' is the name of the role to add the permission to. 401 'rolename' is the name of the role to add the permission to.
401 402
402 'permission' is either a Permission *or* a permission name 403 'permission' is either a Permission *or* a permission name
404 is obtained by passing 'permission' and 'classname' to 405 is obtained by passing 'permission' and 'classname' to
405 self.getPermission) 406 self.getPermission)
406 ''' 407 '''
407 if not isinstance(permission, Permission): 408 if not isinstance(permission, Permission):
408 permission = self.getPermission(permission, classname, 409 permission = self.getPermission(permission, classname,
409 properties, check, props_only) 410 properties, check, props_only)
410 role = self.role[rolename.lower()] 411 role = self.role[rolename.lower()]
411 role.permissions.append(permission) 412 role.permissions.append(permission)
412 413
413 # Convenience methods for removing non-allowed properties from a 414 # Convenience methods for removing non-allowed properties from a
414 # filterspec or sort/group list 415 # filterspec or sort/group list
415 416
416 def filterFilterspec(self, userid, classname, filterspec): 417 def filterFilterspec(self, userid, classname, filterspec):
417 """ Return a filterspec that has all non-allowed properties removed. 418 """ Return a filterspec that has all non-allowed properties removed.
418 """ 419 """
419 return dict ([(k, v) for k, v in filterspec.items() 420 return dict([(k, v) for k, v in filterspec.items()
420 if self.hasSearchPermission(userid,classname,k)]) 421 if self.hasSearchPermission(userid, classname, k)])
421 422
422 def filterSortspec(self, userid, classname, sort): 423 def filterSortspec(self, userid, classname, sort):
423 """ Return a sort- or group-list that has all non-allowed properties 424 """ Return a sort- or group-list that has all non-allowed properties
424 removed. 425 removed.
425 """ 426 """
426 if isinstance(sort, tuple) and sort[0] in '+-': 427 if isinstance(sort, tuple) and sort[0] in '+-':
427 sort = [sort] 428 sort = [sort]
428 return [(d, p) for d, p in sort 429 return [(d, p) for d, p in sort
429 if self.hasSearchPermission(userid,classname,p)] 430 if self.hasSearchPermission(userid, classname, p)]
430 431
431 # vim: set filetype=python sts=4 sw=4 et si : 432 # vim: set filetype=python sts=4 sw=4 et si :

Roundup Issue Tracker: http://roundup-tracker.org/