CVE-2012-5563 (published 2012-12-18T01:55Z)

OpenStack Keystone, as used in OpenStack Folsom 2012.2, does not properly implement token expiration, which allows remote authenticated users to bypass intended authorization restrictions by creating new tokens through token chaining.  NOTE: this issue exists because of a CVE-2012-3426 regression.

Severity: MEDIUM
CVSS v2 base score: 4.0 (AV:N/AC:L/Au:S/C:N/I:P/A:N)

Weakness information:
cwe_id: CWE-255
cwe_name: Credentials Management Errors
description: Weaknesses in this category are related to the management of credentials.

Fix information:
repo_url: https://github.com/openstack/keystone
commit_details: repo_url: https://github.com/openstack/keystone
author: Dolph Mathews
author_date: 2012-11-28 10:28:07-05:00
msg: Ensure token expiration is maintained (bug 1079216)

Change-Id: I95853ec36e9c4cd937cfac7e08b648e830f9efd0
repository: repo_url: https://github.com/openstack/keystone
repo_name: openstack/keystone
description: OpenStack Identity (Keystone). Mirror of code maintained at opendev.org.
repo_language: Python
owner: openstack
file_changes: filename: service.py
change_type: ModificationType.MODIFY
diff: @@ -530,6 +530,7 @@ class TokenController(wsgi.Application):
             self.token_api.create_token(
                 context, token_id, dict(key=token_id,
                                         id=token_id,
+                                        expires=auth_token_data['expires'],
                                         user=user_ref,
                                         tenant=tenant_ref,
                                         metadata=metadata_ref))

programming_language: Python
filename: test_service.py
change_type: ModificationType.MODIFY
diff: @@ -12,10 +12,12 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import time
 import uuid
 
 import default_fixtures
 
+from keystone import config
 from keystone import exception
 from keystone import identity
 from keystone import service
@@ -24,6 +26,9 @@ from keystone.identity.backends import kvs as kvs_identity
 from keystone.openstack.common import timeutils
 
 
+CONF = config.CONF
+
+
 def _build_user_auth(token=None, username=None,
                      password=None, tenant_name=None):
     """Build auth dictionary.
@@ -296,3 +301,55 @@ class AuthWithRemoteUser(TokenControllerTest):
             self.api.authenticate,
             {'REMOTE_USER': uuid.uuid4().hex},
             body_dict)
+
+
+class TokenExpirationTest(test.TestCase):
+    def setUp(self):
+        super(TokenExpirationTest, self).setUp()
+        self.identity_api = kvs_identity.Identity()
+        self.load_fixtures(default_fixtures)
+        self.api = service.TokenController()
+
+    def _maintain_token_expiration(self):
+        """Token expiration should be maintained after re-auth & validation."""
+        r = self.api.authenticate(
+            {},
+            auth={
+                'passwordCredentials': {
+                    'username': self.user_foo['name'],
+                    'password': self.user_foo['password']
+                }
+            })
+        unscoped_token_id = r['access']['token']['id']
+        original_expiration = r['access']['token']['expires']
+
+        time.sleep(0.5)
+
+        r = self.api.validate_token(
+            dict(is_admin=True, query_string={}),
+            token_id=unscoped_token_id)
+        self.assertEqual(original_expiration, r['access']['token']['expires'])
+
+        time.sleep(0.5)
+
+        r = self.api.authenticate(
+            {},
+            auth={
+                'token': {
+                    'id': unscoped_token_id,
+                },
+                'tenantId': self.tenant_bar['id'],
+            })
+        scoped_token_id = r['access']['token']['id']
+        self.assertEqual(original_expiration, r['access']['token']['expires'])
+
+        time.sleep(0.5)
+
+        r = self.api.validate_token(
+            dict(is_admin=True, query_string={}),
+            token_id=scoped_token_id)
+        self.assertEqual(original_expiration, r['access']['token']['expires'])
+
+    def test_maintain_uuid_token_expiration(self):
+        self.opt_in_group('signing', token_format='UUID')
+        self._maintain_token_expiration()

programming_language: Python