Add WSGI environment to context
The environment dictionary contains an unspecified set of variables that contain information about the authentication and authorization processes. Not all of the values are known ahead of time. The two values for Kerberos (REMOTE_USER, AUTH_TYPE) are a subset. Instead of making the WSGI layer know about a growing superset of authentication attributes, the context contains a link to the wsgi environment. The environment is removed from the request dictionary to prevent circular references and potential GC issues. Fixed tests to set environment in the context. While this changed many tests, the alternative was to make the check for the environment optional in the controllers. This is not a realistic way to test. If context['environment'] it missing, a test will trigger a key_error. Closes-Bug: #1241812 Change-Id: I234677547204e9ddc0ab33db3e6aa8b7d959a01a
This commit is contained in:
parent
08b9ef10fc
commit
923b90ef8c
@ -332,7 +332,7 @@ class Auth(controller.V3Controller):
|
||||
"""Authenticate user."""
|
||||
|
||||
# user has been authenticated externally
|
||||
if 'REMOTE_USER' in context:
|
||||
if 'REMOTE_USER' in context['environment']:
|
||||
external = get_auth_method('external')
|
||||
external.authenticate(context, auth_info, auth_context)
|
||||
|
||||
|
@ -40,7 +40,7 @@ class Base(auth.AuthMethodHandler):
|
||||
user_id from the actual user from the REMOTE_USER env variable.
|
||||
"""
|
||||
try:
|
||||
REMOTE_USER = context['REMOTE_USER']
|
||||
REMOTE_USER = context['environment']['REMOTE_USER']
|
||||
except KeyError:
|
||||
msg = _('No authenticated user')
|
||||
raise exception.Unauthorized(msg)
|
||||
@ -48,7 +48,8 @@ class Base(auth.AuthMethodHandler):
|
||||
user_ref = self._authenticate(REMOTE_USER, auth_info)
|
||||
auth_context['user_id'] = user_ref['id']
|
||||
if ('kerberos' in CONF.token.bind and
|
||||
context.get('AUTH_TYPE', '').lower() == 'negotiate'):
|
||||
(context['environment'].get('AUTH_TYPE', '').lower()
|
||||
== 'negotiate')):
|
||||
auth_context['bind']['kerberos'] = user_ref['name']
|
||||
except Exception:
|
||||
msg = _('Unable to lookup user %s') % (REMOTE_USER)
|
||||
|
@ -102,11 +102,12 @@ def validate_token_bind(context, token_ref):
|
||||
|
||||
for bind_type, identifier in bind.iteritems():
|
||||
if bind_type == 'kerberos':
|
||||
if not context.get('AUTH_TYPE', '').lower() == 'negotiate':
|
||||
if not (context['environment'].get('AUTH_TYPE', '').lower()
|
||||
== 'negotiate'):
|
||||
LOG.info(_("Kerberos credentials required and not present"))
|
||||
raise exception.Unauthorized()
|
||||
|
||||
if not context.get('REMOTE_USER') == identifier:
|
||||
if not context['environment'].get('REMOTE_USER') == identifier:
|
||||
LOG.info(_("Kerberos credentials do not match those in bind"))
|
||||
raise exception.Unauthorized()
|
||||
|
||||
@ -214,15 +215,11 @@ class Application(BaseApplication):
|
||||
context['headers'] = dict(req.headers.iteritems())
|
||||
context['path'] = req.environ['PATH_INFO']
|
||||
params = req.environ.get(PARAMS_ENV, {})
|
||||
|
||||
for name in ['REMOTE_USER', 'AUTH_TYPE']:
|
||||
try:
|
||||
context[name] = req.environ[name]
|
||||
except KeyError:
|
||||
try:
|
||||
del context[name]
|
||||
except KeyError:
|
||||
pass
|
||||
#authentication and authorization attributes are set as environment
|
||||
#values by the container and processed by the pipeline. the complete
|
||||
#set is not yet know.
|
||||
context['environment'] = req.environ
|
||||
req.environ = None
|
||||
|
||||
params.update(arg_dict)
|
||||
|
||||
|
@ -71,6 +71,10 @@ class AuthTest(tests.TestCase):
|
||||
# need to register the token provider first because auth controller
|
||||
# depends on it
|
||||
token.provider.Manager()
|
||||
self.context_with_remote_user = {'environment':
|
||||
{'REMOTE_USER': 'FOO',
|
||||
'AUTH_TYPE': 'Negotiate'}}
|
||||
self.empty_context = {'environment': {}}
|
||||
|
||||
self.controller = token.controllers.Auth()
|
||||
|
||||
@ -379,8 +383,8 @@ class AuthWithToken(AuthTest):
|
||||
def test_token_auth_with_binding(self):
|
||||
CONF.token.bind = ['kerberos']
|
||||
body_dict = _build_user_auth()
|
||||
context = {'REMOTE_USER': 'FOO', 'AUTH_TYPE': 'Negotiate'}
|
||||
unscoped_token = self.controller.authenticate(context, body_dict)
|
||||
unscoped_token = self.controller.authenticate(
|
||||
self.context_with_remote_user, body_dict)
|
||||
|
||||
# the token should have bind information in it
|
||||
bind = unscoped_token['access']['token']['bind']
|
||||
@ -394,10 +398,11 @@ class AuthWithToken(AuthTest):
|
||||
self.assertRaises(
|
||||
exception.Unauthorized,
|
||||
self.controller.authenticate,
|
||||
{}, body_dict)
|
||||
self.empty_context, body_dict)
|
||||
|
||||
# using token with remote user context succeeds
|
||||
scoped_token = self.controller.authenticate(context, body_dict)
|
||||
scoped_token = self.controller.authenticate(
|
||||
self.context_with_remote_user, body_dict)
|
||||
|
||||
# the bind information should be carried over from the original token
|
||||
bind = scoped_token['access']['token']['bind']
|
||||
@ -517,7 +522,7 @@ class AuthWithRemoteUser(AuthTest):
|
||||
|
||||
body_dict = _build_user_auth()
|
||||
remote_token = self.controller.authenticate(
|
||||
{'REMOTE_USER': 'FOO'}, body_dict)
|
||||
self.context_with_remote_user, body_dict)
|
||||
|
||||
self.assertEqualTokens(local_token, remote_token)
|
||||
|
||||
@ -541,7 +546,7 @@ class AuthWithRemoteUser(AuthTest):
|
||||
body_dict = _build_user_auth(
|
||||
tenant_name='BAR')
|
||||
remote_token = self.controller.authenticate(
|
||||
{'REMOTE_USER': 'FOO'}, body_dict)
|
||||
self.context_with_remote_user, body_dict)
|
||||
|
||||
self.assertEqualTokens(local_token, remote_token)
|
||||
|
||||
@ -556,7 +561,7 @@ class AuthWithRemoteUser(AuthTest):
|
||||
|
||||
body_dict = _build_user_auth(tenant_name='BAZ')
|
||||
remote_token = self.controller.authenticate(
|
||||
{'REMOTE_USER': 'TWO'}, body_dict)
|
||||
{'environment': {'REMOTE_USER': 'TWO'}}, body_dict)
|
||||
|
||||
self.assertEqualTokens(local_token, remote_token)
|
||||
|
||||
@ -566,21 +571,21 @@ class AuthWithRemoteUser(AuthTest):
|
||||
self.assertRaises(
|
||||
exception.Unauthorized,
|
||||
self.controller.authenticate,
|
||||
{'REMOTE_USER': uuid.uuid4().hex},
|
||||
{'environment': {'REMOTE_USER': uuid.uuid4().hex}},
|
||||
body_dict)
|
||||
|
||||
def test_bind_with_kerberos(self):
|
||||
CONF.token.bind = ['kerberos']
|
||||
kerb = {'REMOTE_USER': 'FOO', 'AUTH_TYPE': 'Negotiate'}
|
||||
body_dict = _build_user_auth(tenant_name="BAR")
|
||||
token = self.controller.authenticate(kerb, body_dict)
|
||||
token = self.controller.authenticate(self.context_with_remote_user,
|
||||
body_dict)
|
||||
self.assertEqual(token['access']['token']['bind']['kerberos'], 'FOO')
|
||||
|
||||
def test_bind_without_config_opt(self):
|
||||
CONF.token.bind = ['x509']
|
||||
kerb = {'REMOTE_USER': 'FOO', 'AUTH_TYPE': 'Negotiate'}
|
||||
body_dict = _build_user_auth(tenant_name='BAR')
|
||||
token = self.controller.authenticate(kerb, body_dict)
|
||||
token = self.controller.authenticate(self.context_with_remote_user,
|
||||
body_dict)
|
||||
self.assertNotIn('bind', token['access']['token'])
|
||||
|
||||
|
||||
@ -715,7 +720,9 @@ class AuthWithTrust(AuthTest):
|
||||
'project': {
|
||||
'id': self.tenant_baz['id']}}}
|
||||
auth_response = (self.auth_v3_controller.authenticate_for_token
|
||||
({'query_string': {}}, v3_password_data))
|
||||
({'environment': {},
|
||||
'query_string': {}},
|
||||
v3_password_data))
|
||||
token = auth_response.headers['X-Subject-Token']
|
||||
|
||||
v3_req_with_trust = {
|
||||
@ -725,7 +732,9 @@ class AuthWithTrust(AuthTest):
|
||||
"scope": {
|
||||
"OS-TRUST:trust": {"id": self.new_trust['id']}}}
|
||||
token_auth_response = (self.auth_v3_controller.authenticate_for_token
|
||||
({'query_string': {}}, v3_req_with_trust))
|
||||
({'environment': {},
|
||||
'query_string': {}},
|
||||
v3_req_with_trust))
|
||||
return token_auth_response
|
||||
|
||||
def test_create_v3_token_from_trust(self):
|
||||
@ -754,7 +763,8 @@ class AuthWithTrust(AuthTest):
|
||||
self.assertRaises(
|
||||
exception.Forbidden,
|
||||
self.auth_v3_controller.authenticate_for_token,
|
||||
{'query_string': {}}, v3_token_data)
|
||||
{'environment': {},
|
||||
'query_string': {}}, v3_token_data)
|
||||
|
||||
def test_token_from_trust(self):
|
||||
auth_response = self.fetch_v2_token_from_trust()
|
||||
|
@ -74,7 +74,7 @@ class TestAuthPlugin(tests.TestCase):
|
||||
auth_info = auth.controllers.AuthInfo(None, auth_data)
|
||||
auth_context = {'extras': {}, 'method_names': []}
|
||||
try:
|
||||
self.api.authenticate({}, auth_info, auth_context)
|
||||
self.api.authenticate({'environment': {}}, auth_info, auth_context)
|
||||
except exception.AdditionalAuthRequired as e:
|
||||
self.assertTrue('methods' in e.authentication)
|
||||
self.assertTrue(METHOD_NAME in e.authentication['methods'])
|
||||
@ -88,7 +88,7 @@ class TestAuthPlugin(tests.TestCase):
|
||||
auth_data = {'identity': auth_data}
|
||||
auth_info = auth.controllers.AuthInfo(None, auth_data)
|
||||
auth_context = {'extras': {}, 'method_names': []}
|
||||
self.api.authenticate({}, auth_info, auth_context)
|
||||
self.api.authenticate({'environment': {}}, auth_info, auth_context)
|
||||
self.assertEqual(auth_context['user_id'], DEMO_USER_ID)
|
||||
|
||||
# test incorrect response
|
||||
@ -100,6 +100,6 @@ class TestAuthPlugin(tests.TestCase):
|
||||
auth_context = {'extras': {}, 'method_names': []}
|
||||
self.assertRaises(exception.Unauthorized,
|
||||
self.api.authenticate,
|
||||
{},
|
||||
{'environment': {}},
|
||||
auth_info,
|
||||
auth_context)
|
||||
|
@ -49,12 +49,12 @@ class BindTest(tests.TestCase):
|
||||
self.assert_kerberos_bind(tokens, bind_level,
|
||||
use_kerberos=val, success=success)
|
||||
else:
|
||||
context = {}
|
||||
context = {'environment': {}}
|
||||
CONF.token.enforce_token_bind = bind_level
|
||||
|
||||
if use_kerberos:
|
||||
context['REMOTE_USER'] = KERBEROS_BIND
|
||||
context['AUTH_TYPE'] = 'Negotiate'
|
||||
context['environment']['REMOTE_USER'] = KERBEROS_BIND
|
||||
context['environment']['AUTH_TYPE'] = 'Negotiate'
|
||||
|
||||
if not success:
|
||||
self.assertRaises(exception.Unauthorized,
|
||||
|
@ -158,6 +158,7 @@ class RestfulTestCase(rest.RestfulTestCase):
|
||||
|
||||
self.public_server = self.serveapp(app_conf, name='main')
|
||||
self.admin_server = self.serveapp(app_conf, name='admin')
|
||||
self.empty_context = {'environment': {}}
|
||||
|
||||
def tearDown(self):
|
||||
self.public_server.kill()
|
||||
@ -1039,7 +1040,7 @@ class RestfulTestCase(rest.RestfulTestCase):
|
||||
return {'auth': auth_data}
|
||||
|
||||
def build_external_auth_request(self, remote_user, auth_data=None):
|
||||
context = {'REMOTE_USER': remote_user}
|
||||
context = {'environment': {'REMOTE_USER': remote_user}}
|
||||
if not auth_data:
|
||||
auth_data = self.build_authentication_request()['auth']
|
||||
no_context = None
|
||||
|
@ -1666,12 +1666,11 @@ class TestAuthJSON(test_v3.RestfulTestCase):
|
||||
auth_data['identity']['methods'] = ["password", "external"]
|
||||
auth_data['identity']['external'] = {}
|
||||
api = auth.controllers.Auth()
|
||||
context = {}
|
||||
auth_info = auth.controllers.AuthInfo(None, auth_data)
|
||||
auth_context = {'extras': {}, 'method_names': []}
|
||||
self.assertRaises(exception.Unauthorized,
|
||||
api.authenticate,
|
||||
context,
|
||||
self.empty_context,
|
||||
auth_info,
|
||||
auth_context)
|
||||
|
||||
|
@ -279,7 +279,7 @@ class Auth(controller.V2Controller):
|
||||
|
||||
Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
|
||||
"""
|
||||
if 'REMOTE_USER' not in context:
|
||||
if 'REMOTE_USER' not in context.get('environment', {}):
|
||||
raise ExternalAuthNotApplicable()
|
||||
|
||||
#NOTE(jamielennox): xml and json differ and get confused about what
|
||||
@ -287,7 +287,7 @@ class Auth(controller.V2Controller):
|
||||
if not auth:
|
||||
auth = {}
|
||||
|
||||
username = context['REMOTE_USER']
|
||||
username = context['environment']['REMOTE_USER']
|
||||
try:
|
||||
user_ref = self.identity_api.get_user_by_name(
|
||||
username, DEFAULT_DOMAIN_ID)
|
||||
@ -303,7 +303,8 @@ class Auth(controller.V2Controller):
|
||||
expiry = core.default_expire_time()
|
||||
bind = None
|
||||
if ('kerberos' in CONF.token.bind and
|
||||
context.get('AUTH_TYPE', '').lower() == 'negotiate'):
|
||||
context['environment'].
|
||||
get('AUTH_TYPE', '').lower() == 'negotiate'):
|
||||
bind = {'kerberos': username}
|
||||
|
||||
return (user_ref, tenant_ref, metadata_ref, expiry, bind)
|
||||
|
Loading…
Reference in New Issue
Block a user