--- /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.
+"""
+
+"""
+__version__ = "$Revision: $"
+# $Source: $
+# $Id: LDAPGroupFolder.py 587 2008-07-31 09:20:06Z pin $
+__docformat__ = 'restructuredtext'
+
+import time, traceback
+
+# Zope imports
+from Globals import DTMLFile, InitializeClass
+from Acquisition import aq_base
+from AccessControl import ClassSecurityInfo
+from AccessControl.User import SimpleUser
+from AccessControl.Permissions import view_management_screens, manage_users
+from OFS.SimpleItem import SimpleItem
+from DateTime import DateTime
+
+from Products.GroupUserFolder import postonly
+import GroupUserFolder
+
+from global_symbols import *
+
+# LDAPUserFolder package imports
+from Products.LDAPUserFolder.SimpleCache import SimpleCache
+
+addLDAPGroupFolderForm = DTMLFile('dtml/addLDAPGroupFolder', globals())
+
+
+class LDAPGroupFolder(SimpleItem):
+ """ """
+ security = ClassSecurityInfo()
+
+ meta_type = 'LDAPGroupFolder'
+ id = 'acl_users'
+
+ isPrincipiaFolderish=1
+ isAUserFolder=1
+
+ manage_options=(
+ ({'label' : 'Groups', 'action' : 'manage_main',},)
+ + SimpleItem.manage_options
+ )
+
+ security.declareProtected(view_management_screens, 'manage_main')
+ manage_main = DTMLFile('dtml/groups', globals())
+
+
+ def __setstate__(self, v):
+ """ """
+ LDAPGroupFolder.inheritedAttribute('__setstate__')(self, v)
+ self._cache = SimpleCache()
+ self._cache.setTimeout(600)
+ self._cache.clear()
+
+ def __init__( self, title, luf=''):
+ """ """
+ self._luf = luf
+ self._cache = SimpleCache()
+ self._cache.setTimeout(600)
+ self._cache.clear()
+
+ security.declarePrivate(manage_users, 'getGRUF')
+ def getGRUF(self):
+ """ """
+ return self.aq_parent.aq_parent
+
+
+ security.declareProtected(manage_users, 'getLUF')
+ def getLUF(self):
+ """ """
+ s = self.getGRUF().getUserSource(self._luf)
+ if getattr(s, 'meta_type', None) != "LDAPUserFolder":
+ # whoops, we moved LDAPUF... let's try to find it back
+ Log(LOG_WARNING, "LDAPUserFolder moved. Trying to find it back.")
+ s = None
+ for src in self.getGRUF().listUserSources():
+ if src.meta_type == "LDAPUserFolder":
+ self._luf = src.getPhysicalPath()[-2]
+ s = src
+ break
+ if not s:
+ raise RuntimeError, "You must change your groups source in GRUF if you do not have a LDAPUserFolder as a users source."
+ return s
+
+
+ security.declareProtected(manage_users, 'getGroups')
+ def getGroups(self, dn='*', attr=None, pwd=''):
+ """ """
+ return self.getLUF().getGroups(dn, attr, pwd)
+
+
+ security.declareProtected(manage_users, 'getGroupType')
+ def getGroupType(self, group_dn):
+ """ """
+ return self.getLUF().getGroupType(group_dn)
+
+ security.declareProtected(manage_users, 'getGroupMappings')
+ def getGroupMappings(self):
+ """ """
+ return self.getLUF().getGroupMappings()
+
+ security.declareProtected(manage_users, 'manage_addGroupMapping')
+ def manage_addGroupMapping(self, group_name, role_name, REQUEST=None):
+ """ """
+ self._cache.remove(group_name)
+ self.getLUF().manage_addGroupMapping(group_name, role_name, None)
+
+ if REQUEST:
+ msg = 'Added LDAP group to Zope role mapping: %s -> %s' % (
+ group_name, role_name)
+ return self.manage_main(manage_tabs_message=msg)
+ manage_addGroupMapping = postonly(manage_addGroupMapping)
+
+ security.declareProtected(manage_users, 'manage_deleteGroupMappings')
+ def manage_deleteGroupMappings(self, group_names, REQUEST=None):
+ """ Delete mappings from LDAP group to Zope role """
+ self._cache.clear()
+ self.getLUF().manage_deleteGroupMappings(group_names, None)
+ if REQUEST:
+ msg = 'Deleted LDAP group to Zope role mapping for: %s' % (
+ ', '.join(group_names))
+ return self.manage_main(manage_tabs_message=msg)
+ manage_deleteGroupMappings = postonly(manage_deleteGroupMappings)
+
+ security.declareProtected(manage_users, 'manage_addGroup')
+ def manage_addGroup( self
+ , newgroup_name
+ , newgroup_type='groupOfUniqueNames'
+ , REQUEST=None
+ ):
+ """Add a new group in groups_base.
+ """
+ self.getLUF().manage_addGroup(newgroup_name, newgroup_type, None)
+
+ if REQUEST:
+ msg = 'Added new group %s' % (newgroup_name)
+ return self.manage_main(manage_tabs_message=msg)
+ manage_addGroup = postonly(manage_addGroup)
+
+ security.declareProtected(manage_users, 'manage_deleteGroups')
+ def manage_deleteGroups(self, dns=[], REQUEST=None):
+ """ Delete groups from groups_base """
+ self.getLUF().manage_deleteGroups(dns, None)
+ self._cache.clear()
+
+ if REQUEST:
+ msg = 'Deleted group(s):<br> %s' % '<br>'.join(dns)
+ return self.manage_main(manage_tabs_message=msg)
+ manage_deleteGroups = postonly(manage_deleteGroups)
+
+ security.declareProtected(manage_users, 'getUser')
+ def getUser(self, name):
+ """ """
+ # Prevent locally stored groups
+ luf = self.getLUF()
+ if luf._local_groups:
+ return []
+
+ # Get the group from the cache
+ user = self._cache.get(name, '')
+ if user:
+ return user
+
+ # Scan groups to find the proper user.
+ # THIS MAY BE EXPENSIVE AND HAS TO BE OPTIMIZED...
+ grps = self.getLUF().getGroups()
+ valid_roles = self.userFolderGetRoles()
+ dn = None
+ for n, g_dn in grps:
+ if n == name:
+ dn = g_dn
+ break
+ if not dn:
+ return None
+
+ # Current mapping
+ roles = self.getLUF()._mapRoles([name])
+
+ # Nested groups
+ groups = list(self.getLUF().getGroups(dn=dn, attr='cn', ))
+ roles.extend(self.getLUF()._mapRoles(groups))
+
+ # !!! start test
+ Log(LOG_DEBUG, name, "roles", groups, roles)
+ Log(LOG_DEBUG, name, "mapping", getattr(self.getLUF(), '_groups_mappings', {}))
+ # !!! end test
+
+ actual_roles = []
+ for r in roles:
+ if r in valid_roles:
+ actual_roles.append(r)
+ elif "%s%s" % (GROUP_PREFIX, r) in valid_roles:
+ actual_roles.append("%s%s" % (GROUP_PREFIX, r))
+ Log(LOG_DEBUG, name, "actual roles", actual_roles)
+ user = GroupUser(n, '', actual_roles, [])
+ self._cache.set(name, user)
+ return user
+
+ security.declareProtected(manage_users, 'getUserNames')
+ def getUserNames(self):
+ """ """
+ Log(LOG_DEBUG, "getUserNames", )
+ LogCallStack(LOG_DEBUG)
+ # Prevent locally stored groups
+ luf = self.getLUF()
+ if luf._local_groups:
+ return []
+ return [g[0] for g in luf.getGroups()]
+
+ security.declareProtected(manage_users, 'getUsers')
+ def getUsers(self, authenticated=1):
+ """ """
+ # Prevent locally stored groups
+ luf = self.getLUF()
+ if luf._local_groups:
+ return []
+
+ data = []
+
+ grps = self.getLUF().getGroups()
+ valid_roles = self.userFolderGetRoles()
+ for n, dn in grps:
+ # Group mapping
+ roles = self.getLUF()._mapRoles([n])
+
+ # computation
+ actual_roles = []
+ for r in roles:
+ if r in valid_roles:
+ actual_roles.append(r)
+ elif "%s%s" % (GROUP_PREFIX, r) in valid_roles:
+ actual_roles.append("%s%s" % (GROUP_PREFIX, r))
+ user = GroupUser(n, '', actual_roles, [])
+ data.append(user)
+
+ return data
+
+ security.declarePrivate('_doAddUser')
+ def _doAddUser(self, name, password, roles, domains, **kw):
+ """WARNING: If a role with exists with the same name as the group, we do not add
+ the group mapping for it, but we create it as if it were a Zope ROLE.
+ Ie. it's not possible to have a GRUF Group name = a Zope role name, BUT,
+ with this system, it's possible to differenciate between LDAP groups and LDAP roles.
+ """
+ self.getLUF().manage_addGroup(name)
+ self.manage_addGroupMapping(name, "group_" + name, None, )
+ self._doChangeUser(name, password, roles, domains, **kw)
+
+ security.declarePrivate('_doDelUsers')
+ def _doDelUsers(self, names):
+ dns = []
+ luf = self.getLUF()
+ for g_name, dn in luf.getGroups():
+ if g_name in names:
+ dns.append(dn)
+ self._cache.clear()
+ return luf.manage_deleteGroups(dns)
+
+ security.declarePrivate('_doChangeUser')
+ def _doChangeUser(self, name, password, roles, domains, **kw):
+ """
+ This is used to change the groups (especially their roles).
+
+ [ THIS TEXT IS OUTDATED :
+ WARNING: If a ZOPE role with the same name as the GRUF group exists,
+ we do not add the group mapping for it, but we create it as if it were a Zope ROLE.
+ Ie. it's not possible to have a GRUF Group name = a Zope role name, BUT,
+ with this system, it's possible to differenciate between LDAP groups and LDAP roles.
+ ]
+ """
+ luf = self.getLUF()
+ self._cache.remove(name)
+
+ # Get group DN
+ dn = None
+ for g_name, g_dn in luf.getGroups():
+ if g_name == name:
+ dn = g_dn
+ break
+ if not dn:
+ raise ValueError, "Invalid LDAP group: '%s'" % (name, )
+
+ # Edit group mappings
+## if name in self.aq_parent.valid_roles():
+## # This is, in fact, a role
+## self.getLUF().manage_addGroupMapping(name, name)
+## else:
+## # This is a group -> we set it as a group
+## self.getLUF().manage_addGroupMapping(name, self.getGroupPrefix() + name)
+
+ # Change roles
+ if luf._local_groups:
+ luf.manage_editUserRoles(dn, roles)
+ else:
+ # We have to transform roles into group dns: transform them as a dict
+ role_dns = []
+ all_groups = luf.getGroups()
+ all_roles = luf.valid_roles()
+ groups = {}
+ for g in all_groups:
+ groups[g[0]] = g[1]
+
+ # LDAPUF < 2.4Beta3 adds 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.
+ # 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 (asked for user '%s')." % (role, name, ))
+ continue
+ role_dns.append(r)
+
+ # Perform the change
+ luf.manage_editGroupRoles(dn, role_dns)
+
+
+
+def manage_addLDAPGroupFolder( self, title = '', luf='', REQUEST=None):
+ """ """
+ this_folder = self.this()
+
+ if hasattr(aq_base(this_folder), 'acl_users') and REQUEST is not None:
+ msg = 'This+object+already+contains+a+User+Folder'
+
+ else:
+ # Try to guess where is LUF
+ if not luf:
+ for src in this_folder.listUserSources():
+ if src.meta_type == "LDAPUserFolder":
+ luf = src.aq_parent.getId()
+
+ # No LUF found : error
+ if not luf:
+ raise KeyError, "You must be within GRUF with a LDAPUserFolder as one of your user sources."
+
+ n = LDAPGroupFolder( title, luf )
+
+ this_folder._setObject('acl_users', n)
+ this_folder.__allow_groups__ = self.acl_users
+
+ msg = 'Added+LDAPGroupFolder'
+
+ # return to the parent object's manage_main
+ if REQUEST:
+ url = REQUEST['URL1']
+ qs = 'manage_tabs_message=%s' % msg
+ REQUEST.RESPONSE.redirect('%s/manage_main?%s' % (url, qs))
+
+
+InitializeClass(LDAPGroupFolder)
+
+
+class GroupUser(SimpleUser):
+ """ """
+
+ def __init__(self, name, password, roles, domains):
+ SimpleUser.__init__(self, name, password, roles, domains)
+ self._created = time.time()
+
+ def getCreationTime(self):
+ """ """
+ return DateTime(self._created)