PY3: Ensure LDAP searches use unicode attributes
This is a bug fix that corresponds to changes missed in commiteca0829c4c
. In Python 3, python-ldap no longer allows bytes for some fields (DNs, RDNs, attribute names, queries). Instead, text values are represented as str, the Unicode text type. Compatibility support is provided for Python 2 by setting bytes_mode=False [1]. This support was provided in commiteca0829c4c
. In this patch we ensure that attribute names specified in searches are no longer encoded. [1] More details about byte/str usage in python-ldap can be found at: http://www.python-ldap.org/en/latest/bytes_mode.html#bytes-mode Change-Id: If3398e2d08ea14fa4b8c498b2a9a7c7edb47b9e5 Closes-Bug: #1820333 Depends-On: https://review.openstack.org/#/c/613648 (cherry picked from commitd6df1dff3e
)
This commit is contained in:
parent
a2e7ccb4b3
commit
6a3888b05b
|
@ -26,7 +26,7 @@ import ldappool
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_utils import reflection
|
from oslo_utils import reflection
|
||||||
import six
|
import six
|
||||||
from six.moves import map, zip
|
from six.moves import zip
|
||||||
from six import PY2
|
from six import PY2
|
||||||
|
|
||||||
from keystone.common import driver_hints
|
from keystone.common import driver_hints
|
||||||
|
@ -951,13 +951,9 @@ class KeystoneLDAPHandler(LDAPHandler):
|
||||||
ldap_result = self._paged_search_s(base, scope,
|
ldap_result = self._paged_search_s(base, scope,
|
||||||
filterstr, attrlist)
|
filterstr, attrlist)
|
||||||
else:
|
else:
|
||||||
if attrlist is None:
|
|
||||||
attrlist_utf8 = None
|
|
||||||
else:
|
|
||||||
attrlist_utf8 = list(map(utf8_encode, attrlist))
|
|
||||||
try:
|
try:
|
||||||
ldap_result = self.conn.search_s(base, scope, filterstr,
|
ldap_result = self.conn.search_s(base, scope, filterstr,
|
||||||
attrlist_utf8, attrsonly)
|
attrlist, attrsonly)
|
||||||
except ldap.SIZELIMIT_EXCEEDED:
|
except ldap.SIZELIMIT_EXCEEDED:
|
||||||
raise exception.LDAPSizeLimitExceeded()
|
raise exception.LDAPSizeLimitExceeded()
|
||||||
|
|
||||||
|
@ -1001,15 +997,10 @@ class KeystoneLDAPHandler(LDAPHandler):
|
||||||
cookie='')
|
cookie='')
|
||||||
page_ctrl_oid = ldap.controls.SimplePagedResultsControl.controlType
|
page_ctrl_oid = ldap.controls.SimplePagedResultsControl.controlType
|
||||||
|
|
||||||
if attrlist is None:
|
|
||||||
attrlist_utf8 = None
|
|
||||||
else:
|
|
||||||
attrlist = [attr for attr in attrlist if attr is not None]
|
|
||||||
attrlist_utf8 = list(map(utf8_encode, attrlist))
|
|
||||||
msgid = self.conn.search_ext(base,
|
msgid = self.conn.search_ext(base,
|
||||||
scope,
|
scope,
|
||||||
filterstr,
|
filterstr,
|
||||||
attrlist_utf8,
|
attrlist,
|
||||||
serverctrls=[lc])
|
serverctrls=[lc])
|
||||||
# Endless loop request pages on ldap server until it has no data
|
# Endless loop request pages on ldap server until it has no data
|
||||||
while True:
|
while True:
|
||||||
|
@ -1033,7 +1024,7 @@ class KeystoneLDAPHandler(LDAPHandler):
|
||||||
msgid = self.conn.search_ext(base,
|
msgid = self.conn.search_ext(base,
|
||||||
scope,
|
scope,
|
||||||
filterstr,
|
filterstr,
|
||||||
attrlist_utf8,
|
attrlist,
|
||||||
serverctrls=[lc])
|
serverctrls=[lc])
|
||||||
else:
|
else:
|
||||||
# Exit condition no more data on server
|
# Exit condition no more data on server
|
||||||
|
|
|
@ -516,7 +516,7 @@ class FakeLdap(common.LDAPHandler):
|
||||||
raise AssertionError('No objectClass in search filter')
|
raise AssertionError('No objectClass in search filter')
|
||||||
# filter the attributes by attrlist
|
# filter the attributes by attrlist
|
||||||
attrs = {k: v for k, v in attrs.items()
|
attrs = {k: v for k, v in attrs.items()
|
||||||
if not attrlist or k in common.utf8_decode(attrlist)}
|
if not attrlist or k in attrlist}
|
||||||
objects.append((dn, attrs))
|
objects.append((dn, attrs))
|
||||||
|
|
||||||
return objects
|
return objects
|
||||||
|
|
|
@ -404,7 +404,14 @@ class LDAPPagedResultsTest(unit.TestCase):
|
||||||
conn = PROVIDERS.identity_api.user.get_connection()
|
conn = PROVIDERS.identity_api.user.get_connection()
|
||||||
conn._paged_search_s('dc=example,dc=test',
|
conn._paged_search_s('dc=example,dc=test',
|
||||||
ldap.SCOPE_SUBTREE,
|
ldap.SCOPE_SUBTREE,
|
||||||
'objectclass=*')
|
'objectclass=*',
|
||||||
|
['mail', 'userPassword'])
|
||||||
|
# verify search_ext() args - attrlist is tricky due to ordering
|
||||||
|
args, _ = mock_search_ext.call_args
|
||||||
|
self.assertEqual(
|
||||||
|
('dc=example,dc=test', 2, 'objectclass=*'), args[0:3])
|
||||||
|
attrlist = sorted([attr for attr in args[3] if attr])
|
||||||
|
self.assertEqual(['mail', 'userPassword'], attrlist)
|
||||||
|
|
||||||
|
|
||||||
class CommonLdapTestCase(unit.BaseTestCase):
|
class CommonLdapTestCase(unit.BaseTestCase):
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
[`bug 1798184 <https://bugs.launchpad.net/keystone/+bug/1798184>`_]
|
||||||
|
[`bug 1820333 <https://bugs.launchpad.net/keystone/+bug/1820333>`_]
|
||||||
|
In Python 3, python-ldap no longer allows bytes for some fields (DNs,
|
||||||
|
RDNs, attribute names, queries). Instead, text values are represented
|
||||||
|
as str, the Unicode text type. Compatibility support is provided for
|
||||||
|
Python 2 by setting bytes_mode=False [1].
|
||||||
|
|
||||||
|
The keystone LDAP backend is updated to adhere to this behavior by using
|
||||||
|
bytes_mode=False for Python 2 and dropping UTF-8 encoding and decoding
|
||||||
|
fields that are now represented as text in python-ldap.
|
||||||
|
|
||||||
|
[1] More details about byte/str usage in python-ldap can be found at:
|
||||||
|
http://www.python-ldap.org/en/latest/bytes_mode.html#bytes-mode
|
||||||
|
|
||||||
|
Note that at a minimum python-ldappool 2.3.1 is required.
|
Loading…
Reference in New Issue