Back to index

plone3  3.1.7
LDAPUserFolderAdapter.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 ## GroupUserFolder
00003 ## Copyright (C)2006 Ingeniweb
00004 
00005 ## This program is free software; you can redistribute it and/or modify
00006 ## it under the terms of the GNU General Public License as published by
00007 ## the Free Software Foundation; either version 2 of the License, or
00008 ## (at your option) any later version.
00009 
00010 ## This program is distributed in the hope that it will be useful,
00011 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 ## GNU General Public License for more details.
00014 
00015 ## You should have received a copy of the GNU General Public License
00016 ## along with this program; see the file COPYING. If not, write to the
00017 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 """
00019 
00020 """
00021 __version__ = "$Revision:  $"
00022 # $Source:  $
00023 # $Id: LDAPUserFolderAdapter.py 40113 2007-04-01 09:30:14Z alecm $
00024 __docformat__ = 'restructuredtext'
00025 
00026 
00027 from global_symbols import *
00028 from Products.GroupUserFolder import postonly
00029 
00030 
00031 # These mandatory attributes are required by LDAP schema.
00032 # They will be filled with user name as a default value.
00033 # You have to provide a gruf_ldap_required_fields python script
00034 # in your Plone's skins if you want to override this.
00035 MANDATORY_ATTRIBUTES = ("sn", "cn", )
00036 
00037 
00038 def _doAddUser(self, name, password, roles, domains, **kw):
00039     """
00040     Special user adding method for use with LDAPUserFolder.
00041     This will ensure parameters are correct for LDAP management
00042     """
00043     kwargs = {}               # We will pass this dict
00044     attrs = {}
00045 
00046     # Get gruf_ldap_required_fields result and fill in mandatory stuff
00047     if hasattr(self, "gruf_ldap_required_fields"):
00048         attrs = self.gruf_ldap_required_fields(login = name)
00049     else:
00050         for attr in MANDATORY_ATTRIBUTES:
00051             attrs[attr] = name
00052     kwargs.update(attrs)
00053 
00054     # We assume that name is rdn attribute
00055     rdn_attr = self._rdnattr
00056     kwargs[rdn_attr] = name
00057 
00058     # Manage password(s)
00059     kwargs['user_pw'] = password
00060     kwargs['confirm_pw'] = password
00061 
00062     # Mangle roles
00063     kwargs['user_roles'] = self._mangleRoles(name, roles)
00064 
00065     # Delegate to LDAPUF default method
00066     msg = self.manage_addUser(kwargs = kwargs)
00067     if msg:
00068         raise RuntimeError, msg
00069 
00070 
00071 def _doDelUsers(self, names):
00072     """
00073     Remove a bunch of users from LDAP.
00074     We have to call manage_deleteUsers but, before, we need to find their dn.
00075     """
00076     dns = []
00077     for name in names:
00078         dns.append(self._find_user_dn(name))
00079 
00080     self.manage_deleteUsers(dns)
00081 
00082 
00083 def _find_user_dn(self, name):
00084     """
00085     Convert a name to an LDAP dn
00086     """
00087     # Search records matching name
00088     login_attr = self._login_attr
00089     v = self.findUser(search_param = login_attr, search_term = name)
00090 
00091     # Filter to keep exact matches only
00092     v = filter(lambda x: x[login_attr] == name, v)
00093 
00094     # Now, decide what to do
00095     l = len(v)
00096     if not l:
00097         # Invalid name
00098         raise "Invalid user name: '%s'" % (name, )
00099     elif l > 1:
00100         # Several records... don't know how to handle
00101         raise "Duplicate user name for '%s'" % (name, )
00102     return v[0]['dn']
00103 
00104 
00105 def _mangleRoles(self, name, roles):
00106     """
00107     Return role_dns for this user
00108     """
00109     # Local groups => the easiest part
00110     if self._local_groups:
00111         return roles
00112 
00113     # We have to transform roles into group dns: transform them as a dict
00114     role_dns = []
00115     all_groups = self.getGroups()
00116     all_roles = self.valid_roles()
00117     groups = {}
00118     for g in all_groups:
00119         groups[g[0]] = g[1]
00120 
00121     # LDAPUF does the mistake of adding possibly invalid roles to the user roles
00122     # (for example, adding the cn of a group additionnaly to the mapped zope role).
00123     # So we must remove from our 'roles' list all roles which are prefixed by group prefix
00124     # but are not actually groups.
00125     # See http://www.dataflake.org/tracker/issue_00376 for more information on that
00126     # particular issue.
00127     # If a group has the same name as a role, we assume that it should be a _role_.
00128     # We should check against group/role mapping here, but... well... XXX TODO !
00129     # See "HERE IT IS" comment below.
00130 
00131     # Scan roles we are asking for to manage groups correctly
00132     for role in roles:
00133         if not role in all_roles:
00134             continue                        # Do not allow propagation of invalid roles
00135         if role.startswith(GROUP_PREFIX):
00136             role = role[GROUP_PREFIX_LEN:]          # Remove group prefix : groups are stored WITHOUT prefix in LDAP
00137             if role in all_roles:
00138                 continue                            # HERE IT IS
00139         r = groups.get(role, None)
00140         if not r:
00141             Log(LOG_WARNING, "LDAP Server doesn't provide a '%s' group (required for user '%s')." % (role, name, ))
00142         else:
00143             role_dns.append(r)
00144 
00145     return role_dns
00146 
00147 
00148 def _doChangeUser(self, name, password, roles, domains, **kw):
00149     """
00150     Update a user
00151     """
00152     # Find the dn at first
00153     dn = self._find_user_dn(name)
00154     
00155     # Change password
00156     if password is not None:
00157         if password == '':
00158             raise ValueError, "Password must not be empty for LDAP users."
00159         self.manage_editUserPassword(dn, password)
00160         
00161     # Perform role change
00162     self.manage_editUserRoles(dn, self._mangleRoles(name, roles))
00163 
00164     # (No domain management with LDAP.)
00165 
00166     
00167 def manage_editGroupRoles(self, user_dn, role_dns=[], REQUEST=None):
00168     """ Edit the roles (groups) of a group """
00169     from Products.LDAPUserFolder.utils import GROUP_MEMBER_MAP
00170     try:
00171         from Products.LDAPUserFolder.LDAPDelegate import ADD, DELETE
00172     except ImportError:
00173         # Support for LDAPUserFolder >= 2.6
00174         ADD = self._delegate.ADD
00175         DELETE = self._delegate.DELETE
00176 
00177     msg = ""
00178 
00179 ##    Log(LOG_DEBUG, "assigning", role_dns, "to", user_dn)
00180     all_groups = self.getGroups(attr='dn')
00181     cur_groups = self.getGroups(dn=user_dn, attr='dn')
00182     group_dns = []
00183     for group in role_dns:
00184         if group.find('=') == -1:
00185             group_dns.append('cn=%s,%s' % (group, self.groups_base))
00186         else:
00187             group_dns.append(group)
00188 
00189     if self._local_groups:
00190         if len(role_dns) == 0:
00191             del self._groups_store[user_dn]
00192         else:
00193             self._groups_store[user_dn] = role_dns
00194 
00195     else:
00196         for group in all_groups:
00197             member_attr = GROUP_MEMBER_MAP.get(self.getGroupType(group))
00198 
00199             if group in cur_groups and group not in group_dns:
00200                 action = DELETE
00201             elif group in group_dns and group not in cur_groups:
00202                 action = ADD
00203             else:
00204                 action = None
00205             if action is not None:
00206                 msg = self._delegate.modify(
00207                     group
00208                     , action
00209                     , {member_attr : [user_dn]}
00210                     )
00211 ##                Log(LOG_DEBUG, "group", group, "subgroup", user_dn, "result", msg)
00212 
00213     if msg:
00214         raise RuntimeError, msg
00215 manage_editGroupRoles = postonly(manage_editGroupRoles)