[Secure-testing-team] Bug#753511: CVE-2014-3520: Keystone V2 trusts privilege escalation through user supplied

Thomas Goirand zigo at debian.org
Wed Jul 2 16:36:37 UTC 2014


Package: keystone
Version: 2014.1.1-2
Severity: important
Tags: security

I'm uploading a fix for this:

Title: Keystone V2 trusts privilege escalation through user supplied
project id
Reporter: Jamie Lennox (Red Hat)
Products: Keystone
Versions: up to 2013.2.3, and 2014.1 to 2014.1.1

Description:
Jamie Lennox from Red Hat reported a vulnerability in Keystone trusts.
By using an out of scope project id, a trustee may gain unauthorized
access if the trustor has the required roles in the requested project
id. All Keystone deployments configured to enable trusts and V2 API are
affected.

Proposed patch:
See attached patches. Unless a flaw is discovered in them, these patches
will be merged to stable/havana, stable/icehouse and master (Juno
development branch) on the public disclosure date.

CVE: CVE-2014-3520

Proposed public disclosure date/time:
2014-07-02, 1500UTC
Please do not make the issue public (or release public patches) before
this coordinated embargo date.

Regards,

--·
Tristan Cacqueray
OpenStack Vulnerability Management Team

>From 8ac8484e1daadfda3f36b3135a8f6de56fc41795 Mon Sep 17 00:00:00 2001
From: Jamie Lennox <jamielennox at redhat.com>
Date: Thu, 19 Jun 2014 14:41:22 +1000
Subject: [PATCH] Ensure that in v2 auth tenant_id matches trust

Previously if a trustee requests a trust scoped token for a project that
is different to the one in the trust, however the trustor has the
appropriate roles then a token would be issued.

Ensure that the trust that was given matches the project that was
specified in the scope.

(cherry picked from commit 1556faec2f65dba60584f0a9657d5b717a6ede3a)

Change-Id: I00ad783bcb93cea9e5622965f81b91c80f4570cc
Closes-Bug: #1331912
---
 keystone/tests/test_auth.py   | 15 +++++++++++++--
 keystone/token/controllers.py |  6 +++++-
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/keystone/tests/test_auth.py b/keystone/tests/test_auth.py
index 6d93e7f..4d9d9da 100644
--- a/keystone/tests/test_auth.py
+++ b/keystone/tests/test_auth.py
@@ -693,13 +693,15 @@ class AuthWithTrust(AuthTest):
         self.new_trust = self.trust_controller.create_trust(
             context, trust=trust_data)['trust']
 
-    def build_v2_token_request(self, username, password):
+    def build_v2_token_request(self, username, password, tenant_id=None):
+        if not tenant_id:
+            tenant_id = self.tenant_bar['id']
         body_dict = _build_user_auth(username=username, password=password)
         self.unscoped_token = self.controller.authenticate({}, body_dict)
         unscoped_token_id = self.unscoped_token['access']['token']['id']
         request_body = _build_user_auth(token={'id': unscoped_token_id},
                                         trust_id=self.new_trust['id'],
-                                        tenant_id=self.tenant_bar['id'])
+                                        tenant_id=tenant_id)
         return request_body
 
     def test_create_trust_bad_data_fails(self):
@@ -782,6 +784,15 @@ class AuthWithTrust(AuthTest):
             exception.Forbidden,
             self.controller.authenticate, {}, request_body)
 
+    def test_token_from_trust_wrong_project_fails(self):
+        for assigned_role in self.assigned_roles:
+            self.assignment_api.add_role_to_user_and_project(
+                self.trustor['id'], self.tenant_baz['id'], assigned_role)
+        request_body = self.build_v2_token_request('TWO', 'two2',
+                                                   self.tenant_baz['id'])
+        self.assertRaises(exception.Forbidden, self.controller.authenticate,
+                          {}, request_body)
+
     def fetch_v2_token_from_trust(self):
         request_body = self.build_v2_token_request('TWO', 'two2')
         auth_response = self.controller.authenticate({}, request_body)
diff --git a/keystone/token/controllers.py b/keystone/token/controllers.py
index bcae12c..be16145 100644
--- a/keystone/token/controllers.py
+++ b/keystone/token/controllers.py
@@ -164,6 +164,8 @@ class Auth(controller.V2Controller):
 
         user_ref = old_token_ref['user']
         user_id = user_ref['id']
+        tenant_id = self._get_project_id_from_auth(auth)
+
         if not CONF.trust.enabled and 'trust_id' in auth:
             raise exception.Forbidden('Trusts are disabled.')
         elif CONF.trust.enabled and 'trust_id' in auth:
@@ -172,6 +174,9 @@ class Auth(controller.V2Controller):
                 raise exception.Forbidden()
             if user_id != trust_ref['trustee_user_id']:
                 raise exception.Forbidden()
+            if (trust_ref['project_id'] and
+                    tenant_id != trust_ref['project_id']):
+                raise exception.Forbidden()
             if ('expires' in trust_ref) and (trust_ref['expires']):
                 expiry = trust_ref['expires']
                 if expiry < timeutils.parse_isotime(timeutils.isotime()):
@@ -196,7 +201,6 @@ class Auth(controller.V2Controller):
             current_user_ref = self.identity_api.get_user(user_id)
 
         metadata_ref = {}
-        tenant_id = self._get_project_id_from_auth(auth)
         tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
             user_id, tenant_id)
 
-- 1.9.3 



More information about the Secure-testing-team mailing list