Skip to content

Commit ee3a4dc

Browse files
author
Ralf Schlatterbeck
committed
more fixes to search permissions:
- require that for links and multilinks the searching user has access to at least the orderprop, labelprop, and ID of the linked class - allow combinations of roles: we previosly required that for transitive properties all elements where searchable by the same role. We now allow that the roles can be different for each property. This allows assigning different roles to different sub-systems and allowing users having all required roles to search across subsystems. - regression test updated - fix doc/upgrading example for new signature of roleHasSearchPermission
1 parent 08baab3 commit ee3a4dc

File tree

3 files changed

+73
-24
lines changed

3 files changed

+73
-24
lines changed

doc/upgrading.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ search for this property::
4747
print " Property:", p
4848
roles = []
4949
for role in sorted(db.security.role.iterkeys()):
50-
if db.security.roleHasSearchPermission(role,cl,p):
50+
if db.security.roleHasSearchPermission(cl,p,role):
5151
roles.append(role)
5252
print " roles may search:", ', '.join(roles)
5353

roundup/security.py

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -197,29 +197,54 @@ def hasPermission(self, permission, userid, classname=None,
197197
return 1
198198
return 0
199199

200-
def roleHasSearchPermission(self, rolename, classname, property):
201-
""" For each of the user's Roles, check the permissions.
200+
def roleHasSearchPermission(self, classname, property, *rolenames):
201+
""" For each of the given roles, check the permissions.
202202
Property can be a transitive property.
203203
"""
204-
cn = classname
205-
last = None
204+
perms = []
205+
# pre-compute permissions
206+
for rn in rolenames :
207+
for perm in self.role[rn].permissions:
208+
perms.append(perm)
206209
# Note: break from inner loop means "found"
207210
# break from outer loop means "not found"
211+
cn = classname
212+
prev = None
213+
prop = None
214+
Link = hyperdb.Link
215+
Multilink = hyperdb.Multilink
208216
for propname in property.split('.'):
209-
if last:
217+
if prev:
210218
try:
211-
cls = self.db.getclass(cn)
212-
lprop = cls.getprops()[last]
213-
except KeyError:
219+
cn = prop.classname
220+
except AttributeError:
214221
break
215-
cn = lprop.classname
216-
last = propname
217-
for perm in self.role[rolename].permissions:
222+
prev = propname
223+
try:
224+
cls = self.db.getclass(cn)
225+
prop = cls.getprops()[propname]
226+
except KeyError:
227+
break
228+
for perm in perms:
218229
if perm.searchable(cn, propname):
219230
break
220231
else:
221232
break
222233
else:
234+
# for Link and Multilink require search permission on label-
235+
# and order-properties and on ID
236+
if isinstance(prop, Multilink) or isinstance(prop, Link):
237+
try:
238+
cls = self.db.getclass(prop.classname)
239+
except KeyError:
240+
return 0
241+
props = dict.fromkeys(('id', cls.labelprop(), cls.orderprop()))
242+
for p in props.iterkeys():
243+
for perm in perms:
244+
if perm.searchable(prop.classname, p):
245+
break
246+
else:
247+
return 0
223248
return 1
224249
return 0
225250

@@ -243,13 +268,9 @@ def hasSearchPermission(self, userid, classname, property):
243268
either no properties listed or the property must appear in
244269
the list.
245270
'''
246-
for rolename in self.db.user.get_roles(userid):
247-
if not rolename or not self.role.has_key(rolename):
248-
continue
249-
# for each of the user's Roles, check the permissions
250-
if self.roleHasSearchPermission (rolename, classname, property):
251-
return 1
252-
return 0
271+
roles = [r for r in self.db.user.get_roles(userid)
272+
if r and self.role.has_key(r)]
273+
return self.roleHasSearchPermission (classname, property, *roles)
253274

254275
def addPermission(self, **propspec):
255276
''' Create a new Permission with the properties defined in

test/test_security.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,28 +183,56 @@ def testTransitiveSearchPermissions(self):
183183
has = self.db.security.hasSearchPermission
184184
addRole = self.db.security.addRole
185185
addToRole = self.db.security.addPermissionToRole
186-
user = self.db.user.create(username='user1', roles='User')
187-
anon = self.db.user.create(username='anonymous', roles='Anonymous')
188186
addRole(name='User')
189187
addRole(name='Anonymous')
188+
addRole(name='Issue')
189+
addRole(name='Msg')
190+
addRole(name='UV')
191+
user = self.db.user.create(username='user1', roles='User')
192+
anon = self.db.user.create(username='anonymous', roles='Anonymous')
193+
ui = self.db.user.create(username='user2', roles='Issue')
194+
uim = self.db.user.create(username='user3', roles='Issue,Msg')
195+
uimu = self.db.user.create(username='user4', roles='Issue,Msg,UV')
190196
iv = add(name="View", klass="issue")
191197
addToRole('User', iv)
192198
addToRole('Anonymous', iv)
199+
addToRole('Issue', iv)
193200
ms = add(name="Search", klass="msg")
194201
addToRole('User', ms)
195202
addToRole('Anonymous', ms)
196-
addToRole('User', add(name="View", klass="user"))
203+
addToRole('Msg', ms)
204+
uv = add(name="View", klass="user")
205+
addToRole('User', uv)
206+
addToRole('UV', uv)
197207
self.assertEquals(has(anon, 'issue', 'messages'), 1)
198-
self.assertEquals(has(anon, 'issue', 'messages.author'), 1)
208+
self.assertEquals(has(anon, 'issue', 'messages.author'), 0)
199209
self.assertEquals(has(anon, 'issue', 'messages.author.username'), 0)
200-
self.assertEquals(has(anon, 'issue', 'messages.recipients'), 1)
210+
self.assertEquals(has(anon, 'issue', 'messages.recipients'), 0)
201211
self.assertEquals(has(anon, 'issue', 'messages.recipients.username'), 0)
202212
self.assertEquals(has(user, 'issue', 'messages'), 1)
203213
self.assertEquals(has(user, 'issue', 'messages.author'), 1)
204214
self.assertEquals(has(user, 'issue', 'messages.author.username'), 1)
205215
self.assertEquals(has(user, 'issue', 'messages.recipients'), 1)
206216
self.assertEquals(has(user, 'issue', 'messages.recipients.username'), 1)
207217

218+
self.assertEquals(has(ui, 'issue', 'messages'), 0)
219+
self.assertEquals(has(ui, 'issue', 'messages.author'), 0)
220+
self.assertEquals(has(ui, 'issue', 'messages.author.username'), 0)
221+
self.assertEquals(has(ui, 'issue', 'messages.recipients'), 0)
222+
self.assertEquals(has(ui, 'issue', 'messages.recipients.username'), 0)
223+
224+
self.assertEquals(has(uim, 'issue', 'messages'), 1)
225+
self.assertEquals(has(uim, 'issue', 'messages.author'), 0)
226+
self.assertEquals(has(uim, 'issue', 'messages.author.username'), 0)
227+
self.assertEquals(has(uim, 'issue', 'messages.recipients'), 0)
228+
self.assertEquals(has(uim, 'issue', 'messages.recipients.username'), 0)
229+
230+
self.assertEquals(has(uimu, 'issue', 'messages'), 1)
231+
self.assertEquals(has(uimu, 'issue', 'messages.author'), 1)
232+
self.assertEquals(has(uimu, 'issue', 'messages.author.username'), 1)
233+
self.assertEquals(has(uimu, 'issue', 'messages.recipients'), 1)
234+
self.assertEquals(has(uimu, 'issue', 'messages.recipients.username'), 1)
235+
208236
def test_suite():
209237
suite = unittest.TestSuite()
210238
suite.addTest(unittest.makeSuite(PermissionTest))

0 commit comments

Comments
 (0)