diff options
Diffstat (limited to 'sys-auth/keystone/files/2013.2.2-CVE-2014-2237.patch')
-rw-r--r-- | sys-auth/keystone/files/2013.2.2-CVE-2014-2237.patch | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/sys-auth/keystone/files/2013.2.2-CVE-2014-2237.patch b/sys-auth/keystone/files/2013.2.2-CVE-2014-2237.patch new file mode 100644 index 000000000000..a19d9440258f --- /dev/null +++ b/sys-auth/keystone/files/2013.2.2-CVE-2014-2237.patch @@ -0,0 +1,183 @@ +From b6f0e26da0e2ab0892a5658da281a065e668637b Mon Sep 17 00:00:00 2001 +From: Morgan Fainberg <m@metacloud.com> +Date: Fri, 21 Feb 2014 21:33:25 +0000 +Subject: Ensure tokens are added to both Trustor and Trustee indexes + +Tokens are now added to both the Trustor and Trustee user-token-index +so that bulk token revocations (e.g. password change) of the trustee +will work as expected. This is a backport of the basic code that was +used in the Icehouse-vintage Dogpile Token KVS backend that resolves +this issue by merging the handling of memcache and KVS backends into +the same logic. + +Change-Id: I3e19e4a8fc1e11cef6db51d364e80061e97befa7 +Closes-Bug: #1260080 +--- +diff --git a/keystone/tests/test_backend.py b/keystone/tests/test_backend.py +index e0e81ca..1e926c8 100644 +--- a/keystone/tests/test_backend.py ++++ b/keystone/tests/test_backend.py +@@ -25,6 +25,7 @@ from keystone import exception + from keystone.openstack.common import timeutils + from keystone import tests + from keystone.tests import default_fixtures ++from keystone.token import provider + + + CONF = config.CONF +@@ -2645,7 +2646,8 @@ class TokenTests(object): + self.token_api.delete_token, token_id) + + def create_token_sample_data(self, tenant_id=None, trust_id=None, +- user_id="testuserid"): ++ user_id='testuserid', ++ trustee_user_id='testuserid2'): + token_id = self._create_token_id() + data = {'id': token_id, 'a': 'b', + 'user': {'id': user_id}} +@@ -2655,6 +2657,15 @@ class TokenTests(object): + data['tenant'] = None + if trust_id is not None: + data['trust_id'] = trust_id ++ data.setdefault('access', {}).setdefault('trust', {}) ++ # Testuserid2 is used here since a trustee will be different in ++ # the cases of impersonation and therefore should not match the ++ # token's user_id. ++ data['access']['trust']['trustee_user_id'] = trustee_user_id ++ data['token_version'] = provider.V2 ++ # Issue token stores a copy of all token data at token['token_data']. ++ # This emulates that assumption as part of the test. ++ data['token_data'] = copy.deepcopy(data) + new_token = self.token_api.create_token(token_id, data) + return new_token['id'] + +@@ -2907,6 +2918,39 @@ class TokenTests(object): + for t in self.token_api.list_revoked_tokens(): + self.assertIn('expires', t) + ++ def test_token_in_trustee_and_trustor_token_list(self): ++ self.opt_in_group('trust', ++ enabled=True) ++ trustor = self.user_foo ++ trustee = self.user_two ++ trust_id = uuid.uuid4().hex ++ trust_info = {'trustor_user_id': trustor['id'], ++ 'trustee_user_id': trustee['id'], ++ 'project_id': self.tenant_bar['id'], ++ 'expires_at': timeutils. ++ parse_isotime('2031-02-18T18:10:00Z'), ++ 'impersonation': True} ++ self.trust_api.create_trust(trust_id, trust_info, ++ roles=[{'id': 'member'}, ++ {'id': 'other'}, ++ {'id': 'browser'}]) ++ ++ token_id = self.create_token_sample_data( ++ tenant_id=self.tenant_bar['id'], ++ trust_id=trust_id, ++ user_id=trustor['id'], ++ trustee_user_id=trustee['id']) ++ ++ # Ensure the token id exists in both the trustor and trustee token ++ # lists ++ ++ self.assertIn(token_id, ++ self.token_api.list_tokens(self.user_two['id'], ++ trust_id=trust_id)) ++ self.assertIn(token_id, ++ self.token_api.list_tokens(self.user_foo['id'], ++ trust_id=trust_id)) ++ + + class TokenCacheInvalidation(object): + def _create_test_data(self): +diff --git a/keystone/tests/test_backend_kvs.py b/keystone/tests/test_backend_kvs.py +index ac9df71..a23882c 100644 +--- a/keystone/tests/test_backend_kvs.py ++++ b/keystone/tests/test_backend_kvs.py +@@ -70,6 +70,7 @@ class KvsToken(tests.TestCase, test_backend.TokenTests): + identity.CONF.identity.driver = ( + 'keystone.identity.backends.kvs.Identity') + self.load_backends() ++ self.load_fixtures(default_fixtures) + + + class KvsTrust(tests.TestCase, test_backend.TrustTests): +diff --git a/keystone/tests/test_backend_memcache.py b/keystone/tests/test_backend_memcache.py +index 964d5b4..c99a6a3 100644 +--- a/keystone/tests/test_backend_memcache.py ++++ b/keystone/tests/test_backend_memcache.py +@@ -26,6 +26,7 @@ from keystone import exception + from keystone.openstack.common import jsonutils + from keystone.openstack.common import timeutils + from keystone import tests ++from keystone.tests import default_fixtures + from keystone.tests import test_backend + from keystone.tests import test_utils + from keystone import token +@@ -115,6 +116,7 @@ class MemcacheToken(tests.TestCase, test_backend.TokenTests): + def setUp(self): + super(MemcacheToken, self).setUp() + self.load_backends() ++ self.load_fixtures(default_fixtures) + fake_client = MemcacheClient() + self.token_man = token.Manager() + self.token_man.driver = token_memcache.Token(client=fake_client) +diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py +index b3f991a..c0d6e36 100644 +--- a/keystone/token/backends/kvs.py ++++ b/keystone/token/backends/kvs.py +@@ -150,5 +150,7 @@ class Token(kvs.Base, token.Driver): + def flush_expired_tokens(self): + now = timeutils.utcnow() + for token, token_ref in self.db.items(): ++ if not token.startswith('revoked-token-'): ++ continue + if self.is_expired(now, token_ref): + self.db.delete(token) +diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py +index a6fe826..08c1c40 100644 +--- a/keystone/token/backends/memcache.py ++++ b/keystone/token/backends/memcache.py +@@ -83,12 +83,33 @@ class Token(token.Driver): + expires_ts = utils.unixtime(data_copy['expires']) + kwargs['time'] = expires_ts + self.client.set(ptk, data_copy, **kwargs) +- if 'id' in data['user']: +- user_id = data['user']['id'] +- user_key = self._prefix_user_id(user_id) +- # Append the new token_id to the token-index-list stored in the +- # user-key within memcache. +- self._update_user_list_with_cas(user_key, token_id, data_copy) ++ user_id = data['user']['id'] ++ user_key = self._prefix_user_id(user_id) ++ # Append the new token_id to the token-index-list stored in the ++ # user-key within memcache. ++ self._update_user_list_with_cas(user_key, token_id, data_copy) ++ if CONF.trust.enabled and data.get('trust_id'): ++ # NOTE(morganfainberg): If trusts are enabled and this is a trust ++ # scoped token, we add the token to the trustee list as well. This ++ # allows password changes of the trustee to also expire the token. ++ # There is no harm in placing the token in multiple lists, as ++ # _list_tokens is smart enough to handle almost any case of ++ # valid/invalid/expired for a given token. ++ token_data = data_copy['token_data'] ++ if data_copy['token_version'] == token.provider.V2: ++ trustee_user_id = token_data['access']['trust'][ ++ 'trustee_user_id'] ++ elif data_copy['token_version'] == token.provider.V3: ++ trustee_user_id = token_data['OS-TRUST:trust'][ ++ 'trustee_user_id'] ++ else: ++ raise token.provider.UnsupportedTokenVersionException( ++ _('Unknown token version %s') % ++ data_copy.get('token_version')) ++ ++ trustee_key = self._prefix_user_id(trustee_user_id) ++ self._update_user_list_with_cas(trustee_key, token_id, data_copy) ++ + return copy.deepcopy(data_copy) + + def _convert_user_index_from_json(self, token_list, user_key): +-- +cgit v0.9.2 |