--- /dev/null
+# -*- coding: utf-8 -*-
+## GroupUserFolder
+## Copyright (C)2006 Ingeniweb
+
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+## You should have received a copy of the GNU General Public License
+## along with this program; see the file COPYING. If not, write to the
+## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+VOCABULARY:
+
+ - [Pure] User: A user is a user atom who can log itself on, and
+ have additional properties such as domains and password.
+
+ - Group: A group is a user atom other atoms can belong to.
+
+ - User atom: Abstract representation of either a User or
+ a Group.
+
+ - Member (of a group): User atom inside a group.
+
+ - Name (of an atom): For a user, the name can be set by
+ the underlying user folder but usually id == name.
+ For a group, its id is prefixed, but its name is NOT prefixed by 'group_'.
+ For method taking a name instead of an id (eg. getUserByName()),
+ if a user and a group have the same name,
+ the USER will have precedence over the group.
+"""
+__version__ = "$Revision: $"
+# $Source: $
+# $Id: IUserFolder.py 30098 2006-09-08 12:35:01Z encolpe $
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Interface, Attribute
+
+
+class IUserFolder(Interface):
+
+ # #
+ # Regular Zope UserFolder API #
+ # #
+
+ # User atom access
+
+ def getUserNames():
+ """
+ Return a list of all possible user atom names in the system.
+ Groups will be returned WITHOUT their prefix by this method.
+ So, there might be a collision between a user name and a group name.
+ [NOTA: This method is time-expensive !]
+ """
+
+ def getUserIds():
+ """
+ Return a list of all possible user atom ids in the system.
+ WARNING: Please see the id Vs. name consideration at the
+ top of this document. So, groups will be returned
+ WITH their prefix by this method
+ [NOTA: This method is time-expensive !]
+ """
+
+ def getUser(name):
+ """Return the named user atom object or None
+ NOTA: If no user can be found, we try to append a group prefix
+ and fetch the user again before returning 'None'. This will ensure
+ backward compatibility. So in fact, both group id and group name can be
+ specified to this method.
+ """
+
+ def getUsers():
+ """Return a list of user atom objects in the users cache.
+ In case of some UF implementations, the returned object may only be a subset
+ of all possible users.
+ In other words, you CANNOT assert that len(getUsers()) equals len(getUserNames()).
+ With cache-support UserFolders, such as LDAPUserFolder, the getUser() method will
+ return only cached user objects instead of fetching all possible users.
+ So this method won't be very time-expensive, but won't be accurate !
+ """
+
+ def getUserById(id, default):
+ """Return the user atom corresponding to the given id.
+ If default is provided, return default if no user found, else return None.
+ """
+
+ def getUserByName(name, default):
+ """Same as getUserById() but works with a name instead of an id.
+ If default is provided, return default if no user found, else return None.
+ [NOTA: Theorically, the id is a handle, while the name is the actual login name.
+ But difference between a user id and a user name is unsignificant in
+ all current User Folder implementations... except for GROUPS.]
+ """
+
+ def hasUsers():
+ """
+ From Zope 2.7's User.py:
+ This is not a formal API method: it is used only to provide
+ a way for the quickstart page to determine if the default user
+ folder contains any users to provide instructions on how to
+ add a user for newbies. Using getUserNames or getUsers would have
+ posed a denial of service risk.
+ In GRUF, this method always return 1."""
+
+
+ # Search interface for users; they won't return groups in any case.
+
+ def searchUsersByName(search_term):
+ """Return user ids which match the specified search_term.
+ If search_term is an empty string, behaviour depends on the underlying user folder:
+ it may return all users, return only cached users (for LDAPUF) or return no users.
+ """
+
+ def searchUsersById(search_term):
+ """Return users whose id match the specified search_term.
+ If search_term is an empty string, behaviour depends on the underlying user folder:
+ it may return all users, return only cached users (for LDAPUF) or return no users.
+ """
+
+ def searchUsersByAttribute(attribute, search_term):
+ """Return user ids whose 'attribute' match the specified search_term.
+ If search_term is an empty string, behaviour depends on the underlying user folder:
+ it may return all users, return only cached users (for LDAPUF) or return no users.
+ This will return all users whose name contains search_term (whaterver its case).
+ THIS METHOD MAY BE VERY EXPENSIVE ON USER FOLDER KINDS WHICH DO NOT PROVIDE A
+ SEARCHING METHOD (ie. every UF kind except LDAPUF).
+ 'attribute' can be 'id' or 'name' for all UF kinds, or anything else for LDAPUF.
+ [NOTA: This method is time-expensive !]
+ """
+
+ # Search interface for groups;
+
+ def searchGroupsByName(search_term):
+ """Return group ids which match the specified search_term.
+ If search_term is an empty string, behaviour depends on the underlying group folder:
+ it may return all groups, return only cached groups (for LDAPUF) or return no groups.
+ """
+
+ def searchGroupsById(search_term):
+ """Return groups whose id match the specified search_term.
+ If search_term is an empty string, behaviour depends on the underlying group folder:
+ it may return all groups, return only cached groups (for LDAPUF) or return no groups.
+ """
+
+ def searchGroupsByAttribute(attribute, search_term):
+ """Return group ids whose 'attribute' match the specified search_term.
+ If search_term is an empty string, behaviour depends on the underlying group folder:
+ it may return all groups, return only cached groups (for LDAPUF) or return no groups.
+ This will return all groups whose name contains search_term (whaterver its case).
+ THIS METHOD MAY BE VERY EXPENSIVE ON GROUP FOLDER KINDS WHICH DO NOT PROVIDE A
+ SEARCHING METHOD (ie. every UF kind except LDAPUF).
+ 'attribute' can be 'id' or 'name' for all UF kinds, or anything else for LDAPUF.
+ [NOTA: This method is time-expensive !]
+ """
+
+
+ # User access
+
+ def getPureUserNames():
+ """Same as getUserNames() but without groups
+ """
+
+ def getPureUserIds():
+ """Same as getUserIds() but without groups
+ """
+
+ def getPureUsers():
+ """Same as getUsers() but without groups.
+ """
+
+ def getPureUser(id):
+ """Same as getUser() but forces returning a user and not a group
+ """
+
+ # Group access
+
+ def getGroupNames():
+ """Same as getUserNames() but without pure users.
+ """
+
+ def getGroupIds():
+ """Same as getUserIds() but without pure users.
+ """
+
+ def getGroups():
+ """Same as getUsers() but without pure users.
+ In case of some UF implementations, the returned object may only be a subset
+ of all possible users.
+ In other words, you CANNOT assert that len(getUsers()) equals len(getUserNames()).
+ With cache-support UserFolders, such as LDAPUserFolder, the getUser() method will
+ return only cached user objects instead of fetching all possible users.
+ So this method won't be very time-expensive, but won't be accurate !
+ """
+
+ def getGroup(name):
+ """Return the named group object or None. As usual, 'id' is prefixed.
+ """
+
+ def getGroupById(id):
+ """Same as getUserById(id) but forces returning a group.
+ """
+
+ def getGroupByName(name):
+ """Same as getUserByName(name) but forces returning a group.
+ The specified name MUST NOT be prefixed !
+ """
+
+
+ # Mutators
+
+ def userFolderAddUser(name, password, roles, domains, groups, **kw):
+ """API method for creating a new user object. Note that not all
+ user folder implementations support dynamic creation of user
+ objects.
+ Groups can be specified by name or by id (preferabily by name)."""
+
+ def userFolderEditUser(name, password, roles, domains, groups, **kw):
+ """API method for changing user object attributes. Note that not
+ all user folder implementations support changing of user object
+ attributes.
+ Groups can be specified by name or by id (preferabily by name)."""
+
+ def userFolderUpdateUser(name, password, roles, domains, groups, **kw):
+ """Same as userFolderEditUser, but with all arguments except name
+ being optional.
+ """
+
+ def userFolderDelUsers(names):
+ """API method for deleting one or more user atom objects. Note that not
+ all user folder implementations support deletion of user objects."""
+
+ def userFolderAddGroup(name, roles, groups, **kw):
+ """API method for creating a new group.
+ """
+
+ def userFolderEditGroup(name, roles, groups, **kw):
+ """API method for changing group object attributes.
+ """
+
+ def userFolderUpdateGroup(name, roles, groups, **kw):
+ """Same as userFolderEditGroup but with all arguments (except name) being
+ optinal.
+ """
+
+ def userFolderDelGroups(names):
+ """API method for deleting one or more group objects.
+ Implem. note : All ids must be prefixed with 'group_',
+ so this method ends up beeing only a filter of non-prefixed ids
+ before calling userFolderDelUsers().
+ """
+
+ # User mutation
+
+
+ # XXX do we have to allow a user to be renamed ?
+## def setUserId(id, newId):
+## """Change id of a user atom. The user name might be changed as well by this operation.
+## """
+
+## def setUserName(id, newName):
+## """Change the name of a user atom. The user id might be changed as well by this operation.
+## """
+
+ def userSetRoles(id, roles):
+ """Change the roles of a user atom
+ """
+
+ def userAddRole(id, role):
+ """Append a role for a user atom
+ """
+
+ def userRemoveRole(id, role):
+ """Remove the role of a user atom.
+ This will not, of course, affect implicitly-acquired roles from the user groups.
+ """
+
+ def userSetPassword(id, newPassword):
+ """Set the password of a user
+ """
+
+ def userSetDomains(id, domains):
+ """Set domains for a user
+ """
+
+ def userGetDomains(id, ):
+ """Get domains for a user
+ """
+
+ def userAddDomain(id, domain):
+ """Append a domain to a user
+ """
+
+ def userRemoveDomain(id, domain):
+ """Remove a domain from a user
+ """
+
+ def userSetGroups(userid, groupnames):
+ """Set the groups of a user. Groupnames are, as usual, not prefixed.
+ However, a groupid can be given as a fallback
+ """
+
+ def userAddGroup(id, groupname):
+ """add a group to a user atom. Groupnames are, as usual, not prefixed.
+ However, a groupid can be given as a fallback
+ """
+
+ def userRemoveGroup(id, groupname):
+ """remove a group from a user atom. Groupnames are, as usual, not prefixed.
+ However, a groupid can be given as a fallback
+ """
+
+
+ # Security management
+
+ def setRolesOnUsers(roles, userids):
+ """Set a common set of roles for a bunch of user atoms.
+ """
+
+## def setUsersOfRole(usernames, role):
+## """Sets the users of a role.
+## XXX THIS METHOD SEEMS TO BE SEAMLESS.
+## """
+
+ def getUsersOfRole(role, object = None):
+ """Gets the user (and group) ids having the specified role...
+ ...on the specified Zope object if it's not None
+ ...on their own information if the object is None.
+ NOTA: THIS METHOD IS VERY EXPENSIVE.
+ """
+
+ def getRolesOfUser(userid):
+ """Alias for user.getRoles()
+ """
+
+ def userFolderAddRole(role):
+ """Add a new role. The role will be appended, in fact, in GRUF's surrounding folder.
+ """
+
+ def userFolderDelRoles(roles):
+ """Delete roles.
+ The removed roles will be removed from the UserFolder's users and groups as well,
+ so this method can be very time consuming with a large number of users.
+ """
+
+ def userFolderGetRoles():
+ """List the roles defined at the top of GRUF's folder.
+ """
+
+
+ # Groups support
+ def setMembers(groupid, userids):
+ """Set the members of the group
+ """
+
+ def addMember(groupid, id):
+ """Add a member to a group
+ """
+
+ def removeMember(groupid, id):
+ """Remove a member from a group
+ """
+
+ def hasMember(groupid, id):
+ """Return true if the specified atom id is in the group.
+ This is the contrary of IUserAtom.isInGroup(groupid).
+ THIS CAN BE VERY EXPENSIVE"""
+
+ def getMemberIds(groupid):
+ """Return the list of member ids (groups and users) in this group.
+ It will unmangle nested groups as well.
+ THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
+ """
+
+ def getUserMemberIds(groupid):
+ """Same as listMemberIds but only return user ids
+ THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
+ """
+
+ def getGroupMemberIds(groupid):
+ """Same as listMemberUserIds but only return group ids.
+ THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
+ """
+
+
+ # Local roles acquisition blocking support
+ def acquireLocalRoles(folder, status):
+ """Enable or disable local role acquisition on the specified folder.
+ If status is true, it will enable, else it will disable.
+ """
+
+ def isLocalRoleAcquired(folder):
+ """Return true if the specified folder allows local role acquisition.
+ """
+
+ # Audit & security checking methods
+
+ def getAllLocalRoles(object):
+ """getAllLocalRoles(self, object): return a dictionnary {user: roles} of local
+ roles defined AND herited at a certain point. This will handle lr-blocking
+ as well.
+ """
+
+
+class IUserAtom(Interface):
+ """
+ This interface is an abstract representation of what both a User and a Group can do.
+ """
+ # Accessors
+
+ def getId(unprefixed = 0):
+ """Get the ID of the user. The ID can be used, at least from
+ Python, to get the user from the user's UserDatabase.
+ If unprefixed, remove all prefixes in any case."""
+
+ def getUserName():
+ """Alias for getName()
+ """
+
+ def getName():
+ """Get user's or group's name.
+ For a user, the name can be set by the underlying user folder but usually id == name.
+ For a group, the ID is prefixed, but the NAME is NOT prefixed by 'group_'.
+ """
+
+ def getRoles():
+ """Return the list of roles assigned to a user atom.
+ This will never return gruf-related roles.
+ """
+
+ # Properties are defined depending on the underlying user folder: some support
+ # properties mutation (such as LDAPUserFolder), some do not (such as regular UF).
+
+ def getProperty(name):
+ """Get a property's value.
+ Will raise if not available.
+ """
+
+ def hasProperty(name):
+ """Return true if the underlying user object has a value for the property.
+ """
+
+ # Mutators
+
+ def setProperty(name, value):
+ """Set a property's value.
+ As some user folders cannot set properties, this method is not guaranteed to work
+ and will raise a NotImplementedError if the underlying user folder cannot store
+ properties (or _this_ particular property) for a user.
+ """
+
+ # XXX We do not allow user name / id changes
+## def setId(newId):
+## """Set the id of the user or group. This might change its name as well.
+## """
+
+## def setName(newName):
+## """Set the name of the user or group. Depending on the UserFolder implementation,
+## this might change the id as well.
+## """
+
+ def setRoles(roles):
+ """Change user's roles
+ """
+
+ def addRole(role):
+ """Append a role to the user
+ """
+
+ def removeRole(role):
+ """Remove a role from the user's ones
+ """
+
+ # Security-related methods
+
+ def getRolesInContext(object):
+ """Return the list of roles assigned to the user,
+ including local roles assigned in context of
+ the passed in object."""
+
+ def has_permission(permission, object):
+ """Check to see if a user has a given permission on an object."""
+
+ def allowed(object, object_roles=None):
+ """Check whether the user has access to object. The user must
+ have one of the roles in object_roles to allow access."""
+
+ def has_role(roles, object=None):
+ """Check to see if a user has a given role or roles."""
+
+
+
+ # Group management
+
+ # XXX TODO: CLARIFY ID VS. NAME
+
+ def isGroup():
+ """Return true if this atom is a group.
+ """
+
+ def getGroupNames():
+ """Return the names of the groups that the user or group is directly a member of.
+ Return an empty list if the user or group doesn't belong to any group.
+ Doesn't include transitive groups."""
+
+ def getGroupIds():
+ """Return the names of the groups that the user or group is a member of.
+ Return an empty list if the user or group doesn't belong to any group.
+ Doesn't include transitive groups."""
+
+ def getGroups():
+ """getAllGroupIds() alias.
+ Return the IDS (not names) of the groups that the user or group is a member of.
+ Return an empty list if the user or group doesn't belong to any group.
+ THIS WILL INCLUDE TRANSITIVE GROUPS AS WELL."""
+
+ def getAllGroupIds():
+ """Return the names of the groups that the user or group is a member of.
+ Return an empty list if the user or group doesn't belong to any group.
+ Include transitive groups."""
+
+ def getAllGroupNames():
+ """Return the names of the groups that the user or group is directly a member of.
+ Return an empty list if the user or group doesn't belong to any group.
+ Include transitive groups."""
+
+ def isInGroup(groupid):
+ """Return true if the user is member of the specified group id
+ (including transitive groups)"""
+
+ def setGroups(groupids):
+ """Set 'groupids' groups for the user or group.
+ """
+
+ def addGroup(groupid):
+ """Append a group to the current object's groups.
+ """
+
+ def removeGroup(groupid):
+ """Remove a group from the object's groups
+ """
+
+ def getRealId():
+ """Return group id WITHOUT group prefix.
+ For a user, return regular user id.
+ This method is essentially internal.
+ """
+
+
+class IUser(IUserAtom):
+ """
+ A user is a user atom who can log itself on, and
+ have additional properties such as domains and password.
+ """
+
+ # Accessors
+
+ def getDomains():
+ """Return the list of domain restrictions for a user"""
+
+ # Mutators
+
+ def setPassword(newPassword):
+ """Set user's password
+ """
+
+ def setDomains(domains):
+ """Replace domains for the user
+ """
+
+ def addDomain(domain):
+ """Append a domain for the user
+ """
+
+ def removeDomain(domain):
+ """Remove a domain for the user
+ """
+
+
+class IGroup(Interface):
+ """
+ A group is a user atom other atoms can belong to.
+ """
+ def getMemberIds(transitive = 1, ):
+ """Return the member ids (users and groups) of the atoms of this group.
+ This method can be very expensive !"""
+
+ def getUserMemberIds(transitive = 1, ):
+ """Return the member ids (users only) of the users of this group"""
+
+ def getGroupMemberIds(transitive = 1, ):
+ """Return the members ids (groups only) of the groups of this group"""
+
+ def hasMember(id):
+ """Return true if the specified atom id is in the group.
+ This is the contrary of IUserAtom.isInGroup(groupid)"""
+
+ def addMember(userid):
+ """Add a user the the current group"""
+
+ def removeMember(userid):
+ """Remove a user from the current group"""