summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLance Bragstad <lbragstad@gmail.com>2020-07-31 15:28:15 -0500
committerLance Bragstad <lbragstad@gmail.com>2020-08-05 14:25:18 -0500
commit8bf222ac5d390e25d306d35f69bd958b18bee4d8 (patch)
treec47171894926fa81160b9f1d9128159582477d9d
parentbcc751b3a24a93b5d8aab1bfb7eb8027d8499e36 (diff)
downloadkeystone-8bf222ac5d390e25d306d35f69bd958b18bee4d8.tar.gz
Properly handle octet (byte) strings when converting LDAP responses
If LDAP returns a UUID as an octet string the LDAP driver will fail to convert it to something meaningful. The error usually looks something like: ID attribute objectGUID not found in LDAP object Microsoft AD's `objectGUID` parameter is stored and transmitted as an octet string [0]. If you attempt to use the `objectGUID` to generate user or group IDs, you'll get an HTTP 404 because keystone can't decode it properly. This is unfortunate because `objectGUID` are a fixed length, UUID format, and ideal for generating IDs in keystone. As opposed to using the object's CN, which is variable length, and can generate hashes that are larger than keystone's database table limit for user IDs. [0] https://docs.microsoft.com/en-us/windows/win32/ad/reading-an-objectampaposs-objectguid-and-creating-a-string-representation-of-the-guid Change-Id: Id80b17bdff015e10340e636102576b7435bd564f Closes-Bug: 1889936
-rw-r--r--keystone/identity/backends/ldap/common.py12
-rw-r--r--keystone/tests/unit/identity/backends/test_ldap_common.py14
-rw-r--r--releasenotes/notes/bug-1889936-78d6853b5212b8f1.yaml5
3 files changed, 30 insertions, 1 deletions
diff --git a/keystone/identity/backends/ldap/common.py b/keystone/identity/backends/ldap/common.py
index 91e071335..d819467d9 100644
--- a/keystone/identity/backends/ldap/common.py
+++ b/keystone/identity/backends/ldap/common.py
@@ -18,6 +18,7 @@ import functools
import os.path
import re
import sys
+import uuid
import weakref
import ldap.controls
@@ -93,7 +94,16 @@ def utf8_decode(value):
:raises UnicodeDecodeError: for invalid UTF-8 encoding
"""
if isinstance(value, bytes):
- return _utf8_decoder(value)[0]
+ try:
+ return _utf8_decoder(value)[0]
+ except UnicodeDecodeError:
+ # NOTE(lbragstad): We could be dealing with a UUID in byte form,
+ # which some LDAP implementations use.
+ uuid_byte_string_length = 16
+ if len(value) == uuid_byte_string_length:
+ return str(uuid.UUID(bytes_le=value))
+ else:
+ raise
return str(value)
diff --git a/keystone/tests/unit/identity/backends/test_ldap_common.py b/keystone/tests/unit/identity/backends/test_ldap_common.py
index 029ded643..6674d9e14 100644
--- a/keystone/tests/unit/identity/backends/test_ldap_common.py
+++ b/keystone/tests/unit/identity/backends/test_ldap_common.py
@@ -520,6 +520,20 @@ class CommonLdapTestCase(unit.BaseTestCase):
# The user name should still be a string value.
self.assertEqual(user_name, py_result[0][1]['user_name'][0])
+ def test_user_id_attribute_is_uuid_in_byte_form(self):
+ results = [(
+ 'cn=alice,dc=example,dc=com',
+ {
+ 'cn': [b'cn=alice'],
+ 'objectGUID': [b'\xdd\xd8Rt\xee]bA\x8e(\xe39\x0b\xe1\xf8\xe8'],
+ 'email': [uuid.uuid4().hex],
+ 'sn': [uuid.uuid4().hex]
+ }
+ )]
+ py_result = common_ldap.convert_ldap_result(results)
+ exp_object_guid = '7452d8dd-5dee-4162-8e28-e3390be1f8e8'
+ self.assertEqual(exp_object_guid, py_result[0][1]['objectGUID'][0])
+
class LDAPFilterQueryCompositionTest(unit.BaseTestCase):
"""These test cases test LDAP filter generation."""
diff --git a/releasenotes/notes/bug-1889936-78d6853b5212b8f1.yaml b/releasenotes/notes/bug-1889936-78d6853b5212b8f1.yaml
new file mode 100644
index 000000000..de96b27f7
--- /dev/null
+++ b/releasenotes/notes/bug-1889936-78d6853b5212b8f1.yaml
@@ -0,0 +1,5 @@
+---
+fixes:
+ - |
+ [`bug 1889936 <https://bugs.launchpad.net/keystone/+bug/1889936>`_]
+ Properly decode octet strings, or byte arrays, returned from LDAP.