summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-09-11 01:41:00 +0000
committerGerrit Code Review <review@openstack.org>2014-09-11 01:41:00 +0000
commit73597a478d5c39aaf314b605272887d010f88513 (patch)
tree85b32ae9d33ba6a73e2bfeb250033e1413c74f2b
parentf4542d281ed007db1358757efc030d35f50bd865 (diff)
parent563991136646eb6d913e94e482323966b0393db2 (diff)
downloadkeystonemiddleware-73597a478d5c39aaf314b605272887d010f88513.tar.gz
Merge "Always add auth URI to unauthorized requests"
-rw-r--r--keystonemiddleware/auth_token.py26
-rw-r--r--keystonemiddleware/tests/test_auth_token_middleware.py40
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)