From 452a43dfa60028e4a4f3ce09c329ac455a83d132 Mon Sep 17 00:00:00 2001 From: Alan Pevec Date: Jul 08 2014 22:16:54 +0000 Subject: Keystone V2 trusts privilege escalation through user supplied project id CVE-2014-3520 --- diff --git a/0005-Ensure-that-in-v2-auth-tenant_id-matches-trust.patch b/0005-Ensure-that-in-v2-auth-tenant_id-matches-trust.patch new file mode 100644 index 0000000..095d6d1 --- /dev/null +++ b/0005-Ensure-that-in-v2-auth-tenant_id-matches-trust.patch @@ -0,0 +1,91 @@ +From 7debbe93a4854026cdc1b8b0473331a8c44874fc Mon Sep 17 00:00:00 2001 +From: Jamie Lennox +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 +(cherry picked from commit 44555e83bad04210cf6ddc24999e753178357043) +--- + 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) + diff --git a/openstack-keystone.spec b/openstack-keystone.spec index aa270c7..f9f1b3c 100644 --- a/openstack-keystone.spec +++ b/openstack-keystone.spec @@ -7,7 +7,7 @@ Name: openstack-keystone Version: 2014.1.1 -Release: 3%{?dist} +Release: 4%{?dist} Summary: OpenStack Identity Service License: ASL 2.0 @@ -27,6 +27,7 @@ Patch0001: 0001-remove-runtime-dep-on-python-pbr.patch Patch0002: 0002-sync-parameter-values-with-keystone-dist.conf.patch Patch0003: 0003-Refactor-service-readiness-notification.patch Patch0004: 0004-Block-delegation-escalation-of-privilege.patch +Patch0005: 0005-Ensure-that-in-v2-auth-tenant_id-matches-trust.patch BuildArch: noarch BuildRequires: python2-devel @@ -103,6 +104,7 @@ This package contains documentation for Keystone. %patch0002 -p1 %patch0003 -p1 %patch0004 -p1 +%patch0005 -p1 find . \( -name .gitignore -o -name .placeholder \) -delete find keystone -name \*.py -exec sed -i '/\/usr\/bin\/env python/d' {} \; @@ -228,6 +230,10 @@ fi %endif %changelog +* Wed Jul 09 2014 Alan Pevec 2014.1.1-4 +- Keystone V2 trusts privilege escalation through user supplied project id + CVE-2014-3520 + * Wed Jun 25 2014 Alan Pevec 2014.1.1-3 - exclude default port 35357 from the ephemeral port range