diff --git a/keystone/contrib/ec2/core.py b/keystone/contrib/ec2/core.py index 246587a60f..2ef9820212 100644 --- a/keystone/contrib/ec2/core.py +++ b/keystone/contrib/ec2/core.py @@ -207,6 +207,9 @@ class Ec2Controller(controller.V2Controller): if not self._is_admin(context): self._assert_identity(context, user_id) + # Disallow trust-scoped tokens from creating credentials. + self._assert_not_trust_scoped(context) + self._assert_valid_user_id(context, user_id) self._assert_valid_project_id(context, tenant_id) @@ -308,6 +311,22 @@ class Ec2Controller(controller.V2Controller): except exception.Forbidden: return False + def _assert_not_trust_scoped(self, context): + try: + token_ref = self.token_api.get_token( + context, token_id=context['token_id']) + except exception.TokenNotFound as e: + raise exception.Unauthorized(e) + + # NOTE(morganfainberg): In Grizzly, it is not allowed to use a + # trust scoped token to create an EC2 credential, this is due to + # privilege escalation possibility (there is no way to correlate + # the trust to the EC2 credential and limit roles to the trust). + if 'trust' in token_ref: + raise exception.Forbidden() + if 'trust_id' in token_ref.get('metadata', {}): + raise exception.Forbidden() + def _assert_owner(self, context, user_id, credential_id): """Ensure the provided user owns the credential. diff --git a/keystone/token/controllers.py b/keystone/token/controllers.py index 1ae1d4fe1e..e42ca7d2e1 100644 --- a/keystone/token/controllers.py +++ b/keystone/token/controllers.py @@ -201,7 +201,7 @@ class Auth(controller.V2Controller): context, trust_ref['trustee_user_id']) if not trustee_user_ref['enabled']: raise exception.Forbidden()() - if trust_ref['impersonation'] == 'True': + if trust_ref['impersonation'] is True: current_user_ref = trustor_user_ref else: current_user_ref = trustee_user_ref diff --git a/tests/test_auth.py b/tests/test_auth.py index 3d4ec87641..8a810a417f 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -19,6 +19,7 @@ import uuid from keystone import auth from keystone import config +from keystone.contrib import ec2 from keystone import exception from keystone import identity from keystone.openstack.common import timeutils @@ -517,7 +518,7 @@ class AuthWithTrust(AuthTest): self.sample_data = {'trustor_user_id': self.trustor['id'], 'trustee_user_id': self.trustee['id'], 'project_id': self.tenant_bar['id'], - 'impersonation': 'True', + 'impersonation': True, 'roles': [{'id': self.role_browser['id']}, {'name': self.role_member['name']}]} expires_at = timeutils.strtime(timeutils.utcnow() + @@ -525,7 +526,7 @@ class AuthWithTrust(AuthTest): fmt=TIME_FORMAT) self.create_trust(expires_at=expires_at) - def create_trust(self, expires_at=None, impersonation='True'): + def create_trust(self, expires_at=None, impersonation=True): username = self.trustor['name'], password = 'foo2' body_dict = _build_user_auth(username=username, password=password) @@ -586,20 +587,42 @@ class AuthWithTrust(AuthTest): self.assertIn(role['id'], role_ids) def test_create_trust_no_impersonation(self): - self.create_trust(expires_at=None, impersonation='False') + self.create_trust(expires_at=None, impersonation=False) self.assertEquals(self.new_trust['trustor_user_id'], self.trustor['id']) self.assertEquals(self.new_trust['trustee_user_id'], self.trustee['id']) - self.assertEquals(self.new_trust['impersonation'], - 'False') + self.assertIs(self.new_trust['impersonation'], False) auth_response = self.fetch_v2_token_from_trust() token_user = auth_response['access']['user'] self.assertEquals(token_user['id'], self.new_trust['trustee_user_id']) - #TODO Endpoints + def test_create_trust_impersonation(self): + self.create_trust(expires_at=None) + self.assertEqual(self.new_trust['trustor_user_id'], self.trustor['id']) + self.assertEqual(self.new_trust['trustee_user_id'], self.trustee['id']) + self.assertIs(self.new_trust['impersonation'], True) + auth_response = self.fetch_v2_token_from_trust() + token_user = auth_response['access']['user'] + self.assertEqual(token_user['id'], self.new_trust['trustor_user_id']) + + def test_disallow_ec2_credential_from_trust_scoped_token(self): + ec2_manager = ec2.Manager() + self.ec2_controller = ec2.Ec2Controller() + self.test_create_trust_impersonation() + auth_response = self.fetch_v2_token_from_trust() + # ensure it is not possible to create an ec2 token from a trust + context = {'token_id': auth_response['access']['token']['id'], + 'is_admin': False} + + self.assertRaises(exception.Forbidden, + self.ec2_controller.create_credential, + context=context, + user_id=self.user_foo['id'], + tenant_id=self.tenant_bar['id']) + def test_token_from_trust_wrong_user_fails(self): new_trust = self.create_trust() request_body = self.build_v2_token_request('FOO', 'foo2')