1 # -*- coding: utf-8 -*-
3 ## Copyright (C)2006 Ingeniweb
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.
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.
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.
21 - [Pure] User: A user is a user atom who can log itself on, and
22 have additional properties such as domains and password.
24 - Group: A group is a user atom other atoms can belong to.
26 - User atom: Abstract representation of either a User or
29 - Member (of a group): User atom inside a group.
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.
38 __version__
= "$Revision: $"
40 # $Id: IUserFolder.py 30098 2006-09-08 12:35:01Z encolpe $
41 __docformat__
= 'restructuredtext'
43 from Interface
import Attribute
45 from Interface
import Interface
47 # for Zope versions before 2.6.0
48 from Interface
import Base
as Interface
52 class IUserFolder(Interface
):
55 # Regular Zope UserFolder API #
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 !]
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 !]
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.
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 !
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.
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.]
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."""
119 # Search interface for users; they won't return groups in any case.
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.
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.
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 !]
144 # Search interface for groups;
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.
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.
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 !]
172 def getPureUserNames():
173 """Same as getUserNames() but without groups
176 def getPureUserIds():
177 """Same as getUserIds() but without groups
181 """Same as getUsers() but without groups.
185 """Same as getUser() but forces returning a user and not a group
191 """Same as getUserNames() but without pure users.
195 """Same as getUserIds() but without pure users.
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 !
209 """Return the named group object or None. As usual, 'id' is prefixed.
212 def getGroupById(id):
213 """Same as getUserById(id) but forces returning a group.
216 def getGroupByName(name
):
217 """Same as getUserByName(name) but forces returning a group.
218 The specified name MUST NOT be prefixed !
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
228 Groups can be specified by name or by id (preferabily by name)."""
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
234 Groups can be specified by name or by id (preferabily by name)."""
236 def userFolderUpdateUser(name
, password
, roles
, domains
, groups
, **kw
):
237 """Same as userFolderEditUser, but with all arguments except name
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."""
245 def userFolderAddGroup(name
, roles
, groups
, **kw
):
246 """API method for creating a new group.
249 def userFolderEditGroup(name
, roles
, groups
, **kw
):
250 """API method for changing group object attributes.
253 def userFolderUpdateGroup(name
, roles
, groups
, **kw
):
254 """Same as userFolderEditGroup but with all arguments (except name) being
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().
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.
273 ## def setUserName(id, newName):
274 ## """Change the name of a user atom. The user id might be changed as well by this operation.
277 def userSetRoles(id, roles
):
278 """Change the roles of a user atom
281 def userAddRole(id, role
):
282 """Append a role for a user atom
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.
290 def userSetPassword(id, newPassword
):
291 """Set the password of a user
294 def userSetDomains(id, domains
):
295 """Set domains for a user
298 def userGetDomains(id, ):
299 """Get domains for a user
302 def userAddDomain(id, domain
):
303 """Append a domain to a user
306 def userRemoveDomain(id, domain
):
307 """Remove a domain from a user
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
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
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
326 # Security management
328 def setRolesOnUsers(roles
, userids
):
329 """Set a common set of roles for a bunch of user atoms.
332 ## def setUsersOfRole(usernames, role):
333 ## """Sets the users of a role.
334 ## XXX THIS METHOD SEEMS TO BE SEAMLESS.
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.
344 def getRolesOfUser(userid
):
345 """Alias for user.getRoles()
348 def userFolderAddRole(role
):
349 """Add a new role. The role will be appended, in fact, in GRUF's surrounding folder.
352 def userFolderDelRoles(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.
358 def userFolderGetRoles():
359 """List the roles defined at the top of GRUF's folder.
364 def setMembers(groupid
, userids
):
365 """Set the members of the group
368 def addMember(groupid
, id):
369 """Add a member to a group
372 def removeMember(groupid
, id):
373 """Remove a member from a group
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"""
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.
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.
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.
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.
404 def isLocalRoleAcquired(folder
):
405 """Return true if the specified folder allows local role acquisition.
408 # Audit & security checking methods
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
417 class IUserAtom(Interface
):
419 This interface is an abstract representation of what both a User and a Group can do.
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."""
429 """Alias for 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_'.
439 """Return the list of roles assigned to a user atom.
440 This will never return gruf-related roles.
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).
446 def getProperty(name
):
447 """Get a property's value.
448 Will raise if not available.
451 def hasProperty(name
):
452 """Return true if the underlying user object has a value for the property.
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.
464 # XXX We do not allow user name / id changes
466 ## """Set the id of the user or group. This might change its name as well.
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.
475 """Change user's roles
479 """Append a role to the user
482 def removeRole(role
):
483 """Remove a role from the user's ones
486 # Security-related methods
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."""
493 def has_permission(permission
, object):
494 """Check to see if a user has a given permission on an object."""
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."""
500 def has_role(roles
, object=None):
501 """Check to see if a user has a given role or roles."""
507 # XXX TODO: CLARIFY ID VS. NAME
510 """Return true if this atom is a group.
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."""
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."""
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."""
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."""
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."""
539 def isInGroup(groupid
):
540 """Return true if the user is member of the specified group id
541 (including transitive groups)"""
543 def setGroups(groupids
):
544 """Set 'groupids' groups for the user or group.
547 def addGroup(groupid
):
548 """Append a group to the current object's groups.
551 def removeGroup(groupid
):
552 """Remove a group from the object's groups
556 """Return group id WITHOUT group prefix.
557 For a user, return regular user id.
558 This method is essentially internal.
562 class IUser(IUserAtom
):
564 A user is a user atom who can log itself on, and
565 have additional properties such as domains and password.
571 """Return the list of domain restrictions for a user"""
575 def setPassword(newPassword
):
576 """Set user's password
579 def setDomains(domains
):
580 """Replace domains for the user
583 def addDomain(domain
):
584 """Append a domain for the user
587 def removeDomain(domain
):
588 """Remove a domain for the user
592 class IGroup(Interface
):
594 A group is a user atom other atoms can belong to.
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 !"""
600 def getUserMemberIds(transitive
= 1, ):
601 """Return the member ids (users only) of the users of this group"""
603 def getGroupMemberIds(transitive
= 1, ):
604 """Return the members ids (groups only) of the groups of this group"""
607 """Return true if the specified atom id is in the group.
608 This is the contrary of IUserAtom.isInGroup(groupid)"""
610 def addMember(userid
):
611 """Add a user the the current group"""
613 def removeMember(userid
):
614 """Remove a user from the current group"""