[openstack-keystone/f19] Fix token revocation list API CVE-2013-4294

Alan Pevec apevec at fedoraproject.org
Thu Sep 12 22:22:51 UTC 2013


commit 9481a877105041845cbdf6d49f3db2b569275f86
Author: Alan Pevec <apevec at redhat.com>
Date:   Fri Sep 13 00:15:06 2013 +0200

    Fix token revocation list API CVE-2013-4294

 0001-Fix-and-test-token-revocation-list-API.patch |  138 +++++++++++++++++++++
 openstack-keystone.spec                           |    7 +-
 2 files changed, 144 insertions(+), 1 deletions(-)
---
diff --git a/0001-Fix-and-test-token-revocation-list-API.patch b/0001-Fix-and-test-token-revocation-list-API.patch
new file mode 100644
index 0000000..975e250
--- /dev/null
+++ b/0001-Fix-and-test-token-revocation-list-API.patch
@@ -0,0 +1,138 @@
+From 74738f64c3f1bdff2a51a62bc73b4b857a1cca44 Mon Sep 17 00:00:00 2001
+From: Morgan Fainberg <m at metacloud.com>
+Date: Fri, 23 Aug 2013 14:53:26 -0700
+Subject: [PATCH] Fix and test token revocation list API
+
+Change-Id: I6c60bf2aecc7c9353e837e59a4e09860d049e0f5
+(cherry picked from commit 775d7a7802bd5cf49880c8a76e9a175e8470adba)
+Fixes CVE-2013-4294
+---
+ keystone/token/backends/kvs.py      |  2 +-
+ keystone/token/backends/memcache.py | 12 ++++++----
+ tests/test_backend.py               | 47 +++++++++++++++++++++++++++++++------
+ 3 files changed, 48 insertions(+), 13 deletions(-)
+
+diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py
+index 49f15ad..1935b41 100644
+--- a/keystone/token/backends/kvs.py
++++ b/keystone/token/backends/kvs.py
+@@ -111,7 +111,7 @@ class Token(kvs.Base, token.Driver):
+             if not token.startswith('revoked-token-'):
+                 continue
+             record = {}
+-            record['id'] = token_ref['id']
++            record['id'] = token[len('revoked-token-'):]
+             record['expires'] = token_ref['expires']
+             tokens.append(record)
+         return tokens
+diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py
+index a62f342..c2c9b51 100644
+--- a/keystone/token/backends/memcache.py
++++ b/keystone/token/backends/memcache.py
+@@ -84,8 +84,9 @@ class Token(token.Driver):
+                         raise exception.UnexpectedError(msg)
+         return copy.deepcopy(data_copy)
+ 
+-    def _add_to_revocation_list(self, data):
+-        data_json = jsonutils.dumps(data)
++    def _add_to_revocation_list(self, token_id, token_data):
++        data_json = jsonutils.dumps({'id': token_id,
++                                     'expires': token_data['expires']})
+         if not self.client.append(self.revocation_key, ',%s' % data_json):
+             if not self.client.add(self.revocation_key, data_json):
+                 if not self.client.append(self.revocation_key,
+@@ -95,10 +96,11 @@ class Token(token.Driver):
+ 
+     def delete_token(self, token_id):
+         # Test for existence
+-        data = self.get_token(token.unique_id(token_id))
+-        ptk = self._prefix_token_id(token.unique_id(token_id))
++        token_id = token.unique_id(token_id)
++        data = self.get_token(token_id)
++        ptk = self._prefix_token_id(token_id)
+         result = self.client.delete(ptk)
+-        self._add_to_revocation_list(data)
++        self._add_to_revocation_list(token_id, data)
+         return result
+ 
+     def list_tokens(self, user_id, tenant_id=None, trust_id=None):
+diff --git a/tests/test_backend.py b/tests/test_backend.py
+index 85ac7cf..d4c2e6c 100644
+--- a/tests/test_backend.py
++++ b/tests/test_backend.py
+@@ -14,10 +14,11 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+ 
++import copy
+ import datetime
+ import default_fixtures
++import hashlib
+ import uuid
+-import nose.exc
+ 
+ from keystone.catalog import core
+ from keystone import config
+@@ -2065,17 +2066,19 @@ class TokenTests(object):
+                 'trust_id': None,
+                 'user': {'id': 'testuserid'}}
+         data_ref = self.token_api.create_token(token_id, data)
+-        expires = data_ref.pop('expires')
+-        data_ref.pop('user_id')
++        data_ref_copy = copy.deepcopy(data_ref)
++        expires = data_ref_copy.pop('expires')
++        data_ref_copy.pop('user_id')
+         self.assertTrue(isinstance(expires, datetime.datetime))
+-        self.assertDictEqual(data_ref, data)
++        self.assertDictEqual(data_ref_copy, data)
+ 
+         new_data_ref = self.token_api.get_token(token_id)
+-        expires = new_data_ref.pop('expires')
+-        new_data_ref.pop('user_id')
++        new_data_ref_copy = copy.deepcopy(new_data_ref)
++        expires = new_data_ref_copy.pop('expires')
++        new_data_ref_copy.pop('user_id')
+ 
+         self.assertTrue(isinstance(expires, datetime.datetime))
+-        self.assertEquals(new_data_ref, data)
++        self.assertEquals(new_data_ref_copy, data)
+ 
+         self.token_api.delete_token(token_id)
+         self.assertRaises(exception.TokenNotFound,
+@@ -2248,6 +2251,36 @@ class TokenTests(object):
+         self.check_list_revoked_tokens([self.delete_token()
+                                         for x in xrange(2)])
+ 
++    def test_predictable_revoked_pki_token_id(self):
++        # NOTE(dolph): _create_token_id() includes 'MII' as a prefix of the
++        #               returned token str in master, but not in grizzly.
++        #               revising _create_token_id() in grizzly to include the
++        #               previx breaks several other tests here
++        token_id = 'MII' + self._create_token_id()
++        token_id_hash = hashlib.md5(token_id).hexdigest()
++        token = {'user': {'id': uuid.uuid4().hex}}
++
++        self.token_api.create_token(token_id, token)
++        self.token_api.delete_token(token_id)
++
++        revoked_ids = [x['id'] for x in self.token_api.list_revoked_tokens()]
++        self.assertIn(token_id_hash, revoked_ids)
++        self.assertNotIn(token_id, revoked_ids)
++        for t in self.token_api.list_revoked_tokens():
++            self.assertIn('expires', t)
++
++    def test_predictable_revoked_uuid_token_id(self):
++        token_id = uuid.uuid4().hex
++        token = {'user': {'id': uuid.uuid4().hex}}
++
++        self.token_api.create_token(token_id, token)
++        self.token_api.delete_token(token_id)
++
++        revoked_ids = [x['id'] for x in self.token_api.list_revoked_tokens()]
++        self.assertIn(token_id, revoked_ids)
++        for t in self.token_api.list_revoked_tokens():
++            self.assertIn('expires', t)
++
+ 
+ class TrustTests(object):
+     def create_sample_trust(self, new_id):
diff --git a/openstack-keystone.spec b/openstack-keystone.spec
index e15e7a7..83eedba 100644
--- a/openstack-keystone.spec
+++ b/openstack-keystone.spec
@@ -7,7 +7,7 @@
 
 Name:           openstack-keystone
 Version:        2013.1.3
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        OpenStack Identity Service
 
 License:        ASL 2.0
@@ -21,6 +21,7 @@ Source5:        openstack-keystone-sample-data
 #
 # patches_base=2013.1.3
 #
+Patch0001: 0001-Fix-and-test-token-revocation-list-API.patch
 
 BuildArch:      noarch
 BuildRequires:  python2-devel
@@ -84,6 +85,7 @@ This package contains documentation for Keystone.
 %prep
 %setup -q -n keystone-%{version}
 
+%patch0001 -p1
 find . \( -name .gitignore -o -name .placeholder \) -delete
 find keystone -name \*.py -exec sed -i '/\/usr\/bin\/env python/d' {} \;
 # Remove bundled egg-info
@@ -202,6 +204,9 @@ fi
 %endif
 
 %changelog
+* Fri Sep 13 2013 Alan Pevec <apevec at redhat.com> 2013.1.3-2
+- Fix token revocation list API CVE-2013-4294
+
 * Mon Aug 12 2013 Alan Pevec <apevec at redhat.com> 2013.1.3-1
 - updated to stable grizzly 2013.1.3 release
 


More information about the scm-commits mailing list