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 <jamielen...@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 -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org