diff --git a/keystone/tests/unit/token/test_fernet_provider.py b/keystone/tests/unit/token/test_fernet_provider.py index fa3d658728..b2661b6801 100644 --- a/keystone/tests/unit/token/test_fernet_provider.py +++ b/keystone/tests/unit/token/test_fernet_provider.py @@ -221,6 +221,37 @@ class TestTokenFormatter(unit.TestCase): ) self.assertEqual(encoded_string, encoded_str_with_padding_restored) + def test_create_validate_federated_unscoped_token_non_uuid_user_id(self): + exp_user_id = hashlib.sha256().hexdigest() + exp_methods = ['password'] + exp_expires_at = utils.isotime(timeutils.utcnow(), subsecond=True) + exp_audit_ids = [provider.random_urlsafe_str()] + exp_federated_group_ids = [{'id': uuid.uuid4().hex}] + exp_idp_id = uuid.uuid4().hex + exp_protocol_id = uuid.uuid4().hex + + token_formatter = token_formatters.TokenFormatter() + token = token_formatter.create_token(user_id=exp_user_id, + expires_at=exp_expires_at, + audit_ids=exp_audit_ids, + payload_class=token_formatters.FederatedUnscopedPayload, + methods=exp_methods, + federated_group_ids=exp_federated_group_ids, + identity_provider_id=exp_idp_id, + protocol_id=exp_protocol_id) + + (user_id, methods, audit_ids, system, domain_id, project_id, trust_id, + federated_group_ids, identity_provider_id, protocol_id, + access_token_id, app_cred_id, issued_at, expires_at) = token_formatter.validate_token(token) + + self.assertEqual(exp_user_id, user_id) + self.assertTrue(isinstance(user_id, six.string_types)) + self.assertEqual(exp_methods, methods) + self.assertEqual(exp_audit_ids, audit_ids) + self.assertEqual(exp_federated_group_ids, federated_group_ids) + self.assertEqual(exp_idp_id, identity_provider_id) + self.assertEqual(exp_protocol_id, protocol_id) + def test_create_validate_federated_scoped_token_non_uuid_user_id(self): exp_user_id = hashlib.sha256().hexdigest() exp_methods = ['password'] diff --git a/keystone/token/token_formatters.py b/keystone/token/token_formatters.py index 1c499883a4..cfd22010a8 100644 --- a/keystone/token/token_formatters.py +++ b/keystone/token/token_formatters.py @@ -558,6 +558,15 @@ class FederatedUnscopedPayload(BasePayload): (is_stored_as_bytes, user_id) = payload[0] if is_stored_as_bytes: user_id = cls.convert_uuid_bytes_to_hex(user_id) + else: + # NOTE(cmurphy): The user ID of shadowed federated users is no + # longer a UUID but a sha256 hash string, and so it should not be + # converted to a byte string since it is not a UUID format. + # However. on python3 msgpack returns the serialized input as a + # byte string anyway. Similar to other msgpack'd values in the + # payload, we need to explicitly decode it to a string value. + if six.PY3 and isinstance(user_id, six.binary_type): + user_id = user_id.decode('utf-8') methods = auth_plugins.convert_integer_to_method_list(payload[1]) group_ids = list(map(cls.unpack_group_id, payload[2])) (is_stored_as_bytes, idp_id) = payload[3]