Support bytes type in generate_public_ID()

python-ldap3.0 or later running on python3 uses str or bytes
data type according to what fields are returned.
local_id may be a bytes data type.
To handle it properly, mapping[key] needs to be examined for
identifying its data type and what python version is used.

Closes-Bug: #1901654
Change-Id: Iac097235fd31e166028c169d14ec0937c663c21c
This commit is contained in:
Keigo Noha 2020-10-27 15:07:53 +09:00 committed by David Hill
parent b0b93c0398
commit f7df9fba82
3 changed files with 35 additions and 2 deletions

View File

@ -13,7 +13,6 @@
# under the License. # under the License.
import hashlib import hashlib
from keystone.identity import generator from keystone.identity import generator
@ -22,5 +21,12 @@ class Generator(generator.IDGenerator):
def generate_public_ID(self, mapping): def generate_public_ID(self, mapping):
m = hashlib.sha256() m = hashlib.sha256()
for key in sorted(mapping.keys()): for key in sorted(mapping.keys()):
m.update(mapping[key].encode('utf-8')) # python-ldap >3.0 returns bytes data type for attribute values
# except distinguished names, relative distinguished names,
# attribute names, queries on python3.
# Please see Bytes/text management in python-ldap module.
if isinstance(mapping[key], bytes):
m.update(mapping[key])
else:
m.update(mapping[key].encode('utf-8'))
return m.hexdigest() return m.hexdigest()

View File

@ -152,6 +152,23 @@ class SqlIDMapping(test_backend_sql.SqlTests):
self.assertEqual( self.assertEqual(
public_id, PROVIDERS.id_mapping_api.get_public_id(local_entity)) public_id, PROVIDERS.id_mapping_api.get_public_id(local_entity))
def test_id_mapping_handles_bytes(self):
initial_mappings = len(mapping_sql.list_id_mappings())
local_id = b'FaKeID'
local_entity = {'domain_id': self.domainA['id'],
'local_id': local_id,
'entity_type': mapping.EntityType.USER}
# Check no mappings for the new local entity
self.assertIsNone(PROVIDERS.id_mapping_api.get_public_id(local_entity))
# Create the new mapping and then read it back
public_id = PROVIDERS.id_mapping_api.create_id_mapping(local_entity)
self.assertThat(mapping_sql.list_id_mappings(),
matchers.HasLength(initial_mappings + 1))
self.assertEqual(
public_id, PROVIDERS.id_mapping_api.get_public_id(local_entity))
def test_delete_public_id_is_silent(self): def test_delete_public_id_is_silent(self):
# Test that deleting an invalid public key is silent # Test that deleting an invalid public key is silent
PROVIDERS.id_mapping_api.delete_id_mapping(uuid.uuid4().hex) PROVIDERS.id_mapping_api.delete_id_mapping(uuid.uuid4().hex)

View File

@ -0,0 +1,10 @@
---
fixes:
- |
[`bug 1901654 <https://bugs.launchpad.net/keystone/+bug/1901654>`_]
Previously, generate_public_ID() in sha256.py assumed the passed arguments is str data type.
However, python-ldap 3.0 or later returns bytes data type for attribute values except fields
of distinguished names, relative distinguished names, attribute names, queries.
If keystone running on Python3 is integrated with LDAP and the LDAP server has local_id variable
in its attribute, user login operations will fail due to the assumption and modifiation of python-ldap.
By this fix, generate_public_ID() properly handles bytes data type in the parameter.