989227403097a65d2c924470744d40a36d4d7aa5
[GroupUserFolder.git] / interfaces / IUserFolder.py
1 # -*- coding: utf-8 -*-
2 ## GroupUserFolder
3 ## Copyright (C)2006 Ingeniweb
4
5 ## This program is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 2 of the License, or
8 ## (at your option) any later version.
9
10 ## This program is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
14
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program; see the file COPYING. If not, write to the
17 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 """
19 VOCABULARY:
20
21 - [Pure] User: A user is a user atom who can log itself on, and
22 have additional properties such as domains and password.
23
24 - Group: A group is a user atom other atoms can belong to.
25
26 - User atom: Abstract representation of either a User or
27 a Group.
28
29 - Member (of a group): User atom inside a group.
30
31 - Name (of an atom): For a user, the name can be set by
32 the underlying user folder but usually id == name.
33 For a group, its id is prefixed, but its name is NOT prefixed by 'group_'.
34 For method taking a name instead of an id (eg. getUserByName()),
35 if a user and a group have the same name,
36 the USER will have precedence over the group.
37 """
38 __version__ = "$Revision: $"
39 # $Source: $
40 # $Id: IUserFolder.py 30098 2006-09-08 12:35:01Z encolpe $
41 __docformat__ = 'restructuredtext'
42
43 from Interface import Attribute
44 try:
45 from Interface import Interface
46 except ImportError:
47 # for Zope versions before 2.6.0
48 from Interface import Base as Interface
49
50
51
52 class IUserFolder(Interface):
53
54 # #
55 # Regular Zope UserFolder API #
56 # #
57
58 # User atom access
59
60 def getUserNames():
61 """
62 Return a list of all possible user atom names in the system.
63 Groups will be returned WITHOUT their prefix by this method.
64 So, there might be a collision between a user name and a group name.
65 [NOTA: This method is time-expensive !]
66 """
67
68 def getUserIds():
69 """
70 Return a list of all possible user atom ids in the system.
71 WARNING: Please see the id Vs. name consideration at the
72 top of this document. So, groups will be returned
73 WITH their prefix by this method
74 [NOTA: This method is time-expensive !]
75 """
76
77 def getUser(name):
78 """Return the named user atom object or None
79 NOTA: If no user can be found, we try to append a group prefix
80 and fetch the user again before returning 'None'. This will ensure
81 backward compatibility. So in fact, both group id and group name can be
82 specified to this method.
83 """
84
85 def getUsers():
86 """Return a list of user atom objects in the users cache.
87 In case of some UF implementations, the returned object may only be a subset
88 of all possible users.
89 In other words, you CANNOT assert that len(getUsers()) equals len(getUserNames()).
90 With cache-support UserFolders, such as LDAPUserFolder, the getUser() method will
91 return only cached user objects instead of fetching all possible users.
92 So this method won't be very time-expensive, but won't be accurate !
93 """
94
95 def getUserById(id, default):
96 """Return the user atom corresponding to the given id.
97 If default is provided, return default if no user found, else return None.
98 """
99
100 def getUserByName(name, default):
101 """Same as getUserById() but works with a name instead of an id.
102 If default is provided, return default if no user found, else return None.
103 [NOTA: Theorically, the id is a handle, while the name is the actual login name.
104 But difference between a user id and a user name is unsignificant in
105 all current User Folder implementations... except for GROUPS.]
106 """
107
108 def hasUsers():
109 """
110 From Zope 2.7's User.py:
111 This is not a formal API method: it is used only to provide
112 a way for the quickstart page to determine if the default user
113 folder contains any users to provide instructions on how to
114 add a user for newbies. Using getUserNames or getUsers would have
115 posed a denial of service risk.
116 In GRUF, this method always return 1."""
117
118
119 # Search interface for users; they won't return groups in any case.
120
121 def searchUsersByName(search_term):
122 """Return user ids which match the specified search_term.
123 If search_term is an empty string, behaviour depends on the underlying user folder:
124 it may return all users, return only cached users (for LDAPUF) or return no users.
125 """
126
127 def searchUsersById(search_term):
128 """Return users whose id match the specified search_term.
129 If search_term is an empty string, behaviour depends on the underlying user folder:
130 it may return all users, return only cached users (for LDAPUF) or return no users.
131 """
132
133 def searchUsersByAttribute(attribute, search_term):
134 """Return user ids whose 'attribute' match the specified search_term.
135 If search_term is an empty string, behaviour depends on the underlying user folder:
136 it may return all users, return only cached users (for LDAPUF) or return no users.
137 This will return all users whose name contains search_term (whaterver its case).
138 THIS METHOD MAY BE VERY EXPENSIVE ON USER FOLDER KINDS WHICH DO NOT PROVIDE A
139 SEARCHING METHOD (ie. every UF kind except LDAPUF).
140 'attribute' can be 'id' or 'name' for all UF kinds, or anything else for LDAPUF.
141 [NOTA: This method is time-expensive !]
142 """
143
144 # Search interface for groups;
145
146 def searchGroupsByName(search_term):
147 """Return group ids which match the specified search_term.
148 If search_term is an empty string, behaviour depends on the underlying group folder:
149 it may return all groups, return only cached groups (for LDAPUF) or return no groups.
150 """
151
152 def searchGroupsById(search_term):
153 """Return groups whose id match the specified search_term.
154 If search_term is an empty string, behaviour depends on the underlying group folder:
155 it may return all groups, return only cached groups (for LDAPUF) or return no groups.
156 """
157
158 def searchGroupsByAttribute(attribute, search_term):
159 """Return group ids whose 'attribute' match the specified search_term.
160 If search_term is an empty string, behaviour depends on the underlying group folder:
161 it may return all groups, return only cached groups (for LDAPUF) or return no groups.
162 This will return all groups whose name contains search_term (whaterver its case).
163 THIS METHOD MAY BE VERY EXPENSIVE ON GROUP FOLDER KINDS WHICH DO NOT PROVIDE A
164 SEARCHING METHOD (ie. every UF kind except LDAPUF).
165 'attribute' can be 'id' or 'name' for all UF kinds, or anything else for LDAPUF.
166 [NOTA: This method is time-expensive !]
167 """
168
169
170 # User access
171
172 def getPureUserNames():
173 """Same as getUserNames() but without groups
174 """
175
176 def getPureUserIds():
177 """Same as getUserIds() but without groups
178 """
179
180 def getPureUsers():
181 """Same as getUsers() but without groups.
182 """
183
184 def getPureUser(id):
185 """Same as getUser() but forces returning a user and not a group
186 """
187
188 # Group access
189
190 def getGroupNames():
191 """Same as getUserNames() but without pure users.
192 """
193
194 def getGroupIds():
195 """Same as getUserIds() but without pure users.
196 """
197
198 def getGroups():
199 """Same as getUsers() but without pure users.
200 In case of some UF implementations, the returned object may only be a subset
201 of all possible users.
202 In other words, you CANNOT assert that len(getUsers()) equals len(getUserNames()).
203 With cache-support UserFolders, such as LDAPUserFolder, the getUser() method will
204 return only cached user objects instead of fetching all possible users.
205 So this method won't be very time-expensive, but won't be accurate !
206 """
207
208 def getGroup(name):
209 """Return the named group object or None. As usual, 'id' is prefixed.
210 """
211
212 def getGroupById(id):
213 """Same as getUserById(id) but forces returning a group.
214 """
215
216 def getGroupByName(name):
217 """Same as getUserByName(name) but forces returning a group.
218 The specified name MUST NOT be prefixed !
219 """
220
221
222 # Mutators
223
224 def userFolderAddUser(name, password, roles, domains, groups, **kw):
225 """API method for creating a new user object. Note that not all
226 user folder implementations support dynamic creation of user
227 objects.
228 Groups can be specified by name or by id (preferabily by name)."""
229
230 def userFolderEditUser(name, password, roles, domains, groups, **kw):
231 """API method for changing user object attributes. Note that not
232 all user folder implementations support changing of user object
233 attributes.
234 Groups can be specified by name or by id (preferabily by name)."""
235
236 def userFolderUpdateUser(name, password, roles, domains, groups, **kw):
237 """Same as userFolderEditUser, but with all arguments except name
238 being optional.
239 """
240
241 def userFolderDelUsers(names):
242 """API method for deleting one or more user atom objects. Note that not
243 all user folder implementations support deletion of user objects."""
244
245 def userFolderAddGroup(name, roles, groups, **kw):
246 """API method for creating a new group.
247 """
248
249 def userFolderEditGroup(name, roles, groups, **kw):
250 """API method for changing group object attributes.
251 """
252
253 def userFolderUpdateGroup(name, roles, groups, **kw):
254 """Same as userFolderEditGroup but with all arguments (except name) being
255 optinal.
256 """
257
258 def userFolderDelGroups(names):
259 """API method for deleting one or more group objects.
260 Implem. note : All ids must be prefixed with 'group_',
261 so this method ends up beeing only a filter of non-prefixed ids
262 before calling userFolderDelUsers().
263 """
264
265 # User mutation
266
267
268 # XXX do we have to allow a user to be renamed ?
269 ## def setUserId(id, newId):
270 ## """Change id of a user atom. The user name might be changed as well by this operation.
271 ## """
272
273 ## def setUserName(id, newName):
274 ## """Change the name of a user atom. The user id might be changed as well by this operation.
275 ## """
276
277 def userSetRoles(id, roles):
278 """Change the roles of a user atom
279 """
280
281 def userAddRole(id, role):
282 """Append a role for a user atom
283 """
284
285 def userRemoveRole(id, role):
286 """Remove the role of a user atom.
287 This will not, of course, affect implicitly-acquired roles from the user groups.
288 """
289
290 def userSetPassword(id, newPassword):
291 """Set the password of a user
292 """
293
294 def userSetDomains(id, domains):
295 """Set domains for a user
296 """
297
298 def userGetDomains(id, ):
299 """Get domains for a user
300 """
301
302 def userAddDomain(id, domain):
303 """Append a domain to a user
304 """
305
306 def userRemoveDomain(id, domain):
307 """Remove a domain from a user
308 """
309
310 def userSetGroups(userid, groupnames):
311 """Set the groups of a user. Groupnames are, as usual, not prefixed.
312 However, a groupid can be given as a fallback
313 """
314
315 def userAddGroup(id, groupname):
316 """add a group to a user atom. Groupnames are, as usual, not prefixed.
317 However, a groupid can be given as a fallback
318 """
319
320 def userRemoveGroup(id, groupname):
321 """remove a group from a user atom. Groupnames are, as usual, not prefixed.
322 However, a groupid can be given as a fallback
323 """
324
325
326 # Security management
327
328 def setRolesOnUsers(roles, userids):
329 """Set a common set of roles for a bunch of user atoms.
330 """
331
332 ## def setUsersOfRole(usernames, role):
333 ## """Sets the users of a role.
334 ## XXX THIS METHOD SEEMS TO BE SEAMLESS.
335 ## """
336
337 def getUsersOfRole(role, object = None):
338 """Gets the user (and group) ids having the specified role...
339 ...on the specified Zope object if it's not None
340 ...on their own information if the object is None.
341 NOTA: THIS METHOD IS VERY EXPENSIVE.
342 """
343
344 def getRolesOfUser(userid):
345 """Alias for user.getRoles()
346 """
347
348 def userFolderAddRole(role):
349 """Add a new role. The role will be appended, in fact, in GRUF's surrounding folder.
350 """
351
352 def userFolderDelRoles(roles):
353 """Delete roles.
354 The removed roles will be removed from the UserFolder's users and groups as well,
355 so this method can be very time consuming with a large number of users.
356 """
357
358 def userFolderGetRoles():
359 """List the roles defined at the top of GRUF's folder.
360 """
361
362
363 # Groups support
364 def setMembers(groupid, userids):
365 """Set the members of the group
366 """
367
368 def addMember(groupid, id):
369 """Add a member to a group
370 """
371
372 def removeMember(groupid, id):
373 """Remove a member from a group
374 """
375
376 def hasMember(groupid, id):
377 """Return true if the specified atom id is in the group.
378 This is the contrary of IUserAtom.isInGroup(groupid).
379 THIS CAN BE VERY EXPENSIVE"""
380
381 def getMemberIds(groupid):
382 """Return the list of member ids (groups and users) in this group.
383 It will unmangle nested groups as well.
384 THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
385 """
386
387 def getUserMemberIds(groupid):
388 """Same as listMemberIds but only return user ids
389 THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
390 """
391
392 def getGroupMemberIds(groupid):
393 """Same as listMemberUserIds but only return group ids.
394 THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
395 """
396
397
398 # Local roles acquisition blocking support
399 def acquireLocalRoles(folder, status):
400 """Enable or disable local role acquisition on the specified folder.
401 If status is true, it will enable, else it will disable.
402 """
403
404 def isLocalRoleAcquired(folder):
405 """Return true if the specified folder allows local role acquisition.
406 """
407
408 # Audit & security checking methods
409
410 def getAllLocalRoles(object):
411 """getAllLocalRoles(self, object): return a dictionnary {user: roles} of local
412 roles defined AND herited at a certain point. This will handle lr-blocking
413 as well.
414 """
415
416
417 class IUserAtom(Interface):
418 """
419 This interface is an abstract representation of what both a User and a Group can do.
420 """
421 # Accessors
422
423 def getId(unprefixed = 0):
424 """Get the ID of the user. The ID can be used, at least from
425 Python, to get the user from the user's UserDatabase.
426 If unprefixed, remove all prefixes in any case."""
427
428 def getUserName():
429 """Alias for getName()
430 """
431
432 def getName():
433 """Get user's or group's name.
434 For a user, the name can be set by the underlying user folder but usually id == name.
435 For a group, the ID is prefixed, but the NAME is NOT prefixed by 'group_'.
436 """
437
438 def getRoles():
439 """Return the list of roles assigned to a user atom.
440 This will never return gruf-related roles.
441 """
442
443 # Properties are defined depending on the underlying user folder: some support
444 # properties mutation (such as LDAPUserFolder), some do not (such as regular UF).
445
446 def getProperty(name):
447 """Get a property's value.
448 Will raise if not available.
449 """
450
451 def hasProperty(name):
452 """Return true if the underlying user object has a value for the property.
453 """
454
455 # Mutators
456
457 def setProperty(name, value):
458 """Set a property's value.
459 As some user folders cannot set properties, this method is not guaranteed to work
460 and will raise a NotImplementedError if the underlying user folder cannot store
461 properties (or _this_ particular property) for a user.
462 """
463
464 # XXX We do not allow user name / id changes
465 ## def setId(newId):
466 ## """Set the id of the user or group. This might change its name as well.
467 ## """
468
469 ## def setName(newName):
470 ## """Set the name of the user or group. Depending on the UserFolder implementation,
471 ## this might change the id as well.
472 ## """
473
474 def setRoles(roles):
475 """Change user's roles
476 """
477
478 def addRole(role):
479 """Append a role to the user
480 """
481
482 def removeRole(role):
483 """Remove a role from the user's ones
484 """
485
486 # Security-related methods
487
488 def getRolesInContext(object):
489 """Return the list of roles assigned to the user,
490 including local roles assigned in context of
491 the passed in object."""
492
493 def has_permission(permission, object):
494 """Check to see if a user has a given permission on an object."""
495
496 def allowed(object, object_roles=None):
497 """Check whether the user has access to object. The user must
498 have one of the roles in object_roles to allow access."""
499
500 def has_role(roles, object=None):
501 """Check to see if a user has a given role or roles."""
502
503
504
505 # Group management
506
507 # XXX TODO: CLARIFY ID VS. NAME
508
509 def isGroup():
510 """Return true if this atom is a group.
511 """
512
513 def getGroupNames():
514 """Return the names of the groups that the user or group is directly a member of.
515 Return an empty list if the user or group doesn't belong to any group.
516 Doesn't include transitive groups."""
517
518 def getGroupIds():
519 """Return the names of the groups that the user or group is a member of.
520 Return an empty list if the user or group doesn't belong to any group.
521 Doesn't include transitive groups."""
522
523 def getGroups():
524 """getAllGroupIds() alias.
525 Return the IDS (not names) of the groups that the user or group is a member of.
526 Return an empty list if the user or group doesn't belong to any group.
527 THIS WILL INCLUDE TRANSITIVE GROUPS AS WELL."""
528
529 def getAllGroupIds():
530 """Return the names of the groups that the user or group is a member of.
531 Return an empty list if the user or group doesn't belong to any group.
532 Include transitive groups."""
533
534 def getAllGroupNames():
535 """Return the names of the groups that the user or group is directly a member of.
536 Return an empty list if the user or group doesn't belong to any group.
537 Include transitive groups."""
538
539 def isInGroup(groupid):
540 """Return true if the user is member of the specified group id
541 (including transitive groups)"""
542
543 def setGroups(groupids):
544 """Set 'groupids' groups for the user or group.
545 """
546
547 def addGroup(groupid):
548 """Append a group to the current object's groups.
549 """
550
551 def removeGroup(groupid):
552 """Remove a group from the object's groups
553 """
554
555 def getRealId():
556 """Return group id WITHOUT group prefix.
557 For a user, return regular user id.
558 This method is essentially internal.
559 """
560
561
562 class IUser(IUserAtom):
563 """
564 A user is a user atom who can log itself on, and
565 have additional properties such as domains and password.
566 """
567
568 # Accessors
569
570 def getDomains():
571 """Return the list of domain restrictions for a user"""
572
573 # Mutators
574
575 def setPassword(newPassword):
576 """Set user's password
577 """
578
579 def setDomains(domains):
580 """Replace domains for the user
581 """
582
583 def addDomain(domain):
584 """Append a domain for the user
585 """
586
587 def removeDomain(domain):
588 """Remove a domain for the user
589 """
590
591
592 class IGroup(Interface):
593 """
594 A group is a user atom other atoms can belong to.
595 """
596 def getMemberIds(transitive = 1, ):
597 """Return the member ids (users and groups) of the atoms of this group.
598 This method can be very expensive !"""
599
600 def getUserMemberIds(transitive = 1, ):
601 """Return the member ids (users only) of the users of this group"""
602
603 def getGroupMemberIds(transitive = 1, ):
604 """Return the members ids (groups only) of the groups of this group"""
605
606 def hasMember(id):
607 """Return true if the specified atom id is in the group.
608 This is the contrary of IUserAtom.isInGroup(groupid)"""
609
610 def addMember(userid):
611 """Add a user the the current group"""
612
613 def removeMember(userid):
614 """Remove a user from the current group"""