diff --git a/mistral/actions/openstack/actions.py b/mistral/actions/openstack/actions.py index 73d90358b..0aeb8ebbc 100644 --- a/mistral/actions/openstack/actions.py +++ b/mistral/actions/openstack/actions.py @@ -44,6 +44,7 @@ class NovaAction(base.OpenStackAction): LOG.debug("Nova action security context: %s" % ctx) keystone_endpoint = keystone_utils.get_keystone_endpoint_v2() + nova_endpoint = keystone_utils.get_endpoint_for_project('nova') client = self._client_class( username=None, @@ -56,6 +57,11 @@ class NovaAction(base.OpenStackAction): auth_url=keystone_endpoint.url ) + client.client.management_url = keystone_utils.format_url( + nova_endpoint.url, + {'tenant_id': ctx.project_id} + ) + return client @@ -88,12 +94,23 @@ class KeystoneAction(base.OpenStackAction): LOG.debug("Keystone action security context: %s" % ctx) - return self._client_class( - token=ctx.auth_token, - auth_url=CONF.keystone_authtoken.auth_uri, - project_id=ctx.project_id, - cacert=CONF.keystone_authtoken.cafile - ) + kwargs = { + 'token': ctx.auth_token, + 'auth_url': CONF.keystone_authtoken.auth_uri, + 'project_id': ctx.project_id, + 'cacert': CONF.keystone_authtoken.cafile, + } + + # In case of trust-scoped token explicitly pass endpoint parameter. + if (ctx.is_trust_scoped + or keystone_utils.is_token_trust_scoped(ctx.auth_token)): + kwargs['endpoint'] = CONF.keystone_authtoken.auth_uri + + client = self._client_class(**kwargs) + + client.management_url = CONF.keystone_authtoken.auth_uri + + return client @classmethod def _get_fake_client(cls): diff --git a/mistral/context.py b/mistral/context.py index ec52add93..b5cf347c9 100644 --- a/mistral/context.py +++ b/mistral/context.py @@ -76,6 +76,7 @@ class MistralContext(BaseContext): "project_name", "roles", "is_admin", + "is_trust_scoped", ]) def __repr__(self): @@ -127,7 +128,8 @@ def context_from_headers(headers): service_catalog=headers.get('X-Service-Catalog'), user_name=headers.get('X-User-Name'), project_name=headers.get('X-Project-Name'), - roles=headers.get('X-Roles', "").split(",") + roles=headers.get('X-Roles', "").split(","), + is_trust_scoped=False, ) @@ -136,7 +138,8 @@ def context_from_config(): username=CONF.keystone_authtoken.admin_user, password=CONF.keystone_authtoken.admin_password, tenant_name=CONF.keystone_authtoken.admin_tenant_name, - auth_url=CONF.keystone_authtoken.auth_uri + auth_url=CONF.keystone_authtoken.auth_uri, + is_trust_scoped=False, ) keystone.authenticate() @@ -146,7 +149,8 @@ def context_from_config(): project_id=keystone.project_id, auth_token=keystone.auth_token, project_name=CONF.keystone_authtoken.admin_tenant_name, - user_name=CONF.keystone_authtoken.admin_user + user_name=CONF.keystone_authtoken.admin_user, + is_trust_scoped=False, ) diff --git a/mistral/services/security.py b/mistral/services/security.py index 04b5c8c79..2f499b554 100644 --- a/mistral/services/security.py +++ b/mistral/services/security.py @@ -70,7 +70,8 @@ def create_context(trust_id, project_id): return auth_ctx.MistralContext( user_id=client.user_id, project_id=project_id, - auth_token=client.auth_token + auth_token=client.auth_token, + is_trust_scoped=True, ) return auth_ctx.MistralContext( diff --git a/mistral/utils/openstack/keystone.py b/mistral/utils/openstack/keystone.py index 9ad675c4e..1c5b1f800 100644 --- a/mistral/utils/openstack/keystone.py +++ b/mistral/utils/openstack/keystone.py @@ -104,3 +104,12 @@ def format_url(url_template, values): # see https://github.com/openstack/keystone/blob/master/keystone/ # catalog/core.py#L42-L60 return url_template.replace('$(', '%(') % values + + +def is_token_trust_scoped(auth_token): + admin_project_name = CONF.keystone_authtoken.admin_tenant_name + keystone_client = _admin_client(project_name=admin_project_name) + + token_info = keystone_client.tokens.validate(auth_token) + + return 'OS-TRUST:trust' in token_info