diff --git a/keystone/assignment/controllers.py b/keystone/assignment/controllers.py index 0a489bf11f..5bfc6ec9dd 100644 --- a/keystone/assignment/controllers.py +++ b/keystone/assignment/controllers.py @@ -26,10 +26,10 @@ from six.moves import urllib from keystone.assignment import schema from keystone.common import controller from keystone.common import dependency +from keystone.common import utils from keystone.common import validation from keystone import exception from keystone.i18n import _, _LW -from keystone.models import token_model from keystone import notifications @@ -51,14 +51,7 @@ class TenantAssignment(controller.V2Controller): Doesn't care about token scopedness. """ - try: - token_data = self.token_provider_api.validate_token( - context['token_id']) - token_ref = token_model.KeystoneToken(token_id=context['token_id'], - token_data=token_data) - except exception.NotFound as e: - LOG.warning(_LW('Authentication failed: %s'), e) - raise exception.Unauthorized(e) + token_ref = utils.get_token_ref(context) tenant_refs = ( self.assignment_api.list_projects_for_user(token_ref.user_id)) diff --git a/keystone/common/controller.py b/keystone/common/controller.py index aafc161e88..af7d661414 100644 --- a/keystone/common/controller.py +++ b/keystone/common/controller.py @@ -690,19 +690,7 @@ class V3Controller(wsgi.Application): if context['query_string'].get('domain_id') is not None: return context['query_string'].get('domain_id') - try: - token_ref = token_model.KeystoneToken( - token_id=context['token_id'], - token_data=self.token_provider_api.validate_token( - context['token_id'])) - except KeyError: - raise exception.ValidationError( - _('domain_id is required as part of entity')) - except (exception.TokenNotFound, - exception.UnsupportedTokenVersionException): - LOG.warning(_LW('Invalid token found while getting domain ID ' - 'for list request')) - raise exception.Unauthorized() + token_ref = utils.get_token_ref(context) if token_ref.domain_scoped: return token_ref.domain_id @@ -719,25 +707,7 @@ class V3Controller(wsgi.Application): being used. """ - # We could make this more efficient by loading the domain_id - # into the context in the wrapper function above (since - # this version of normalize_domain will only be called inside - # a v3 protected call). However, this optimization is probably not - # worth the duplication of state - try: - token_ref = token_model.KeystoneToken( - token_id=context['token_id'], - token_data=self.token_provider_api.validate_token( - context['token_id'])) - except KeyError: - # This might happen if we use the Admin token, for instance - raise exception.ValidationError( - _('A domain-scoped token must be used')) - except (exception.TokenNotFound, - exception.UnsupportedTokenVersionException): - LOG.warning(_LW('Invalid token found while getting domain ID ' - 'for create request')) - raise exception.Unauthorized() + token_ref = utils.get_token_ref(context) if token_ref.domain_scoped: return token_ref.domain_id diff --git a/keystone/common/utils.py b/keystone/common/utils.py index 88a61ca39c..1fc7221a4a 100644 --- a/keystone/common/utils.py +++ b/keystone/common/utils.py @@ -32,6 +32,7 @@ import passlib.hash import six from six import moves +from keystone.common import authorization from keystone import exception from keystone.i18n import _, _LE, _LW @@ -504,3 +505,20 @@ def isotime(at=None, subsecond=False): def strtime(): at = timeutils.utcnow() return at.strftime(timeutils.PERFECT_TIME_FORMAT) + + +def get_token_ref(context): + """Retrieves KeystoneToken object from the auth context and returns it. + + :param dict context: The request context. + :raises: exception.Unauthorized if auth context cannot be found. + :returns: The KeystoneToken object. + """ + try: + # Retrieve the auth context that was prepared by AuthContextMiddleware. + auth_context = (context['environment'] + [authorization.AUTH_CONTEXT_ENV]) + return auth_context['token'] + except KeyError: + LOG.warning(_LW("Couldn't find the auth context.")) + raise exception.Unauthorized() diff --git a/keystone/common/wsgi.py b/keystone/common/wsgi.py index f280f7119e..2fc754257b 100644 --- a/keystone/common/wsgi.py +++ b/keystone/common/wsgi.py @@ -299,13 +299,7 @@ class Application(BaseApplication): """ if not context['is_admin']: - try: - user_token_ref = token_model.KeystoneToken( - token_id=context['token_id'], - token_data=self.token_provider_api.validate_token( - context['token_id'])) - except exception.TokenNotFound as e: - raise exception.Unauthorized(e) + user_token_ref = utils.get_token_ref(context) validate_token_bind(context, user_token_ref) creds = copy.deepcopy(user_token_ref.metadata) @@ -364,16 +358,7 @@ class Application(BaseApplication): LOG.debug(('will not lookup trust as the request auth token is ' 'either absent or it is the system admin token')) return None - - try: - token_data = self.token_provider_api.validate_token( - context['token_id']) - except exception.TokenNotFound: - LOG.warning(_LW('Invalid token in _get_trust_id_for_request')) - raise exception.Unauthorized() - - token_ref = token_model.KeystoneToken(token_id=context['token_id'], - token_data=token_data) + token_ref = utils.get_token_ref(context) return token_ref.trust_id @classmethod diff --git a/keystone/contrib/ec2/controllers.py b/keystone/contrib/ec2/controllers.py index 18aeca4966..78172ec9b2 100644 --- a/keystone/contrib/ec2/controllers.py +++ b/keystone/contrib/ec2/controllers.py @@ -46,7 +46,6 @@ from keystone.common import utils from keystone.common import wsgi from keystone import exception from keystone.i18n import _ -from keystone.models import token_model @dependency.requires('assignment_api', 'catalog_api', 'credential_api', @@ -319,14 +318,7 @@ class Ec2Controller(Ec2ControllerCommon, controller.V2Controller): :raises exception.Forbidden: when token is invalid """ - try: - token_data = self.token_provider_api.validate_token( - context['token_id']) - except exception.TokenNotFound as e: - raise exception.Unauthorized(e) - - token_ref = token_model.KeystoneToken(token_id=context['token_id'], - token_data=token_data) + token_ref = utils.get_token_ref(context) if token_ref.user_id != user_id: raise exception.Forbidden(_('Token belongs to another user')) diff --git a/keystone/contrib/oauth1/controllers.py b/keystone/contrib/oauth1/controllers.py index fb5d0bc284..d12fc96b88 100644 --- a/keystone/contrib/oauth1/controllers.py +++ b/keystone/contrib/oauth1/controllers.py @@ -20,12 +20,12 @@ from oslo_utils import timeutils from keystone.common import controller from keystone.common import dependency +from keystone.common import utils from keystone.common import wsgi from keystone.contrib.oauth1 import core as oauth1 from keystone.contrib.oauth1 import validator from keystone import exception from keystone.i18n import _ -from keystone.models import token_model from keystone import notifications @@ -84,10 +84,7 @@ class ConsumerCrudV3(controller.V3Controller): @controller.protected() def delete_consumer(self, context, consumer_id): - user_token_ref = token_model.KeystoneToken( - token_id=context['token_id'], - token_data=self.token_provider_api.validate_token( - context['token_id'])) + user_token_ref = utils.get_token_ref(context) payload = {'user_id': user_token_ref.user_id, 'consumer_id': consumer_id} _emit_user_oauth_consumer_token_invalidate(payload) @@ -382,10 +379,7 @@ class OAuthControllerV3(controller.V3Controller): authed_roles.add(role['id']) # verify the authorizing user has the roles - user_token = token_model.KeystoneToken( - token_id=context['token_id'], - token_data=self.token_provider_api.validate_token( - context['token_id'])) + user_token = utils.get_token_ref(context) user_id = user_token.user_id project_id = req_token['requested_project_id'] user_roles = self.assignment_api.get_roles_for_user_and_project( diff --git a/keystone/tests/unit/test_auth.py b/keystone/tests/unit/test_auth.py index 9b11ddebbd..f253b02d07 100644 --- a/keystone/tests/unit/test_auth.py +++ b/keystone/tests/unit/test_auth.py @@ -933,8 +933,8 @@ class AuthWithTrust(AuthTest): def test_get_trust(self): unscoped_token = self.get_unscoped_token(self.trustor['name']) - context = {'token_id': unscoped_token['access']['token']['id'], - 'host_url': HOST_URL} + context = self._create_auth_context( + unscoped_token['access']['token']['id']) new_trust = self.trust_controller.create_trust( context, trust=self.sample_data)['trust'] trust = self.trust_controller.get_trust(context, @@ -945,6 +945,21 @@ class AuthWithTrust(AuthTest): for role in new_trust['roles']: self.assertIn(role['id'], role_ids) + def test_get_trust_without_auth_context(self): + """Verify that a trust cannot be retrieved when the auth context is + missing. + """ + unscoped_token = self.get_unscoped_token(self.trustor['name']) + context = self._create_auth_context( + unscoped_token['access']['token']['id']) + new_trust = self.trust_controller.create_trust( + context, trust=self.sample_data)['trust'] + # Delete the auth context before calling get_trust(). + del context['environment'][authorization.AUTH_CONTEXT_ENV] + self.assertRaises(exception.Forbidden, + self.trust_controller.get_trust, context, + new_trust['id']) + def test_create_trust_no_impersonation(self): new_trust = self.create_trust(self.sample_data, self.trustor['name'], expires_at=None, impersonation=False) diff --git a/keystone/trust/controllers.py b/keystone/trust/controllers.py index 889902e0bc..e30cd38256 100644 --- a/keystone/trust/controllers.py +++ b/keystone/trust/controllers.py @@ -27,7 +27,6 @@ from keystone.common import utils from keystone.common import validation from keystone import exception from keystone.i18n import _ -from keystone.models import token_model from keystone import notifications from keystone.trust import schema @@ -64,13 +63,11 @@ class TrustV3(controller.V3Controller): return super(TrustV3, cls).base_url(context, path=path) def _get_user_id(self, context): - if 'token_id' in context: - token_id = context['token_id'] - token_data = self.token_provider_api.validate_token(token_id) - token_ref = token_model.KeystoneToken(token_id=token_id, - token_data=token_data) - return token_ref.user_id - return None + try: + token_ref = utils.get_token_ref(context) + except exception.Unauthorized: + return None + return token_ref.user_id def get_trust(self, context, trust_id): user_id = self._get_user_id(context)