Skip to content

Commit 8cb96da

Browse files
committed
bug: check function not used by history, displays hidden fields
The user class uses check functions (own_record) to restrict viewing of fields that are allowed to be seen if the user page is for the current user. This display history showed the fields/oldvalues for all users (with class access) if the permission had a check function. Changed the history command to use item level and not class level checks. Check functions are not used in class level checks. Also needed to fix memorydb. It uses an in memory dict as its database. The getjournal function returned the values in the database. However testing modified the database copies. So added a copy.deepcopy() around the returned journal so it can be modified without changing the database. Test added for the problem replacing a useless test. Also fixed test that was affected by addig additional security permissions.
1 parent d1f3899 commit 8cb96da

4 files changed

Lines changed: 66 additions & 5 deletions

File tree

CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ Fixed:
127127
John Rouillard)
128128
- Handle ConfigurationErrors in demo.py cleanly. Used to dump a full
129129
traceback. Now prints error and exits. (John Rouillard)
130+
- Do not display journal/history fields when user does not have access
131+
to the property being changed. (John Rouillard)
130132

131133
Features:
132134

roundup/hyperdb.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,13 +1392,18 @@ def history(self, nodeid, enforceperm=True, skipquiet=True):
13921392
self.classname, key, j_repr)
13931393
del args[key]
13941394
continue
1395+
# check if user can access the property on the
1396+
# item. This allows the check function in the
1397+
# property to deny access.
13951398
if enforceperm and not (perm("View",
13961399
uid,
13971400
self.classname,
1401+
itemid=nodeid,
13981402
property=key) or
13991403
perm("Edit",
14001404
uid,
14011405
self.classname,
1406+
itemid=nodeid,
14021407
property=key)):
14031408
logger.debug("skipping unaccessible property "
14041409
"%s::%s seen by user%s in %s",

roundup/test/memorydb.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'''Implement an in-memory hyperdb for testing purposes.
22
'''
33

4+
import copy
45
import os
56
import shutil
67
import time
@@ -439,7 +440,7 @@ def getjournal(self, classname, nodeid):
439440
# add any journal entries for transactions not committed to the
440441
# database
441442
for method, args in self.transactions:
442-
if method != self.doSaveJournal:
443+
if method not in (self.doSaveJournal, self.doSetJournal):
443444
continue
444445
(cache_classname, cache_nodeid, cache_action, cache_params,
445446
cache_creator, cache_creation) = args
@@ -455,7 +456,10 @@ def getjournal(self, classname, nodeid):
455456
except KeyError:
456457
if res: return res # noqa: E701
457458
raise IndexError(nodeid)
458-
return res
459+
# use copy otherwise we are returning the actual in memory
460+
# database entry. Hence changes to the journal (e.g. remove quiet
461+
# properties) changes the actual database.
462+
return copy.deepcopy(res)
459463

460464
def pack(self, pack_before):
461465
""" Delete all journal entries except "create" before 'pack_before'.

test/db_test_base.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ def setupSchema(db, create, module):
165165

166166
db.security.addPermissionToRole("User", v1)
167167

168+
# testFilteredJournal requires this. Allow age prop access if
169+
# db user is accessing own record.
170+
def own_record(db, userid, itemid):
171+
'''Determine whether the userid matches the item being accessed.'''
172+
return userid == itemid
173+
174+
v2 = db.security.addPermission(
175+
name='View', klass='user', check=own_record,
176+
properties=['username', 'supervisor', 'assignable', 'age'],
177+
description="Allow viewing of age by own user")
178+
179+
db.security.addPermissionToRole("User", v2)
180+
181+
# update testAdminOtherCommands do_security test
182+
# if you add permissions
183+
168184
class MyTestCase(object):
169185
def tearDown(self):
170186
if hasattr(self, 'db'):
@@ -1146,8 +1162,41 @@ def testQuietChangenote(self):
11461162
self.db.issue.properties['nosy'].quiet=True
11471163
self.db.issue.properties['deadline'].quiet=True
11481164

1149-
def testViewPremJournal(self):
1150-
pass
1165+
def testFilteredJournal(self):
1166+
"""Create two new users pete, david. Permissions do not allow
1167+
access to the user's age prop by any user except admin and
1168+
the same user. Change david's age prop. Invoke
1169+
history/journal as pete, david and admin. Verify age
1170+
changes are not shown to pete, but are shown in other two
1171+
cases.
1172+
1173+
"""
1174+
1175+
new_pete=self.db.user.create(username="pete",
1176+
age=10, roles="User", assignable=False)
1177+
new_david=self.db.user.create(username="david",
1178+
age=10, roles="User", assignable=False)
1179+
1180+
self.db.user.set(new_david, age=20)
1181+
self.db.commit()
1182+
1183+
self.db.setCurrentUser("pete")
1184+
journal = self.db.user.history(new_david, skipquiet=False)
1185+
entry = journal[-1]
1186+
self.assertIsInstance(entry[4], dict)
1187+
self.assertNotIn('age', entry[4])
1188+
1189+
self.db.setCurrentUser("david")
1190+
journal = self.db.user.history(new_david, skipquiet=False)
1191+
entry = journal[-1]
1192+
self.assertIsInstance(entry[4], dict)
1193+
self.assertIn('age', entry[4])
1194+
1195+
self.db.setCurrentUser("admin") # "1" is admin
1196+
journal = self.db.user.history(new_david, skipquiet=False)
1197+
entry = journal[-1]
1198+
self.assertIsInstance(entry[4], dict)
1199+
self.assertIn('age', entry[4])
11511200

11521201
def testQuietJournal(self):
11531202
## This is an example of how to enable logging module
@@ -3565,7 +3614,8 @@ def stdoutwrite(s):
35653614
' User may access the xmlrpc interface (Xmlrpc Access)\n',
35663615
'Role "anonymous":\n', 'Role "user":\n',
35673616
' User is allowed to access msg (View for "msg" only)\n',
3568-
' Prevent users from seeing roles (View for "user": [\'username\', \'supervisor\', \'assignable\'] only)\n']
3617+
' Prevent users from seeing roles (View for "user": [\'username\', \'supervisor\', \'assignable\'] only)\n',
3618+
' Allow viewing of age by own user (View for "user": [\'username\', \'supervisor\', \'assignable\', \'age\'] only)\n']
35693619

35703620
self.assertEqual(soutput, expected)
35713621

0 commit comments

Comments
 (0)