Pass role ids to trust if possible

currently Heat fails to create a stack requiring deferred auth with
trusts when user happens to have a role assigned for which a different
but similar named role exist in another Keystone domain.

This patch makes Heat to attempt extract role IDs from the
auth_token_info first and pass those to Keystone trust if found.

Change-Id: Ic9207e3f027f9c56c14d548d404ecc0c2427f326
Story: 2002613
Task: 22237
This commit is contained in:
Pavlo Shchelokovskyy 2018-06-19 15:48:14 +00:00 committed by Pavlo Shchelokovskyy
parent 0b83b05115
commit 66442554d2
2 changed files with 40 additions and 6 deletions

View File

@ -212,22 +212,28 @@ class KsClientWrapper(object):
trustor_user_id = self.context.auth_plugin.get_user_id(self.session)
trustor_proj_id = self.context.auth_plugin.get_project_id(self.session)
role_kw = {}
# inherit the roles of the trustor, unless set trusts_delegated_roles
if cfg.CONF.trusts_delegated_roles:
roles = cfg.CONF.trusts_delegated_roles
role_kw['role_names'] = cfg.CONF.trusts_delegated_roles
else:
roles = self.context.roles
token_info = self.context.auth_token_info
if token_info and token_info.get('token', {}).get('roles'):
role_kw['role_ids'] = [r['id'] for r in
token_info['token']['roles']]
else:
role_kw['role_names'] = self.context.roles
try:
trust = self.client.trusts.create(trustor_user=trustor_user_id,
trustee_user=trustee_user_id,
project=trustor_proj_id,
impersonation=True,
role_names=roles)
**role_kw)
except ks_exception.NotFound:
LOG.debug("Failed to find roles %s for user %s"
% (roles, trustor_user_id))
% (role_kw, trustor_user_id))
raise exception.MissingCredentialError(
required=_("roles %s") % roles)
required=_("roles %s") % role_kw)
context_data = self.context.to_dict()
context_data['overwrite'] = False

View File

@ -577,6 +577,33 @@ class KeystoneClientTest(common.HeatTestCase):
impersonation=True,
role_names=trustee_roles)
def test_create_trust_context_trust_create_delegate_all_roleids(self):
"""Test create_trust_context when creating a trust using role IDs."""
class MockTrust(object):
id = 'atrust123'
self._stubs_auth(user_id='5678', project_id='42',
stub_trust_context=True,
stub_admin_auth=True)
cfg.CONF.set_override('deferred_auth_method', 'trusts')
self.mock_ks_v3_client.trusts.create.return_value = MockTrust()
trustor_roles = [{'name': 'spam', 'id': 'ham'}]
ctx = utils.dummy_context(roles=trustor_roles)
ctx.trust_id = None
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
# doing that late monkeypatching to not mock extra keystone stuff
ctx.auth_token_info = {'token': {'roles': trustor_roles}}
trust_context = heat_ks_client.create_trust_context()
self.assertEqual('atrust123', trust_context.trust_id)
self.assertEqual('5678', trust_context.trustor_user_id)
args, kwargs = self.mock_ks_v3_client.trusts.create.call_args
self.assertEqual(["ham"], kwargs["role_ids"])
def test_create_trust_context_trust_create_norole(self):
"""Test create_trust_context when creating a trust."""
@ -597,7 +624,8 @@ class KeystoneClientTest(common.HeatTestCase):
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
exc = self.assertRaises(exception.MissingCredentialError,
heat_ks_client.create_trust_context)
expected = "Missing required credential: roles ['heat_stack_owner']"
expected = "Missing required credential: roles "
"{'role_names': ['heat_stack_owner']}"
self.assertIn(expected, six.text_type(exc))
self.m_load_auth.assert_called_with(
cfg.CONF, 'trustee', trust_id=None)