diff options
author | Jamie Lennox <jamielennox@redhat.com> | 2015-02-19 15:21:55 +1100 |
---|---|---|
committer | Jamie Lennox <jamielennox@redhat.com> | 2015-02-23 14:20:29 +1100 |
commit | 96579f7c26efbf1c4fd8c5b326cc9288b17525e4 (patch) | |
tree | b281c2ff94c869b41117f29d7cbe4788dd96a7a2 | |
parent | 782fb0129d2eb7f181f890068767ce2b6906b2bd (diff) | |
download | keystonemiddleware-96579f7c26efbf1c4fd8c5b326cc9288b17525e4.tar.gz |
Separate exceptions into their own file
Extract all the common exceptions from auth_token middleware and put it
into its own file. This is first to prove the concept and as exceptions
will be the most shared component of the other modules.
Change-Id: I5436404788d38c0fee87960139a413af780f0c34
Implements: bp refactor-extract-module
-rw-r--r-- | keystonemiddleware/auth_token/__init__.py | 106 | ||||
-rw-r--r-- | keystonemiddleware/auth_token/_exceptions.py | 27 | ||||
-rw-r--r-- | keystonemiddleware/tests/auth_token/test_auth_token_middleware.py | 43 | ||||
-rw-r--r-- | keystonemiddleware/tests/unit/test_auth_token.py | 3 |
4 files changed, 100 insertions, 79 deletions
diff --git a/keystonemiddleware/auth_token/__init__.py b/keystonemiddleware/auth_token/__init__.py index 0044bff..ed0a5b6 100644 --- a/keystonemiddleware/auth_token/__init__.py +++ b/keystonemiddleware/auth_token/__init__.py @@ -195,6 +195,7 @@ import six from six.moves import urllib from keystonemiddleware import _memcache_crypt as memcache_crypt +from keystonemiddleware.auth_token import _exceptions as exc from keystonemiddleware.i18n import _, _LC, _LE, _LI, _LW from keystonemiddleware.openstack.common import memorycache @@ -396,13 +397,13 @@ def _token_is_v3(token_info): def _get_token_expiration(data): if not data: - raise InvalidToken(_('Token authorization failed')) + raise exc.InvalidToken(_('Token authorization failed')) if _token_is_v2(data): return data['access']['token']['expires'] elif _token_is_v3(data): return data['token']['expires_at'] else: - raise InvalidToken(_('Token authorization failed')) + raise exc.InvalidToken(_('Token authorization failed')) def _confirm_token_not_expired(expires): @@ -410,7 +411,7 @@ def _confirm_token_not_expired(expires): expires = timeutils.normalize_time(expires) utcnow = timeutils.utcnow() if utcnow >= expires: - raise InvalidToken(_('Token authorization failed')) + raise exc.InvalidToken(_('Token authorization failed')) def _v3_to_v2_catalog(catalog): @@ -478,29 +479,13 @@ def _conf_values_type_convert(conf): # This option is not known to auth_token. pass except ValueError as e: - raise ConfigurationError( + raise exc.ConfigurationError( _('Unable to convert the value of %(key)s option into correct ' 'type: %(ex)s') % {'key': k, 'ex': e}) opts[dest] = v return opts -class InvalidToken(Exception): - pass - - -class ServiceError(Exception): - pass - - -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 @@ -931,7 +916,7 @@ class AuthProtocol(object): user_headers = self._build_user_headers(user_auth_ref, user_token_info) self._add_headers(env, user_headers) - except InvalidToken: + except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid user token - deferring reject ' @@ -953,7 +938,7 @@ class AuthProtocol(object): auth_token=serv_token) serv_headers = self._build_service_headers(serv_token_info) self._add_headers(env, serv_headers) - except InvalidToken: + except exc.InvalidToken: # Delayed auth not currently supported for service tokens. # (Can be implemented if a use case is found.) self._LOG.info( @@ -963,7 +948,7 @@ class AuthProtocol(object): env['keystone.token_auth'] = _UserAuthPlugin(user_auth_ref, serv_auth_ref) - except ServiceError as e: + except exc.ServiceError as e: self._LOG.critical(_LC('Unable to obtain admin token: %s'), e) return self._do_503_error(env, start_response) @@ -1014,7 +999,7 @@ class AuthProtocol(object): :param env: wsgi request environment :returns: token id - :raises InvalidToken: if no token is provided in request + :raises exc.InvalidToken: if no token is provided in request """ token = self._get_header(env, 'X-Auth-Token', @@ -1026,7 +1011,7 @@ class AuthProtocol(object): self._LOG.warn(_LW('Unable to find authentication token' ' in headers')) self._LOG.debug('Headers: %s', env) - raise InvalidToken(_('Unable to find token in headers')) + raise exc.InvalidToken(_('Unable to find token in headers')) def _get_service_token_from_header(self, env): """Get service token id from request. @@ -1062,7 +1047,7 @@ class AuthProtocol(object): :param env: wsgi environment :param retry: Ignored, as it is not longer relevant :returns: uncrypted body of the token if the token is valid - :raises InvalidToken: if token is rejected + :raises exc.InvalidToken: if token is rejected """ token_id = None @@ -1096,7 +1081,7 @@ class AuthProtocol(object): except exceptions.CertificateConfigError: self._LOG.warn(_LW('Fetch certificate config failed, ' 'fallback to online validation.')) - except RevocationListError: + except exc.RevocationListError: self._LOG.warn(_LW('Fetch revocation list failed, ' 'fallback to online validation.')) @@ -1115,15 +1100,15 @@ class AuthProtocol(object): except (exceptions.ConnectionRefused, exceptions.RequestTimeout): self._LOG.debug('Token validation failure.', exc_info=True) self._LOG.warn(_LW('Authorization failed for token')) - raise InvalidToken(_('Token authorization failed')) - except ServiceError: + raise exc.InvalidToken(_('Token authorization failed')) + except exc.ServiceError: raise except Exception: self._LOG.debug('Token validation failure.', exc_info=True) if token_id: self._token_cache.store_invalid(token_id) self._LOG.warn(_LW('Authorization failed for token')) - raise InvalidToken(_('Token authorization failed')) + raise exc.InvalidToken(_('Token authorization failed')) def _build_user_headers(self, auth_ref, token_info): """Convert token object into headers. @@ -1133,13 +1118,13 @@ class AuthProtocol(object): :param token_info: token object returned by identity server on authentication - :raises InvalidToken: when unable to parse token object + :raises exc.InvalidToken: when unable to parse token object """ roles = ','.join(auth_ref.role_names) if _token_is_v2(token_info) and not auth_ref.project_id: - raise InvalidToken(_('Unable to determine tenancy.')) + raise exc.InvalidToken(_('Unable to determine tenancy.')) rval = { 'X-Identity-Status': 'Confirmed', @@ -1170,13 +1155,13 @@ class AuthProtocol(object): :param token_info: token object returned by identity server on authentication - :raises InvalidToken: when unable to parse token object + :raises exc.InvalidToken: when unable to parse token object """ auth_ref = access.AccessInfo.factory(body=token_info) if _token_is_v2(token_info) and not auth_ref.project_id: - raise InvalidToken(_('Unable to determine service tenancy.')) + raise exc.InvalidToken(_('Unable to determine service tenancy.')) roles = ','.join(auth_ref.role_names) rval = { @@ -1223,7 +1208,7 @@ class AuthProtocol(object): if msg is False: msg = _('Token authorization failed') - raise InvalidToken(msg) + raise exc.InvalidToken(msg) def _confirm_token_bind(self, data, env): bind_mode = self._conf_get('enforce_token_bind') @@ -1340,7 +1325,7 @@ class AuthProtocol(object): return verified # TypeError If the signed_text is not zlib compressed except TypeError: - raise InvalidToken(signed_text) + raise exc.InvalidToken(signed_text) def _fetch_signing_cert(self): self._signing_directory.write_file( @@ -1562,7 +1547,7 @@ class _IdentityServer(object): ', '.join(versions)) msg = _('No compatible apis supported by server') - raise ServiceError(msg) + raise exc.ServiceError(msg) def verify_token(self, user_token, retry=True): """Authenticate user token with identity server. @@ -1572,8 +1557,8 @@ class _IdentityServer(object): user authentication when an indeterminate response is received. Optional. :returns: token object received from identity server on success - :raises InvalidToken: if token is rejected - :raises ServiceError: if unable to authenticate token + :raises exc.InvalidToken: if token is rejected + :raises exc.ServiceError: if unable to authenticate token """ user_token = _safe_quote(user_token) @@ -1598,7 +1583,7 @@ class _IdentityServer(object): if response.status_code == 200: return data - raise InvalidToken() + raise exc.InvalidToken() def fetch_revocation_list(self): try: @@ -1607,14 +1592,14 @@ class _IdentityServer(object): authenticated=True, endpoint_filter={'version': (2, 0)}) except exceptions.HTTPError as e: - raise RevocationListError(_('Failed to fetch token revocation ' - 'list: %d') % e.http_status) + msg = _('Failed to fetch token revocation list: %d') + raise exc.RevocationListError(msg % e.http_status) if response.status_code != 200: - raise RevocationListError(_('Unable to fetch token revocation ' - 'list.')) + msg = _('Unable to fetch token revocation list.') + raise exc.RevocationListError(msg) if 'signed' not in data: - raise RevocationListError(_('Revocation list improperly ' - 'formatted.')) + msg = _('Revocation list improperly formatted.') + raise exc.RevocationListError(msg) return data['signed'] def fetch_signing_cert(self): @@ -1792,7 +1777,7 @@ class _Revocations(object): def check(self, token_ids): if self._any_revoked(token_ids): self._log.debug('Token is marked as having been revoked') - raise InvalidToken(_('Token has been revoked')) + raise exc.InvalidToken(_('Token has been revoked')) class _SigningDirectory(object): @@ -1839,7 +1824,7 @@ class _SigningDirectory(object): def _verify_signing_dir(self): if os.path.isdir(self._directory_name): if not os.access(self._directory_name, os.W_OK): - raise ConfigurationError( + raise exc.ConfigurationError( _('unable to access signing_dir %s') % self._directory_name) uid = os.getuid() @@ -1935,7 +1920,7 @@ class _TokenCache(object): The second element is the token data from the cache if the token was cached, otherwise ``None``. - :raises InvalidToken: if the token is invalid + :raises exc.InvalidToken: if the token is invalid """ @@ -2028,7 +2013,7 @@ class _TokenCache(object): def _cache_get(self, token_id): """Return token information from cache. - If token is invalid raise InvalidToken + If token is invalid raise exc.InvalidToken return token only if fresh (not expired). """ @@ -2054,7 +2039,7 @@ class _TokenCache(object): cached = jsonutils.loads(data) if cached == self._INVALID_INDICATOR: self._LOG.debug('Cached Token is marked unauthorized') - raise InvalidToken(_('Token authorization failed')) + raise exc.InvalidToken(_('Token authorization failed')) data, expires = cached @@ -2073,7 +2058,7 @@ class _TokenCache(object): return data else: self._LOG.debug('Cached Token seems expired') - raise InvalidToken(_('Token authorization failed')) + raise exc.InvalidToken(_('Token authorization failed')) def _cache_store(self, token_id, data): """Store value into memcache. @@ -2105,12 +2090,12 @@ class _SecureTokenCache(_TokenCache): security_strategy = security_strategy.upper() if security_strategy not in ('MAC', 'ENCRYPT'): - raise ConfigurationError(_('memcache_security_strategy must be ' - 'ENCRYPT or MAC')) + msg = _('memcache_security_strategy must be ENCRYPT or MAC') + raise exc.ConfigurationError(msg) if not secret_key: - raise ConfigurationError(_('memcache_secret_key must be defined ' - 'when a memcache_security_strategy ' - 'is defined')) + msg = _('memcache_secret_key must be defined when a ' + 'memcache_security_strategy is defined') + raise exc.ConfigurationError(msg) if isinstance(security_strategy, six.string_types): security_strategy = security_strategy.encode('utf-8') @@ -2175,3 +2160,10 @@ if __name__ == '__main__': server = simple_server.make_server('', 8000, app) print('Serving on port 8000 (Ctrl+C to end)...') server.serve_forever() + + +# NOTE(jamielennox): Maintained here for public API compatibility. +InvalidToken = exc.InvalidToken +ServiceError = exc.ServiceError +ConfigurationError = exc.ConfigurationError +RevocationListError = exc.RevocationListError diff --git a/keystonemiddleware/auth_token/_exceptions.py b/keystonemiddleware/auth_token/_exceptions.py new file mode 100644 index 0000000..be045c9 --- /dev/null +++ b/keystonemiddleware/auth_token/_exceptions.py @@ -0,0 +1,27 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +class InvalidToken(Exception): + pass + + +class ServiceError(Exception): + pass + + +class ConfigurationError(Exception): + pass + + +class RevocationListError(Exception): + pass diff --git a/keystonemiddleware/tests/auth_token/test_auth_token_middleware.py b/keystonemiddleware/tests/auth_token/test_auth_token_middleware.py index 723a53e..99a01b1 100644 --- a/keystonemiddleware/tests/auth_token/test_auth_token_middleware.py +++ b/keystonemiddleware/tests/auth_token/test_auth_token_middleware.py @@ -43,6 +43,7 @@ import webob import webob.dec from keystonemiddleware import auth_token +from keystonemiddleware.auth_token import _exceptions as exc from keystonemiddleware.openstack.common import memorycache from keystonemiddleware.tests import client_fixtures from keystonemiddleware.tests import utils @@ -562,35 +563,35 @@ class GeneralAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, 'memcached_servers': ','.join(MEMCACHED_SERVERS), 'memcache_security_strategy': 'Encrypt' } - self.assertRaises(auth_token.ConfigurationError, self.set_middleware, + self.assertRaises(exc.ConfigurationError, self.set_middleware, conf=conf) # test invalue memcache_security_strategy conf = { 'memcached_servers': ','.join(MEMCACHED_SERVERS), 'memcache_security_strategy': 'whatever' } - self.assertRaises(auth_token.ConfigurationError, self.set_middleware, + self.assertRaises(exc.ConfigurationError, self.set_middleware, conf=conf) # test missing memcache_secret_key conf = { 'memcached_servers': ','.join(MEMCACHED_SERVERS), 'memcache_security_strategy': 'mac' } - self.assertRaises(auth_token.ConfigurationError, self.set_middleware, + self.assertRaises(exc.ConfigurationError, self.set_middleware, conf=conf) conf = { 'memcached_servers': ','.join(MEMCACHED_SERVERS), 'memcache_security_strategy': 'Encrypt', 'memcache_secret_key': '' } - self.assertRaises(auth_token.ConfigurationError, self.set_middleware, + self.assertRaises(exc.ConfigurationError, self.set_middleware, conf=conf) conf = { 'memcached_servers': ','.join(MEMCACHED_SERVERS), 'memcache_security_strategy': 'mAc', 'memcache_secret_key': '' } - self.assertRaises(auth_token.ConfigurationError, self.set_middleware, + self.assertRaises(exc.ConfigurationError, self.set_middleware, conf=conf) def test_config_revocation_cache_timeout(self): @@ -630,7 +631,7 @@ class GeneralAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, conf = { 'include_service_catalog': '123', } - self.assertRaises(auth_token.ConfigurationError, + self.assertRaises(exc.ConfigurationError, auth_token.AuthProtocol, self.fake_app, conf) @@ -844,7 +845,7 @@ class CommonAuthTokenMiddlewareTest(object): def test_verify_signed_token_raises_exception_for_revoked_token(self): self.middleware._revocations._list = ( self.get_revocation_list_json()) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self.middleware._verify_signed_token, self.token_dict['revoked_token'], [self.token_dict['revoked_token_hash']]) @@ -854,7 +855,7 @@ class CommonAuthTokenMiddlewareTest(object): self.set_middleware() self.middleware._revocations._list = ( self.get_revocation_list_json(mode='sha256')) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self.middleware._verify_signed_token, self.token_dict['revoked_token'], [self.token_dict['revoked_token_hash_sha256'], @@ -863,7 +864,7 @@ class CommonAuthTokenMiddlewareTest(object): def test_verify_signed_token_raises_exception_for_revoked_pkiz_token(self): self.middleware._revocations._list = ( self.examples.REVOKED_TOKEN_PKIZ_LIST_JSON) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self.middleware._verify_pkiz_token, self.token_dict['revoked_token_pkiz'], [self.token_dict['revoked_token_pkiz_hash']]) @@ -960,7 +961,7 @@ class CommonAuthTokenMiddlewareTest(object): def test_invalid_revocation_list_raises_error(self): self.requests.get('%s/v2.0/tokens/revoked' % BASE_URI, json={}) - self.assertRaises(auth_token.RevocationListError, + self.assertRaises(exc.RevocationListError, self.middleware._revocations._fetch) def test_fetch_revocation_list(self): @@ -1019,7 +1020,7 @@ class CommonAuthTokenMiddlewareTest(object): self.middleware._LOG = FakeLog() self.middleware._delay_auth_decision = False - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self.middleware._get_user_token_from_header, {}) self.assertIsNotNone(self.middleware._LOG.msg) self.assertIsNotNone(self.middleware._LOG.debugmsg) @@ -1067,7 +1068,7 @@ class CommonAuthTokenMiddlewareTest(object): token = 'invalid-token' req.headers['X-Auth-Token'] = token self.middleware(req.environ, self.start_fake_response) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self._get_cached_token, token) def _test_memcache_set_invalid_signed(self, hash_algorithms=None, @@ -1079,7 +1080,7 @@ class CommonAuthTokenMiddlewareTest(object): self.conf['hash_algorithms'] = ','.join(hash_algorithms) self.set_middleware() self.middleware(req.environ, self.start_fake_response) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self._get_cached_token, token, mode=exp_mode) def test_memcache_set_invalid_signed(self): @@ -1994,13 +1995,13 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): def test_no_data(self): data = {} - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, auth_token._get_token_expiration, data) def test_bad_data(self): data = {'my_happy_token_dict': 'woo'} - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, auth_token._get_token_expiration, data) @@ -2018,7 +2019,7 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): def test_v2_token_expired(self): data = self.create_v2_token_fixture(expires=self.one_hour_ago) expires = auth_token._get_token_expiration(data) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, auth_token._confirm_token_not_expired, expires) @@ -2035,7 +2036,7 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): data = self.create_v2_token_fixture( expires='1999-12-31T19:05:10Z') expires = auth_token._get_token_expiration(data) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, auth_token._confirm_token_not_expired, expires) @@ -2053,7 +2054,7 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): def test_v3_token_expired(self): data = self.create_v3_token_fixture(expires=self.one_hour_ago) expires = auth_token._get_token_expiration(data) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, auth_token._confirm_token_not_expired, expires) @@ -2071,7 +2072,7 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): data = self.create_v3_token_fixture( expires='1999-12-31T19:05:10Z') expires = auth_token._get_token_expiration(data) - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, auth_token._confirm_token_not_expired, expires) @@ -2112,7 +2113,7 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): expires = some_time_earlier self.middleware._token_cache.store(token, data, expires) self.assertThat(lambda: self.middleware._token_cache._cache_get(token), - matchers.raises(auth_token.InvalidToken)) + matchers.raises(exc.InvalidToken)) def test_cached_token_with_timezone_offset_not_expired(self): token = 'mytoken' @@ -2135,7 +2136,7 @@ class TokenExpirationTest(BaseAuthTokenMiddlewareTest): expires = timeutils.strtime(some_time_earlier) + '-02:00' self.middleware._token_cache.store(token, data, expires) self.assertThat(lambda: self.middleware._token_cache._cache_get(token), - matchers.raises(auth_token.InvalidToken)) + matchers.raises(exc.InvalidToken)) class CatalogConversionTests(BaseAuthTokenMiddlewareTest): diff --git a/keystonemiddleware/tests/unit/test_auth_token.py b/keystonemiddleware/tests/unit/test_auth_token.py index 1041f43..a909be7 100644 --- a/keystonemiddleware/tests/unit/test_auth_token.py +++ b/keystonemiddleware/tests/unit/test_auth_token.py @@ -23,6 +23,7 @@ import mock import testtools from keystonemiddleware import auth_token +from keystonemiddleware.auth_token import _exceptions as exc class RevocationsTests(testtools.TestCase): @@ -61,7 +62,7 @@ class RevocationsTests(testtools.TestCase): token_id = uuid.uuid4().hex revoked_tokens = [token_id] token_ids = [token_id] - self.assertRaises(auth_token.InvalidToken, + self.assertRaises(exc.InvalidToken, self._check_with_list, revoked_tokens, token_ids) |