summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-08-12 06:56:40 +0000
committerGerrit Code Review <review@openstack.org>2015-08-12 06:56:40 +0000
commit9db204e5c2d5632ee8c3f316bae83ba0234fadab (patch)
treed1afc4e04b5f768d486bb19c1d5932fdce310349
parent64b6e3db7eac4d9c22db566e2c37b4fb27f517b6 (diff)
parent4fe8ae52a6d2fbccc876efd0573685d1ab20855c (diff)
downloadkeystonemiddleware-9db204e5c2d5632ee8c3f316bae83ba0234fadab.tar.gz
Merge "Move common request processing to base class"
-rw-r--r--keystonemiddleware/auth_token/__init__.py115
-rw-r--r--keystonemiddleware/auth_token/_user_plugin.py5
-rw-r--r--keystonemiddleware/tests/unit/auth_token/test_base_middleware.py153
3 files changed, 214 insertions, 59 deletions
diff --git a/keystonemiddleware/auth_token/__init__.py b/keystonemiddleware/auth_token/__init__.py
index 6babf50..930e847 100644
--- a/keystonemiddleware/auth_token/__init__.py
+++ b/keystonemiddleware/auth_token/__init__.py
@@ -457,6 +457,38 @@ class _BaseAuthProtocol(object):
By default this method does not return a value.
"""
+ request.remove_auth_headers()
+
+ user_auth_ref = None
+ serv_auth_ref = None
+
+ if request.user_token:
+ self.log.debug('Authenticating user token')
+ try:
+ data, user_auth_ref = self._do_fetch_token(request.user_token)
+ self._validate_token(user_auth_ref)
+ self._confirm_token_bind(user_auth_ref, request)
+ except exc.InvalidToken:
+ self.log.info(_LI('Invalid user token'))
+ request.user_token_valid = False
+ else:
+ request.user_token_valid = True
+ request.environ['keystone.token_info'] = data
+
+ if request.service_token:
+ self.log.debug('Authenticating service token')
+ try:
+ _, serv_auth_ref = self._do_fetch_token(request.service_token)
+ self._validate_token(serv_auth_ref)
+ self._confirm_token_bind(serv_auth_ref, request)
+ except exc.InvalidToken:
+ self.log.info(_LI('Invalid service token'))
+ request.service_token_valid = False
+ else:
+ request.service_token_valid = True
+
+ p = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref)
+ request.environ['keystone.token_auth'] = p
def _validate_token(self, auth_ref):
"""Perform the validation steps on the token.
@@ -649,57 +681,39 @@ class AuthProtocol(_BaseAuthProtocol):
depending on configuration.
"""
self._token_cache.initialize(request.environ)
- request.remove_auth_headers()
- user_auth_ref = None
- serv_auth_ref = None
+ resp = super(AuthProtocol, self).process_request(request)
+ if resp:
+ return resp
- self.log.debug('Authenticating user token')
- try:
- user_token = self._get_user_token_from_request(request)
- data, user_auth_ref = self._do_fetch_token(user_token)
- self._validate_token(user_auth_ref)
- self._confirm_token_bind(user_auth_ref, request)
- except exc.InvalidToken:
+ if not request.user_token:
+ # if no user token is present then that's an invalid request
+ request.user_token_valid = False
+
+ # NOTE(jamielennox): The service status is allowed to be missing if a
+ # service token is not passed. If the service status is missing that's
+ # a valid request. We should find a better way to expose this from the
+ # request object.
+ user_status = request.user_token and request.user_token_valid
+ service_status = request.headers.get('X-Service-Identity-Status',
+ 'Confirmed')
+
+ if not (user_status and service_status == 'Confirmed'):
if self._delay_auth_decision:
- self.log.info(
- _LI('Invalid user token - deferring reject '
- 'downstream'))
- request.user_token_valid = False
+ self.log.info(_LI('Deferring reject downstream'))
else:
- self.log.info(
- _LI('Invalid user token - rejecting request'))
+ self.log.info(_LI('Rejecting request'))
self._reject_request()
- else:
- request.environ['keystone.token_info'] = data
- request.set_user_headers(user_auth_ref,
- self._include_service_catalog)
- if request.service_token is not None:
- self.log.debug('Authenticating service token')
- try:
- _ignore, serv_auth_ref = self._do_fetch_token(
- request.service_token)
- self._validate_token(serv_auth_ref)
- self._confirm_token_bind(serv_auth_ref, request)
- except exc.InvalidToken:
- if self._delay_auth_decision:
- self.log.info(
- _LI('Invalid service token - deferring reject '
- 'downstream'))
- request.service_token_valid = False
- else:
- self.log.info(
- _LI('Invalid service token - rejecting request'))
- self._reject_request()
- else:
- request.set_service_headers(serv_auth_ref)
+ if request.user_token_valid:
+ request.set_user_headers(request.token_auth._user_auth_ref,
+ self._include_service_catalog)
- request.token_auth = _user_plugin.UserAuthPlugin(user_auth_ref,
- serv_auth_ref)
+ if request.service_token and request.service_token_valid:
+ request.set_service_headers(request.token_auth._serv_auth_ref)
if self.log.isEnabledFor(logging.DEBUG):
- self.log.debug('Received request from %s' %
+ self.log.debug('Received request from %s',
request.token_auth._log_format)
def process_response(self, response):
@@ -713,23 +727,6 @@ class AuthProtocol(_BaseAuthProtocol):
return response
- def _get_user_token_from_request(self, request):
- """Get token id from request.
-
- :param env: wsgi request environment
- :returns: token id
- :raises exc.InvalidToken: if no token is provided in request
-
- """
- token = request.user_token
-
- if token:
- return token
- else:
- if not self._delay_auth_decision:
- self.log.debug('Headers: %s', dict(request.headers))
- raise exc.InvalidToken(_('Unable to find token in headers'))
-
@property
def _reject_auth_headers(self):
header_val = 'Keystone uri=\'%s\'' % self._auth_uri
diff --git a/keystonemiddleware/auth_token/_user_plugin.py b/keystonemiddleware/auth_token/_user_plugin.py
index 9bdc400..93075c5 100644
--- a/keystonemiddleware/auth_token/_user_plugin.py
+++ b/keystonemiddleware/auth_token/_user_plugin.py
@@ -126,8 +126,13 @@ class UserAuthPlugin(base_identity.BaseIdentityPlugin):
def __init__(self, user_auth_ref, serv_auth_ref):
super(UserAuthPlugin, self).__init__(reauthenticate=False)
+
+ # NOTE(jamielennox): _user_auth_ref and _serv_auth_ref are private
+ # because this object ends up in the environ that is passed to the
+ # service, however they are used within auth_token middleware.
self._user_auth_ref = user_auth_ref
self._serv_auth_ref = serv_auth_ref
+
self._user_data = None
self._serv_data = None
diff --git a/keystonemiddleware/tests/unit/auth_token/test_base_middleware.py b/keystonemiddleware/tests/unit/auth_token/test_base_middleware.py
index cf7d812..b213f54 100644
--- a/keystonemiddleware/tests/unit/auth_token/test_base_middleware.py
+++ b/keystonemiddleware/tests/unit/auth_token/test_base_middleware.py
@@ -10,7 +10,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import datetime
+import uuid
+
+from keystoneclient import fixture
import mock
+import six
import testtools
import webob
@@ -25,6 +30,19 @@ class FakeApp(object):
return webob.Response()
+class FetchingMiddleware(auth_token._BaseAuthProtocol):
+
+ def __init__(self, app, token_dict={}, **kwargs):
+ super(FetchingMiddleware, self).__init__(app, **kwargs)
+ self.token_dict = token_dict
+
+ def _fetch_token(self, token):
+ try:
+ return self.token_dict[token]
+ except KeyError:
+ raise auth_token.InvalidToken()
+
+
class BaseAuthProtocolTests(testtools.TestCase):
@mock.patch.multiple(auth_token._BaseAuthProtocol,
@@ -47,3 +65,138 @@ class BaseAuthProtocolTests(testtools.TestCase):
self.assertEqual(1, process_response.call_count)
self.assertIsInstance(process_response.call_args[0][0], webob.Response)
+
+ @classmethod
+ def call(cls, middleware, method='GET', path='/', headers=None):
+ req = webob.Request.blank(path)
+ req.method = method
+
+ for k, v in six.iteritems(headers or {}):
+ req.headers[k] = v
+
+ resp = req.get_response(middleware)
+ resp.request = req
+ return resp
+
+ def test_good_v3_user_token(self):
+ t = fixture.V3Token()
+ t.set_project_scope()
+ role = t.add_role()
+
+ token_id = uuid.uuid4().hex
+ token_dict = {token_id: t}
+
+ @webob.dec.wsgify
+ def _do_cb(req):
+ self.assertEqual(token_id, req.headers['X-Auth-Token'])
+
+ self.assertEqual('Confirmed', req.headers['X-Identity-Status'])
+ self.assertNotIn('X-Service-Token', req.headers)
+
+ p = req.environ['keystone.token_auth']
+
+ self.assertTrue(p.has_user_token)
+ self.assertFalse(p.has_service_token)
+
+ self.assertEqual(t.project_id, p.user.project_id)
+ self.assertEqual(t.project_domain_id, p.user.project_domain_id)
+ self.assertEqual(t.user_id, p.user.user_id)
+ self.assertEqual(t.user_domain_id, p.user.user_domain_id)
+ self.assertIn(role['name'], p.user.role_names)
+
+ return webob.Response()
+
+ m = FetchingMiddleware(_do_cb, token_dict)
+ self.call(m, headers={'X-Auth-Token': token_id})
+
+ def test_invalid_user_token(self):
+ token_id = uuid.uuid4().hex
+
+ @webob.dec.wsgify
+ def _do_cb(req):
+ self.assertEqual('Invalid', req.headers['X-Identity-Status'])
+ self.assertEqual(token_id, req.headers['X-Auth-Token'])
+ return webob.Response()
+
+ m = FetchingMiddleware(_do_cb)
+ self.call(m, headers={'X-Auth-Token': token_id})
+
+ def test_expired_user_token(self):
+ t = fixture.V3Token()
+ t.set_project_scope()
+ t.expires = datetime.datetime.utcnow() - datetime.timedelta(minutes=10)
+
+ token_id = uuid.uuid4().hex
+ token_dict = {token_id: t}
+
+ @webob.dec.wsgify
+ def _do_cb(req):
+ self.assertEqual('Invalid', req.headers['X-Identity-Status'])
+ self.assertEqual(token_id, req.headers['X-Auth-Token'])
+ return webob.Response()
+
+ m = FetchingMiddleware(_do_cb, token_dict=token_dict)
+ self.call(m, headers={'X-Auth-Token': token_id})
+
+ def test_good_v3_service_token(self):
+ t = fixture.V3Token()
+ t.set_project_scope()
+ role = t.add_role()
+
+ token_id = uuid.uuid4().hex
+ token_dict = {token_id: t}
+
+ @webob.dec.wsgify
+ def _do_cb(req):
+ self.assertEqual(token_id, req.headers['X-Service-Token'])
+
+ self.assertEqual('Confirmed',
+ req.headers['X-Service-Identity-Status'])
+ self.assertNotIn('X-Auth-Token', req.headers)
+
+ p = req.environ['keystone.token_auth']
+
+ self.assertFalse(p.has_user_token)
+ self.assertTrue(p.has_service_token)
+
+ self.assertEqual(t.project_id, p.service.project_id)
+ self.assertEqual(t.project_domain_id, p.service.project_domain_id)
+ self.assertEqual(t.user_id, p.service.user_id)
+ self.assertEqual(t.user_domain_id, p.service.user_domain_id)
+ self.assertIn(role['name'], p.service.role_names)
+
+ return webob.Response()
+
+ m = FetchingMiddleware(_do_cb, token_dict)
+ self.call(m, headers={'X-Service-Token': token_id})
+
+ def test_invalid_service_token(self):
+ token_id = uuid.uuid4().hex
+
+ @webob.dec.wsgify
+ def _do_cb(req):
+ self.assertEqual('Invalid',
+ req.headers['X-Service-Identity-Status'])
+ self.assertEqual(token_id, req.headers['X-Service-Token'])
+ return webob.Response()
+
+ m = FetchingMiddleware(_do_cb)
+ self.call(m, headers={'X-Service-Token': token_id})
+
+ def test_expired_service_token(self):
+ t = fixture.V3Token()
+ t.set_project_scope()
+ t.expires = datetime.datetime.utcnow() - datetime.timedelta(minutes=10)
+
+ token_id = uuid.uuid4().hex
+ token_dict = {token_id: t}
+
+ @webob.dec.wsgify
+ def _do_cb(req):
+ self.assertEqual('Invalid',
+ req.headers['X-Service-Identity-Status'])
+ self.assertEqual(token_id, req.headers['X-Service-Token'])
+ return webob.Response()
+
+ m = FetchingMiddleware(_do_cb, token_dict=token_dict)
+ self.call(m, headers={'X-Service-Token': token_id})