Don't cache tokens as invalid on network errors

Closes-Bug: 1172802
Change-Id: Ifc04f565b96d58a7a2f477a216b57af7f8de6a8e
This commit is contained in:
Chmouel Boudjnah
2013-08-07 07:22:13 +02:00
parent 648c4b5e2f
commit aeffdc8929
2 changed files with 32 additions and 3 deletions

View File

@@ -251,6 +251,10 @@ class ConfigurationError(Exception):
pass
class NetworkError(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
@@ -363,6 +367,7 @@ class AuthProtocol(object):
self.http_connect_timeout = (http_connect_timeout_cfg and
int(http_connect_timeout_cfg))
self.auth_version = None
self.http_request_max_retries = 3
def _assert_valid_memcache_protection_config(self):
if self._memcache_security_strategy:
@@ -594,9 +599,8 @@ class AuthProtocol(object):
"""
conn = self._get_http_connection()
RETRIES = 3
RETRIES = self.http_request_max_retries
retry = 0
while True:
try:
conn.request(method, path, **kwargs)
@@ -606,7 +610,7 @@ class AuthProtocol(object):
except Exception as e:
if retry == RETRIES:
self.LOG.error('HTTP connection exception: %s' % e)
raise ServiceError('Unable to communicate with keystone')
raise NetworkError('Unable to communicate with keystone')
# NOTE(vish): sleep 0.5, 1, 2
self.LOG.warn('Retrying on HTTP connection exception: %s' % e)
time.sleep(2.0 ** retry / 2)
@@ -717,6 +721,10 @@ class AuthProtocol(object):
expires = self._confirm_token_not_expired(data)
self._cache_put(token_id, data, expires)
return data
except NetworkError as e:
self.LOG.debug('Token validation failure.', exc_info=True)
self.LOG.warn("Authorization failed for token %s", user_token)
raise InvalidUserToken('Token authorization failed')
except Exception as e:
self.LOG.debug('Token validation failure.', exc_info=True)
self._cache_store_invalid(user_token)

View File

@@ -556,6 +556,13 @@ class RaisingHTTPConnection(FakeHTTPConnection):
raise AssertionError("HTTP request was called.")
class RaisingHTTPNetworkError(FakeHTTPConnection):
"""An HTTPConnection that always raises network error."""
def request(self, method, path, **kwargs):
raise auth_token.NetworkError("Network connection error.")
class FakeApp(object):
"""This represents a WSGI app protected by the auth_token middleware."""
def __init__(self, expected_env=None):
@@ -1211,6 +1218,20 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest):
self.assertEquals(middleware.token_revocation_list_cache_timeout,
datetime.timedelta(seconds=24))
def test_http_error_not_cached_token(self):
"""Test to don't cache token as invalid on network errors.
We use UUID tokens since they are the easiest one to reach
get_http_connection.
"""
req = webob.Request.blank('/')
token = self.token_dict['uuid_token_default']
req.headers['X-Auth-Token'] = token
self.set_fake_http(RaisingHTTPNetworkError)
self.middleware.http_request_max_retries = 0
self.middleware(req.environ, self.start_fake_response)
self.assertEqual(self._get_cached_token(token), None)
class CertDownloadMiddlewareTest(BaseAuthTokenMiddlewareTest):
def setUp(self):