Mercurial > p > roundup > code
comparison roundup/hyperdb.py @ 8126:f7bd22bdef9d permission-performance
Move permission check code to hyperdb
Now the hyperdb has a method filter_with_permissions that performs the
permission checks before (for filtering on sort/group/filterspec
arguments) and after a call to hyperdb.filter.
This also fixes possible problems on the unfiltered
sort/group/filterspec arguments in roundup/rest.py and
roundup/cgi/templating.py
| author | Ralf Schlatterbeck <rsc@runtux.com> |
|---|---|
| date | Mon, 21 Oct 2024 18:12:03 +0200 |
| parents | b8dc16d9624a |
| children | 627871650f4f |
comparison
equal
deleted
inserted
replaced
| 8125:b358da7c89e5 | 8126:f7bd22bdef9d |
|---|---|
| 1794 # cache for each id returned. Note that the filter_iter doesn't | 1794 # cache for each id returned. Note that the filter_iter doesn't |
| 1795 # promise to correctly sort by multilink (which isn't sane to do | 1795 # promise to correctly sort by multilink (which isn't sane to do |
| 1796 # anyway). | 1796 # anyway). |
| 1797 filter_iter = filter | 1797 filter_iter = filter |
| 1798 | 1798 |
| 1799 def filter_with_permissions(self, search_matches, filterspec, sort=[], | |
| 1800 group=[], retired=False, exact_match_spec={}, | |
| 1801 limit=None, offset=None, | |
| 1802 permission='View', userid=None): | |
| 1803 """ Do the same as filter but return only the items the user is | |
| 1804 entitled to see, running the results through security checks. | |
| 1805 The userid defaults to the current database user. | |
| 1806 """ | |
| 1807 if userid is None: | |
| 1808 userid = self.db.getuid() | |
| 1809 cn = self.classname | |
| 1810 sec = self.db.security | |
| 1811 filterspec = sec.filterFilterspec(userid, cn, filterspec) | |
| 1812 sort = sec.filterSortspec(userid, cn, sort) | |
| 1813 group = sec.filterSortspec(userid, cn, group) | |
| 1814 item_ids = self.filter(search_matches, filterspec, sort, group, | |
| 1815 retired, exact_match_spec, limit, offset) | |
| 1816 check = sec.hasPermission | |
| 1817 if check(permission, userid, cn, only_no_check = True): | |
| 1818 allowed = item_ids | |
| 1819 else: | |
| 1820 # Note that is_filterable returns True if no permissions are | |
| 1821 # found. This makes it fail early (with an empty allowed list) | |
| 1822 # instead of running through all ids with an empty | |
| 1823 # permission list. | |
| 1824 if sec.is_filterable(permission, userid, cn): | |
| 1825 new_ids = set(item_ids) | |
| 1826 confirmed = set() | |
| 1827 for perm in sec.filter_iter(permission, userid, cn): | |
| 1828 fargs = perm.filter(self._client.db, userid, klass) | |
| 1829 for farg in fargs: | |
| 1830 farg.update(sort=[], group=[], retired=None) | |
| 1831 result = klass.filter(list(new_ids), **farg) | |
| 1832 new_ids.difference_update(result) | |
| 1833 confirmed.update(result) | |
| 1834 # all allowed? | |
| 1835 if not new_ids: | |
| 1836 break | |
| 1837 # all allowed? | |
| 1838 if not new_ids: | |
| 1839 break | |
| 1840 # Need to sort again in database | |
| 1841 allowed = self.filter(confirmed, {}, sort=sort, group=group, | |
| 1842 retired=None) | |
| 1843 else: # Last resort: filter in python | |
| 1844 allowed = [id for id in item_ids | |
| 1845 if check(permission, userid, cn, itemid=id)] | |
| 1846 return allowed | |
| 1847 | |
| 1848 | |
| 1799 def count(self): | 1849 def count(self): |
| 1800 """Get the number of nodes in this class. | 1850 """Get the number of nodes in this class. |
| 1801 | 1851 |
| 1802 If the returned integer is 'numnodes', the ids of all the nodes | 1852 If the returned integer is 'numnodes', the ids of all the nodes |
| 1803 in this class run from 1 to numnodes, and numnodes+1 will be the | 1853 in this class run from 1 to numnodes, and numnodes+1 will be the |
