From e43ef0ed0936b6eea08bb9d89a55547c33d2ed4a Mon Sep 17 00:00:00 2001 From: Jamie Lennox Date: Tue, 28 Apr 2015 11:05:01 +1000 Subject: [PATCH] Use auth plugin for trustee Create a new config section for configuring the user that trusts are assigned to. This section should be configured like any other auth plugin however it should not provide scoping information. Closes-Bug: #1446918 DocImpact: Creates a new section 'trustee' that contains the credentials for the user that will receive delegated roles. Change-Id: Idead7f505c41a55356f3670b322cbb831d442276 Co-Authored-By: Miguel Grinberg --- heat/common/context.py | 52 +++++++++++++++++++------- heat/common/heat_keystoneclient.py | 16 +------- heat/tests/clients/test_heat_client.py | 3 +- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/heat/common/context.py b/heat/common/context.py index 1d1d61fe7a..23b00cd4b6 100644 --- a/heat/common/context.py +++ b/heat/common/context.py @@ -12,6 +12,7 @@ # under the License. from keystoneclient import access +from keystoneclient import auth from keystoneclient.auth.identity import access as access_plugin from keystoneclient.auth.identity import v3 from keystoneclient.auth import token_endpoint @@ -25,7 +26,7 @@ from oslo_utils import importutils import six from heat.common import exception -from heat.common.i18n import _LE +from heat.common.i18n import _LE, _LW from heat.common import policy from heat.common import wsgi from heat.db import api as db_api @@ -33,6 +34,9 @@ from heat.engine import clients LOG = logging.getLogger(__name__) +TRUSTEE_CONF_GROUP = 'trustee' +auth.register_conf_options(cfg.CONF, TRUSTEE_CONF_GROUP) + class RequestContext(context.RequestContext): """ @@ -46,7 +50,7 @@ class RequestContext(context.RequestContext): read_only=False, show_deleted=False, overwrite=True, trust_id=None, trustor_user_id=None, request_id=None, auth_token_info=None, region_name=None, - auth_plugin=None, **kwargs): + auth_plugin=None, trusts_auth_plugin=None, **kwargs): """ :param overwrite: Set to False to ensure that the greenthread local copy of the index is not overwritten. @@ -76,6 +80,7 @@ class RequestContext(context.RequestContext): self.trustor_user_id = trustor_user_id self.policy = policy.Enforcer() self._auth_plugin = auth_plugin + self._trusts_auth_plugin = trusts_auth_plugin if is_admin is None: self.is_admin = self.policy.check_is_admin(self) @@ -146,18 +151,34 @@ class RequestContext(context.RequestContext): raise exception.AuthorizationFailure() return auth_uri + @property + def trusts_auth_plugin(self): + if self._trusts_auth_plugin: + return self._trusts_auth_plugin + + self._trusts_auth_plugin = auth.load_from_conf_options( + cfg.CONF, TRUSTEE_CONF_GROUP, trust_id=self.trust_id) + + if self._trusts_auth_plugin: + return self._trusts_auth_plugin + + LOG.warn(_LW('Using the keystone_authtoken user as the heat ' + 'trustee user directly is deprecated. Please add the ' + 'trustee credentials you need to the %s section of ' + 'your heat.conf file.') % TRUSTEE_CONF_GROUP) + + cfg.CONF.import_group('keystone_authtoken', + 'keystonemiddleware.auth_token') + + self._trusts_auth_plugin = v3.Password( + username=cfg.CONF.keystone_authtoken.admin_user, + password=cfg.CONF.keystone_authtoken.admin_password, + user_domain_id='default', + auth_url=self.keystone_v3_endpoint, + trust_id=self.trust_id) + return self._trusts_auth_plugin + def _create_auth_plugin(self): - if self.trust_id: - importutils.import_module('keystonemiddleware.auth_token') - username = cfg.CONF.keystone_authtoken.admin_user - password = cfg.CONF.keystone_authtoken.admin_password - - return v3.Password(username=username, - password=password, - user_domain_id='default', - auth_url=self.keystone_v3_endpoint, - trust_id=self.trust_id) - if self.auth_token_info: auth_ref = access.AccessInfo.factory(body=self.auth_token_info, auth_token=self.auth_token) @@ -187,7 +208,10 @@ class RequestContext(context.RequestContext): @property def auth_plugin(self): if not self._auth_plugin: - self._auth_plugin = self._create_auth_plugin() + if self.trust_id: + self._auth_plugin = self.trusts_auth_plugin + else: + self._auth_plugin = self._create_auth_plugin() return self._auth_plugin diff --git a/heat/common/heat_keystoneclient.py b/heat/common/heat_keystoneclient.py index ffc6b4059f..94ff90f053 100644 --- a/heat/common/heat_keystoneclient.py +++ b/heat/common/heat_keystoneclient.py @@ -111,19 +111,6 @@ class KeystoneClientV3(object): self._client = self._v3_client_init() return self._client - @property - def admin_auth(self): - if not self._admin_auth: - importutils.import_module('keystonemiddleware.auth_token') - - self._admin_auth = kc_auth_v3.Password( - username=cfg.CONF.keystone_authtoken.admin_user, - password=cfg.CONF.keystone_authtoken.admin_password, - user_domain_id='default', - auth_url=self.v3_endpoint) - - return self._admin_auth - @property def domain_admin_auth(self): if not self._domain_admin_auth: @@ -219,7 +206,8 @@ class KeystoneClientV3(object): # workaround this by getting the user_id from admin_client try: - trustee_user_id = self.admin_auth.get_user_id(self.session) + trustee_user_id = self.context.trusts_auth_plugin.get_user_id( + self.session) except kc_exception.Unauthorized: LOG.error(_LE("Domain admin client authentication failed")) raise exception.AuthorizationFailure() diff --git a/heat/tests/clients/test_heat_client.py b/heat/tests/clients/test_heat_client.py index 8f2d1e1c81..2defbfb594 100644 --- a/heat/tests/clients/test_heat_client.py +++ b/heat/tests/clients/test_heat_client.py @@ -81,7 +81,8 @@ class KeystoneClientTest(common.HeatTestCase): m = ks_auth_v3.Password(auth_url='http://server.test:5000/v3', password='verybadpass', user_domain_id='default', - username='heat') + username='heat', + trust_id=None) m.AndReturn(mock_ks_auth) def _stub_domain_admin_client(self, domain_id=None):