예제 #1
0
            def get_entries():
                base_dn = ldap.dn.str2dn(common.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(common.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)
예제 #2
0
            def get_entries():
                base_dn = ldap.dn.str2dn(common.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(common.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)
예제 #3
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(common.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 = common.utf8_decode(name)
            name = name.upper()
            norm.append([(name, val, i)])
        return common.utf8_decode(ldap.dn.dn2str(norm))
예제 #4
0
    def simple_bind_s(self,
                      who='',
                      cred='',
                      serverctrls=None,
                      clientctrls=None):
        """Provide for compatibility but this method is ignored."""
        if server_fail:
            raise ldap.SERVER_DOWN
        whos = ['cn=Admin', CONF.ldap.user]
        if (common.utf8_decode(who) in whos and common.utf8_decode(cred)
                in ['password', CONF.ldap.password]):
            return

        attrs = self.db.get(self.key(who))
        if not attrs:
            LOG.debug('who=%s not found, binding anonymously',
                      common.utf8_decode(who))

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

        if cred != common.utf8_encode(db_password):
            LOG.debug('bind fail: password for who=%s does not match',
                      common.utf8_decode(who))
            raise ldap.INVALID_CREDENTIALS
예제 #5
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(common.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 = common.utf8_decode(name)
            name = name.upper()
            norm.append([(name, val, i)])
        return common.utf8_decode(ldap.dn.dn2str(norm))
예제 #6
0
    def simple_bind_s(self, who='', cred='',
                      serverctrls=None, clientctrls=None):
        """Provide for compatibility but this method is ignored."""
        if server_fail:
            raise ldap.SERVER_DOWN
        whos = ['cn=Admin', CONF.ldap.user]
        if (common.utf8_decode(who) in whos and
                common.utf8_decode(cred) in ['password', CONF.ldap.password]):
            return

        attrs = self.db.get(self.key(who))
        if not attrs:
            LOG.debug('who=%s not found, binding anonymously',
                      common.utf8_decode(who))

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

        if cred != common.utf8_encode(db_password):
            LOG.debug('bind fail: password for who=%s does not match',
                      common.utf8_decode(who))
            raise ldap.INVALID_CREDENTIALS
예제 #7
0
    def test_utf8_conversion(self):
        value_unicode = u'fäké1'
        value_utf8 = value_unicode.encode('utf-8')

        result_utf8 = common_ldap.utf8_encode(value_unicode)
        self.assertEqual(value_utf8, result_utf8)

        result_utf8 = common_ldap.utf8_encode(value_utf8)
        self.assertEqual(value_utf8, result_utf8)

        result_unicode = common_ldap.utf8_decode(value_utf8)
        self.assertEqual(value_unicode, result_unicode)

        result_unicode = common_ldap.utf8_decode(value_unicode)
        self.assertEqual(value_unicode, result_unicode)

        self.assertRaises(TypeError, common_ldap.utf8_encode, 100)

        result_unicode = common_ldap.utf8_decode(100)
        self.assertEqual(u'100', result_unicode)
예제 #8
0
    def test_utf8_conversion(self):
        value_unicode = u'fäké1'
        value_utf8 = value_unicode.encode('utf-8')

        result_utf8 = common_ldap.utf8_encode(value_unicode)
        self.assertEqual(value_utf8, result_utf8)

        result_utf8 = common_ldap.utf8_encode(value_utf8)
        self.assertEqual(value_utf8, result_utf8)

        result_unicode = common_ldap.utf8_decode(value_utf8)
        self.assertEqual(value_unicode, result_unicode)

        result_unicode = common_ldap.utf8_decode(value_unicode)
        self.assertEqual(value_unicode, result_unicode)

        self.assertRaises(TypeError,
                          common_ldap.utf8_encode,
                          100)

        result_unicode = common_ldap.utf8_decode(100)
        self.assertEqual(u'100', result_unicode)
예제 #9
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(common.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(common.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(common.utf8_encode(dn))[0][0]
            id_attr = common.utf8_decode(id_attr)
            id_val = common.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            attrs_checked = set()
            if not filterstr or _match_query(common.utf8_decode(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 common.utf8_decode(attrlist)
                }
                objects.append((dn, attrs))

        return objects
예제 #10
0
 def _dn_to_id_value(self, dn):
     return common.utf8_decode(
         ldap.dn.str2dn(common.utf8_encode(dn))[0][0][1])
예제 #11
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(common.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(common.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(common.utf8_encode(dn))[0][0]
            id_attr = common.utf8_decode(id_attr)
            id_val = common.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            attrs_checked = set()
            if not filterstr or _match_query(common.utf8_decode(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 common.utf8_decode(attrlist)}
                objects.append((dn, attrs))

        return objects
예제 #12
0
 def _dn_to_id_value(self, dn):
     return common.utf8_decode(
         ldap.dn.str2dn(common.utf8_encode(dn))[0][0][1])