Mercurial > p > roundup > code
comparison roundup/security.py @ 4437:261c9f913ff7
- Add explicit "Search" permissions, see Security Fix below.
- Security Fix: Add a check for search-permissions: now we allow
searching for properties only if the property is readable without a
check method or if an explicit search permission (see above unter
"Features) is given for the property. This fixes cases where a user
doesn't have access to a property but can deduce the content by
crafting a clever search, group or sort query.
see doc/upgrading.txt for how to fix your trackers!
| author | Ralf Schlatterbeck <schlatterbeck@users.sourceforge.net> |
|---|---|
| date | Tue, 19 Oct 2010 15:29:05 +0000 |
| parents | 966592263fb8 |
| children | 222efa59ee6c |
comparison
equal
deleted
inserted
replaced
| 4436:528ace81fd16 | 4437:261c9f913ff7 |
|---|---|
| 52 return 0 | 52 return 0 |
| 53 | 53 |
| 54 # we have a winner | 54 # we have a winner |
| 55 return 1 | 55 return 1 |
| 56 | 56 |
| 57 def searchable(self, db, permission, classname, property): | |
| 58 """ A Permission is searchable for the given permission if it | |
| 59 doesn't include a check method and otherwise matches the | |
| 60 given parameters. | |
| 61 """ | |
| 62 if permission != self.name: | |
| 63 return 0 | |
| 64 | |
| 65 # are we checking the correct class | |
| 66 if self.klass != classname: | |
| 67 return 0 | |
| 68 | |
| 69 # what about property? | |
| 70 if not self._properties_dict[property]: | |
| 71 return 0 | |
| 72 | |
| 73 if self.check: | |
| 74 return 0 | |
| 75 | |
| 76 return 1 | |
| 77 | |
| 78 | |
| 57 def __repr__(self): | 79 def __repr__(self): |
| 58 return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name, | 80 return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name, |
| 59 self.klass, self.properties, self.check) | 81 self.klass, self.properties, self.check) |
| 60 | 82 |
| 61 def __cmp__(self, other): | 83 def __cmp__(self, other): |
| 173 if perm.test(self.db, permission, classname, property, | 195 if perm.test(self.db, permission, classname, property, |
| 174 userid, itemid): | 196 userid, itemid): |
| 175 return 1 | 197 return 1 |
| 176 return 0 | 198 return 0 |
| 177 | 199 |
| 200 def roleHasSearchPermission(self, rolename, classname, property): | |
| 201 """ for each of the user's Roles, check the permissions | |
| 202 """ | |
| 203 for perm in self.role[rolename].permissions: | |
| 204 # permission match? | |
| 205 for p in 'View', 'Search': | |
| 206 if perm.searchable(self.db, p, classname, property): | |
| 207 return 1 | |
| 208 return 0 | |
| 209 | |
| 210 def hasSearchPermission(self, userid, classname, property): | |
| 211 '''Look through all the Roles, and hence Permissions, and | |
| 212 see if "permission" exists given the constraints of | |
| 213 classname and property. | |
| 214 | |
| 215 A search permission is granted if we find a 'View' or | |
| 216 'Search' permission for the user which does *not* include | |
| 217 a check function. If such a permission is found, the user may | |
| 218 search for the given property in the given class. | |
| 219 | |
| 220 Note that classname *and* property are mandatory arguments. | |
| 221 | |
| 222 Contrary to hasPermission, the search will *not* match if | |
| 223 there are additional constraints (namely a search function) | |
| 224 on a Permission found. | |
| 225 | |
| 226 Concerning property, the Permission matched must have | |
| 227 either no properties listed or the property must appear in | |
| 228 the list. | |
| 229 ''' | |
| 230 for rolename in self.db.user.get_roles(userid): | |
| 231 if not rolename or not self.role.has_key(rolename): | |
| 232 continue | |
| 233 # for each of the user's Roles, check the permissions | |
| 234 if self.roleHasSearchPermission (rolename, classname, property): | |
| 235 return 1 | |
| 236 return 0 | |
| 237 | |
| 178 def addPermission(self, **propspec): | 238 def addPermission(self, **propspec): |
| 179 ''' Create a new Permission with the properties defined in | 239 ''' Create a new Permission with the properties defined in |
| 180 'propspec'. See the Permission class for the possible | 240 'propspec'. See the Permission class for the possible |
| 181 keyword args. | 241 keyword args. |
| 182 ''' | 242 ''' |
| 206 permission = self.getPermission(permission, classname, | 266 permission = self.getPermission(permission, classname, |
| 207 properties, check) | 267 properties, check) |
| 208 role = self.role[rolename.lower()] | 268 role = self.role[rolename.lower()] |
| 209 role.permissions.append(permission) | 269 role.permissions.append(permission) |
| 210 | 270 |
| 271 # Convenience methods for removing non-allowed properties from a | |
| 272 # filterspec or sort/group list | |
| 273 | |
| 274 def filterFilterspec(self, userid, classname, filterspec): | |
| 275 """ Return a filterspec that has all non-allowed properties removed. | |
| 276 """ | |
| 277 return dict ([(k, v) for k, v in filterspec.iteritems() | |
| 278 if self.hasSearchPermission(userid,classname,k)]) | |
| 279 | |
| 280 def filterSortspec(self, userid, classname, sort): | |
| 281 """ Return a sort- or group-list that has all non-allowed properties | |
| 282 removed. | |
| 283 """ | |
| 284 if isinstance(sort, tuple) and sort[0] in '+-': | |
| 285 sort = [sort] | |
| 286 return [(d, p) for d, p in sort | |
| 287 if self.hasSearchPermission(userid,classname,p)] | |
| 288 | |
| 211 # vim: set filetype=python sts=4 sw=4 et si : | 289 # vim: set filetype=python sts=4 sw=4 et si : |
