Mercurial > p > roundup > code
comparison test/db_test_base.py @ 5232:462b0f76fce8
issue2550864 - Potential information leakage via journal/history
Fix this by making the hyperdb::Class::history function check for view
permissions on the journaled properties. So a user that sees [hidden]
for a property in the web interface doesn;t see the property changes
in the history.
While doing this, relocated the filter for quiet properties
from the templating class to the hyperdb.
Also added the skipquiet option to the history command in
roundup-admin.py to enable filtering of quiet params.
Also changed calls to history() in the backend databases to report all
items.
Changed inline documentation for all history calls that document the
actions. The create action (before nov 6 2002) used to record all
parameters. After that point the create call uses an empty dictionary.
The filtering code depends on the create dictionary being empty.
It may not operate properly on very old roundup databases.
Changed calls to logging.getLogger to roundup.hyperdb.backends to
allow filtering the back end while keeping hyperdb logging.
In cgi/templating.py, changed history() function consolidating
handiling of link and unlink actions
Added tests for quiet property filtering and permission filtering
of history.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Fri, 14 Apr 2017 23:24:18 -0400 |
| parents | e1e40674a0bc |
| children | ebc27b90aa3b |
comparison
equal
deleted
inserted
replaced
| 5231:8743b7226dc7 | 5232:462b0f76fce8 |
|---|---|
| 123 db.commit() | 123 db.commit() |
| 124 | 124 |
| 125 # nosy tests require this | 125 # nosy tests require this |
| 126 db.security.addPermissionToRole('User', 'View', 'msg') | 126 db.security.addPermissionToRole('User', 'View', 'msg') |
| 127 | 127 |
| 128 # quiet journal tests require this | |
| 129 # QuietJournal - reference used later in tests | |
| 130 v1 = db.security.addPermission(name='View', klass='user', | |
| 131 properties=['username', 'supervisor', 'assignable'], | |
| 132 description="Prevent users from seeing roles") | |
| 133 | |
| 134 db.security.addPermissionToRole("User", v1) | |
| 128 | 135 |
| 129 class MyTestCase(object): | 136 class MyTestCase(object): |
| 130 def tearDown(self): | 137 def tearDown(self): |
| 131 if hasattr(self, 'db'): | 138 if hasattr(self, 'db'): |
| 132 self.db.close() | 139 self.db.close() |
| 970 result=self.db.issue.generateCreateNote(new_issue) | 977 result=self.db.issue.generateCreateNote(new_issue) |
| 971 self.assertEqual(result, '\n----------\ndeadline: 2016-07-13.22:39:00\nnosy: admin, fred\ntitle: title2') | 978 self.assertEqual(result, '\n----------\ndeadline: 2016-07-13.22:39:00\nnosy: admin, fred\ntitle: title2') |
| 972 self.db.issue.properties['nosy'].quiet=True | 979 self.db.issue.properties['nosy'].quiet=True |
| 973 self.db.issue.properties['deadline'].quiet=True | 980 self.db.issue.properties['deadline'].quiet=True |
| 974 | 981 |
| 982 def testViewPremJournal(self): | |
| 983 pass | |
| 984 | |
| 975 def testQuietJournal(self): | 985 def testQuietJournal(self): |
| 976 # FIXME this doesn't work. I need to call | 986 # FIXME There should be a test via |
| 977 # template.py::_HTMLItem::history() and verify the output. | 987 # template.py::_HTMLItem::history() and verify the output. |
| 978 # not sure how to get there from here. -- rouilj | 988 # not sure how to get there from here. -- rouilj |
| 979 # make sure that the quiet properties: "assignable" and "age" are not | 989 |
| 980 # returned as part of the journal | 990 # The Class::history() method now does filtering of quiet |
| 981 # so comment out tests here but leave framework for later. | 991 # props. Make sure that the quiet properties: "assignable" |
| 992 # and "age" are not returned as part of the journal | |
| 982 new_user=self.db.user.create(username="pete", age=10, assignable=False) | 993 new_user=self.db.user.create(username="pete", age=10, assignable=False) |
| 983 new_issue=self.db.issue.create(title="title", deadline=date.Date('2016-6-30.22:39')) | 994 new_issue=self.db.issue.create(title="title", deadline=date.Date('2016-6-30.22:39')) |
| 984 | 995 |
| 985 # change all quiet params. Verify they aren't returned in journal. | 996 # change all quiet params. Verify they aren't returned in journal. |
| 986 # between this and the issue class every type represented in hyperdb | 997 # between this and the issue class every type represented in hyperdb |
| 987 # should be initalized with a quiet parameter. | 998 # should be initalized with a quiet parameter. |
| 988 result=self.db.user.set(new_user, username="new", age=20, supervisor='3', assignable=True, | 999 result=self.db.user.set(new_user, username="new", age=20, |
| 989 password=password.Password("3456"), rating=4, realname="newname") | 1000 supervisor='1', assignable=True, |
| 990 result=self.db.user.history(new_user) | 1001 password=password.Password("3456"), |
| 991 #self.assertEqual(result, 20) | 1002 rating=4, realname="newname") |
| 992 | 1003 result=self.db.user.history(new_user, skipquiet=False) |
| 993 # change all quiet params. Verify they aren't returned in object. | 1004 ''' |
| 994 result=self.db.issue.set(new_issue, title="title2", deadline=date.Date('2016-6-30.22:39'), | 1005 [('3', <Date 2017-04-14.02:12:20.922>, '1', 'create', {}), |
| 1006 ('3', <Date 2017-04-14.02:12:20.922>, '1', 'set', | |
| 1007 {'username': 'pete', 'assignable': False, | |
| 1008 'supervisor': None, 'realname': None, 'rating': None, | |
| 1009 'age': 10, 'password': None})] | |
| 1010 ''' | |
| 1011 expected = {'username': 'pete', 'assignable': False, | |
| 1012 'supervisor': None, 'realname': None, 'rating': None, | |
| 1013 'age': 10, 'password': None} | |
| 1014 | |
| 1015 result.sort() | |
| 1016 (id, tx_date, user, action, args) = result[-1] | |
| 1017 # check piecewise ignoring date of transaction | |
| 1018 self.assertEqual('3', id) | |
| 1019 self.assertEqual('1', user) | |
| 1020 self.assertEqual('set', action) | |
| 1021 self.assertEqual(expected, args) | |
| 1022 | |
| 1023 # change all quiet params on issue. | |
| 1024 result=self.db.issue.set(new_issue, title="title2", | |
| 1025 deadline=date.Date('2016-07-30.22:39'), | |
| 995 assignedto="2", nosy=["3", "2"]) | 1026 assignedto="2", nosy=["3", "2"]) |
| 996 result=self.db.issue.generateCreateNote(new_issue) | 1027 result=self.db.issue.generateCreateNote(new_issue) |
| 997 #self.assertEqual(result, '\n----------\ntitle: title2') | 1028 self.assertEqual(result, '\n----------\ntitle: title2') |
| 1029 | |
| 1030 # check history including quiet properties | |
| 1031 result=self.db.issue.history(new_issue, skipquiet=False) | |
| 1032 print result | |
| 1033 ''' output should be like: | |
| 1034 [ ... ('1', <Date 2017-04-14.01:41:08.466>, '1', 'set', | |
| 1035 {'assignedto': None, 'nosy': (('+', ['3', '2']),), | |
| 1036 'deadline': <Date 2016-06-30.22:39:00.000>, | |
| 1037 'title': 'title'}) | |
| 1038 ''' | |
| 1039 expected = {'assignedto': None, | |
| 1040 'nosy': (('+', ['3', '2']),), | |
| 1041 'deadline': date.Date('2016-06-30.22:39'), | |
| 1042 'title': 'title'} | |
| 1043 | |
| 1044 result.sort() | |
| 1045 print "history include quiet props", result[-1] | |
| 1046 (id, tx_date, user, action, args) = result[-1] | |
| 1047 # check piecewise ignoring date of transaction | |
| 1048 self.assertEqual('1', id) | |
| 1049 self.assertEqual('1', user) | |
| 1050 self.assertEqual('set', action) | |
| 1051 self.assertEqual(expected, args) | |
| 1052 | |
| 1053 # check history removing quiet properties | |
| 1054 result=self.db.issue.history(new_issue) | |
| 1055 ''' output should be like: | |
| 1056 [ ... ('1', <Date 2017-04-14.01:41:08.466>, '1', 'set', | |
| 1057 {'title': 'title'}) | |
| 1058 ''' | |
| 1059 expected = {'title': 'title'} | |
| 1060 | |
| 1061 result.sort() | |
| 1062 print "history remove quiet props", result[-1] | |
| 1063 (id, tx_date, user, action, args) = result[-1] | |
| 1064 # check piecewise | |
| 1065 self.assertEqual('1', id) | |
| 1066 self.assertEqual('1', user) | |
| 1067 self.assertEqual('set', action) | |
| 1068 self.assertEqual(expected, args) | |
| 998 | 1069 |
| 999 # also test that we can make a property noisy | 1070 # also test that we can make a property noisy |
| 1000 self.db.issue.properties['nosy'].quiet=False | 1071 self.db.issue.properties['nosy'].quiet=False |
| 1001 self.db.issue.properties['deadline'].quiet=False | 1072 self.db.issue.properties['deadline'].quiet=False |
| 1002 result=self.db.issue.set(new_issue, title="title2", deadline=date.Date('2016-7-13.22:39'), | 1073 result=self.db.issue.set(new_issue, title="title2", |
| 1074 deadline=date.Date('2016-7-13.22:39'), | |
| 1003 assignedto="2", nosy=["1", "2"]) | 1075 assignedto="2", nosy=["1", "2"]) |
| 1004 result=self.db.issue.generateCreateNote(new_issue) | 1076 result=self.db.issue.generateCreateNote(new_issue) |
| 1005 #self.assertEqual(result, '\n----------\ndeadline: 2016-07-13.22:39:00\nnosy: admin, fred\ntitle: title2') | 1077 self.assertEqual(result, '\n----------\ndeadline: 2016-07-13.22:39:00\nnosy: admin, fred\ntitle: title2') |
| 1078 | |
| 1079 | |
| 1080 # check history removing the current quiet properties | |
| 1081 result=self.db.issue.history(new_issue) | |
| 1082 expected = {'nosy': (('+', ['1']), ('-', ['3'])), | |
| 1083 'deadline': date.Date("2016-07-30.22:39:00.000")} | |
| 1084 | |
| 1085 result.sort() | |
| 1086 (id, tx_date, user, action, args) = result[-1] | |
| 1087 # check piecewise | |
| 1088 self.assertEqual('1', id) | |
| 1089 self.assertEqual('1', user) | |
| 1090 self.assertEqual('set', action) | |
| 1091 self.assertEqual(expected, args) | |
| 1092 | |
| 1093 # reset quiet props | |
| 1006 self.db.issue.properties['nosy'].quiet=True | 1094 self.db.issue.properties['nosy'].quiet=True |
| 1007 self.db.issue.properties['deadline'].quiet=True | 1095 self.db.issue.properties['deadline'].quiet=True |
| 1096 | |
| 1097 # Change the role for the new_user. | |
| 1098 # If journal is retrieved by admin this adds the role | |
| 1099 # change as the last element. If retreived by non-admin | |
| 1100 # it should not be returned because the user has no | |
| 1101 # View permissons on role.. | |
| 1102 result=self.db.user.set(new_user, roles="foo, bar") | |
| 1103 | |
| 1104 # Verify last journal entry as admin is a role change | |
| 1105 # from None | |
| 1106 result=self.db.user.history(new_user, skipquiet=False) | |
| 1107 result.sort() | |
| 1108 ''' result should end like: | |
| 1109 [ ... | |
| 1110 ('3', <Date 2017-04-15.02:06:11.482>, '1', 'set', | |
| 1111 {'username': 'pete', 'assignable': False, | |
| 1112 'supervisor': None, 'realname': None, | |
| 1113 'rating': None, 'age': 10, 'password': None}), | |
| 1114 ('3', <Date 2017-04-15.02:06:11.482>, '1', 'link', | |
| 1115 ('issue', '1', 'nosy')), | |
| 1116 ('3', <Date 2017-04-15.02:06:11.482>, '1', 'unlink', | |
| 1117 ('issue', '1', 'nosy')), | |
| 1118 ('3', <Date 2017-04-15.02:06:11.482>, '1', 'set', | |
| 1119 {'roles': None})] | |
| 1120 ''' | |
| 1121 (id, tx_date, user, action, args) = result[-1] | |
| 1122 expected= {'roles': None } | |
| 1123 | |
| 1124 self.assertEqual('3', id) | |
| 1125 self.assertEqual('1', user) | |
| 1126 self.assertEqual('set', action) | |
| 1127 self.assertEqual(expected, args) | |
| 1128 | |
| 1129 # set an existing user's role to User so it can | |
| 1130 # view some props of the user class (search backwards | |
| 1131 # for QuietJournal to see the properties, they should be: | |
| 1132 # 'username', 'supervisor', 'assignable' i.e. age is not | |
| 1133 # one of them. | |
| 1134 id = self.db.user.lookup("fred") | |
| 1135 result=self.db.user.set(id, roles="User") | |
| 1136 # make the user fred current. | |
| 1137 self.db.setCurrentUser('fred') | |
| 1138 self.assertEqual(self.db.getuid(), id) | |
| 1139 | |
| 1140 # check history as the user fred | |
| 1141 # include quiet properties | |
| 1142 # but require View perms | |
| 1143 result=self.db.user.history(new_user, skipquiet=False) | |
| 1144 result.sort() | |
| 1145 ''' result should look like | |
| 1146 [('3', <Date 2017-04-15.01:43:26.911>, '1', 'create', {}), | |
| 1147 ('3', <Date 2017-04-15.01:43:26.911>, '1', 'set', | |
| 1148 {'username': 'pete', 'assignable': False, | |
| 1149 'supervisor': None, 'age': 10})] | |
| 1150 ''' | |
| 1151 # analyze last item | |
| 1152 (id, tx_date, user, action, args) = result[-1] | |
| 1153 expected= {'username': 'pete', 'assignable': False, | |
| 1154 'supervisor': None} | |
| 1155 | |
| 1156 self.assertEqual('3', id) | |
| 1157 self.assertEqual('1', user) | |
| 1158 self.assertEqual('set', action) | |
| 1159 self.assertEqual(expected, args) | |
| 1160 | |
| 1161 # reset the user to admin | |
| 1162 self.db.setCurrentUser('admin') | |
| 1163 self.assertEqual(self.db.getuid(), '1') # admin is always 1 | |
| 1008 | 1164 |
| 1009 def testJournals(self): | 1165 def testJournals(self): |
| 1010 muid = self.db.user.create(username="mary") | 1166 muid = self.db.user.create(username="mary") |
| 1011 self.db.user.create(username="pete") | 1167 self.db.user.create(username="pete") |
| 1012 self.db.issue.create(title="spam", status='1') | 1168 self.db.issue.create(title="spam", status='1') |
| 2189 ' User may view everything (View)\n', | 2345 ' User may view everything (View)\n', |
| 2190 ' User may access the web interface (Web Access)\n', | 2346 ' User may access the web interface (Web Access)\n', |
| 2191 ' User may manipulate user Roles through the web (Web Roles)\n', | 2347 ' User may manipulate user Roles through the web (Web Roles)\n', |
| 2192 ' User may use the email interface (Email Access)\n', | 2348 ' User may use the email interface (Email Access)\n', |
| 2193 'Role "anonymous":\n', 'Role "user":\n', | 2349 'Role "anonymous":\n', 'Role "user":\n', |
| 2194 ' User is allowed to access msg (View for "msg" only)\n']) | 2350 ' User is allowed to access msg (View for "msg" only)\n', |
| 2351 ' Prevent users from seeing roles (View for "user": [\'username\', \'supervisor\', \'assignable\'] only)\n']) | |
| 2195 | 2352 |
| 2196 | 2353 |
| 2197 self.nukeAndCreate() | 2354 self.nukeAndCreate() |
| 2198 tool = roundup.admin.AdminTool() | 2355 tool = roundup.admin.AdminTool() |
| 2199 tool.tracker_home = home | 2356 tool.tracker_home = home |
