comparison roundup/security.py @ 3117:460eb0209a9e

Permissions improvements. - have Permissions only test the check function if itemid is suppled - modify index templates to check for row-level Permission - more documentation of security mechanisms - better unit tests for security mechanisms
author Richard Jones <richard@users.sourceforge.net>
date Fri, 28 Jan 2005 03:51:19 +0000
parents ece73371713c
children 75dc225613cc
comparison
equal deleted inserted replaced
3115:ece73371713c 3117:460eb0209a9e
46 # what about property? 46 # what about property?
47 if property is not None and not self._properties_dict[property]: 47 if property is not None and not self._properties_dict[property]:
48 return 0 48 return 0
49 49
50 # check code 50 # check code
51 if self.check is not None: 51 if itemid is not None and self.check is not None:
52 if not self.check(db, userid, itemid): 52 if not self.check(db, userid, itemid):
53 return 0 53 return 0
54 54
55 # we have a winner 55 # we have a winner
56 return 1 56 return 1
57 57
58 def __repr__(self): 58 def __repr__(self):
59 return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name, 59 return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name,
60 self.klass, self.properties, self.check) 60 self.klass, self.properties, self.check)
61
62 def __cmp__(self, other):
63 if self.name != other.name:
64 return cmp(self.name, other.name)
65
66 if self.klass != other.klass: return 1
67 if self.properties != other.properties: return 1
68 if self.check != other.check: return 1
69
70 # match
71 return 0
61 72
62 class Role: 73 class Role:
63 ''' Defines a Role with the attributes 74 ''' Defines a Role with the attributes
64 - name 75 - name
65 - description 76 - description
107 from roundup.cgi import client 118 from roundup.cgi import client
108 client.initialiseSecurity(self) 119 client.initialiseSecurity(self)
109 from roundup import mailgw 120 from roundup import mailgw
110 mailgw.initialiseSecurity(self) 121 mailgw.initialiseSecurity(self)
111 122
112 def getPermission(self, permission, classname=None): 123 def getPermission(self, permission, classname=None, properties=None,
124 check=None):
113 ''' Find the Permission matching the name and for the class, if the 125 ''' Find the Permission matching the name and for the class, if the
114 classname is specified. 126 classname is specified.
115 127
116 Raise ValueError if there is no exact match. 128 Raise ValueError if there is no exact match.
117 ''' 129 '''
123 self.db.getclass(classname) 135 self.db.getclass(classname)
124 except KeyError: 136 except KeyError:
125 raise ValueError, 'No class "%s" defined'%classname 137 raise ValueError, 'No class "%s" defined'%classname
126 138
127 # look through all the permissions of the given name 139 # look through all the permissions of the given name
140 tester = Permission(permission, klass=classname, properties=properties,
141 check=check)
128 for perm in self.permission[permission]: 142 for perm in self.permission[permission]:
129 # if we're passed a classname, the permission must match 143 if perm == tester:
130 if perm.klass is not None and perm.klass == classname:
131 return perm
132 # otherwise the permission klass must be unset
133 elif not perm.klass and not classname:
134 return perm 144 return perm
135 raise ValueError, 'No permission "%s" defined for "%s"'%(permission, 145 raise ValueError, 'No permission "%s" defined for "%s"'%(permission,
136 classname) 146 classname)
137 147
138 def hasPermission(self, permission, userid, classname=None, 148 def hasPermission(self, permission, userid, classname=None,
139 property=None, itemid=None): 149 property=None, itemid=None):
140 ''' Look through all the Roles, and hence Permissions, and see if 150 '''Look through all the Roles, and hence Permissions, and
141 "permission" is there for the specified classname. 151 see if "permission" exists given the constraints of
152 classname, property and itemid.
153
154 If classname is specified (and only classname) then the
155 search will match if there is *any* Permission for that
156 classname, even if the Permission has additional
157 constraints.
158
159 If property is specified, the Permission matched must have
160 either no properties listed or the property must appear in
161 the list.
162
163 If itemid is specified, the Permission matched must have
164 either no check function defined or the check function,
165 when invoked, must return a True value.
166
167 Note that this functionality is actually implemented by the
168 Permission.test() method.
142 ''' 169 '''
143 roles = self.db.user.get(userid, 'roles') 170 roles = self.db.user.get(userid, 'roles')
144 if roles is None: 171 if roles is None:
145 return 0 172 return 0
146 if itemid and classname is None: 173 if itemid and classname is None:
148 for rolename in [x.lower().strip() for x in roles.split(',')]: 175 for rolename in [x.lower().strip() for x in roles.split(',')]:
149 if not rolename or not self.role.has_key(rolename): 176 if not rolename or not self.role.has_key(rolename):
150 continue 177 continue
151 # for each of the user's Roles, check the permissions 178 # for each of the user's Roles, check the permissions
152 for perm in self.role[rolename].permissions: 179 for perm in self.role[rolename].permissions:
153 # permission name match? 180 # permission match?
154 if perm.test(self.db, permission, classname, property, 181 if perm.test(self.db, permission, classname, property,
155 userid, itemid): 182 userid, itemid):
156 return 1 183 return 1
157 return 0 184 return 0
158 185
159 def hasNodePermission(self, classname, nodeid, **propspec):
160 ''' Check the named properties of the given node to see if the
161 userid appears in them. If it does, then the user is granted
162 this permission check.
163
164 'propspec' consists of a set of properties and values that
165 must be present on the given node for access to be granted.
166
167 If a property is a Link, the value must match the property
168 value. If a property is a Multilink, the value must appear
169 in the Multilink list.
170 '''
171 klass = self.db.getclass(classname)
172 properties = klass.getprops()
173 for k,v in propspec.items():
174 value = klass.get(nodeid, k)
175 if isinstance(properties[k], hyperdb.Multilink):
176 if v not in value:
177 return 0
178 else:
179 if v != value:
180 return 0
181 return 1
182
183 def addPermission(self, **propspec): 186 def addPermission(self, **propspec):
184 ''' Create a new Permission with the properties defined in 187 ''' Create a new Permission with the properties defined in
185 'propspec' 188 'propspec'. See the Permission class for the possible
189 keyword args.
186 ''' 190 '''
187 perm = Permission(**propspec) 191 perm = Permission(**propspec)
188 self.permission.setdefault(perm.name, []).append(perm) 192 self.permission.setdefault(perm.name, []).append(perm)
189 return perm 193 return perm
190 194
193 ''' 197 '''
194 role = Role(**propspec) 198 role = Role(**propspec)
195 self.role[role.name] = role 199 self.role[role.name] = role
196 return role 200 return role
197 201
198 def addPermissionToRole(self, rolename, permission, classname=None): 202 def addPermissionToRole(self, rolename, permission, classname=None,
203 properties=None, check=None):
199 ''' Add the permission to the role's permission list. 204 ''' Add the permission to the role's permission list.
200 205
201 'rolename' is the name of the role to add the permission to. 206 'rolename' is the name of the role to add the permission to.
202 207
203 'permission' is either a Permission *or* a permission name 208 'permission' is either a Permission *or* a permission name
204 accompanied by 'classname' (thus in the second case a Permission 209 accompanied by 'classname' (thus in the second case a Permission
205 is obtained by passing 'permission' and 'classname' to 210 is obtained by passing 'permission' and 'classname' to
206 self.getPermission) 211 self.getPermission)
207 ''' 212 '''
208 if not isinstance(permission, Permission): 213 if not isinstance(permission, Permission):
209 permission = self.getPermission(permission, classname) 214 permission = self.getPermission(permission, classname,
215 properties, check)
210 role = self.role[rolename.lower()] 216 role = self.role[rolename.lower()]
211 role.permissions.append(permission) 217 role.permissions.append(permission)
212 218
213 # vim: set filetype=python sts=4 sw=4 et si : 219 # vim: set filetype=python sts=4 sw=4 et si :

Roundup Issue Tracker: http://roundup-tracker.org/