Merge "Require auth_context middleware in the pipeline"

This commit is contained in:
Jenkins 2016-07-14 05:08:52 +00:00 committed by Gerrit Code Review
commit a6c0b71252
6 changed files with 30 additions and 45 deletions

View File

@ -29,6 +29,7 @@ class RequestContext(oslo_context.RequestContext):
self.username = kwargs.pop('username', None)
self.user_domain_name = kwargs.pop('user_domain_name', None)
self.project_domain_name = kwargs.pop('project_domain_name', None)
self.authenticated = kwargs.pop('authenticated', False)
super(RequestContext, self).__init__(**kwargs)
@classmethod

View File

@ -79,32 +79,7 @@ def _build_policy_check_credentials(self, action, context, kwargs):
'action': action,
'kwargs': kwargs_str})
# see if auth context has already been created. If so use it.
if ('environment' in context and
authorization.AUTH_CONTEXT_ENV in context['environment']):
LOG.debug('RBAC: using auth context from the request environment')
return context['environment'].get(authorization.AUTH_CONTEXT_ENV)
# There is no current auth context, build it from the incoming token.
# TODO(morganfainberg): Collapse this logic with AuthContextMiddleware
# in a sane manner as this just mirrors the logic in AuthContextMiddleware
try:
LOG.debug('RBAC: building auth context from the incoming auth token')
token_ref = token_model.KeystoneToken(
token_id=context['token_id'],
token_data=self.token_provider_api.validate_token(
context['token_id']))
# NOTE(jamielennox): whilst this maybe shouldn't be within this
# function it would otherwise need to reload the token_ref from
# backing store.
wsgi.validate_token_bind(context, token_ref)
except exception.TokenNotFound:
LOG.warning(_LW('RBAC: Invalid token'))
raise exception.Unauthorized()
auth_context = authorization.token_to_auth_context(token_ref)
return auth_context
return context['environment'].get(authorization.AUTH_CONTEXT_ENV, {})
def protected(callback=None):
@ -123,6 +98,8 @@ def protected(callback=None):
def wrapper(f):
@functools.wraps(f)
def inner(self, request, *args, **kwargs):
request.assert_authenticated()
if request.context.is_admin:
LOG.warning(_LW('RBAC: Bypassing authorization'))
elif callback is not None:
@ -205,6 +182,8 @@ def filterprotected(*filters, **callback):
def _filterprotected(f):
@functools.wraps(f)
def wrapper(self, request, **kwargs):
request.assert_authenticated()
if not request.context.is_admin:
# The target dict for the policy check will include:
#

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
import webob
from webob.descriptors import environ_getter
@ -17,13 +19,14 @@ from keystone.common import authorization
from keystone.common import context
import keystone.conf
from keystone import exception
from keystone.i18n import _
from keystone.i18n import _, _LW
# Environment variable used to pass the request context
CONTEXT_ENV = 'openstack.context'
CONF = keystone.conf.CONF
LOG = logging.getLogger(__name__)
class Request(webob.Request):
@ -73,6 +76,20 @@ class Request(webob.Request):
def auth_context(self):
return self.environ.get(authorization.AUTH_CONTEXT_ENV, {})
def assert_authenticated(self):
"""Ensure that the current request has been authenticated."""
if not self.context:
LOG.warning(_LW('An authenticated call was made and there is '
'no request.context. This means the '
'auth_context middleware is not in place. You '
'must have this middleware in your pipeline '
'to perform authenticated calls'))
raise exception.Unauthorized()
if not self.context.authenticated:
# auth_context didn't decode anything we can use
raise exception.Unauthorized()
auth_type = environ_getter('AUTH_TYPE', None)
remote_domain = environ_getter('REMOTE_DOMAIN', None)
context = environ_getter(context.REQUEST_CONTEXT_ENV, None)

View File

@ -154,6 +154,7 @@ class AuthContextMiddleware(auth_token.BaseAuthProtocol):
# The request context stores itself in thread-local memory for logging.
request_context = context.RequestContext(
request_id=request.environ.get('openstack.request_id'),
authenticated=False,
overwrite=True)
request.environ[context.REQUEST_CONTEXT_ENV] = request_context
@ -203,6 +204,9 @@ class AuthContextMiddleware(auth_token.BaseAuthProtocol):
'context will be set.')
return
# set authenticated to flag to keystone that a token has been validated
request_context.authenticated = True
# The attributes of request_context are put into the logs. This is a
# common pattern for all the OpenStack services. In all the other
# projects these are IDs, so set the attributes to IDs here rather than

View File

@ -594,7 +594,8 @@ class TestCase(BaseTestCase):
if not environ.get(context.REQUEST_CONTEXT_ENV):
environ[context.REQUEST_CONTEXT_ENV] = context.RequestContext(
is_admin=is_admin)
is_admin=is_admin,
authenticated=kwargs.pop('authenticated', True))
req = request.Request.blank(path=path, **kwargs)
req.context_dict['is_admin'] = is_admin

View File

@ -4699,23 +4699,6 @@ class TestTrustChain(test_v3.RestfulTestCase):
expected_status=http_client.FORBIDDEN)
class TestAPIProtectionWithoutAuthContextMiddleware(test_v3.RestfulTestCase):
def test_api_protection_with_no_auth_context_in_env(self):
auth_data = self.build_authentication_request(
user_id=self.default_domain_user['id'],
password=self.default_domain_user['password'],
project_id=self.project['id'])
token = self.get_requested_token(auth_data)
auth_controller = auth.controllers.Auth()
# all we care is that auth context is not in the environment and
# 'token_id' is used to build the auth context instead
request = self.make_request()
request.context_dict['subject_token_id'] = token
request.context_dict['token_id'] = token
r = auth_controller.validate_token(request)
self.assertEqual(http_client.OK, r.status_code)
class TestAuthContext(unit.TestCase):
def setUp(self):
super(TestAuthContext, self).setUp()