Reuse token_ref fetched in AuthContextMiddleware.
All keystone middleware components should reuse the auth context prepared by AuthContextMiddleware. Note that AuthContextMiddleware is listed in etc/keystone-paste.ini as one of the earliest middleware components in the keystone pipeline. This means that almost all other middleware components can depend on the auth context being available for use. Also added a test to check that a trust cannot be retrived in case of a missing auth context. Such a request should throw Forbidden exception. Change-Id: I1c08976cf4d175fa2cfe2e39fe55811f04f13243 Closes-Bug: #1433211
This commit is contained in:
parent
c387a9353e
commit
288a05a4de
@ -26,10 +26,10 @@ from six.moves import urllib
|
|||||||
from keystone.assignment import schema
|
from keystone.assignment import schema
|
||||||
from keystone.common import controller
|
from keystone.common import controller
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
|
from keystone.common import utils
|
||||||
from keystone.common import validation
|
from keystone.common import validation
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _, _LW
|
from keystone.i18n import _, _LW
|
||||||
from keystone.models import token_model
|
|
||||||
from keystone import notifications
|
from keystone import notifications
|
||||||
|
|
||||||
|
|
||||||
@ -51,14 +51,7 @@ class TenantAssignment(controller.V2Controller):
|
|||||||
Doesn't care about token scopedness.
|
Doesn't care about token scopedness.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
token_ref = utils.get_token_ref(context)
|
||||||
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)
|
|
||||||
|
|
||||||
tenant_refs = (
|
tenant_refs = (
|
||||||
self.assignment_api.list_projects_for_user(token_ref.user_id))
|
self.assignment_api.list_projects_for_user(token_ref.user_id))
|
||||||
|
@ -690,19 +690,7 @@ class V3Controller(wsgi.Application):
|
|||||||
if context['query_string'].get('domain_id') is not None:
|
if context['query_string'].get('domain_id') is not None:
|
||||||
return context['query_string'].get('domain_id')
|
return context['query_string'].get('domain_id')
|
||||||
|
|
||||||
try:
|
token_ref = utils.get_token_ref(context)
|
||||||
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()
|
|
||||||
|
|
||||||
if token_ref.domain_scoped:
|
if token_ref.domain_scoped:
|
||||||
return token_ref.domain_id
|
return token_ref.domain_id
|
||||||
@ -719,25 +707,7 @@ class V3Controller(wsgi.Application):
|
|||||||
being used.
|
being used.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# We could make this more efficient by loading the domain_id
|
token_ref = utils.get_token_ref(context)
|
||||||
# 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()
|
|
||||||
|
|
||||||
if token_ref.domain_scoped:
|
if token_ref.domain_scoped:
|
||||||
return token_ref.domain_id
|
return token_ref.domain_id
|
||||||
|
@ -32,6 +32,7 @@ import passlib.hash
|
|||||||
import six
|
import six
|
||||||
from six import moves
|
from six import moves
|
||||||
|
|
||||||
|
from keystone.common import authorization
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _, _LE, _LW
|
from keystone.i18n import _, _LE, _LW
|
||||||
|
|
||||||
@ -504,3 +505,20 @@ def isotime(at=None, subsecond=False):
|
|||||||
def strtime():
|
def strtime():
|
||||||
at = timeutils.utcnow()
|
at = timeutils.utcnow()
|
||||||
return at.strftime(timeutils.PERFECT_TIME_FORMAT)
|
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()
|
||||||
|
@ -299,13 +299,7 @@ class Application(BaseApplication):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not context['is_admin']:
|
if not context['is_admin']:
|
||||||
try:
|
user_token_ref = utils.get_token_ref(context)
|
||||||
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)
|
|
||||||
|
|
||||||
validate_token_bind(context, user_token_ref)
|
validate_token_bind(context, user_token_ref)
|
||||||
creds = copy.deepcopy(user_token_ref.metadata)
|
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 '
|
LOG.debug(('will not lookup trust as the request auth token is '
|
||||||
'either absent or it is the system admin token'))
|
'either absent or it is the system admin token'))
|
||||||
return None
|
return None
|
||||||
|
token_ref = utils.get_token_ref(context)
|
||||||
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)
|
|
||||||
return token_ref.trust_id
|
return token_ref.trust_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -46,7 +46,6 @@ from keystone.common import utils
|
|||||||
from keystone.common import wsgi
|
from keystone.common import wsgi
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _
|
from keystone.i18n import _
|
||||||
from keystone.models import token_model
|
|
||||||
|
|
||||||
|
|
||||||
@dependency.requires('assignment_api', 'catalog_api', 'credential_api',
|
@dependency.requires('assignment_api', 'catalog_api', 'credential_api',
|
||||||
@ -319,14 +318,7 @@ class Ec2Controller(Ec2ControllerCommon, controller.V2Controller):
|
|||||||
:raises exception.Forbidden: when token is invalid
|
:raises exception.Forbidden: when token is invalid
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
token_ref = utils.get_token_ref(context)
|
||||||
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)
|
|
||||||
|
|
||||||
if token_ref.user_id != user_id:
|
if token_ref.user_id != user_id:
|
||||||
raise exception.Forbidden(_('Token belongs to another user'))
|
raise exception.Forbidden(_('Token belongs to another user'))
|
||||||
|
@ -20,12 +20,12 @@ from oslo_utils import timeutils
|
|||||||
|
|
||||||
from keystone.common import controller
|
from keystone.common import controller
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
|
from keystone.common import utils
|
||||||
from keystone.common import wsgi
|
from keystone.common import wsgi
|
||||||
from keystone.contrib.oauth1 import core as oauth1
|
from keystone.contrib.oauth1 import core as oauth1
|
||||||
from keystone.contrib.oauth1 import validator
|
from keystone.contrib.oauth1 import validator
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _
|
from keystone.i18n import _
|
||||||
from keystone.models import token_model
|
|
||||||
from keystone import notifications
|
from keystone import notifications
|
||||||
|
|
||||||
|
|
||||||
@ -84,10 +84,7 @@ class ConsumerCrudV3(controller.V3Controller):
|
|||||||
|
|
||||||
@controller.protected()
|
@controller.protected()
|
||||||
def delete_consumer(self, context, consumer_id):
|
def delete_consumer(self, context, consumer_id):
|
||||||
user_token_ref = token_model.KeystoneToken(
|
user_token_ref = utils.get_token_ref(context)
|
||||||
token_id=context['token_id'],
|
|
||||||
token_data=self.token_provider_api.validate_token(
|
|
||||||
context['token_id']))
|
|
||||||
payload = {'user_id': user_token_ref.user_id,
|
payload = {'user_id': user_token_ref.user_id,
|
||||||
'consumer_id': consumer_id}
|
'consumer_id': consumer_id}
|
||||||
_emit_user_oauth_consumer_token_invalidate(payload)
|
_emit_user_oauth_consumer_token_invalidate(payload)
|
||||||
@ -382,10 +379,7 @@ class OAuthControllerV3(controller.V3Controller):
|
|||||||
authed_roles.add(role['id'])
|
authed_roles.add(role['id'])
|
||||||
|
|
||||||
# verify the authorizing user has the roles
|
# verify the authorizing user has the roles
|
||||||
user_token = token_model.KeystoneToken(
|
user_token = utils.get_token_ref(context)
|
||||||
token_id=context['token_id'],
|
|
||||||
token_data=self.token_provider_api.validate_token(
|
|
||||||
context['token_id']))
|
|
||||||
user_id = user_token.user_id
|
user_id = user_token.user_id
|
||||||
project_id = req_token['requested_project_id']
|
project_id = req_token['requested_project_id']
|
||||||
user_roles = self.assignment_api.get_roles_for_user_and_project(
|
user_roles = self.assignment_api.get_roles_for_user_and_project(
|
||||||
|
@ -933,8 +933,8 @@ class AuthWithTrust(AuthTest):
|
|||||||
|
|
||||||
def test_get_trust(self):
|
def test_get_trust(self):
|
||||||
unscoped_token = self.get_unscoped_token(self.trustor['name'])
|
unscoped_token = self.get_unscoped_token(self.trustor['name'])
|
||||||
context = {'token_id': unscoped_token['access']['token']['id'],
|
context = self._create_auth_context(
|
||||||
'host_url': HOST_URL}
|
unscoped_token['access']['token']['id'])
|
||||||
new_trust = self.trust_controller.create_trust(
|
new_trust = self.trust_controller.create_trust(
|
||||||
context, trust=self.sample_data)['trust']
|
context, trust=self.sample_data)['trust']
|
||||||
trust = self.trust_controller.get_trust(context,
|
trust = self.trust_controller.get_trust(context,
|
||||||
@ -945,6 +945,21 @@ class AuthWithTrust(AuthTest):
|
|||||||
for role in new_trust['roles']:
|
for role in new_trust['roles']:
|
||||||
self.assertIn(role['id'], role_ids)
|
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):
|
def test_create_trust_no_impersonation(self):
|
||||||
new_trust = self.create_trust(self.sample_data, self.trustor['name'],
|
new_trust = self.create_trust(self.sample_data, self.trustor['name'],
|
||||||
expires_at=None, impersonation=False)
|
expires_at=None, impersonation=False)
|
||||||
|
@ -27,7 +27,6 @@ from keystone.common import utils
|
|||||||
from keystone.common import validation
|
from keystone.common import validation
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _
|
from keystone.i18n import _
|
||||||
from keystone.models import token_model
|
|
||||||
from keystone import notifications
|
from keystone import notifications
|
||||||
from keystone.trust import schema
|
from keystone.trust import schema
|
||||||
|
|
||||||
@ -64,13 +63,11 @@ class TrustV3(controller.V3Controller):
|
|||||||
return super(TrustV3, cls).base_url(context, path=path)
|
return super(TrustV3, cls).base_url(context, path=path)
|
||||||
|
|
||||||
def _get_user_id(self, context):
|
def _get_user_id(self, context):
|
||||||
if 'token_id' in context:
|
try:
|
||||||
token_id = context['token_id']
|
token_ref = utils.get_token_ref(context)
|
||||||
token_data = self.token_provider_api.validate_token(token_id)
|
except exception.Unauthorized:
|
||||||
token_ref = token_model.KeystoneToken(token_id=token_id,
|
|
||||||
token_data=token_data)
|
|
||||||
return token_ref.user_id
|
|
||||||
return None
|
return None
|
||||||
|
return token_ref.user_id
|
||||||
|
|
||||||
def get_trust(self, context, trust_id):
|
def get_trust(self, context, trust_id):
|
||||||
user_id = self._get_user_id(context)
|
user_id = self._get_user_id(context)
|
||||||
|
Loading…
Reference in New Issue
Block a user