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 __version__
= "$Revision: $"
23 # $Id: LDAPUserFolderAdapter.py 587 2008-07-31 09:20:06Z pin $
24 __docformat__
= 'restructuredtext'
27 from global_symbols
import *
28 from Products
.GroupUserFolder
import postonly
31 # These mandatory attributes are required by LDAP schema.
32 # They will be filled with user name as a default value.
33 # You have to provide a gruf_ldap_required_fields python script
34 # in your Plone's skins if you want to override this.
35 MANDATORY_ATTRIBUTES
= ("sn", "cn", )
38 def _doAddUser(self
, name
, password
, roles
, domains
, **kw
):
40 Special user adding method for use with LDAPUserFolder.
41 This will ensure parameters are correct for LDAP management
43 kwargs
= {} # We will pass this dict
46 # Get gruf_ldap_required_fields result and fill in mandatory stuff
47 if hasattr(self
, "gruf_ldap_required_fields"):
48 attrs
= self
.gruf_ldap_required_fields(login
= name
)
50 for attr
in MANDATORY_ATTRIBUTES
:
54 # We assume that name is rdn attribute
55 rdn_attr
= self
._rdnattr
56 kwargs
[rdn_attr
] = name
59 kwargs
['user_pw'] = password
60 kwargs
['confirm_pw'] = password
63 kwargs
['user_roles'] = self
._mangleRoles
(name
, roles
)
65 # Delegate to LDAPUF default method
66 msg
= self
.manage_addUser(kwargs
= kwargs
)
68 raise RuntimeError, msg
71 def _doDelUsers(self
, names
):
73 Remove a bunch of users from LDAP.
74 We have to call manage_deleteUsers but, before, we need to find their dn.
78 dns
.append(self
._find
_user
_dn
(name
))
80 self
.manage_deleteUsers(dns
)
83 def _find_user_dn(self
, name
):
85 Convert a name to an LDAP dn
87 # Search records matching name
88 login_attr
= self
._login
_attr
89 v
= self
.findUser(search_param
= login_attr
, search_term
= name
)
91 # Filter to keep exact matches only
92 v
= filter(lambda x
: x
[login_attr
] == name
, v
)
94 # Now, decide what to do
98 raise "Invalid user name: '%s'" % (name
, )
100 # Several records... don't know how to handle
101 raise "Duplicate user name for '%s'" % (name
, )
105 def _mangleRoles(self
, name
, roles
):
107 Return role_dns for this user
109 # Local groups => the easiest part
110 if self
._local
_groups
:
113 # We have to transform roles into group dns: transform them as a dict
115 all_groups
= self
.getGroups()
116 all_roles
= self
.valid_roles()
121 # LDAPUF does the mistake of adding possibly invalid roles to the user roles
122 # (for example, adding the cn of a group additionnaly to the mapped zope role).
123 # So we must remove from our 'roles' list all roles which are prefixed by group prefix
124 # but are not actually groups.
125 # See http://www.dataflake.org/tracker/issue_00376 for more information on that
127 # If a group has the same name as a role, we assume that it should be a _role_.
128 # We should check against group/role mapping here, but... well... XXX TODO !
129 # See "HERE IT IS" comment below.
131 # Scan roles we are asking for to manage groups correctly
133 if not role
in all_roles
:
134 continue # Do not allow propagation of invalid roles
135 if role
.startswith(GROUP_PREFIX
):
136 role
= role
[GROUP_PREFIX_LEN
:] # Remove group prefix : groups are stored WITHOUT prefix in LDAP
137 if role
in all_roles
:
138 continue # HERE IT IS
139 r
= groups
.get(role
, None)
141 Log(LOG_WARNING
, "LDAP Server doesn't provide a '%s' group (required for user '%s')." % (role
, name
, ))
148 def _doChangeUser(self
, name
, password
, roles
, domains
, **kw
):
152 # Find the dn at first
153 dn
= self
._find
_user
_dn
(name
)
156 if password
is not None:
158 raise ValueError, "Password must not be empty for LDAP users."
159 self
.manage_editUserPassword(dn
, password
)
161 # Perform role change
162 self
.manage_editUserRoles(dn
, self
._mangleRoles
(name
, roles
))
164 # (No domain management with LDAP.)
167 def manage_editGroupRoles(self
, user_dn
, role_dns
=[], REQUEST
=None):
168 """ Edit the roles (groups) of a group """
169 from Products
.LDAPUserFolder
.utils
import GROUP_MEMBER_MAP
171 from Products
.LDAPUserFolder
.LDAPDelegate
import ADD
, DELETE
173 # Support for LDAPUserFolder >= 2.6
174 ADD
= self
._delegate
.ADD
175 DELETE
= self
._delegate
.DELETE
179 ## Log(LOG_DEBUG, "assigning", role_dns, "to", user_dn)
180 all_groups
= self
.getGroups(attr
='dn')
181 cur_groups
= self
.getGroups(dn
=user_dn
, attr
='dn')
183 for group
in role_dns
:
184 if group
.find('=') == -1:
185 group_dns
.append('cn=%s,%s' % (group
, self
.groups_base
))
187 group_dns
.append(group
)
189 if self
._local
_groups
:
190 if len(role_dns
) == 0:
191 del self
._groups
_store
[user_dn
]
193 self
._groups
_store
[user_dn
] = role_dns
196 for group
in all_groups
:
197 member_attr
= GROUP_MEMBER_MAP
.get(self
.getGroupType(group
))
199 if group
in cur_groups
and group
not in group_dns
:
201 elif group
in group_dns
and group
not in cur_groups
:
205 if action
is not None:
206 msg
= self
._delegate
.modify(
209 , {member_attr
: [user_dn
]}
211 ## Log(LOG_DEBUG, "group", group, "subgroup", user_dn, "result", msg)
214 raise RuntimeError, msg
215 manage_editGroupRoles
= postonly(manage_editGroupRoles
)