diff options
author | Morgan Fainberg <morgan.fainberg@gmail.com> | 2015-05-29 17:43:31 -0700 |
---|---|---|
committer | Morgan Fainberg <morgan.fainberg@gmail.com> | 2015-06-12 10:36:56 +0200 |
commit | 2d4e19404aa33200767dab86956608878876b03a (patch) | |
tree | 279b637e80a03269a27f7ea4570d21e643b471a8 | |
parent | 666150149889d1d167fb3fba06d43f4b07809503 (diff) | |
download | keystonemiddleware-2.0.0.tar.gz |
Ensure cache keys are a known/fixed length2.0.0
Do not assume a token_id will result in a sane length for a memcache
key length. In cases such as Fernet, these ids can easily exceed the
limit on memcache key size. This change ensures we always use a SHA256
of the token id passed in, resulting in a fixed length cache key.
Change-Id: I550e0a1b190047438756bbf40490815a5f177ea7
Closes-Bug: #1460225
-rw-r--r-- | keystonemiddleware/auth_token/_cache.py | 19 | ||||
-rw-r--r-- | keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py | 15 |
2 files changed, 33 insertions, 1 deletions
diff --git a/keystonemiddleware/auth_token/_cache.py b/keystonemiddleware/auth_token/_cache.py index dbcdebf..ce5faf6 100644 --- a/keystonemiddleware/auth_token/_cache.py +++ b/keystonemiddleware/auth_token/_cache.py @@ -11,6 +11,7 @@ # under the License. import contextlib +import hashlib from oslo_serialization import jsonutils import six @@ -21,6 +22,22 @@ from keystonemiddleware.i18n import _, _LE from keystonemiddleware.openstack.common import memorycache +def _hash_key(key): + """Turn a set of arguments into a SHA256 hash. + + Using a known-length cache key is important to ensure that memcache + maximum key length is not exceeded causing failures to validate. + """ + if isinstance(key, six.text_type): + # NOTE(morganfainberg): Ensure we are always working with a bytes + # type required for the hasher. In python 2.7 it is possible to + # get a text_type (unicode). In python 3.4 all strings are + # text_type and not bytes by default. This encode coerces the + # text_type to the appropriate bytes values. + key = key.encode('utf-8') + return hashlib.sha256(key).hexdigest() + + class _CachePool(list): """A lazy pool of cache references.""" @@ -178,7 +195,7 @@ class TokenCache(object): # NOTE(jamielennox): in the basic implementation there is no need for # a context so just pass None as it will only get passed back later. unused_context = None - return self._CACHE_KEY_TEMPLATE % token_id, unused_context + return self._CACHE_KEY_TEMPLATE % _hash_key(token_id), unused_context def _deserialize(self, data, context): """Deserialize data from the cache back into python objects. diff --git a/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py b/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py index 7b3d574..8657deb 100644 --- a/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py +++ b/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py @@ -500,6 +500,21 @@ class GeneralAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, token_response = self.examples.TOKEN_RESPONSES[token] self.assertTrue(auth_token._token_is_v3(token_response)) + def test_fixed_cache_key_length(self): + self.set_middleware() + short_string = uuid.uuid4().hex + long_string = 8 * uuid.uuid4().hex + + token_cache = self.middleware._token_cache + hashed_short_string_key, context_ = token_cache._get_cache_key( + short_string) + hashed_long_string_key, context_ = token_cache._get_cache_key( + long_string) + + # The hash keys should always match in length + self.assertThat(hashed_short_string_key, + matchers.HasLength(len(hashed_long_string_key))) + @testtools.skipUnless(memcached_available(), 'memcached not available') def test_encrypt_cache_data(self): conf = { |