diff options
author | wanghong <w.wanghong@huawei.com> | 2014-10-27 15:12:05 +0800 |
---|---|---|
committer | wanghong <w.wanghong@huawei.com> | 2014-12-17 16:39:26 +0800 |
commit | 136f85c01ad4da01f9e073619f22eed5ca2378cc (patch) | |
tree | 0c1336d5dfe1d0858cff1fed62a0b1e4a38212c0 | |
parent | 0bd661fcbb423b2225acc40131088da46969e574 (diff) | |
download | keystonemiddleware-136f85c01ad4da01f9e073619f22eed5ca2378cc.tar.gz |
fallback to online validation if offline validation fails
Authmiddleware should fallback to purely online validation when
fetching certificate config failed or fetching revocation list failed.
Change-Id: I532e667cc26bbeb9bbd03605b9fb7ea7ebf14afa
Closes-Bug: #1384898
-rw-r--r-- | keystonemiddleware/auth_token.py | 37 | ||||
-rw-r--r-- | keystonemiddleware/tests/test_auth_token_middleware.py | 29 |
2 files changed, 52 insertions, 14 deletions
diff --git a/keystonemiddleware/auth_token.py b/keystonemiddleware/auth_token.py index 5d407c8..eef430e 100644 --- a/keystonemiddleware/auth_token.py +++ b/keystonemiddleware/auth_token.py @@ -498,6 +498,10 @@ class ConfigurationError(Exception): pass +class RevocationListError(Exception): + pass + + class _MiniResp(object): def __init__(self, error_message, env, headers=[]): # The HEAD method is unique: it must never return a body, even if @@ -947,19 +951,26 @@ class AuthProtocol(object): _('Token authorization failed')) self._confirm_token_bind(data, env) else: + verified = None # Token wasn't cached. In this case, the token needs to be # checked that it's not expired, and also put in the cache. - if cms.is_pkiz(token): - verified = self._verify_pkiz_token(token, token_ids) - data = jsonutils.loads(verified) - expires = _confirm_token_not_expired(data) - elif cms.is_asn1_token(token): - verified = self._verify_signed_token(token, token_ids) + try: + if cms.is_pkiz(token): + verified = self._verify_pkiz_token(token, token_ids) + elif cms.is_asn1_token(token): + verified = self._verify_signed_token(token, token_ids) + except exceptions.CertificateConfigError: + self._LOG.warn(_LW('Fetch certificate config failed, ' + 'fallback to online validation.')) + except RevocationListError: + self._LOG.warn(_LW('Fetch revocation list failed, ' + 'fallback to online validation.')) + + if verified is not None: data = jsonutils.loads(verified) expires = _confirm_token_not_expired(data) else: - data = self._identity_server.verify_token(token, - retry) + data = self._identity_server.verify_token(token, retry) # No need to confirm token expiration here since # verify_token fails for expired tokens. expires = _get_token_expiration(data) @@ -1549,12 +1560,14 @@ class _IdentityServer(object): authenticated=True, endpoint_filter={'version': (2, 0)}) except exceptions.HTTPError as e: - raise ServiceError(_('Failed to fetch token revocation list: %d') % - e.http_status) + raise RevocationListError(_('Failed to fetch token revocation ' + 'list: %d') % e.http_status) if response.status_code != 200: - raise ServiceError(_('Unable to fetch token revocation list.')) + raise RevocationListError(_('Unable to fetch token revocation ' + 'list.')) if 'signed' not in data: - raise ServiceError(_('Revocation list improperly formatted.')) + raise RevocationListError(_('Revocation list improperly ' + 'formatted.')) return data['signed'] def fetch_signing_cert(self): diff --git a/keystonemiddleware/tests/test_auth_token_middleware.py b/keystonemiddleware/tests/test_auth_token_middleware.py index f35af8a..c5240b5 100644 --- a/keystonemiddleware/tests/test_auth_token_middleware.py +++ b/keystonemiddleware/tests/test_auth_token_middleware.py @@ -938,10 +938,10 @@ class CommonAuthTokenMiddlewareTest(object): self.assertEqual(self.middleware._token_revocation_list, in_memory_list) - def test_invalid_revocation_list_raises_service_error(self): + def test_invalid_revocation_list_raises_error(self): self.requests.get('%s/v2.0/tokens/revoked' % BASE_URI, json={}) - self.assertRaises(auth_token.ServiceError, + self.assertRaises(auth_token.RevocationListError, self.middleware._fetch_revocation_list) def test_fetch_revocation_list(self): @@ -1796,6 +1796,31 @@ class v3AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, self.assertIn('publicURL', endpoint) self.assertIn('adminURL', endpoint) + def test_fallback_to_online_validation_with_signing_error(self): + self.requests.register_uri( + 'GET', + '%s/v3/OS-SIMPLE-CERT/certificates' % BASE_URI, + status_code=404) + self.assert_valid_request_200(self.token_dict['signed_token_scoped']) + self.assert_valid_request_200( + self.token_dict['signed_token_scoped_pkiz']) + + def test_fallback_to_online_validation_with_ca_error(self): + self.requests.register_uri('GET', + '%s/v3/OS-SIMPLE-CERT/ca' % BASE_URI, + status_code=404) + self.assert_valid_request_200(self.token_dict['signed_token_scoped']) + self.assert_valid_request_200( + self.token_dict['signed_token_scoped_pkiz']) + + def test_fallback_to_online_validation_with_revocation_list_error(self): + self.requests.register_uri('GET', + '%s/v2.0/tokens/revoked' % BASE_URI, + status_code=404) + self.assert_valid_request_200(self.token_dict['signed_token_scoped']) + self.assert_valid_request_200( + self.token_dict['signed_token_scoped_pkiz']) + class TokenEncodingTest(testtools.TestCase): def test_unquoted_token(self): |