コード例 #1
0
ファイル: _api.py プロジェクト: datakurre/node.ext.ldap
 def __init__(self, props, cfg):
     context = LDAPNode(name=cfg.baseDN, props=props)
     context.search_filter = cfg.queryFilter
     context.search_scope = int(cfg.scope)
     context.child_defaults = dict()
     context.child_defaults['objectClass'] = cfg.objectClasses
     context.child_defaults.update(cfg.defaults)
     for oc in cfg.objectClasses:
         for key, val in creation_defaults.get(oc, dict()).items():
             if key not in context.child_defaults:
                 context.child_defaults[key] = val
     # if cfg.member_relation:
     #     context.search_relation = cfg.member_relation
     self._rdn_attr = cfg.attrmap['rdn']
     self._key_attr = cfg.attrmap['id']
     if self._key_attr not in cfg.attrmap:
         cfg.attrmap[self._key_attr] = self._key_attr
     self._login_attr = None
     if cfg.attrmap.get('login') \
             and cfg.attrmap['login'] != cfg.attrmap['id']:
         self._login_attr = cfg.attrmap['login']
     self.expiresAttr = getattr(cfg, 'expiresAttr', None)
     self.expiresUnit = getattr(cfg, 'expiresUnit', None)
     self.principal_attrmap = cfg.attrmap
     self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
     self.context = context
     self.context.root.search_attrlist = list(sorted(set(
         self.principal_attrmap.values() + ['rdn', 'memberOf']
     )))
コード例 #2
0
    def __init__(self, props, cfg):
        context = LDAPNode(name=cfg.baseDN, props=props)
        context.search_filter = cfg.queryFilter
        context.search_scope = int(cfg.scope)

        context.child_defaults = dict()
        context.child_defaults['objectClass'] = cfg.objectClasses
        if hasattr(cfg, 'defaults'):
            context.child_defaults.update(cfg.defaults)
        for oc in cfg.objectClasses:
            for key, val in creation_defaults.get(oc, dict()).items():
                if not key in context.child_defaults:
                    context.child_defaults[key] = val

        # XXX: make these attrs public
        context._key_attr = cfg.attrmap['id']
        context._rdn_attr = cfg.attrmap['rdn']

        #if cfg.member_relation:
        #    context.search_relation = cfg.member_relation

        context._seckey_attrs = ('dn', )
        if cfg.attrmap.get('login') \
          and cfg.attrmap['login'] != cfg.attrmap['id']:
            context._seckey_attrs += (cfg.attrmap['login'], )

        context._load_keys()

        self.expiresAttr = getattr(cfg, 'expiresAttr', None)
        self.expiresUnit = getattr(cfg, 'expiresUnit', None)
        self.principal_attrmap = cfg.attrmap
        self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
        self.context = context
コード例 #3
0
ファイル: _api.py プロジェクト: bluedynamics/node.ext.ldap
 def __init__(self, props, cfg):
     context = LDAPNode(name=cfg.baseDN, props=props)
     context.search_filter = cfg.queryFilter
     context.search_scope = int(cfg.scope)
     context.child_defaults = dict()
     context.child_defaults["objectClass"] = cfg.objectClasses
     context.child_defaults.update(cfg.defaults)
     for oc in cfg.objectClasses:
         for key, val in creation_defaults.get(oc, dict()).items():
             if key not in context.child_defaults:
                 context.child_defaults[key] = val
     # if cfg.member_relation:
     #     context.search_relation = cfg.member_relation
     self._rdn_attr = cfg.attrmap["rdn"]
     self._key_attr = cfg.attrmap["id"]
     if self._key_attr not in cfg.attrmap:
         cfg.attrmap[self._key_attr] = self._key_attr
     self._login_attr = None
     if cfg.attrmap.get("login") and cfg.attrmap["login"] != cfg.attrmap["id"]:
         self._login_attr = cfg.attrmap["login"]
     self.expiresAttr = getattr(cfg, "expiresAttr", None)
     self.expiresUnit = getattr(cfg, "expiresUnit", None)
     self.principal_attrmap = cfg.attrmap
     self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
     self.context = context
コード例 #4
0
ファイル: _api.py プロジェクト: syslabcom/node.ext.ldap
    def __init__(self, props, cfg):
        context = LDAPNode(name=cfg.baseDN, props=props)
        context.search_filter = cfg.queryFilter
        context.search_scope = int(cfg.scope)

        context.child_defaults = dict()
        context.child_defaults['objectClass'] = cfg.objectClasses
        if hasattr(cfg, 'defaults'):
            context.child_defaults.update(cfg.defaults)
        for oc in cfg.objectClasses:
            for key, val in creation_defaults.get(oc, dict()).items():
                if not key in context.child_defaults:
                    context.child_defaults[key] = val

        # XXX: make these attrs public
        context._key_attr = cfg.attrmap['id']
        context._rdn_attr = cfg.attrmap['rdn']

        #if cfg.member_relation:
        #    context.search_relation = cfg.member_relation

        context._seckey_attrs = ('dn',)
        if cfg.attrmap.get('login') \
          and cfg.attrmap['login'] != cfg.attrmap['id']:
            context._seckey_attrs += (cfg.attrmap['login'],)

        context._load_keys()

        self.expiresAttr = getattr(cfg, 'expiresAttr', None)
        self.expiresUnit = getattr(cfg, 'expiresUnit', None)
        self.principal_attrmap = cfg.attrmap
        self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
        self.context = context
コード例 #5
0
    def test_DictAliaser(self):
        # A dict aliaser takes a dictionary as base for aliasing
        da = DictAliaser([('alias1', 'key1'), ('alias2', 'key2')])
        self.assertEqual(da.alias('key1'), 'alias1')
        self.assertEqual(da.unalias('alias2'), 'key2')

        # By default, aliasing is strict, which means that only key/value pairs
        # set in aliaser are valid
        err = self.expectError(KeyError, da.alias, 'foo')
        self.assertEqual(str(err), '\'foo\'')
        err = self.expectError(KeyError, da.unalias, 'foo')
        self.assertEqual(str(err), '\'foo\'')

        # By setting strict to False, inexistent keys are returned as fallback
        da = DictAliaser([('alias1', 'key1'), ('alias2', 'key2')],
                         strict=False)
        self.assertEqual(da.alias('foo'), 'foo')
        self.assertEqual(da.unalias('foo'), 'foo')
コード例 #6
0
ファイル: test_alias.py プロジェクト: bluedynamics/node
    def test_DictAliaser(self):
        # A dict aliaser takes a dictionary as base for aliasing
        da = DictAliaser([('alias1', 'key1'), ('alias2', 'key2')])
        self.assertEqual(da.alias('key1'), 'alias1')
        self.assertEqual(da.unalias('alias2'), 'key2')

        # By default, aliasing is strict, which means that only key/value pairs
        # set in aliaser are valid
        err = self.expect_error(KeyError, da.alias, 'foo')
        self.assertEqual(str(err), '\'foo\'')
        err = self.expect_error(KeyError, da.unalias, 'foo')
        self.assertEqual(str(err), '\'foo\'')

        # By setting strict to False, inexistent keys are returned as fallback
        da = DictAliaser(
            [('alias1', 'key1'), ('alias2', 'key2')],
            strict=False
        )
        self.assertEqual(da.alias('foo'), 'foo')
        self.assertEqual(da.unalias('foo'), 'foo')
コード例 #7
0
ファイル: _api.py プロジェクト: bluedynamics/node.ext.ldap
class LDAPPrincipals(OdictStorage):
    principal_attrmap = default(None)
    principal_attraliaser = default(None)

    @override
    def __init__(self, props, cfg):
        context = LDAPNode(name=cfg.baseDN, props=props)
        context.search_filter = cfg.queryFilter
        context.search_scope = int(cfg.scope)
        context.child_defaults = dict()
        context.child_defaults["objectClass"] = cfg.objectClasses
        context.child_defaults.update(cfg.defaults)
        for oc in cfg.objectClasses:
            for key, val in creation_defaults.get(oc, dict()).items():
                if key not in context.child_defaults:
                    context.child_defaults[key] = val
        # if cfg.member_relation:
        #     context.search_relation = cfg.member_relation
        self._rdn_attr = cfg.attrmap["rdn"]
        self._key_attr = cfg.attrmap["id"]
        if self._key_attr not in cfg.attrmap:
            cfg.attrmap[self._key_attr] = self._key_attr
        self._login_attr = None
        if cfg.attrmap.get("login") and cfg.attrmap["login"] != cfg.attrmap["id"]:
            self._login_attr = cfg.attrmap["login"]
        self.expiresAttr = getattr(cfg, "expiresAttr", None)
        self.expiresUnit = getattr(cfg, "expiresUnit", None)
        self.principal_attrmap = cfg.attrmap
        self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
        self.context = context

    @default
    def idbydn(self, dn, strict=False):
        """Return a principal's id for a given dn.

        Raise KeyError if not enlisted.
        """
        # XXX: rename to id_by_dn
        # XXX: what was strict good for? remove
        # if strict:
        #     raise KeyError(dn)
        try:
            search = self.context.ldap_session.search
            res = search(baseDN=dn.encode("utf-8"))[0]
            return res[1][self._key_attr][0].decode("utf-8")
        except ldap.NO_SUCH_OBJECT:
            raise KeyError(dn)

    @override
    @property
    def ids(self):
        return list(self.__iter__())

    @default
    @locktree
    def __delitem__(self, key):
        principal = self[key]
        context = principal.context
        del context.parent[context.name]
        del self.storage[key]

    @default
    @locktree
    def __getitem__(self, key):
        key = decode_utf8(key)
        try:
            return self.storage[key]
        except KeyError:
            criteria = {self._key_attr: key}
            attrlist = ["rdn", self._key_attr]
            res = self.context.search(criteria=criteria, attrlist=attrlist)
            if not res:
                raise KeyError(key)
            if len(res) > 1:
                msg = u'More than one principal with id "{0}" found.'
                logger.warning(msg.format(key))
            prdn = res[0][1]["rdn"]
            if prdn in self.context._deleted_children:
                raise KeyError(key)
            dn = res[0][0]
            # XXX: use explode_dn
            path = dn.split(",")[: len(self.context.DN.split(",")) * -1]
            context = self.context
            for rdn in reversed(path):
                context = context[rdn]
            principal = self.principal_factory(context, attraliaser=self.principal_attraliaser)
            principal.__name__ = key
            principal.__parent__ = self
            self.storage[key] = principal
            return principal

    @default
    @locktree
    def __iter__(self):
        attrlist = ["rdn", self._key_attr]
        for principal in self.context.batched_search(attrlist=attrlist):
            prdn = principal[1]["rdn"]
            if prdn in self.context._deleted_children:
                continue
            yield principal[1][self._key_attr][0]
        for principal in self.context._added_children:
            yield self.context[principal].attrs[self._key_attr]

    @default
    @locktree
    def __setitem__(self, name, value):
        if not isinstance(value, self.principal_factory):
            raise ValueError(u"Given value not instance of '{0}'".format(self.principal_factory.__name__))
        # XXX: check if there is valid user context
        exists = False
        try:
            self[name]
            exists = True
        except KeyError:
            pass
        if exists:
            raise KeyError(u"Principal with id '{0}' already exists.".format(name))
        value.__name__ = name
        value.__parent__ = self
        self.storage[name] = value

    @default
    @property
    def changed(self):
        return self.context.changed

    @default
    @locktree
    def invalidate(self, key=None):
        """Invalidate LDAPPrincipals.
        """
        if key is None:
            self.context.invalidate()
            self.storage.clear()
            return
        try:
            principal = self.storage[key]
            principal.context.parent.invalidate(principal.context.name)
            del self.storage[key]
        except KeyError:
            pass

    @default
    @locktree
    def __call__(self):
        self.context()

    @default
    def _alias_dict(self, dct):
        ret = dict()
        for key, val in self.principal_attraliaser.iteritems():
            for k, v in dct.iteritems():
                if val == k:
                    ret[key] = v
        return ret

    @default
    def _unalias_list(self, lst):
        if lst is None:
            return None
        unalias = self.principal_attraliaser.unalias
        return [unalias(x) for x in lst]

    @default
    def _unalias_dict(self, dct):
        if dct is None:
            return None
        unalias = self.principal_attraliaser.unalias
        unaliased_dct = dict([(unalias(key), val) for key, val in dct.iteritems()])
        return unaliased_dct

    @default
    def search(
        self,
        criteria=None,
        attrlist=None,
        exact_match=False,
        or_search=False,
        or_keys=None,
        or_values=None,
        page_size=None,
        cookie=None,
    ):
        search_attrlist = [self._key_attr]
        if attrlist is not None and self._key_attr not in attrlist:
            search_attrlist += attrlist
        try:
            results = self.context.search(
                criteria=self._unalias_dict(criteria),
                attrlist=self._unalias_list(search_attrlist),
                exact_match=exact_match,
                or_search=or_search,
                or_keys=or_keys,
                or_values=or_values,
                page_size=page_size,
                cookie=cookie,
            )
        except ldap.NO_SUCH_OBJECT:
            return []
        if type(results) is tuple:
            results, cookie = results
        if attrlist is not None:
            _results = list()
            for _, att in results:
                user_id = att[self._key_attr][0]
                aliased = self._alias_dict(att)
                keys = aliased.keys()
                for key in keys:
                    if key not in attrlist:
                        del aliased[key]
                _results.append((user_id, aliased))
            results = _results
        else:
            results = [att[self._key_attr][0] for _, att in results]
        if cookie is not None:
            return results, cookie
        return results

    @default
    @locktree
    def create(self, pid, **kw):
        # XXX: mechanism for defining a target container if scope is SUBTREE
        # create principal with LDAPNode as context
        context = LDAPNode()
        principal = self.principal_factory(context, attraliaser=self.principal_attraliaser)
        # ensure id on attributes
        kw["id"] = pid
        # avoid overwriting key attribute if given in kw
        if self._key_attr in kw:
            del kw[self._key_attr]
        # set additional attributes on principal
        for k, v in kw.items():
            principal.attrs[k] = v
        # set principal to self
        self[pid] = principal
        # if setting principal has been successful, hook up principal context
        # to ldap tree
        rdn = u"{0}={1}".format(self._rdn_attr, principal.context.attrs[self._rdn_attr])
        self.context[rdn] = context
        # return newly created principal
        return self[pid]
コード例 #8
0
ファイル: _api.py プロジェクト: datakurre/node.ext.ldap
class LDAPPrincipals(OdictStorage):
    principal_attrmap = default(None)
    principal_attraliaser = default(None)

    @override
    def __init__(self, props, cfg):
        context = LDAPNode(name=cfg.baseDN, props=props)
        context.search_filter = cfg.queryFilter
        context.search_scope = int(cfg.scope)
        context.child_defaults = dict()
        context.child_defaults['objectClass'] = cfg.objectClasses
        context.child_defaults.update(cfg.defaults)
        for oc in cfg.objectClasses:
            for key, val in creation_defaults.get(oc, dict()).items():
                if key not in context.child_defaults:
                    context.child_defaults[key] = val
        # if cfg.member_relation:
        #     context.search_relation = cfg.member_relation
        self._rdn_attr = cfg.attrmap['rdn']
        self._key_attr = cfg.attrmap['id']
        if self._key_attr not in cfg.attrmap:
            cfg.attrmap[self._key_attr] = self._key_attr
        self._login_attr = None
        if cfg.attrmap.get('login') \
                and cfg.attrmap['login'] != cfg.attrmap['id']:
            self._login_attr = cfg.attrmap['login']
        self.expiresAttr = getattr(cfg, 'expiresAttr', None)
        self.expiresUnit = getattr(cfg, 'expiresUnit', None)
        self.principal_attrmap = cfg.attrmap
        self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
        self.context = context
        self.context.root.search_attrlist = list(sorted(set(
            self.principal_attrmap.values() + ['rdn', 'memberOf']
        )))

    @default
    def idbydn(self, dn, strict=False):
        """Return a principal's id for a given dn.

        Raise KeyError if not enlisted.
        """
        node = self.context.node_by_dn(dn, strict)
        node.attrs.load()
        return node.attrs[self._key_attr]

    @override
    @property
    def ids(self):
        return list(self.__iter__())

    @default
    @locktree
    def __delitem__(self, key):
        principal = self[key]
        context = principal.context
        del context.parent[context.name]
        del self.storage[key]

    @default
    @locktree
    def __getitem__(self, key):
        try:
            return self.storage[key]
        except KeyError:
            criteria = {self._key_attr: key}
            attrlist = self.context.root.search_attrlist
            res = self.context.search(criteria=criteria, attrlist=attrlist)
            if not res:
                raise KeyError(key)
            if len(res) > 1:
                msg = 'More than one principal with id "{0}" found.'
                logger.warning(msg.format(key))
            prdn = res[0][1]['rdn']
            if prdn in self.context._deleted_children:
                raise KeyError(key)
            dn = res[0][0]
            # XXX: use explode_dn
            path = dn.split(',')[:len(self.context.DN.split(',')) * -1]
            context = self.context
            for rdn in reversed(path):
                if rdn not in context.storage:
                    val = context.child_factory()
                    val.__name__ = rdn
                    val.__parent__ = context
                    # remember DN
                    val._dn = '{0:s},{1:s}'.format(
                        rdn, context._dn or context.__name__)
                    val._ldap_session = context.ldap_session
                    context.storage[rdn] = val
                context = context[rdn]
            context.search_criteria = criteria
            principal = self.principal_factory(
                context,
                attraliaser=self.principal_attraliaser
            )
            principal.__name__ = key
            principal.__parent__ = self
            self.storage[key] = principal
            return principal

    @default
    @locktree
    def __iter__(self):
        attrlist = self.context.root.search_attrlist
        for principal in self.context.batched_search(attrlist=attrlist):
            prdn = principal[1]['rdn']
            if prdn in self.context._deleted_children:
                continue
            yield principal[1][self._key_attr][0]
        for principal in self.context._added_children:
            yield self.context[principal].attrs[self._key_attr]

    @default
    @locktree
    def __setitem__(self, name, value):
        if not isinstance(value, self.principal_factory):
            raise ValueError("Given value not instance of '{0}'".format(
                self.principal_factory.__name__
            ))
        # XXX: check if there is valid user context
        exists = False
        try:
            self[name]
            exists = True
        except KeyError:
            pass
        if exists:
            raise KeyError(
                "Principal with id '{0}' already exists.".format(name)
            )
        value.__name__ = name
        value.__parent__ = self
        self.storage[name] = value

    @default
    @property
    def changed(self):
        return self.context.changed

    @default
    @locktree
    def invalidate(self, key=None):
        """Invalidate LDAPPrincipals.
        """
        if key is None:
            self.context.invalidate()
            self.storage.clear()
            return
        try:
            principal = self.storage[key]
            principal.context.parent.invalidate(principal.context.name)
            del self.storage[key]
        except KeyError:
            pass

    @default
    @locktree
    def __call__(self):
        self.context()

    @default
    def _alias_dict(self, dct):
        ret = dict()
        for key, val in self.principal_attraliaser.iteritems():
            for k, v in dct.iteritems():
                if val == k:
                    ret[key] = v
        return ret

    @default
    def _unalias_list(self, lst):
        if lst is None:
            return None
        unalias = self.principal_attraliaser.unalias
        return [unalias(x) for x in lst]

    @default
    def _unalias_dict(self, dct):
        if dct is None:
            return None
        unalias = self.principal_attraliaser.unalias
        unaliased_dct = dict(
            [(unalias(key), val) for key, val in dct.iteritems()])
        return unaliased_dct

    @default
    def search(self, criteria=None, attrlist=None,
               exact_match=False, or_search=False, or_keys=None,
               or_values=None, page_size=None, cookie=None):
        search_attrlist = [self._key_attr]
        if attrlist is not None:
            search_attrlist += attrlist
        try:
            results = self.context.search(
                criteria=self._unalias_dict(criteria),
                attrlist=self._unalias_list(search_attrlist),
                exact_match=exact_match,
                or_search=or_search,
                or_keys=or_keys,
                or_values=or_values,
                page_size=page_size,
                cookie=cookie
            )
        except ldap.NO_SUCH_OBJECT:
            return []
        if type(results) is tuple:
            results, cookie = results
        if attrlist is not None:
            _results = list()
            for _, att in results:
                try:
                    user_id = att[self._key_attr][0]
                except (KeyError, IndexError):
                    continue
                aliased = self._alias_dict(att)
                # append all matching aliases (in addition to attrlist oness)
                _results.append((user_id, aliased))
            results = _results
        else:
            results = [att[self._key_attr][0] for _, att in results]
        if cookie is not None:
            return results, cookie
        return results

    @default
    @locktree
    def create(self, pid, **kw):
        # XXX: mechanism for defining a target container if scope is SUBTREE
        # create principal with LDAPNode as context
        context = LDAPNode()
        principal = self.principal_factory(
            context,
            attraliaser=self.principal_attraliaser
        )
        # ensure id on attributes
        kw['id'] = pid
        # avoid overwriting key attribute if given in kw
        if self._key_attr in kw:
            del kw[self._key_attr]
        # set additional attributes on principal
        for k, v in kw.items():
            principal.attrs[k] = v
        # set principal to self
        self[pid] = principal
        # if setting principal has been successful, hook up principal context
        # to ldap tree
        rdn = '{0}={1}'.format(
            self._rdn_attr,
            principal.context.attrs[self._rdn_attr]
        )
        self.context[rdn] = context
        # return newly created principal
        return self[pid]
コード例 #9
0
ファイル: _api.py プロジェクト: syslabcom/node.ext.ldap
class LDAPPrincipals(OdictStorage):
    principal_attrmap = default(None)
    principal_attraliaser = default(None)

    @override
    def __init__(self, props, cfg):
        context = LDAPNode(name=cfg.baseDN, props=props)
        context.search_filter = cfg.queryFilter
        context.search_scope = int(cfg.scope)

        context.child_defaults = dict()
        context.child_defaults['objectClass'] = cfg.objectClasses
        if hasattr(cfg, 'defaults'):
            context.child_defaults.update(cfg.defaults)
        for oc in cfg.objectClasses:
            for key, val in creation_defaults.get(oc, dict()).items():
                if not key in context.child_defaults:
                    context.child_defaults[key] = val

        # XXX: make these attrs public
        context._key_attr = cfg.attrmap['id']
        context._rdn_attr = cfg.attrmap['rdn']

        #if cfg.member_relation:
        #    context.search_relation = cfg.member_relation

        context._seckey_attrs = ('dn',)
        if cfg.attrmap.get('login') \
          and cfg.attrmap['login'] != cfg.attrmap['id']:
            context._seckey_attrs += (cfg.attrmap['login'],)

        context._load_keys()

        self.expiresAttr = getattr(cfg, 'expiresAttr', None)
        self.expiresUnit = getattr(cfg, 'expiresUnit', None)
        self.principal_attrmap = cfg.attrmap
        self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
        self.context = context

    @default
    def idbydn(self, dn, strict=False):
        """Return a principal's id for a given dn.

        Raise KeyError if not enlisted.
        """
        self.context.keys()
        idsbydn = self.context._seckeys['dn']
        try:
            return idsbydn[dn]
        except KeyError:
            # It's possible that we got a different string resulting
            # in the same DN, as every components can have individual
            # comparison rules (see also node.ext.ldap._node.LDAPNode.DN).
            # We leave the job to LDAP and try again with the resulting DN.
            #
            # This was introduced because a customer has group
            # member attributes where the DN string differs.
            #
            # This would not be necessary, if an LDAP directory
            # is consistent, i.e does not use different strings to
            # talk about the same.
            #
            # Normalization of DN in python would also be a
            # solution, but requires implementation of all comparison
            # rules defined in schemas. Maybe we can retrieve them
            # from LDAP.
            if strict:
                raise KeyError(dn)
            search = self.context.ldap_session.search
            try:
                dn = search(baseDN=dn.encode('utf-8'))[0][0]
            except ldap.NO_SUCH_OBJECT:
                raise KeyError(dn)
            return idsbydn[dn.decode('utf-8')]

    @override
    @property
    def ids(self):
        return self.context.keys()

    @default
    @locktree
    def __delitem__(self, key):
        key = decode_utf8(key)
        del self.context[key]
        try:
            del self.storage[key]
        except KeyError:
            pass

    @default
    @locktree
    def __getitem__(self, key):
        key = decode_utf8(key)
        try:
            return self.storage[key]
        except KeyError:
            principal = self.principal_factory(
                self.context[key],
                attraliaser=self.principal_attraliaser)
            principal.__name__ = self.context[key].name
            principal.__parent__ = self
            self.storage[key] = principal
            return principal

    @default
    @locktree
    def __iter__(self):
        return self.context.__iter__()

    @default
    @locktree
    def __setitem__(self, name, vessel):
        """XXX: mechanism for defining a target container if search scope is
                SUBTREE
        """
        try:
            attrs = vessel.attrs
        except AttributeError:
            raise ValueError(u"no attributes found, cannot convert.")
        if name in self:
            raise KeyError(u"Key already exists: '%s'." % (name,))
        nextvessel = AttributedNode()
        nextvessel.__name__ = name
        nextvessel.attribute_access_for_attrs = False
        principal = self.principal_factory(
            nextvessel,
            attraliaser=self.principal_attraliaser)
        principal.__name__ = name
        principal.__parent__ = self
        # XXX: cache
        for key, val in attrs.iteritems():
            principal.attrs[key] = val
        self.context[name] = nextvessel

    @default
    @property
    def changed(self):
        return self.context.changed

    @default
    @locktree
    def invalidate(self, key=None):
        """Invalidate LDAPPrincipals.
        """
        key = decode_utf8(key)
        self.context.invalidate(key)
        if key is None:
            self.storage.clear()
            return
        try:
            del self.storage[key]
        except KeyError:
            pass

    @default
    @locktree
    def __call__(self):
        self.context()

    @default
    def _alias_dict(self, dct):
        # XXX: seem to be not reached at all
        #if dct is None:
        #    return None

        # XXX: this code does not work if multiple keys map to same value
        #alias = self.principal_attraliaser.alias
        #aliased_dct = dict(
        #    [(alias(key), val) for key, val in dct.iteritems()])
        #return aliased_dct

        # XXX: generalization in aliaser needed
        ret = dict()
        for key, val in self.principal_attraliaser.iteritems():
            for k, v in dct.iteritems():
                if val == k:
                    ret[key] = v
        return ret

    @default
    def _unalias_list(self, lst):
        if lst is None:
            return None
        unalias = self.principal_attraliaser.unalias
        return [unalias(x) for x in lst]

    @default
    def _unalias_dict(self, dct):
        if dct is None:
            return None
        unalias = self.principal_attraliaser.unalias
        unaliased_dct = dict(
            [(unalias(key), val) for key, val in dct.iteritems()])
        return unaliased_dct

    @default
    def search(self, criteria=None, attrlist=None,
               exact_match=False, or_search=False, or_keys=None,
               or_values=None, page_size=None, cookie=None):
        results = self.context.search(
            criteria=self._unalias_dict(criteria),
            attrlist=self._unalias_list(attrlist),
            exact_match=exact_match,
            or_search=or_search,
            or_keys=or_keys,
            or_values=or_values,
            page_size=page_size,
            cookie=cookie
            )
        if type(results) is tuple:
            results, cookie = results
        if attrlist is not None:
            results = [(uid, self._alias_dict(att)) for uid, att in results]
        if cookie is not None:
            return results, cookie
        return results

    @default
    @locktree
    def create(self, pid, **kw):
        vessel = AttributedNode()
        for k, v in kw.items():
            vessel.attrs[k] = v
        self[pid] = vessel
        return self[pid]
コード例 #10
0
 class AliasDict(dict):
     aliaser = DictAliaser(data=(('foo', 'f00'), ('bar', 'b4r')))
コード例 #11
0
class LDAPPrincipals(OdictStorage):
    principal_attrmap = default(None)
    principal_attraliaser = default(None)

    @override
    def __init__(self, props, cfg):
        context = LDAPNode(name=cfg.baseDN, props=props)
        context.search_filter = cfg.queryFilter
        context.search_scope = int(cfg.scope)

        context.child_defaults = dict()
        context.child_defaults['objectClass'] = cfg.objectClasses
        if hasattr(cfg, 'defaults'):
            context.child_defaults.update(cfg.defaults)
        for oc in cfg.objectClasses:
            for key, val in creation_defaults.get(oc, dict()).items():
                if not key in context.child_defaults:
                    context.child_defaults[key] = val

        # XXX: make these attrs public
        context._key_attr = cfg.attrmap['id']
        context._rdn_attr = cfg.attrmap['rdn']

        #if cfg.member_relation:
        #    context.search_relation = cfg.member_relation

        context._seckey_attrs = ('dn', )
        if cfg.attrmap.get('login') \
          and cfg.attrmap['login'] != cfg.attrmap['id']:
            context._seckey_attrs += (cfg.attrmap['login'], )

        context._load_keys()

        self.expiresAttr = getattr(cfg, 'expiresAttr', None)
        self.expiresUnit = getattr(cfg, 'expiresUnit', None)
        self.principal_attrmap = cfg.attrmap
        self.principal_attraliaser = DictAliaser(cfg.attrmap, cfg.strict)
        self.context = context

    @default
    def idbydn(self, dn, strict=False):
        """Return a principal's id for a given dn.

        Raise KeyError if not enlisted.
        """
        self.context.keys()
        idsbydn = self.context._seckeys['dn']
        try:
            return idsbydn[dn]
        except KeyError:
            # It's possible that we got a different string resulting
            # in the same DN, as every components can have individual
            # comparison rules (see also node.ext.ldap._node.LDAPNode.DN).
            # We leave the job to LDAP and try again with the resulting DN.
            #
            # This was introduced because a customer has group
            # member attributes where the DN string differs.
            #
            # This would not be necessary, if an LDAP directory
            # is consistent, i.e does not use different strings to
            # talk about the same.
            #
            # Normalization of DN in python would also be a
            # solution, but requires implementation of all comparison
            # rules defined in schemas. Maybe we can retrieve them
            # from LDAP.
            if strict:
                raise KeyError(dn)
            search = self.context.ldap_session.search
            try:
                dn = search(baseDN=dn.encode('utf-8'))[0][0]
            except ldap.NO_SUCH_OBJECT:
                raise KeyError(dn)
            return idsbydn[dn.decode('utf-8')]

    @override
    @property
    def ids(self):
        return self.context.keys()

    @default
    @locktree
    def __delitem__(self, key):
        key = decode_utf8(key)
        del self.context[key]
        try:
            del self.storage[key]
        except KeyError:
            pass

    @default
    @locktree
    def __getitem__(self, key):
        key = decode_utf8(key)
        try:
            return self.storage[key]
        except KeyError:
            principal = self.principal_factory(
                self.context[key], attraliaser=self.principal_attraliaser)
            principal.__name__ = self.context[key].name
            principal.__parent__ = self
            self.storage[key] = principal
            return principal

    @default
    @locktree
    def __iter__(self):
        return self.context.__iter__()

    @default
    @locktree
    def __setitem__(self, name, vessel):
        """XXX: mechanism for defining a target container if search scope is
                SUBTREE
        """
        try:
            attrs = vessel.attrs
        except AttributeError:
            raise ValueError(u"no attributes found, cannot convert.")
        if name in self:
            raise KeyError(u"Key already exists: '%s'." % (name, ))
        nextvessel = AttributedNode()
        nextvessel.__name__ = name
        nextvessel.attribute_access_for_attrs = False
        principal = self.principal_factory(
            nextvessel, attraliaser=self.principal_attraliaser)
        principal.__name__ = name
        principal.__parent__ = self
        # XXX: cache
        for key, val in attrs.iteritems():
            principal.attrs[key] = val
        self.context[name] = nextvessel

    @default
    @property
    def changed(self):
        return self.context.changed

    @default
    @locktree
    def invalidate(self, key=None):
        """Invalidate LDAPPrincipals.
        """
        key = decode_utf8(key)
        self.context.invalidate(key)
        if key is None:
            self.storage.clear()
            return
        try:
            del self.storage[key]
        except KeyError:
            pass

    @default
    @locktree
    def __call__(self):
        self.context()

    @default
    def _alias_dict(self, dct):
        # XXX: seem to be not reached at all
        #if dct is None:
        #    return None

        # XXX: this code does not work if multiple keys map to same value
        #alias = self.principal_attraliaser.alias
        #aliased_dct = dict(
        #    [(alias(key), val) for key, val in dct.iteritems()])
        #return aliased_dct

        # XXX: generalization in aliaser needed
        ret = dict()
        for key, val in self.principal_attraliaser.iteritems():
            for k, v in dct.iteritems():
                if val == k:
                    ret[key] = v
        return ret

    @default
    def _unalias_list(self, lst):
        if lst is None:
            return None
        unalias = self.principal_attraliaser.unalias
        return [unalias(x) for x in lst]

    @default
    def _unalias_dict(self, dct):
        if dct is None:
            return None
        unalias = self.principal_attraliaser.unalias
        unaliased_dct = dict([(unalias(key), val)
                              for key, val in dct.iteritems()])
        return unaliased_dct

    @default
    def search(self,
               criteria=None,
               attrlist=None,
               exact_match=False,
               or_search=False,
               or_keys=None,
               or_values=None,
               page_size=None,
               cookie=None):
        results = self.context.search(criteria=self._unalias_dict(criteria),
                                      attrlist=self._unalias_list(attrlist),
                                      exact_match=exact_match,
                                      or_search=or_search,
                                      or_keys=or_keys,
                                      or_values=or_values,
                                      page_size=page_size,
                                      cookie=cookie)
        if type(results) is tuple:
            results, cookie = results
        if attrlist is not None:
            results = [(uid, self._alias_dict(att)) for uid, att in results]
        if cookie is not None:
            return results, cookie
        return results

    @default
    @locktree
    def create(self, pid, **kw):
        vessel = AttributedNode()
        for k, v in kw.items():
            vessel.attrs[k] = v
        self[pid] = vessel
        return self[pid]