diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-09-11 01:41:00 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-09-11 01:41:00 +0000 |
commit | 73597a478d5c39aaf314b605272887d010f88513 (patch) | |
tree | 85b32ae9d33ba6a73e2bfeb250033e1413c74f2b | |
parent | f4542d281ed007db1358757efc030d35f50bd865 (diff) | |
parent | 563991136646eb6d913e94e482323966b0393db2 (diff) | |
download | keystonemiddleware-73597a478d5c39aaf314b605272887d010f88513.tar.gz |
Merge "Always add auth URI to unauthorized requests"
-rw-r--r-- | keystonemiddleware/auth_token.py | 26 | ||||
-rw-r--r-- | keystonemiddleware/tests/test_auth_token_middleware.py | 40 |
2 files changed, 60 insertions, 6 deletions
diff --git a/keystonemiddleware/auth_token.py b/keystonemiddleware/auth_token.py index 15d3df7..c84e6de 100644 --- a/keystonemiddleware/auth_token.py +++ b/keystonemiddleware/auth_token.py @@ -549,6 +549,18 @@ class AuthProtocol(object): else: return CONF.keystone_authtoken[name] + def _call_app(self, env, start_response): + # NOTE(jamielennox): We wrap the given start response so that if an + # application with a 'delay_auth_decision' setting fails, or otherwise + # raises Unauthorized that we include the Authentication URL headers. + def _fake_start_response(status, response_headers, exc_info=None): + if status.startswith('401'): + response_headers.extend(self._reject_auth_headers) + + return start_response(status, response_headers, exc_info) + + return self._app(env, _fake_start_response) + def __call__(self, env, start_response): """Handle incoming request. @@ -567,14 +579,14 @@ class AuthProtocol(object): env['keystone.token_info'] = token_info user_headers = self._build_user_headers(token_info) self._add_headers(env, user_headers) - return self._app(env, start_response) + return self._call_app(env, start_response) except InvalidUserToken: if self._delay_auth_decision: self._LOG.info( 'Invalid user token - deferring reject downstream') self._add_headers(env, {'X-Identity-Status': 'Invalid'}) - return self._app(env, start_response) + return self._call_app(env, start_response) else: self._LOG.info('Invalid user token - rejecting request') return self._reject_request(env, start_response) @@ -635,6 +647,11 @@ class AuthProtocol(object): self._LOG.debug('Headers: %s', env) raise InvalidUserToken('Unable to find token in headers') + @property + def _reject_auth_headers(self): + header_val = 'Keystone uri=\'%s\'' % self._identity_server.auth_uri + return [('WWW-Authenticate', header_val)] + def _reject_request(self, env, start_response): """Redirect client to auth server. @@ -643,9 +660,8 @@ class AuthProtocol(object): :returns HTTPUnauthorized http response """ - header_val = 'Keystone uri=\'%s\'' % self._identity_server.auth_uri - headers = [('WWW-Authenticate', header_val)] - resp = _MiniResp('Authentication required', env, headers) + resp = _MiniResp('Authentication required', + env, self._reject_auth_headers) start_response('401 Unauthorized', resp.headers) return resp.body diff --git a/keystonemiddleware/tests/test_auth_token_middleware.py b/keystonemiddleware/tests/test_auth_token_middleware.py index f392c45..430d21b 100644 --- a/keystonemiddleware/tests/test_auth_token_middleware.py +++ b/keystonemiddleware/tests/test_auth_token_middleware.py @@ -17,6 +17,7 @@ import datetime import json import os import shutil +import six import stat import tempfile import time @@ -34,6 +35,7 @@ import testresources import testtools from testtools import matchers import webob +import webob.dec from keystonemiddleware import auth_token from keystonemiddleware.openstack.common import jsonutils @@ -201,6 +203,22 @@ class v3FakeApp(FakeApp): super(v3FakeApp, self).__init__(v3_default_env_additions) +def new_app(status, body, headers={}): + + class _App(object): + + def __init__(self, expected_env=None): + self.expected_env = expected_env + + @webob.dec.wsgify + def __call__(self, req): + resp = webob.Response(body, status) + resp.headers.update(headers) + return resp + + return _App + + class BaseAuthTokenMiddlewareTest(testtools.TestCase): """Base test class for auth_token middleware. @@ -262,7 +280,7 @@ class BaseAuthTokenMiddlewareTest(testtools.TestCase): self.middleware._token_revocation_list = jsonutils.dumps( {"revoked": [], "extra": "success"}) - def start_fake_response(self, status, headers): + def start_fake_response(self, status, headers, exc_info=None): self.response_status = int(status.split(' ', 1)[0]) self.response_headers = dict(headers) @@ -2018,5 +2036,25 @@ class CatalogConversionTests(BaseAuthTokenMiddlewareTest): self.assertIn(e, expected) +class DelayedAuthTests(BaseAuthTokenMiddlewareTest): + + def test_header_in_401(self): + body = uuid.uuid4().hex + auth_uri = 'http://local.test' + conf = {'delay_auth_decision': True, 'auth_uri': auth_uri} + + self.fake_app = new_app('401 Unauthorized', body) + self.set_middleware(conf=conf) + + req = webob.Request.blank('/') + resp = self.middleware(req.environ, self.start_fake_response) + + self.assertEqual([six.b(body)], resp) + + self.assertEqual(401, self.response_status) + self.assertEqual("Keystone uri='%s'" % auth_uri, + self.response_headers['WWW-Authenticate']) + + def load_tests(loader, tests, pattern): return testresources.OptimisingTestSuite(tests) |