X-Git-Url: https://scm.cri.minesparis.psl.eu/git/GroupUserFolder.git/blobdiff_plain/e9d14b6b5cc9cd4775c60cb340b5c4c787536fc3..3e1ba4932c34812cf2f6f3569b0f0dbea97b7a0b:/Products/GroupUserFolder/LDAPUserFolderAdapter.py?ds=inline diff --git a/Products/GroupUserFolder/LDAPUserFolderAdapter.py b/Products/GroupUserFolder/LDAPUserFolderAdapter.py new file mode 100755 index 0000000..642cdb8 --- /dev/null +++ b/Products/GroupUserFolder/LDAPUserFolderAdapter.py @@ -0,0 +1,215 @@ +# -*- 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. +""" + +""" +__version__ = "$Revision: $" +# $Source: $ +# $Id: LDAPUserFolderAdapter.py 587 2008-07-31 09:20:06Z pin $ +__docformat__ = 'restructuredtext' + + +from global_symbols import * +from Products.GroupUserFolder import postonly + + +# These mandatory attributes are required by LDAP schema. +# They will be filled with user name as a default value. +# You have to provide a gruf_ldap_required_fields python script +# in your Plone's skins if you want to override this. +MANDATORY_ATTRIBUTES = ("sn", "cn", ) + + +def _doAddUser(self, name, password, roles, domains, **kw): + """ + Special user adding method for use with LDAPUserFolder. + This will ensure parameters are correct for LDAP management + """ + kwargs = {} # We will pass this dict + attrs = {} + + # Get gruf_ldap_required_fields result and fill in mandatory stuff + if hasattr(self, "gruf_ldap_required_fields"): + attrs = self.gruf_ldap_required_fields(login = name) + else: + for attr in MANDATORY_ATTRIBUTES: + attrs[attr] = name + kwargs.update(attrs) + + # We assume that name is rdn attribute + rdn_attr = self._rdnattr + kwargs[rdn_attr] = name + + # Manage password(s) + kwargs['user_pw'] = password + kwargs['confirm_pw'] = password + + # Mangle roles + kwargs['user_roles'] = self._mangleRoles(name, roles) + + # Delegate to LDAPUF default method + msg = self.manage_addUser(kwargs = kwargs) + if msg: + raise RuntimeError, msg + + +def _doDelUsers(self, names): + """ + Remove a bunch of users from LDAP. + We have to call manage_deleteUsers but, before, we need to find their dn. + """ + dns = [] + for name in names: + dns.append(self._find_user_dn(name)) + + self.manage_deleteUsers(dns) + + +def _find_user_dn(self, name): + """ + Convert a name to an LDAP dn + """ + # Search records matching name + login_attr = self._login_attr + v = self.findUser(search_param = login_attr, search_term = name) + + # Filter to keep exact matches only + v = filter(lambda x: x[login_attr] == name, v) + + # Now, decide what to do + l = len(v) + if not l: + # Invalid name + raise "Invalid user name: '%s'" % (name, ) + elif l > 1: + # Several records... don't know how to handle + raise "Duplicate user name for '%s'" % (name, ) + return v[0]['dn'] + + +def _mangleRoles(self, name, roles): + """ + Return role_dns for this user + """ + # Local groups => the easiest part + if self._local_groups: + return roles + + # We have to transform roles into group dns: transform them as a dict + role_dns = [] + all_groups = self.getGroups() + all_roles = self.valid_roles() + groups = {} + for g in all_groups: + groups[g[0]] = g[1] + + # LDAPUF does the mistake of adding possibly invalid roles to the user roles + # (for example, adding the cn of a group additionnaly to the mapped zope role). + # So we must remove from our 'roles' list all roles which are prefixed by group prefix + # but are not actually groups. + # See http://www.dataflake.org/tracker/issue_00376 for more information on that + # particular issue. + # If a group has the same name as a role, we assume that it should be a _role_. + # We should check against group/role mapping here, but... well... XXX TODO ! + # See "HERE IT IS" comment below. + + # Scan roles we are asking for to manage groups correctly + for role in roles: + if not role in all_roles: + continue # Do not allow propagation of invalid roles + if role.startswith(GROUP_PREFIX): + role = role[GROUP_PREFIX_LEN:] # Remove group prefix : groups are stored WITHOUT prefix in LDAP + if role in all_roles: + continue # HERE IT IS + r = groups.get(role, None) + if not r: + Log(LOG_WARNING, "LDAP Server doesn't provide a '%s' group (required for user '%s')." % (role, name, )) + else: + role_dns.append(r) + + return role_dns + + +def _doChangeUser(self, name, password, roles, domains, **kw): + """ + Update a user + """ + # Find the dn at first + dn = self._find_user_dn(name) + + # Change password + if password is not None: + if password == '': + raise ValueError, "Password must not be empty for LDAP users." + self.manage_editUserPassword(dn, password) + + # Perform role change + self.manage_editUserRoles(dn, self._mangleRoles(name, roles)) + + # (No domain management with LDAP.) + + +def manage_editGroupRoles(self, user_dn, role_dns=[], REQUEST=None): + """ Edit the roles (groups) of a group """ + from Products.LDAPUserFolder.utils import GROUP_MEMBER_MAP + try: + from Products.LDAPUserFolder.LDAPDelegate import ADD, DELETE + except ImportError: + # Support for LDAPUserFolder >= 2.6 + ADD = self._delegate.ADD + DELETE = self._delegate.DELETE + + msg = "" + +## Log(LOG_DEBUG, "assigning", role_dns, "to", user_dn) + all_groups = self.getGroups(attr='dn') + cur_groups = self.getGroups(dn=user_dn, attr='dn') + group_dns = [] + for group in role_dns: + if group.find('=') == -1: + group_dns.append('cn=%s,%s' % (group, self.groups_base)) + else: + group_dns.append(group) + + if self._local_groups: + if len(role_dns) == 0: + del self._groups_store[user_dn] + else: + self._groups_store[user_dn] = role_dns + + else: + for group in all_groups: + member_attr = GROUP_MEMBER_MAP.get(self.getGroupType(group)) + + if group in cur_groups and group not in group_dns: + action = DELETE + elif group in group_dns and group not in cur_groups: + action = ADD + else: + action = None + if action is not None: + msg = self._delegate.modify( + group + , action + , {member_attr : [user_dn]} + ) +## Log(LOG_DEBUG, "group", group, "subgroup", user_dn, "result", msg) + + if msg: + raise RuntimeError, msg +manage_editGroupRoles = postonly(manage_editGroupRoles)