diff options
-rw-r--r-- | dev-python/python-keystoneclient/ChangeLog | 10 | ||||
-rw-r--r-- | dev-python/python-keystoneclient/Manifest | 37 | ||||
-rw-r--r-- | dev-python/python-keystoneclient/files/0.2.4-CVE-2013-2166-7.patch | 745 | ||||
-rw-r--r-- | dev-python/python-keystoneclient/python-keystoneclient-0.2.5.ebuild (renamed from dev-python/python-keystoneclient/python-keystoneclient-0.2.4-r2.ebuild) | 3 | ||||
-rw-r--r-- | dev-python/python-keystoneclient/python-keystoneclient-0.3.1.ebuild | 57 |
5 files changed, 86 insertions, 766 deletions
diff --git a/dev-python/python-keystoneclient/ChangeLog b/dev-python/python-keystoneclient/ChangeLog index 20e5ea86f42f..1364992e185b 100644 --- a/dev-python/python-keystoneclient/ChangeLog +++ b/dev-python/python-keystoneclient/ChangeLog @@ -1,6 +1,14 @@ # ChangeLog for dev-python/python-keystoneclient # Copyright 1999-2013 Gentoo Foundation; Distributed under the GPL v2 -# $Header: /var/cvsroot/gentoo-x86/dev-python/python-keystoneclient/ChangeLog,v 1.12 2013/06/20 14:39:43 prometheanfire Exp $ +# $Header: /var/cvsroot/gentoo-x86/dev-python/python-keystoneclient/ChangeLog,v 1.13 2013/08/11 01:54:05 prometheanfire Exp $ + +*python-keystoneclient-0.3.1 (11 Aug 2013) +*python-keystoneclient-0.2.5 (11 Aug 2013) + + 11 Aug 2013; Matthew Thode <prometheanfire@gentoo.org> + +python-keystoneclient-0.2.5.ebuild, +python-keystoneclient-0.3.1.ebuild, + -files/0.2.4-CVE-2013-2166-7.patch, -python-keystoneclient-0.2.4-r2.ebuild: + just an update for keystoneclient *python-keystoneclient-0.2.4-r2 (20 Jun 2013) diff --git a/dev-python/python-keystoneclient/Manifest b/dev-python/python-keystoneclient/Manifest index 409dbd73ff12..babf01679142 100644 --- a/dev-python/python-keystoneclient/Manifest +++ b/dev-python/python-keystoneclient/Manifest @@ -1,26 +1,27 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 -AUX 0.2.4-CVE-2013-2166-7.patch 30702 SHA256 a9863655ad76d7bd7076b8fa310411ac513f7b5b6f29f817c63c00c2116f34ef SHA512 fc0168eab4eda0c5286a6b8a9ab0976256a1da5b878c9fdbc5ebdcd9d1ef1bd41c95b7bce8f39716b6e27f6fad1d3e8b3d0c8c8f0c2f2306a3ae8f4073ebf9b1 WHIRLPOOL 8cb13c57409549475fa66277a85fe9f15d776f00472bc3de03b633877ceb2332136281b8012331e87118a271e84a43549f6ca53409b5d14ab4b6de31dca09517 -DIST python-keystoneclient-0.2.4.tar.gz 194758 SHA256 1286a32cc08436410e00704177e3e5ced6ba88ac4eab62a6a55cbad7cadc6cc0 SHA512 e064e9fa7118f300467910b33fa693842db10326dd3c75701fba7edb76896c1fedbec8fbbe2f56e7260ecbfe35b4ee9fac463fcc0f93e47496a57516f708a472 WHIRLPOOL dad8fec545130c74780d1eff49642c8e0b48914a16e9ee4e7215a12d3e3a488c7b85c7d837d041caae8a7ca54570ba750f435e4c718479e8aa9abdaedf33ad6a -EBUILD python-keystoneclient-0.2.4-r2.ebuild 2054 SHA256 11e77804df0d43d63361b51f323b40982c1940c53c6cc22e99b5aa45edd69925 SHA512 784227bff389f210ca9df967aa0a1fa8c80ceb03c73c3e268edd0b7c6fcdf29ab5a5c3e408f9b183dc6d3f3d107c79318149809f8cfc7c8654db63edeeabda7d WHIRLPOOL 89f7f73d30ed2825923def6cee9040f0241e40b798ae7de9977db28d7fdfa5376305936f3dcbf4b7585b3108df76fbbfbd93e6a44f0d9338b0d5d6d37909de66 +DIST python-keystoneclient-0.2.5.tar.gz 196496 SHA256 3985ab402b3b63510f387df639658687ee001c047ed710bee9a46219ebc31e2b SHA512 2c14d039a80a8b8ac65c974410722b5726b2f0f94c238b60ac93d09828abcf4518cec16af10387ccaa5e1639a5c9e168afa32623e507899c8486152c3d785c8b WHIRLPOOL aa82ee7f157c8573978b04b485068cc5d3f3f8bcfc4e573b8ed631b23ca3ffd8eb47830449c13da5e93e674c42a23c1efb072ffd5005c93a3c6f84a12e1b4063 +DIST python-keystoneclient-0.3.1.tar.gz 209845 SHA256 bfc149b2d161bfe168be0fde41d9e75f2c0a99b9f398672f92c7c54c6f62fa26 SHA512 e79a4ab0b8e2c99a94efd6bf6690abd15cf41ea6b4e605c1a3534ee9788cb38239b6cd43e2956bd513b1149ab359af63eb46c7a61a9ebe3f3c1005068a7533de WHIRLPOOL ab4636f77e8de91fe38718f3f43a9f81d4bde69ed02710fe0d02ce1e8965f728c53fff6f28780981e7303c16fe43a33c9c30ac21a7cb1cfc8a2e855bc47c1f36 +EBUILD python-keystoneclient-0.2.5.ebuild 2008 SHA256 bf8a08c00c628ff38a4fa302ef4c14da80280f37fb6bde99be87eda903291825 SHA512 d8c1c1ea5fc98cbb1796651fcdf711a0a70102756285e79214f0cd24a39a56a266a92844b7f7872a005f15578f019f16676b4d44342b0429fdd7669063c463c4 WHIRLPOOL 4552217863d7c9368d9293fc5f9ad2a8d8aa96165f920aba62e6345f632bceb8f63d72bbc0774bc08bef60aed8afd38ae83f12f9dd7756b3d7050e00796ab715 +EBUILD python-keystoneclient-0.3.1.ebuild 2050 SHA256 54af41db1b51e6ee3daff919e37ad93df7891db3bb9bdd0b6aacbb91d4dcc6b6 SHA512 f44edfe1c935c23288d53f178ad92f6c4c95546d7f9b5608a7abb496f98add622b56b1baa83a64a476dbe06f4f973a049e5bb2d2c5ed58da0b9739f97c28717f WHIRLPOOL 6dcedbf4890949e1db271088a4f000413b6f3510b3fda22a548bb8b20fb178c92796fa94b6f60c361310c15584184698487e7bfd987fd52a0f006d9c06f223c4 EBUILD python-keystoneclient-9999.ebuild 1597 SHA256 0062df58f82beaaa54dd279e7a95ae8540c51cc1a2bb32e4621ae96cf2508216 SHA512 6de16b203f9cdf88cad8c8c19c99bfd1f243de807971ca2292437074b147f02476d526974cab64b8f881afb6e2c8f19938966f5322eed50b95c5a95de25461e0 WHIRLPOOL 8d26907ba7ac0e570a3fa245b8d2e04d5285c4ff02c2ecafd7fa9cf9cd4b3a6b938abfe9efb925e02b5733320a4cb05b2fb1aca005ca5ffd0f19ab4d19db58a4 -MISC ChangeLog 3433 SHA256 e095b5bfd2dd1fa7b0b6cfe2d342a6093d21db310ca66d39273206fd54bf294e SHA512 ce0268a41f621ff939725e429d239a4069f776f912399c125db54e8d2ff2a49c4b072376b18ac76cd3cd94812cf9f5b1b9176f392c262c0357668a1b7bde7baa WHIRLPOOL 8d856cf253c380aac1bf1bf27f2f99a5a4c31ed2f479facb926350d6cbaef6c54a9a55763cabe8c1da51762b97290b03fdd2aadfcc537219ff9d95980ee72035 +MISC ChangeLog 3768 SHA256 a05f96cbfc0e227f365c7967afd514f4e510f100cbaa90a423c96ebdbc231c3f SHA512 bb1aba8322102ecad7e5bc1d362c43c75a6dbdab1934f2ed0ccb2d19d342b6e05ad47bd52095dd35d61a539585d451c3bd5b23bf6cd03e3c359fc14c3bc68b28 WHIRLPOOL 575f0b9b96e56589790ea251bdec100f8a7cfaee13a66f590053d85ae1d697c74ed4d3b901f09e23e982bd813db4983c23f185d002ec4f646b68629ebfb8bb52 MISC metadata.xml 343 SHA256 716e96a66916d216f80e7ce0283db63bd6d18a95e2365d9d1a35964b2ef461f9 SHA512 fd28e5434f725af6a835205ae8cfae1354983f8e68f6c25f9a4f56ec17041ac9bb1a460ff8e82d0e165ab19c5b0f26e0f0c8c5124dfcc37723c786e12cd4d3bf WHIRLPOOL b486328b67aa7f6e4b68adc757bf5d3983077a894d7ded68be7723fe5655805324a73e5914fda0f81ae334e75db9557e2675a43e9437df633311590758466c5c -----BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.19 (GNU/Linux) +Version: GnuPG v2.0.20 (GNU/Linux) -iQIcBAEBCAAGBQJRwxRaAAoJECRx6z5ArFrDC1sP/3/D1vfg7puyzTPMf/dYGQfg -QzAKDmh9l7Ed3GfzfJYQToG4wk1LvstO2yOIXUr15v4Zdz6VteiEoj5jGwbCuqID -1jdSyzcHUWsSJm7DanVA9ZS+PiCeAqkSwp9/4EyAa+JbFVVpXIGaW1HbytQo5Ubh -rJSlV+n/ZIX5kqSFECRRUafBXchf+KHAqigK8Ty3XhyI7P/DHRBwP8TSpynQVsuo -IJSTkisSgzh0PpysF8xxncBoul4utesdJ4yjX9vU6luw0iXh+UfJAyeE8C8rg8RC -/0tSeZwkZvqBxhp4CqJtc9qIrDErh2OkJzU+3LS3xeli34i59lsbe9LFgOlve1ig -EYXiOZBQAuMvGP4iBIw8V7zU6gNeZPH53++p8YQqIlwwYgXKQrQ8dFaafpF/dkaF -8AOj85Nq2rURnEK2p7t2Bl/lxcXVLfbnC/RKyacF01DihAeoGwhqrdwtQaHKtTIy -rUqPay3MKwqOIC4ao4sOOX9mVvhOsGIi9SRsX6Bk8fFKAsWawxH31rPI3lFLRyPR -6PMZvHwR3HTKNWDe3wmGXnjXsRhPxuP5LYENvvrUWs3LzoBvEmeEGlzlwz1RNKEq -mClAfvzqJVRe3IOzgI44nNNy3z55/yffMqFnwNcXqT6S2PxHSfzVCnsyWeb2KNgq -yXVDU07YEaaptSwvRP2D -=nJfd +iQIcBAEBCAAGBQJSBu75AAoJECRx6z5ArFrDreMQALELned4fi7OeJQA2wMGMRSf +vOHQvvY1YtXJVUiBAJt4e3kYWVV3Z0MXhnvvGhFbVSDOg1CbYLooi3VoBYSH+Oem +grJU1huIfLZmwA0R1rU68ens2OE5k07Ku+QQCDTBIt38TtQYHpqTexi0L35R9awy +To2ruvcntfVOKPVjhEjFPxbITqyNYK0NEN5CLoTNhDtdp0OLswezMW73cZuQaELF +kRvaGo1wdLLA6LVOXyj1sgXFStsKxooOdMG6nOexGCZMXc0omzkS9BZ5uIMnqgbM +Hwkg0+Qi1+LSHWWcxdnye9Lavm3k7ADs2kicetgul5vX9EdCTVer7zLkqWH2AtCS ++w30a7jZAs4yYD4KBja7asWtF4/VMePso2rkA1+nxQPTSZ0Dvx+EYhdJ4PJel5p8 +Wm82IzLMsZ7l8MSh+dtIeml0PDfdOEwh/PiMk1VbsU/Jl/2oqUfGunbjU4dQ9MeR +GaBtbhvkYU7UjE+jkXN8qaPC2G0P7iAuXZZI+6Jjm9R7ItImOqRo5YfvB+AYKwmN +GxfCM8m9UuPNRTshYOC9V8w3q0MLgnXRLqLQtcsX+ksr48r19bQqickq2GWHUinL +38gChfrjxwvtX/YGdhD1D1FAAD3xlzmst01ZKdOQ2+3D/veJ2GteZtcyqWaqKtvM +xkfNbjE+brKSxtkXy477 +=j/bp -----END PGP SIGNATURE----- diff --git a/dev-python/python-keystoneclient/files/0.2.4-CVE-2013-2166-7.patch b/dev-python/python-keystoneclient/files/0.2.4-CVE-2013-2166-7.patch deleted file mode 100644 index 4d5b160a95d8..000000000000 --- a/dev-python/python-keystoneclient/files/0.2.4-CVE-2013-2166-7.patch +++ /dev/null @@ -1,745 +0,0 @@ -From eeefb784f24c37d5f56a421e1ccc911cace9385e Mon Sep 17 00:00:00 2001 -From: "Bryan D. Payne" <bdpayne@acm.org> -Date: Fri, 7 Jun 2013 09:34:25 -0700 -Subject: [PATCH] Fix memcache encryption middleware - -This fixes lp1175367 and lp1175368 by redesigning the memcache crypt -middleware to not do dangerous things. It is forward compatible, but -will invalidate any existing ephemeral encrypted or signed memcache -entries. - -Change-Id: Ice8724949a48bfad3b8b7c41b5f50a18a9ad9f42 -Signed-off-by: Bryan D. Payne <bdpayne@acm.org> ---- - doc/source/middlewarearchitecture.rst | 37 +++--- - keystoneclient/middleware/auth_token.py | 131 +++++++++--------- - keystoneclient/middleware/memcache_crypt.py | 197 +++++++++++++++++----------- - tests/test_auth_token_middleware.py | 89 +++---------- - tests/test_memcache_crypt.py | 96 ++++++++------ - 5 files changed, 277 insertions(+), 273 deletions(-) - -diff --git a/doc/source/middlewarearchitecture.rst b/doc/source/middlewarearchitecture.rst -index 803fbd9..894d40d 100644 ---- a/doc/source/middlewarearchitecture.rst -+++ b/doc/source/middlewarearchitecture.rst -@@ -1,5 +1,5 @@ - .. -- Copyright 2011-2012 OpenStack, LLC -+ Copyright 2011-2013 OpenStack, LLC - All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); you may -@@ -188,7 +188,8 @@ Configuration Options - the timeout when validating token by http). - * ``auth_port``: (optional, default `35357`) the port used to validate tokens - * ``auth_protocol``: (optional, default `https`) --* ``auth_uri``: (optional, defaults to `auth_protocol`://`auth_host`:`auth_port`) -+* ``auth_uri``: (optional, defaults to -+ `auth_protocol`://`auth_host`:`auth_port`) - * ``certfile``: (required, if Keystone server requires client cert) - * ``keyfile``: (required, if Keystone server requires client cert) This can be - the same as the certfile if the certfile includes the private key. -@@ -232,22 +233,24 @@ Memcache Protection - =================== - - When using memcached, we are storing user tokens and token validation --information into the cache as raw data. Which means anyone who have access --to the memcache servers can read and modify data stored there. To mitigate --this risk, ``auth_token`` middleware provides an option to either encrypt --or authenticate the token data stored in the cache. -- --* ``memcache_security_strategy``: (optional) if defined, indicate whether token -- data should be encrypted or authenticated. Acceptable values are ``ENCRYPT`` -- or ``MAC``. If ``ENCRYPT``, token data is encrypted in the cache. If -- ``MAC``, token data is authenticated (with HMAC) in the cache. If its value -- is neither ``MAC`` nor ``ENCRYPT``, ``auth_token`` will raise an exception -- on initialization. -+information into the cache as raw data. Which means that anyone who -+has access to the memcache servers can read and modify data stored -+there. To mitigate this risk, ``auth_token`` middleware provides an -+option to authenticate and optionally encrypt the token data stored in -+the cache. -+ -+* ``memcache_security_strategy``: (optional) if defined, indicate -+ whether token data should be authenticated or authenticated and -+ encrypted. Acceptable values are ``MAC`` or ``ENCRYPT``. If ``MAC``, -+ token data is authenticated (with HMAC) in the cache. If -+ ``ENCRYPT``, token data is encrypted and authenticated in the -+ cache. If the value is not one of these options or empty, -+ ``auth_token`` will raise an exception on initialization. - * ``memcache_secret_key``: (optional, mandatory if -- ``memcache_security_strategy`` is defined) if defined, -- a random string to be used for key derivation. If -- ``memcache_security_strategy`` is defined and ``memcache_secret_key`` is -- absent, ``auth_token`` will raise an exception on initialization. -+ ``memcache_security_strategy`` is defined) this string is used for -+ key derivation. If ``memcache_security_strategy`` is defined and -+ ``memcache_secret_key`` is absent, ``auth_token`` will raise an -+ exception on initialization. - - Exchanging User Information - =========================== -diff --git a/keystoneclient/middleware/auth_token.py b/keystoneclient/middleware/auth_token.py -index 7e3012c..e50f723 100644 ---- a/keystoneclient/middleware/auth_token.py -+++ b/keystoneclient/middleware/auth_token.py -@@ -222,6 +222,7 @@ opts = [ - CONF.register_opts(opts, group='keystone_authtoken') - - LIST_OF_VERSIONS_TO_ATTEMPT = ['v2.0', 'v3.0'] -+CACHE_KEY_TEMPLATE = 'tokens/%s' - - - def will_expire_soon(expiry): -@@ -847,91 +848,81 @@ class AuthProtocol(object): - env_key = self._header_to_env_var(key) - return env.get(env_key, default) - -- def _protect_cache_value(self, token, data): -- """ Encrypt or sign data if necessary. """ -- try: -- if self._memcache_security_strategy == 'ENCRYPT': -- return memcache_crypt.encrypt_data(token, -- self._memcache_secret_key, -- data) -- elif self._memcache_security_strategy == 'MAC': -- return memcache_crypt.sign_data(token, data) -- else: -- return data -- except: -- msg = 'Failed to encrypt/sign cache data.' -- self.LOG.exception(msg) -- return data -- -- def _unprotect_cache_value(self, token, data): -- """ Decrypt or verify signed data if necessary. """ -- if data is None: -- return data -- -- try: -- if self._memcache_security_strategy == 'ENCRYPT': -- return memcache_crypt.decrypt_data(token, -- self._memcache_secret_key, -- data) -- elif self._memcache_security_strategy == 'MAC': -- return memcache_crypt.verify_signed_data(token, data) -- else: -- return data -- except: -- msg = 'Failed to decrypt/verify cache data.' -- self.LOG.exception(msg) -- # this should have the same effect as data not found in cache -- return None -- -- def _get_cache_key(self, token): -- """ Return the cache key. -- -- Do not use clear token as key if memcache protection is on. -- -- """ -- htoken = token -- if self._memcache_security_strategy in ('ENCRYPT', 'MAC'): -- derv_token = token + self._memcache_secret_key -- htoken = memcache_crypt.hash_data(derv_token) -- return 'tokens/%s' % htoken -- -- def _cache_get(self, token): -+ def _cache_get(self, token, ignore_expires=False): - """Return token information from cache. - - If token is invalid raise InvalidUserToken - return token only if fresh (not expired). - """ -+ - if self._cache and token: -- key = self._get_cache_key(token) -- cached = self._cache.get(key) -- cached = self._unprotect_cache_value(token, cached) -+ if self._memcache_security_strategy is None: -+ key = CACHE_KEY_TEMPLATE % token -+ serialized = self._cache.get(key) -+ else: -+ keys = memcache_crypt.derive_keys( -+ token, -+ self._memcache_secret_key, -+ self._memcache_security_strategy) -+ cache_key = CACHE_KEY_TEMPLATE % ( -+ memcache_crypt.get_cache_key(keys)) -+ raw_cached = self._cache.get(cache_key) -+ try: -+ # unprotect_data will return None if raw_cached is None -+ serialized = memcache_crypt.unprotect_data(keys, -+ raw_cached) -+ except Exception: -+ msg = 'Failed to decrypt/verify cache data' -+ self.LOG.exception(msg) -+ # this should have the same effect as data not -+ # found in cache -+ serialized = None -+ -+ if serialized is None: -+ return None -+ -+ # Note that 'invalid' and (data, expires) are the only -+ # valid types of serialized cache entries, so there is not -+ # a collision with json.loads(serialized) == None. -+ cached = json.loads(serialized) - if cached == 'invalid': - self.LOG.debug('Cached Token %s is marked unauthorized', token) - raise InvalidUserToken('Token authorization failed') -- if cached: -- data, expires = cached -- if time.time() < float(expires): -- self.LOG.debug('Returning cached token %s', token) -- return data -- else: -- self.LOG.debug('Cached Token %s seems expired', token) -- -- def _cache_store(self, token, data, expires=None): -- """ Store value into memcache. """ -- key = self._get_cache_key(token) -- data = self._protect_cache_value(token, data) -- data_to_store = data -- if expires: -- data_to_store = (data, expires) -+ -+ data, expires = cached -+ if ignore_expires or time.time() < float(expires): -+ self.LOG.debug('Returning cached token %s', token) -+ return data -+ else: -+ self.LOG.debug('Cached Token %s seems expired', token) -+ -+ def _cache_store(self, token, data): -+ """ Store value into memcache. -+ -+ data may be the string 'invalid' or a tuple like (data, expires) -+ -+ """ -+ serialized_data = json.dumps(data) -+ if self._memcache_security_strategy is None: -+ cache_key = CACHE_KEY_TEMPLATE % token -+ data_to_store = serialized_data -+ else: -+ keys = memcache_crypt.derive_keys( -+ token, -+ self._memcache_secret_key, -+ self._memcache_security_strategy) -+ cache_key = CACHE_KEY_TEMPLATE % memcache_crypt.get_cache_key(keys) -+ data_to_store = memcache_crypt.protect_data(keys, serialized_data) -+ - # we need to special-case set() because of the incompatibility between - # Swift MemcacheRing and python-memcached. See - # https://bugs.launchpad.net/swift/+bug/1095730 - if self._use_keystone_cache: -- self._cache.set(key, -+ self._cache.set(cache_key, - data_to_store, - time=self.token_cache_time) - else: -- self._cache.set(key, -+ self._cache.set(cache_key, - data_to_store, - timeout=self.token_cache_time) - -@@ -959,7 +950,7 @@ class AuthProtocol(object): - """ - if self._cache: - self.LOG.debug('Storing %s token in memcache', token) -- self._cache_store(token, data, expires) -+ self._cache_store(token, (data, expires)) - - def _cache_store_invalid(self, token): - """Store invalid token in cache.""" -diff --git a/keystoneclient/middleware/memcache_crypt.py b/keystoneclient/middleware/memcache_crypt.py -index 91e261d..6cadf3a 100755 ---- a/keystoneclient/middleware/memcache_crypt.py -+++ b/keystoneclient/middleware/memcache_crypt.py -@@ -1,6 +1,6 @@ - # vim: tabstop=4 shiftwidth=4 softtabstop=4 - --# Copyright 2010-2012 OpenStack LLC -+# Copyright 2010-2013 OpenStack LLC - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. -@@ -18,33 +18,34 @@ - """ - Utilities for memcache encryption and integrity check. - --Data is serialized before been encrypted or MACed. Encryption have a --dependency on the pycrypto. If pycrypto is not available, --CryptoUnabailableError will be raised. -+Data should be serialized before entering these functions. Encryption -+has a dependency on the pycrypto. If pycrypto is not available, -+CryptoUnavailableError will be raised. - --Encrypted data stored in memcache are prefixed with '{ENCRYPT:AES256}'. -- --MACed data stored in memcache are prefixed with '{MAC:SHA1}'. -+This module will not be called unless signing or encryption is enabled -+in the config. It will always validate signatures, and will decrypt -+data if encryption is enabled. It is not valid to mix protection -+modes. - - """ - - import base64 - import functools - import hashlib --import json -+import hmac -+import math - import os - --# make sure pycrypt is available -+# make sure pycrypto is available - try: - from Crypto.Cipher import AES - except ImportError: - AES = None - -- --# prefix marker indicating data is HMACed (signed by a secret key) --MAC_MARKER = '{MAC:SHA1}' --# prefix marker indicating data is encrypted --ENCRYPT_MARKER = '{ENCRYPT:AES256}' -+HASH_FUNCTION = hashlib.sha384 -+DIGEST_LENGTH = HASH_FUNCTION().digest_size -+DIGEST_SPLIT = DIGEST_LENGTH // 3 -+DIGEST_LENGTH_B64 = 4 * int(math.ceil(DIGEST_LENGTH / 3.0)) - - - class InvalidMacError(Exception): -@@ -81,77 +82,121 @@ def assert_crypto_availability(f): - return wrapper - - --def generate_aes_key(token, secret): -- """ Generates and returns a 256 bit AES key, based on sha256 hash. """ -- return hashlib.sha256(token + secret).digest() -- -- --def compute_mac(token, serialized_data): -- """ Computes and returns the base64 encoded MAC. """ -- return hash_data(serialized_data + token) -+def constant_time_compare(first, second): -+ """ Returns True if both string inputs are equal, otherwise False - -+ This function should take a constant amount of time regardless of -+ how many characters in the strings match. - --def hash_data(data): -- """ Return the base64 encoded SHA1 hash of the data. """ -- return base64.b64encode(hashlib.sha1(data).digest()) -- -- --def sign_data(token, data): -- """ MAC the data using SHA1. """ -- mac_data = {} -- mac_data['serialized_data'] = json.dumps(data) -- mac = compute_mac(token, mac_data['serialized_data']) -- mac_data['mac'] = mac -- md = MAC_MARKER + base64.b64encode(json.dumps(mac_data)) -- return md -+ """ -+ if len(first) != len(second): -+ return False -+ result = 0 -+ for x, y in zip(first, second): -+ result |= ord(x) ^ ord(y) -+ return result == 0 -+ -+ -+def derive_keys(token, secret, strategy): -+ """ Derives keys for MAC and ENCRYPTION from the user-provided -+ secret. The resulting keys should be passed to the protect and -+ unprotect functions. -+ -+ As suggested by NIST Special Publication 800-108, this uses the -+ first 128 bits from the sha384 KDF for the obscured cache key -+ value, the second 128 bits for the message authentication key and -+ the remaining 128 bits for the encryption key. -+ -+ This approach is faster than computing a separate hmac as the KDF -+ for each desired key. -+ """ -+ digest = hmac.new(secret, token + strategy, HASH_FUNCTION).digest() -+ return {'CACHE_KEY': digest[:DIGEST_SPLIT], -+ 'MAC': digest[DIGEST_SPLIT: 2 * DIGEST_SPLIT], -+ 'ENCRYPTION': digest[2 * DIGEST_SPLIT:], -+ 'strategy': strategy} - - --def verify_signed_data(token, data): -- """ Verify data integrity by ensuring MAC is valid. """ -- if data.startswith(MAC_MARKER): -- try: -- data = data[len(MAC_MARKER):] -- mac_data = json.loads(base64.b64decode(data)) -- mac = compute_mac(token, mac_data['serialized_data']) -- if mac != mac_data['mac']: -- raise InvalidMacError('invalid MAC; expect=%s, actual=%s' % -- (mac_data['mac'], mac)) -- return json.loads(mac_data['serialized_data']) -- except: -- raise InvalidMacError('invalid MAC; data appeared to be corrupted') -- else: -- # doesn't appear to be MACed data -- return data -+def sign_data(key, data): -+ """ Sign the data using the defined function and the derived key""" -+ mac = hmac.new(key, data, HASH_FUNCTION).digest() -+ return base64.b64encode(mac) - - - @assert_crypto_availability --def encrypt_data(token, secret, data): -- """ Encryptes the data with the given secret key. """ -+def encrypt_data(key, data): -+ """ Encrypt the data with the given secret key. -+ -+ Padding is n bytes of the value n, where 1 <= n <= blocksize. -+ """ - iv = os.urandom(16) -- aes_key = generate_aes_key(token, secret) -- cipher = AES.new(aes_key, AES.MODE_CFB, iv) -- data = json.dumps(data) -- encoded_data = base64.b64encode(iv + cipher.encrypt(data)) -- encoded_data = ENCRYPT_MARKER + encoded_data -- return encoded_data -+ cipher = AES.new(key, AES.MODE_CBC, iv) -+ padding = 16 - len(data) % 16 -+ return iv + cipher.encrypt(data + chr(padding) * padding) - - - @assert_crypto_availability --def decrypt_data(token, secret, data): -+def decrypt_data(key, data): - """ Decrypt the data with the given secret key. """ -- if data.startswith(ENCRYPT_MARKER): -- try: -- # encrypted data -- encoded_data = data[len(ENCRYPT_MARKER):] -- aes_key = generate_aes_key(token, secret) -- decoded_data = base64.b64decode(encoded_data) -- iv = decoded_data[:16] -- encrypted_data = decoded_data[16:] -- cipher = AES.new(aes_key, AES.MODE_CFB, iv) -- decrypted_data = cipher.decrypt(encrypted_data) -- return json.loads(decrypted_data) -- except: -- raise DecryptError('data appeared to be corrupted') -- else: -- # doesn't appear to be encrypted data -- return data -+ iv = data[:16] -+ cipher = AES.new(key, AES.MODE_CBC, iv) -+ try: -+ result = cipher.decrypt(data[16:]) -+ except Exception: -+ raise DecryptError('Encrypted data appears to be corrupted.') -+ -+ # Strip the last n padding bytes where n is the last value in -+ # the plaintext -+ padding = ord(result[-1]) -+ return result[:-1 * padding] -+ -+ -+def protect_data(keys, data): -+ """ Given keys and serialized data, returns an appropriately -+ protected string suitable for storage in the cache. -+ -+ """ -+ if keys['strategy'] == 'ENCRYPT': -+ data = encrypt_data(keys['ENCRYPTION'], data) -+ -+ encoded_data = base64.b64encode(data) -+ -+ signature = sign_data(keys['MAC'], encoded_data) -+ return signature + encoded_data -+ -+ -+def unprotect_data(keys, signed_data): -+ """ Given keys and cached string data, verifies the signature, -+ decrypts if necessary, and returns the original serialized data. -+ -+ """ -+ # cache backends return None when no data is found. We don't mind -+ # that this particular special value is unsigned. -+ if signed_data is None: -+ return None -+ -+ # First we calculate the signature -+ provided_mac = signed_data[:DIGEST_LENGTH_B64] -+ calculated_mac = sign_data( -+ keys['MAC'], -+ signed_data[DIGEST_LENGTH_B64:]) -+ -+ # Then verify that it matches the provided value -+ if not constant_time_compare(provided_mac, calculated_mac): -+ raise InvalidMacError('Invalid MAC; data appears to be corrupted.') -+ -+ data = base64.b64decode(signed_data[DIGEST_LENGTH_B64:]) -+ -+ # then if necessary decrypt the data -+ if keys['strategy'] == 'ENCRYPT': -+ data = decrypt_data(keys['ENCRYPTION'], data) -+ -+ return data -+ -+ -+def get_cache_key(keys): -+ """ Given keys generated by derive_keys(), returns a base64 -+ encoded value suitable for use as a cache key in memcached. -+ -+ """ -+ return base64.b64encode(keys['CACHE_KEY']) -diff --git a/tests/test_auth_token_middleware.py b/tests/test_auth_token_middleware.py -index 06054d0..a428504 100644 ---- a/tests/test_auth_token_middleware.py -+++ b/tests/test_auth_token_middleware.py -@@ -28,7 +28,6 @@ import webob - from keystoneclient.common import cms - from keystoneclient import utils - from keystoneclient.middleware import auth_token --from keystoneclient.middleware import memcache_crypt - from keystoneclient.openstack.common import memorycache - from keystoneclient.openstack.common import jsonutils - from keystoneclient.openstack.common import timeutils -@@ -1013,9 +1012,7 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): - def _get_cached_token(self, token): - token_id = cms.cms_hash_token(token) - # NOTE(vish): example tokens are expired so skip the expiration check. -- key = self.middleware._get_cache_key(token_id) -- cached = self.middleware._cache.get(key) -- return self.middleware._unprotect_cache_value(token, cached) -+ return self.middleware._cache_get(token_id, ignore_expires=True) - - def test_memcache(self): - req = webob.Request.blank('/') -@@ -1036,7 +1033,8 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): - token = 'invalid-token' - req.headers['X-Auth-Token'] = token - self.middleware(req.environ, self.start_fake_response) -- self.assertEqual(self._get_cached_token(token), "invalid") -+ self.assertRaises(auth_token.InvalidUserToken, -+ self._get_cached_token, token) - - def test_memcache_set_expired(self): - token_cache_time = 10 -@@ -1096,18 +1094,11 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): - 'memcache_secret_key': 'mysecret' - } - self.set_middleware(conf=conf) -- encrypted_data = self.middleware._protect_cache_value( -- 'token', TOKEN_RESPONSES[self.token_dict['uuid_token_default']]) -- self.assertEqual('{ENCRYPT:AES256}', encrypted_data[:16]) -- self.assertEqual( -- TOKEN_RESPONSES[self.token_dict['uuid_token_default']], -- self.middleware._unprotect_cache_value('token', encrypted_data)) -- # should return None if unable to decrypt -- self.assertIsNone( -- self.middleware._unprotect_cache_value( -- 'token', '{ENCRYPT:AES256}corrupted')) -- self.assertIsNone( -- self.middleware._unprotect_cache_value('mykey', encrypted_data)) -+ token = 'my_token' -+ data = ('this_data', 10e100) -+ self.middleware._init_cache({}) -+ self.middleware._cache_store(token, data) -+ self.assertEqual(self.middleware._cache_get(token), data[0]) - - def test_sign_cache_data(self): - conf = { -@@ -1119,19 +1110,11 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): - 'memcache_secret_key': 'mysecret' - } - self.set_middleware(conf=conf) -- signed_data = self.middleware._protect_cache_value( -- 'mykey', TOKEN_RESPONSES[self.token_dict['uuid_token_default']]) -- expected = '{MAC:SHA1}' -- self.assertEqual( -- signed_data[:10], -- expected) -- self.assertEqual( -- TOKEN_RESPONSES[self.token_dict['uuid_token_default']], -- self.middleware._unprotect_cache_value('mykey', signed_data)) -- # should return None on corrupted data -- self.assertIsNone( -- self.middleware._unprotect_cache_value('mykey', -- '{MAC:SHA1}corrupted')) -+ token = 'my_token' -+ data = ('this_data', 10e100) -+ self.middleware._init_cache({}) -+ self.middleware._cache_store(token, data) -+ self.assertEqual(self.middleware._cache_get(token), data[0]) - - def test_no_memcache_protection(self): - conf = { -@@ -1142,47 +1125,11 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): - 'memcache_secret_key': 'mysecret' - } - self.set_middleware(conf=conf) -- data = self.middleware._protect_cache_value('mykey', -- 'This is a test!') -- self.assertEqual(data, 'This is a test!') -- self.assertEqual( -- 'This is a test!', -- self.middleware._unprotect_cache_value('mykey', data)) -- -- def test_get_cache_key(self): -- conf = { -- 'auth_host': 'keystone.example.com', -- 'auth_port': 1234, -- 'auth_admin_prefix': '/testadmin', -- 'memcache_servers': ['localhost:11211'], -- 'memcache_secret_key': 'mysecret' -- } -- self.set_middleware(conf=conf) -- self.assertEqual( -- 'tokens/mytoken', -- self.middleware._get_cache_key('mytoken')) -- conf = { -- 'auth_host': 'keystone.example.com', -- 'auth_port': 1234, -- 'auth_admin_prefix': '/testadmin', -- 'memcache_servers': ['localhost:11211'], -- 'memcache_security_strategy': 'mac', -- 'memcache_secret_key': 'mysecret' -- } -- self.set_middleware(conf=conf) -- expected = 'tokens/' + memcache_crypt.hash_data('mytoken' + 'mysecret') -- self.assertEqual(self.middleware._get_cache_key('mytoken'), expected) -- conf = { -- 'auth_host': 'keystone.example.com', -- 'auth_port': 1234, -- 'auth_admin_prefix': '/testadmin', -- 'memcache_servers': ['localhost:11211'], -- 'memcache_security_strategy': 'Encrypt', -- 'memcache_secret_key': 'abc!' -- } -- self.set_middleware(conf=conf) -- expected = 'tokens/' + memcache_crypt.hash_data('mytoken' + 'abc!') -- self.assertEqual(self.middleware._get_cache_key('mytoken'), expected) -+ token = 'my_token' -+ data = ('this_data', 10e100) -+ self.middleware._init_cache({}) -+ self.middleware._cache_store(token, data) -+ self.assertEqual(self.middleware._cache_get(token), data[0]) - - def test_assert_valid_memcache_protection_config(self): - # test missing memcache_secret_key -diff --git a/tests/test_memcache_crypt.py b/tests/test_memcache_crypt.py -index b2281d9..524cd21 100644 ---- a/tests/test_memcache_crypt.py -+++ b/tests/test_memcache_crypt.py -@@ -4,48 +4,66 @@ from keystoneclient.middleware import memcache_crypt - - - class MemcacheCryptPositiveTests(testtools.TestCase): -- def test_generate_aes_key(self): -- self.assertEqual( -- len(memcache_crypt.generate_aes_key('Gimme Da Key', 'hush')), 32) -+ def _setup_keys(self, strategy): -+ return memcache_crypt.derive_keys('token', 'secret', strategy) - -- def test_compute_mac(self): -- self.assertEqual( -- memcache_crypt.compute_mac('mykey', 'This is a test!'), -- 'tREu41yR5tEgeBWIuv9ag4AeKA8=') -+ def test_constant_time_compare(self): -+ # make sure it works as a compare, the "constant time" aspect -+ # isn't appropriate to test in unittests -+ ctc = memcache_crypt.constant_time_compare -+ self.assertTrue(ctc('abcd', 'abcd')) -+ self.assertTrue(ctc('', '')) -+ self.assertFalse(ctc('abcd', 'efgh')) -+ self.assertFalse(ctc('abc', 'abcd')) -+ self.assertFalse(ctc('abc', 'abc\x00')) -+ self.assertFalse(ctc('', 'abc')) -+ -+ def test_derive_keys(self): -+ keys = memcache_crypt.derive_keys('token', 'secret', 'strategy') -+ self.assertEqual(len(keys['ENCRYPTION']), -+ len(keys['CACHE_KEY'])) -+ self.assertEqual(len(keys['CACHE_KEY']), -+ len(keys['MAC'])) -+ self.assertNotEqual(keys['ENCRYPTION'], -+ keys['MAC']) -+ self.assertIn('strategy', keys.keys()) -+ -+ def test_key_strategy_diff(self): -+ k1 = self._setup_keys('MAC') -+ k2 = self._setup_keys('ENCRYPT') -+ self.assertNotEqual(k1, k2) - - def test_sign_data(self): -- expected = '{MAC:SHA1}eyJtYWMiOiAiM0FrQmdPZHRybGo1RFFESHA1eUxqcDVq' +\ -- 'Si9BPSIsICJzZXJpYWxpemVkX2RhdGEiOiAiXCJUaGlzIGlzIGEgdG' +\ -- 'VzdCFcIiJ9' -- self.assertEqual( -- memcache_crypt.sign_data('mykey', 'This is a test!'), -- expected) -- -- def test_verify_signed_data(self): -- signed = memcache_crypt.sign_data('mykey', 'Testz') -- self.assertEqual( -- memcache_crypt.verify_signed_data('mykey', signed), -- 'Testz') -- self.assertEqual( -- memcache_crypt.verify_signed_data('aasSFWE13WER', 'not MACed'), -- 'not MACed') -- -- def test_encrypt_data(self): -- expected = '{ENCRYPT:AES256}' -- self.assertEqual( -- memcache_crypt.encrypt_data('mykey', 'mysecret', -- 'This is a test!')[:16], -- expected) -- -- def test_decrypt_data(self): -- encrypted = memcache_crypt.encrypt_data('mykey', 'mysecret', 'Testz') -- self.assertEqual( -- memcache_crypt.decrypt_data('mykey', 'mysecret', encrypted), -- 'Testz') -- self.assertEqual( -- memcache_crypt.decrypt_data('mykey', 'mysecret', -- 'Not Encrypted!'), -- 'Not Encrypted!') -+ keys = self._setup_keys('MAC') -+ sig = memcache_crypt.sign_data(keys['MAC'], 'data') -+ self.assertEqual(len(sig), memcache_crypt.DIGEST_LENGTH_B64) -+ -+ def test_encryption(self): -+ keys = self._setup_keys('ENCRYPT') -+ # what you put in is what you get out -+ for data in ['data', '1234567890123456', '\x00\xFF' * 13 -+ ] + [chr(x % 256) * x for x in range(768)]: -+ crypt = memcache_crypt.encrypt_data(keys['ENCRYPTION'], data) -+ decrypt = memcache_crypt.decrypt_data(keys['ENCRYPTION'], crypt) -+ self.assertEqual(data, decrypt) -+ self.assertRaises(memcache_crypt.DecryptError, -+ memcache_crypt.decrypt_data, -+ keys['ENCRYPTION'], crypt[:-1]) -+ -+ def test_protect_wrappers(self): -+ data = 'My Pretty Little Data' -+ for strategy in ['MAC', 'ENCRYPT']: -+ keys = self._setup_keys(strategy) -+ protected = memcache_crypt.protect_data(keys, data) -+ self.assertNotEqual(protected, data) -+ if strategy == 'ENCRYPT': -+ self.assertNotIn(data, protected) -+ unprotected = memcache_crypt.unprotect_data(keys, protected) -+ self.assertEqual(data, unprotected) -+ self.assertRaises(memcache_crypt.InvalidMacError, -+ memcache_crypt.unprotect_data, -+ keys, protected[:-1]) -+ self.assertIsNone(memcache_crypt.unprotect_data(keys, None)) - - def test_no_pycrypt(self): - aes = memcache_crypt.AES --- -1.8.1.5 - diff --git a/dev-python/python-keystoneclient/python-keystoneclient-0.2.4-r2.ebuild b/dev-python/python-keystoneclient/python-keystoneclient-0.2.5.ebuild index 6b9be04110b1..f2737b46b48d 100644 --- a/dev-python/python-keystoneclient/python-keystoneclient-0.2.4-r2.ebuild +++ b/dev-python/python-keystoneclient/python-keystoneclient-0.2.5.ebuild @@ -1,6 +1,6 @@ # Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/dev-python/python-keystoneclient/python-keystoneclient-0.2.4-r2.ebuild,v 1.1 2013/06/20 14:39:43 prometheanfire Exp $ +# $Header: /var/cvsroot/gentoo-x86/dev-python/python-keystoneclient/python-keystoneclient-0.2.5.ebuild,v 1.1 2013/08/11 01:54:05 prometheanfire Exp $ EAPI=5 #restricted due to packages missing and bad depends in the test ==webob-1.0.8 @@ -48,7 +48,6 @@ RDEPEND=">=dev-python/d2to1-0.2.10[${PYTHON_USEDEP}] virtual/python-argparse[${PYTHON_USEDEP}]" PATCHES=( - "${FILESDIR}/0.2.4-CVE-2013-2166-7.patch" ) # "${FILESDIR}/0.2.3-CVE-2013-2104.patch" diff --git a/dev-python/python-keystoneclient/python-keystoneclient-0.3.1.ebuild b/dev-python/python-keystoneclient/python-keystoneclient-0.3.1.ebuild new file mode 100644 index 000000000000..d5230ff4d2f5 --- /dev/null +++ b/dev-python/python-keystoneclient/python-keystoneclient-0.3.1.ebuild @@ -0,0 +1,57 @@ +# Copyright 1999-2013 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-x86/dev-python/python-keystoneclient/python-keystoneclient-0.3.1.ebuild,v 1.1 2013/08/11 01:54:05 prometheanfire Exp $ + +EAPI=5 +#restricted due to packages missing and bad depends in the test ==webob-1.0.8 +RESTRICT="test" +#PYTHON_COMPAT=( python2_5 python2_6 python2_7 ) +PYTHON_COMPAT=( python2_7 ) + +inherit distutils-r1 + +DESCRIPTION="A client for the OpenStack Keystone API" +HOMEPAGE="https://github.com/openstack/python-keystoneclient" +SRC_URI="mirror://pypi/${PN:0:1}/${PN}/${P}.tar.gz" + +LICENSE="Apache-2.0" +SLOT="0" +KEYWORDS="~amd64 ~x86" +IUSE="test" + +DEPEND="dev-python/setuptools[${PYTHON_USEDEP}] + test? ( dev-python/Babel[${PYTHON_USEDEP}] + dev-python/coverage[${PYTHON_USEDEP}] + dev-python/fixtures[${PYTHON_USEDEP}] + dev-python/keyring[${PYTHON_USEDEP}] + dev-python/mock[${PYTHON_USEDEP}] + dev-python/mox[${PYTHON_USEDEP}] + dev-python/nose[${PYTHON_USEDEP}] + dev-python/nose-exclude[${PYTHON_USEDEP}] + dev-python/nosehtmloutput[${PYTHON_USEDEP}] + dev-python/openstack-nose-plugin[${PYTHON_USEDEP}] + =dev-python/pep8-1.4.5[${PYTHON_USEDEP}] + >=dev-python/sphinx-1.1.2[${PYTHON_USEDEP}] + >=dev-python/testtools-0.9.22[${PYTHON_USEDEP}] + dev-python/unittest2[${PYTHON_USEDEP}] + >=dev-python/webob-1.0.8[${PYTHON_USEDEP}] )" +RDEPEND=">=dev-python/d2to1-0.2.10[${PYTHON_USEDEP}] + <dev-python/d2to1-0.3[${PYTHON_USEDEP}] + >=dev-python/iso8601-0.1.4[${PYTHON_USEDEP}] + >=dev-python/oslo-config-1.1.0[${PYTHON_USEDEP}] + >=dev-python/pbr-0.5[${PYTHON_USEDEP}] + <dev-python/pbr-0.6[${PYTHON_USEDEP}] + >=dev-python/prettytable-0.6[${PYTHON_USEDEP}] + <dev-python/prettytable-0.8[${PYTHON_USEDEP}] + >=dev-python/requests-0.8.8[${PYTHON_USEDEP}] + dev-python/simplejson[${PYTHON_USEDEP}] + dev-python/six[${PYTHON_USEDEP}] + virtual/python-argparse[${PYTHON_USEDEP}]" + +PATCHES=( +) +# "${FILESDIR}/0.2.3-CVE-2013-2104.patch" + +python_test() { + ${PYTHON} setup.py nosetests || die +} |