Code

- Add explicit "Search" permissions, see Security Fix below.
[roundup.git] / roundup / security.py
index 3dfa8bd442c13ec068ca90589a10e55fc9f5b9fa..9bfb0ecdd773777011f7ee4e7634a9e51745526a 100644 (file)
@@ -54,6 +54,28 @@ class Permission:
         # we have a winner
         return 1
 
+    def searchable(self, db, permission, classname, property):
+        """ A Permission is searchable for the given permission if it
+            doesn't include a check method and otherwise matches the
+            given parameters.
+        """
+        if permission != self.name:
+            return 0
+
+        # are we checking the correct class
+        if self.klass != classname:
+            return 0
+
+        # what about property?
+        if not self._properties_dict[property]:
+            return 0
+
+        if self.check:
+            return 0
+
+        return 1
+
+
     def __repr__(self):
         return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name,
             self.klass, self.properties, self.check)
@@ -175,6 +197,44 @@ class Security:
                     return 1
         return 0
 
+    def roleHasSearchPermission(self, rolename, classname, property):
+        """ for each of the user's Roles, check the permissions
+        """
+        for perm in self.role[rolename].permissions:
+            # permission match?
+            for p in 'View', 'Search':
+                if perm.searchable(self.db, p, classname, property):
+                    return 1
+        return 0
+
+    def hasSearchPermission(self, userid, classname, property):
+        '''Look through all the Roles, and hence Permissions, and
+           see if "permission" exists given the constraints of
+           classname and property.
+
+           A search permission is granted if we find a 'View' or
+           'Search' permission for the user which does *not* include
+           a check function. If such a permission is found, the user may
+           search for the given property in the given class.
+
+           Note that classname *and* property are mandatory arguments.
+
+           Contrary to hasPermission, the search will *not* match if
+           there are additional constraints (namely a search function)
+           on a Permission found.
+
+           Concerning property, the Permission matched must have
+           either no properties listed or the property must appear in
+           the list.
+        '''
+        for rolename in self.db.user.get_roles(userid):
+            if not rolename or not self.role.has_key(rolename):
+                continue
+            # for each of the user's Roles, check the permissions
+            if self.roleHasSearchPermission (rolename, classname, property):
+                return 1
+        return 0
+
     def addPermission(self, **propspec):
         ''' Create a new Permission with the properties defined in
             'propspec'. See the Permission class for the possible
@@ -208,4 +268,22 @@ class Security:
         role = self.role[rolename.lower()]
         role.permissions.append(permission)
 
+    # Convenience methods for removing non-allowed properties from a
+    # filterspec or sort/group list
+
+    def filterFilterspec(self, userid, classname, filterspec):
+        """ Return a filterspec that has all non-allowed properties removed.
+        """
+        return dict ([(k, v) for k, v in filterspec.iteritems()
+            if self.hasSearchPermission(userid,classname,k)])
+
+    def filterSortspec(self, userid, classname, sort):
+        """ Return a sort- or group-list that has all non-allowed properties
+            removed.
+        """
+        if isinstance(sort, tuple) and sort[0] in '+-':
+            sort = [sort]
+        return [(d, p) for d, p in sort
+            if self.hasSearchPermission(userid,classname,p)]
+
 # vim: set filetype=python sts=4 sw=4 et si :