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: LDAPGroupFolder.py 587 2008-07-31 09:20:06Z pin $
24 __docformat__
= 'restructuredtext'
26 import time
, traceback
29 from Globals
import DTMLFile
, InitializeClass
30 from Acquisition
import aq_base
31 from AccessControl
import ClassSecurityInfo
32 from AccessControl
.User
import SimpleUser
33 from AccessControl
.Permissions
import view_management_screens
, manage_users
34 from OFS
.SimpleItem
import SimpleItem
35 from DateTime
import DateTime
37 from Products
.GroupUserFolder
import postonly
38 import GroupUserFolder
40 from global_symbols
import *
42 # LDAPUserFolder package imports
43 from Products
.LDAPUserFolder
.SimpleCache
import SimpleCache
45 addLDAPGroupFolderForm
= DTMLFile('dtml/addLDAPGroupFolder', globals())
48 class LDAPGroupFolder(SimpleItem
):
50 security
= ClassSecurityInfo()
52 meta_type
= 'LDAPGroupFolder'
55 isPrincipiaFolderish
=1
59 ({'label' : 'Groups', 'action' : 'manage_main',},)
60 + SimpleItem
.manage_options
63 security
.declareProtected(view_management_screens
, 'manage_main')
64 manage_main
= DTMLFile('dtml/groups', globals())
67 def __setstate__(self
, v
):
69 LDAPGroupFolder
.inheritedAttribute('__setstate__')(self
, v
)
70 self
._cache
= SimpleCache()
71 self
._cache
.setTimeout(600)
74 def __init__( self
, title
, luf
=''):
77 self
._cache
= SimpleCache()
78 self
._cache
.setTimeout(600)
81 security
.declarePrivate(manage_users
, 'getGRUF')
84 return self
.aq_parent
.aq_parent
87 security
.declareProtected(manage_users
, 'getLUF')
90 s
= self
.getGRUF().getUserSource(self
._luf
)
91 if getattr(s
, 'meta_type', None) != "LDAPUserFolder":
92 # whoops, we moved LDAPUF... let's try to find it back
93 Log(LOG_WARNING
, "LDAPUserFolder moved. Trying to find it back.")
95 for src
in self
.getGRUF().listUserSources():
96 if src
.meta_type
== "LDAPUserFolder":
97 self
._luf
= src
.getPhysicalPath()[-2]
101 raise RuntimeError, "You must change your groups source in GRUF if you do not have a LDAPUserFolder as a users source."
105 security
.declareProtected(manage_users
, 'getGroups')
106 def getGroups(self
, dn
='*', attr
=None, pwd
=''):
108 return self
.getLUF().getGroups(dn
, attr
, pwd
)
111 security
.declareProtected(manage_users
, 'getGroupType')
112 def getGroupType(self
, group_dn
):
114 return self
.getLUF().getGroupType(group_dn
)
116 security
.declareProtected(manage_users
, 'getGroupMappings')
117 def getGroupMappings(self
):
119 return self
.getLUF().getGroupMappings()
121 security
.declareProtected(manage_users
, 'manage_addGroupMapping')
122 def manage_addGroupMapping(self
, group_name
, role_name
, REQUEST
=None):
124 self
._cache
.remove(group_name
)
125 self
.getLUF().manage_addGroupMapping(group_name
, role_name
, None)
128 msg
= 'Added LDAP group to Zope role mapping: %s -> %s' % (
129 group_name
, role_name
)
130 return self
.manage_main(manage_tabs_message
=msg
)
131 manage_addGroupMapping
= postonly(manage_addGroupMapping
)
133 security
.declareProtected(manage_users
, 'manage_deleteGroupMappings')
134 def manage_deleteGroupMappings(self
, group_names
, REQUEST
=None):
135 """ Delete mappings from LDAP group to Zope role """
137 self
.getLUF().manage_deleteGroupMappings(group_names
, None)
139 msg
= 'Deleted LDAP group to Zope role mapping for: %s' % (
140 ', '.join(group_names
))
141 return self
.manage_main(manage_tabs_message
=msg
)
142 manage_deleteGroupMappings
= postonly(manage_deleteGroupMappings
)
144 security
.declareProtected(manage_users
, 'manage_addGroup')
145 def manage_addGroup( self
147 , newgroup_type
='groupOfUniqueNames'
150 """Add a new group in groups_base.
152 self
.getLUF().manage_addGroup(newgroup_name
, newgroup_type
, None)
155 msg
= 'Added new group %s' % (newgroup_name
)
156 return self
.manage_main(manage_tabs_message
=msg
)
157 manage_addGroup
= postonly(manage_addGroup
)
159 security
.declareProtected(manage_users
, 'manage_deleteGroups')
160 def manage_deleteGroups(self
, dns
=[], REQUEST
=None):
161 """ Delete groups from groups_base """
162 self
.getLUF().manage_deleteGroups(dns
, None)
166 msg
= 'Deleted group(s):<br> %s' % '<br>'.join(dns
)
167 return self
.manage_main(manage_tabs_message
=msg
)
168 manage_deleteGroups
= postonly(manage_deleteGroups
)
170 security
.declareProtected(manage_users
, 'getUser')
171 def getUser(self
, name
):
173 # Prevent locally stored groups
175 if luf
._local
_groups
:
178 # Get the group from the cache
179 user
= self
._cache
.get(name
, '')
183 # Scan groups to find the proper user.
184 # THIS MAY BE EXPENSIVE AND HAS TO BE OPTIMIZED...
185 grps
= self
.getLUF().getGroups()
186 valid_roles
= self
.userFolderGetRoles()
196 roles
= self
.getLUF()._mapRoles
([name
])
199 groups
= list(self
.getLUF().getGroups(dn
=dn
, attr
='cn', ))
200 roles
.extend(self
.getLUF()._mapRoles
(groups
))
203 Log(LOG_DEBUG
, name
, "roles", groups
, roles
)
204 Log(LOG_DEBUG
, name
, "mapping", getattr(self
.getLUF(), '_groups_mappings', {}))
210 actual_roles
.append(r
)
211 elif "%s%s" % (GROUP_PREFIX
, r
) in valid_roles
:
212 actual_roles
.append("%s%s" % (GROUP_PREFIX
, r
))
213 Log(LOG_DEBUG
, name
, "actual roles", actual_roles
)
214 user
= GroupUser(n
, '', actual_roles
, [])
215 self
._cache
.set(name
, user
)
218 security
.declareProtected(manage_users
, 'getUserNames')
219 def getUserNames(self
):
221 Log(LOG_DEBUG
, "getUserNames", )
222 LogCallStack(LOG_DEBUG
)
223 # Prevent locally stored groups
225 if luf
._local
_groups
:
227 return [g
[0] for g
in luf
.getGroups()]
229 security
.declareProtected(manage_users
, 'getUsers')
230 def getUsers(self
, authenticated
=1):
232 # Prevent locally stored groups
234 if luf
._local
_groups
:
239 grps
= self
.getLUF().getGroups()
240 valid_roles
= self
.userFolderGetRoles()
243 roles
= self
.getLUF()._mapRoles
([n
])
249 actual_roles
.append(r
)
250 elif "%s%s" % (GROUP_PREFIX
, r
) in valid_roles
:
251 actual_roles
.append("%s%s" % (GROUP_PREFIX
, r
))
252 user
= GroupUser(n
, '', actual_roles
, [])
257 security
.declarePrivate('_doAddUser')
258 def _doAddUser(self
, name
, password
, roles
, domains
, **kw
):
259 """WARNING: If a role with exists with the same name as the group, we do not add
260 the group mapping for it, but we create it as if it were a Zope ROLE.
261 Ie. it's not possible to have a GRUF Group name = a Zope role name, BUT,
262 with this system, it's possible to differenciate between LDAP groups and LDAP roles.
264 self
.getLUF().manage_addGroup(name
)
265 self
.manage_addGroupMapping(name
, "group_" + name
, None, )
266 self
._doChangeUser
(name
, password
, roles
, domains
, **kw
)
268 security
.declarePrivate('_doDelUsers')
269 def _doDelUsers(self
, names
):
272 for g_name
, dn
in luf
.getGroups():
276 return luf
.manage_deleteGroups(dns
)
278 security
.declarePrivate('_doChangeUser')
279 def _doChangeUser(self
, name
, password
, roles
, domains
, **kw
):
281 This is used to change the groups (especially their roles).
283 [ THIS TEXT IS OUTDATED :
284 WARNING: If a ZOPE role with the same name as the GRUF group exists,
285 we do not add the group mapping for it, but we create it as if it were a Zope ROLE.
286 Ie. it's not possible to have a GRUF Group name = a Zope role name, BUT,
287 with this system, it's possible to differenciate between LDAP groups and LDAP roles.
291 self
._cache
.remove(name
)
295 for g_name
, g_dn
in luf
.getGroups():
300 raise ValueError, "Invalid LDAP group: '%s'" % (name
, )
302 # Edit group mappings
303 ## if name in self.aq_parent.valid_roles():
304 ## # This is, in fact, a role
305 ## self.getLUF().manage_addGroupMapping(name, name)
307 ## # This is a group -> we set it as a group
308 ## self.getLUF().manage_addGroupMapping(name, self.getGroupPrefix() + name)
311 if luf
._local
_groups
:
312 luf
.manage_editUserRoles(dn
, roles
)
314 # We have to transform roles into group dns: transform them as a dict
316 all_groups
= luf
.getGroups()
317 all_roles
= luf
.valid_roles()
322 # LDAPUF < 2.4Beta3 adds possibly invalid roles to the user roles
323 # (for example, adding the cn of a group additionnaly to the mapped zope role).
324 # So we must remove from our 'roles' list all roles which are prefixed by group prefix
325 # but are not actually groups.
326 # If a group has the same name as a role, we assume that it should be a _role_.
327 # We should check against group/role mapping here, but... well... XXX TODO !
328 # See "HERE IT IS" comment below.
330 # Scan roles we are asking for to manage groups correctly
332 if not role
in all_roles
:
333 continue # Do not allow propagation of invalid roles
334 if role
.startswith(GROUP_PREFIX
):
335 role
= role
[GROUP_PREFIX_LEN
:] # Remove group prefix : groups are stored WITHOUT prefix in LDAP
336 if role
in all_roles
:
337 continue # HERE IT IS
338 r
= groups
.get(role
, None)
340 Log(LOG_WARNING
, "LDAP Server doesn't provide a '%s' group (asked for user '%s')." % (role
, name
, ))
345 luf
.manage_editGroupRoles(dn
, role_dns
)
349 def manage_addLDAPGroupFolder( self
, title
= '', luf
='', REQUEST
=None):
351 this_folder
= self
.this()
353 if hasattr(aq_base(this_folder
), 'acl_users') and REQUEST
is not None:
354 msg
= 'This+object+already+contains+a+User+Folder'
357 # Try to guess where is LUF
359 for src
in this_folder
.listUserSources():
360 if src
.meta_type
== "LDAPUserFolder":
361 luf
= src
.aq_parent
.getId()
363 # No LUF found : error
365 raise KeyError, "You must be within GRUF with a LDAPUserFolder as one of your user sources."
367 n
= LDAPGroupFolder( title
, luf
)
369 this_folder
._setObject
('acl_users', n
)
370 this_folder
.__allow
_groups
__ = self
.acl_users
372 msg
= 'Added+LDAPGroupFolder'
374 # return to the parent object's manage_main
376 url
= REQUEST
['URL1']
377 qs
= 'manage_tabs_message=%s' % msg
378 REQUEST
.RESPONSE
.redirect('%s/manage_main?%s' % (url
, qs
))
381 InitializeClass(LDAPGroupFolder
)
384 class GroupUser(SimpleUser
):
387 def __init__(self
, name
, password
, roles
, domains
):
388 SimpleUser
.__init
__(self
, name
, password
, roles
, domains
)
389 self
._created
= time
.time()
391 def getCreationTime(self
):
393 return DateTime(self
._created
)