Esempio n. 1
0
    def normalize_dn(dn):
        # Capitalize the attribute names as an LDAP server might.

        # NOTE(blk-u): Special case for this tested value, used with
        # test_user_id_comma. The call to str2dn here isn't always correct
        # here, because `dn` is escaped for an LDAP filter. str2dn() normally
        # works only because there's no special characters in `dn`.
        if dn == 'cn=Doe\\5c, John,ou=Users,cn=example,cn=com':
            return 'CN=Doe\\, John,OU=Users,CN=example,CN=com'

        # NOTE(blk-u): Another special case for this tested value. When a
        # roleOccupant has an escaped comma, it gets converted to \2C.
        if dn == 'cn=Doe\\, John,ou=Users,cn=example,cn=com':
            return 'CN=Doe\\2C John,OU=Users,CN=example,CN=com'

        try:
            dn = ldap.dn.str2dn(core.utf8_encode(dn))
        except ldap.DECODING_ERROR:
            # NOTE(amakarov): In case of IDs instead of DNs in group members
            # they must be handled as regular values.
            return normalize_value(dn)

        norm = []
        for part in dn:
            name, val, i = part[0]
            name = core.utf8_decode(name)
            name = name.upper()
            name = core.utf8_encode(name)
            norm.append([(name, val, i)])
        return core.utf8_decode(ldap.dn.dn2str(norm))
Esempio n. 2
0
    def simple_bind_s(self, who='', cred='',
                      serverctrls=None, clientctrls=None):
        """This method is ignored, but provided for compatibility."""
        if server_fail:
            raise ldap.SERVER_DOWN
        whos = ['cn=Admin', CONF.ldap.user]
        if who in whos and cred in ['password', CONF.ldap.password]:
            return

        try:
            attrs = self.db[self.key(who)]
        except KeyError:
            LOG.debug('bind fail: who=%s not found', core.utf8_decode(who))
            raise ldap.NO_SUCH_OBJECT

        db_password = None
        try:
            db_password = attrs['userPassword'][0]
        except (KeyError, IndexError):
            LOG.debug('bind fail: password for who=%s not found',
                      core.utf8_decode(who))
            raise ldap.INAPPROPRIATE_AUTH

        if cred != db_password:
            LOG.debug('bind fail: password for who=%s does not match',
                      core.utf8_decode(who))
            raise ldap.INVALID_CREDENTIALS
Esempio n. 3
0
    def add_s(self, dn, modlist):
        """Add an object with the specified attributes at dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        id_attr_in_modlist = False
        id_attr = self._dn_to_id_attr(dn)
        id_value = self._dn_to_id_value(dn)

        # The LDAP API raises a TypeError if attr name is None.
        for k, dummy_v in modlist:
            if k is None:
                raise TypeError('must be string, not None. modlist=%s' %
                                modlist)

            if k == id_attr:
                for val in dummy_v:
                    if core.utf8_decode(val) == id_value:
                        id_attr_in_modlist = True

        if not id_attr_in_modlist:
            LOG.debug('id_attribute=%(attr)s missing, attributes=%(attrs)s' %
                      {'attr': id_attr, 'attrs': modlist})
            raise ldap.NAMING_VIOLATION
        key = self.key(dn)
        LOG.debug('add item: dn=%(dn)s, attrs=%(attrs)s', {
            'dn': core.utf8_decode(dn), 'attrs': modlist})
        if key in self.db:
            LOG.debug('add item failed: dn=%s is already in store.',
                      core.utf8_decode(dn))
            raise ldap.ALREADY_EXISTS(dn)

        self.db[key] = {k: _internal_attr(k, v) for k, v in modlist}
        self.db.sync()
Esempio n. 4
0
 def normalize_dn(dn):
     # Capitalize the attribute names as an LDAP server might.
     dn = ldap.dn.str2dn(core.utf8_encode(dn))
     norm = []
     for part in dn:
         name, val, i = part[0]
         name = core.utf8_decode(name)
         name = name.upper()
         name = core.utf8_encode(name)
         norm.append([(name, val, i)])
     return core.utf8_decode(ldap.dn.dn2str(norm))
Esempio n. 5
0
    def modify_s(self, dn, modlist):
        """Modify the object at dn using the attribute list.

        :param dn: an LDAP DN
        :param modlist: a list of tuples in the following form:
                      ([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
        """
        if server_fail:
            raise ldap.SERVER_DOWN

        key = self.key(dn)
        LOG.debug('modify item: dn=%(dn)s attrs=%(attrs)s', {
            'dn': core.utf8_decode(dn), 'attrs': modlist})
        try:
            entry = self.db[key]
        except KeyError:
            LOG.debug('modify item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT

        for cmd, k, v in modlist:
            values = entry.setdefault(k, [])
            if cmd == ldap.MOD_ADD:
                v = _internal_attr(k, v)
                for x in v:
                    if x in values:
                        raise ldap.TYPE_OR_VALUE_EXISTS
                values += v
            elif cmd == ldap.MOD_REPLACE:
                values[:] = _internal_attr(k, v)
            elif cmd == ldap.MOD_DELETE:
                if v is None:
                    if not values:
                        LOG.debug('modify item failed: '
                                  'item has no attribute "%s" to delete', k)
                        raise ldap.NO_SUCH_ATTRIBUTE
                    values[:] = []
                else:
                    for val in _internal_attr(k, v):
                        try:
                            values.remove(val)
                        except ValueError:
                            LOG.debug('modify item failed: '
                                      'item has no attribute "%(k)s" with '
                                      'value "%(v)s" to delete', {
                                          'k': k, 'v': val})
                            raise ldap.NO_SUCH_ATTRIBUTE
            else:
                LOG.debug('modify item failed: unknown command %s', cmd)
                raise NotImplementedError('modify_s action %s not'
                                          ' implemented' % cmd)
        self.db[key] = entry
        self.db.sync()
Esempio n. 6
0
    def delete_s(self, dn):
        """Remove the ldap object at specified dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        key = self.key(dn)
        LOG.debug('delete item: dn=%s', core.utf8_decode(dn))
        try:
            del self.db[key]
        except KeyError:
            LOG.debug('delete item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT
        self.db.sync()
Esempio n. 7
0
    def normalize_dn(dn):
        # Capitalize the attribute names as an LDAP server might.

        # NOTE(blk-u): Special case for this tested value, used with
        # test_user_id_comma. The call to str2dn here isn't always correct
        # here, because `dn` is escaped for an LDAP filter. str2dn() normally
        # works only because there's no special characters in `dn`.
        if dn == 'cn=Doe\\5c, John,ou=Users,cn=example,cn=com':
            return 'CN=Doe\\, John,OU=Users,CN=example,CN=com'

        dn = ldap.dn.str2dn(core.utf8_encode(dn))
        norm = []
        for part in dn:
            name, val, i = part[0]
            name = core.utf8_decode(name)
            name = name.upper()
            name = core.utf8_encode(name)
            norm.append([(name, val, i)])
        return core.utf8_decode(ldap.dn.dn2str(norm))
Esempio n. 8
0
    def delete_ext_s(self, dn, serverctrls, clientctrls=None):
        """Remove the ldap object at specified dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        try:
            if CONTROL_TREEDELETE in [c.controlType for c in serverctrls]:
                LOG.debug('FakeLdap subtree_delete item: dn=%s',
                          core.utf8_decode(dn))
                children = self._getChildren(dn)
                for c in children:
                    del self.db[c]

            key = self.key(dn)
            LOG.debug('FakeLdap delete item: dn=%s', core.utf8_decode(dn))
            del self.db[key]
        except KeyError:
            LOG.debug('delete item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT
        self.db.sync()
Esempio n. 9
0
    def add_s(self, dn, modlist):
        """Add an object with the specified attributes at dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        # The LDAP API raises a TypeError if attr name is None.
        for k, dummy_v in modlist:
            if k is None:
                raise TypeError('must be string, not None. modlist=%s' %
                                modlist)

        key = self.key(dn)
        LOG.debug('add item: dn=%(dn)s, attrs=%(attrs)s', {
            'dn': core.utf8_decode(dn), 'attrs': modlist})
        if key in self.db:
            LOG.debug('add item failed: dn=%s is already in store.',
                      core.utf8_decode(dn))
            raise ldap.ALREADY_EXISTS(dn)

        self.db[key] = dict([(k, _internal_attr(k, v))
                             for k, v in modlist])
        self.db.sync()
Esempio n. 10
0
    def delete_ext_s(self, dn, serverctrls, clientctrls=None):
        """Remove the ldap object at specified dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        try:
            if CONTROL_TREEDELETE in [c.controlType for c in serverctrls]:
                LOG.debug('FakeLdap subtree_delete item: dn=%s',
                          core.utf8_decode(dn))
                children = [k for k, v in six.iteritems(self.db)
                            if re.match('%s.*,%s' % (
                                        re.escape(self.__prefix),
                                        re.escape(self.dn(dn))), k)]
                for c in children:
                    del self.db[c]

            key = self.key(dn)
            LOG.debug(_('FakeLdap delete item: dn=%s'), dn)
            del self.db[key]
        except KeyError:
            LOG.debug('delete item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT
        self.db.sync()
Esempio n. 11
0
    def delete_ext_s(self, dn, serverctrls, clientctrls=None):
        """Remove the ldap object at specified dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        try:
            children = self._getChildren(dn)
            if children:
                raise ldap.NOT_ALLOWED_ON_NONLEAF

        except KeyError:
            LOG.debug('delete item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT
        super(FakeLdapNoSubtreeDelete, self).delete_ext_s(dn,
                                                          serverctrls,
                                                          clientctrls)
Esempio n. 12
0
 def _dn_to_id_value(self, dn):
     return core.utf8_decode(ldap.dn.str2dn(core.utf8_encode(dn))[0][0][1])
Esempio n. 13
0
    def search_s(self, base, scope,
                 filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- search scope (base, subtree, onelevel)
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if (not filterstr) and (scope != ldap.SCOPE_BASE):
            raise AssertionError('Search without filter on onelevel or '
                                 'subtree scope')

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            # FIXME - LDAP search with SUBTREE scope must return the base
            # entry, but the code below does _not_.  Unfortunately, there are
            # several tests that depend on this broken behavior, and fail
            # when the base entry is returned in the search results.  The
            # fix is easy here, just initialize results as above for
            # the SCOPE_BASE case.
            # https://bugs.launchpad.net/keystone/+bug/1368772
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_SUBTREE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
            extraresults = [(k[len(self.__prefix):], v)
                            for k, v in self.db.items()
                            if re.match('%s.*,%s' %
                                        (re.escape(self.__prefix),
                                         re.escape(self.dn(base))), k)]
            results.extend(extraresults)
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in self.db.items():
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            # openldap client/server raises PROTOCOL_ERROR for unexpected scope
            raise ldap.PROTOCOL_ERROR

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            attrs_checked = set()
            if not filterstr or _match_query(filterstr, match_attrs,
                                             attrs_checked):
                if (filterstr and
                        (scope != ldap.SCOPE_BASE) and
                        ('objectclass' not in attrs_checked)):
                    raise AssertionError('No objectClass in search filter')
                # filter the attributes by attrlist
                attrs = {k: v for k, v in attrs.items()
                         if not attrlist or k in attrlist}
                objects.append((dn, attrs))

        return objects
Esempio n. 14
0
 def normalize_value(value):
     return core.utf8_decode(value)
Esempio n. 15
0
 def dn(self, dn):
     return core.utf8_decode(dn)
Esempio n. 16
0
    def search_s(self, base, scope,
                 filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            # FIXME - LDAP search with SUBTREE scope must return the base
            # entry, but the code below does _not_.  Unfortunately, there are
            # several tests that depend on this broken behavior, and fail
            # when the base entry is returned in the search results.  The
            # fix is easy here, just initialize results as above for
            # the SCOPE_BASE case.
            # https://bugs.launchpad.net/keystone/+bug/1368772
            results = []
            try:
                item_dict = self.db[self.key(base)]
                results.extend([(base, item_dict)])
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_SUBTREE')
            extraresults = [(k[len(self.__prefix):], v)
                            for k, v in six.iteritems(self.db)
                            if re.match('%s.*,%s' %
                                        (re.escape(self.__prefix),
                                         re.escape(self.dn(base))), k)]
            results.extend(extraresults)
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in six.iteritems(self.db):
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            LOG.debug('search fail: unknown scope %s', scope)
            raise NotImplementedError('Search scope %s not implemented.'
                                      % scope)

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            if not filterstr or _match_query(filterstr, match_attrs):
                # filter the attributes by attrlist
                attrs = dict([(k, v) for k, v in six.iteritems(attrs)
                              if not attrlist or k in attrlist])
                objects.append((dn, attrs))

        return objects
Esempio n. 17
0
 def normalize_value(value):
     return core.utf8_decode(value)
Esempio n. 18
0
    def search_s(self,
                 base,
                 scope,
                 filterstr='(objectClass=*)',
                 attrlist=None,
                 attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            results = [
                (k[len(self.__prefix):], v) for k, v in six.iteritems(self.db)
                if re.match(
                    '%s.*,%s' %
                    (re.escape(self.__prefix), re.escape(self.dn(base))), k)
            ]
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in six.iteritems(self.db):
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            LOG.debug('search fail: unknown scope %s', scope)
            raise NotImplementedError('Search scope %s not implemented.' %
                                      scope)

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            if not filterstr or _match_query(filterstr, match_attrs):
                # filter the attributes by attrlist
                attrs = dict([(k, v) for k, v in six.iteritems(attrs)
                              if not attrlist or k in attrlist])
                objects.append((dn, attrs))

        return objects
Esempio n. 19
0
 def _dn_to_id_value(self, dn):
     return core.utf8_decode(ldap.dn.str2dn(core.utf8_encode(dn))[0][0][1])
Esempio n. 20
0
 def dn(self, dn):
     return core.utf8_decode(dn)
Esempio n. 21
0
    def search_s(self, base, scope,
                 filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            results = [(k[len(self.__prefix):], v)
                       for k, v in six.iteritems(self.db)
                       if re.match('%s.*,%s' % (re.escape(self.__prefix),
                                                re.escape(self.dn(base))), k)]
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in six.iteritems(self.db):
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            LOG.debug('search fail: unknown scope %s', scope)
            raise NotImplementedError('Search scope %s not implemented.'
                                      % scope)

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            if not filterstr or _match_query(filterstr, match_attrs):
                # filter the attributes by attrlist
                attrs = dict([(k, v) for k, v in six.iteritems(attrs)
                              if not attrlist or k in attrlist])
                objects.append((dn, attrs))

        return objects
Esempio n. 22
0
    def search_s(self, base, scope,
                 filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            # FIXME - LDAP search with SUBTREE scope must return the base
            # entry, but the code below does _not_.  Unfortunately, there are
            # several tests that depend on this broken behavior, and fail
            # when the base entry is returned in the search results.  The
            # fix is easy here, just initialize results as above for
            # the SCOPE_BASE case.
            # https://bugs.launchpad.net/keystone/+bug/1368772
            results = []
            try:
                item_dict = self.db[self.key(base)]
                results.extend([(base, item_dict)])
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_SUBTREE')
            extraresults = [(k[len(self.__prefix):], v)
                            for k, v in six.iteritems(self.db)
                            if re.match('%s.*,%s' %
                                        (re.escape(self.__prefix),
                                         re.escape(self.dn(base))), k)]
            results.extend(extraresults)
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in six.iteritems(self.db):
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            LOG.debug('search fail: unknown scope %s', scope)
            raise NotImplementedError('Search scope %s not implemented.'
                                      % scope)

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            if not filterstr or _match_query(filterstr, match_attrs):
                # filter the attributes by attrlist
                attrs = dict([(k, v) for k, v in six.iteritems(attrs)
                              if not attrlist or k in attrlist])
                objects.append((dn, attrs))

        return objects
Esempio n. 23
0
    def search_s(self,
                 base,
                 scope,
                 filterstr='(objectClass=*)',
                 attrlist=None,
                 attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- search scope (base, subtree, onelevel)
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if (not filterstr) and (scope != ldap.SCOPE_BASE):
            raise AssertionError('Search without filter on onelevel or '
                                 'subtree scope')

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            # FIXME - LDAP search with SUBTREE scope must return the base
            # entry, but the code below does _not_.  Unfortunately, there are
            # several tests that depend on this broken behavior, and fail
            # when the base entry is returned in the search results.  The
            # fix is easy here, just initialize results as above for
            # the SCOPE_BASE case.
            # https://bugs.launchpad.net/keystone/+bug/1368772
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_SUBTREE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
            extraresults = [
                (k[len(self.__prefix):], v) for k, v in self.db.items()
                if re.match(
                    '%s.*,%s' %
                    (re.escape(self.__prefix), re.escape(self.dn(base))), k)
            ]
            results.extend(extraresults)
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in self.db.items():
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            # openldap client/server raises PROTOCOL_ERROR for unexpected scope
            raise ldap.PROTOCOL_ERROR

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            attrs_checked = set()
            if not filterstr or _match_query(filterstr, match_attrs,
                                             attrs_checked):
                if (filterstr and (scope != ldap.SCOPE_BASE)
                        and ('objectclass' not in attrs_checked)):
                    raise AssertionError('No objectClass in search filter')
                # filter the attributes by attrlist
                attrs = {
                    k: v
                    for k, v in attrs.items() if not attrlist or k in attrlist
                }
                objects.append((dn, attrs))

        return objects