Exemple #1
0
class TestSimpleCache(unittest.TestCase):
    def setUp(self):
        from Products.LDAPUserFolder.SimpleCache import SimpleCache
        self.cache = SimpleCache()
        self.cache.setTimeout(0.1)

    def testInstantiation(self):
        self.assertEqual(len(self.cache.getCache()), 0)

    def testCaching(self):
        nonauth_ob = CacheObject('nonauth')
        self.cache.set('TestId', nonauth_ob)
        self.assertEqual(len(self.cache.getCache()), 1)
        self.assertEqual(self.cache.get('testid', password=None), nonauth_ob)
        time.sleep(0.5)
        self.assertEqual(self.cache.get('testid', password=None), None)
        self.assertEqual(len(self.cache.getCache()), 0)
        auth_ob = CacheObject('auth')
        self.cache.set('NewId', auth_ob)
        self.assertEqual(len(self.cache.getCache()), 1)
        self.assertEqual(self.cache.get('newid', password=TESTPWD), auth_ob)
        time.sleep(0.5)
        self.assertEqual(self.cache.get('newid', password=TESTPWD), None)
        self.assertEqual(len(self.cache.getCache()), 0)

    def testRemove(self):
        nonauth_ob = CacheObject('nonauth')
        self.cache.set('TestId', nonauth_ob)
        self.cache.remove('testid')
        self.assertEqual(len(self.cache.getCache()), 0)
        auth_ob = CacheObject('auth')
        self.cache.set('NewId', auth_ob)
        self.cache.remove('newid')
        self.assertEqual(len(self.cache.getCache()), 0)

    def testClear(self):
        nonauth_ob = CacheObject('nonauth')
        self.cache.set('TestId', nonauth_ob)
        auth_ob = CacheObject('auth')
        self.cache.set('NewId', auth_ob)
        self.cache.clear()
        self.assertEqual(len(self.cache.getCache()), 0)
        self.assertEqual(len(self.cache.getCache()), 0)
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)
class TestSimpleCache(unittest.TestCase):

    def setUp(self):
        self.cache = SimpleCache()
        self.cache.setTimeout(0.1)

    def testInstantiation(self):
        self.assertEqual(len(self.cache.getCache()), 0)

    def testCaching(self):
        nonauth_ob = CacheObject('nonauth')
        self.cache.set('TestId', nonauth_ob)
        self.assertEqual(len(self.cache.getCache()), 1)
        self.assertEqual( self.cache.get('testid', password=None)
                        , nonauth_ob
                        )
        time.sleep(0.5)
        self.assertEqual( self.cache.get('testid', password=None)
                        , None
                        )
        self.assertEqual(len(self.cache.getCache()), 0)
        auth_ob = CacheObject('auth')
        self.cache.set('NewId', auth_ob)
        self.assertEqual(len(self.cache.getCache()), 1)
        self.assertEqual( self.cache.get('newid', password=TESTPWD)
                        , auth_ob
                        )
        time.sleep(0.5)
        self.assertEqual( self.cache.get('newid', password=TESTPWD)
                        , None
                        )
        self.assertEqual(len(self.cache.getCache()), 0)

    def testRemove(self):
        nonauth_ob = CacheObject('nonauth')
        self.cache.set('TestId', nonauth_ob)
        self.cache.remove('testid')
        self.assertEqual(len(self.cache.getCache()), 0)
        auth_ob = CacheObject('auth')
        self.cache.set('NewId', auth_ob)
        self.cache.remove('newid')
        self.assertEqual(len(self.cache.getCache()), 0)

    def testClear(self):
        nonauth_ob = CacheObject('nonauth')
        self.cache.set('TestId', nonauth_ob)
        auth_ob = CacheObject('auth')
        self.cache.set('NewId', auth_ob)
        self.cache.clear()
        self.assertEqual(len(self.cache.getCache()), 0)
        self.assertEqual(len(self.cache.getCache()), 0)
Exemple #4
0
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)