From b1f1e50a0d6005aeed8553db0928e9f6d16a5dc3 Mon Sep 17 00:00:00 2001 From: Clenimar Sousa Date: Fri, 19 Feb 2016 11:23:22 -0300 Subject: [PATCH] Add is_domain to keystoneauth token This patch allows keystoneauth to handle the v3 project scoped token 'is_domain' flag, that represents whether the scoped project acts as a domain. Follow on patches will build on this to create policy rules to execute domain scoped token operations with project tokens. Change-Id: I28bea2aa1e1ab299eba1dfa9f0a8451a7846a5d5 Partially-Implements: add-isdomain-to-token Depends-On: Ic0bd0c6cf2c47680063752820a067cf40d47b184 --- keystoneauth1/access/access.py | 16 ++++++ keystoneauth1/fixture/v3.py | 18 +++++-- .../tests/unit/access/test_v3_access.py | 49 +++++++++++++++++++ keystoneauth1/tests/unit/test_fixtures.py | 28 +++++++++++ 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/keystoneauth1/access/access.py b/keystoneauth1/access/access.py index de299e3e..69ca1b50 100644 --- a/keystoneauth1/access/access.py +++ b/keystoneauth1/access/access.py @@ -397,6 +397,14 @@ class AccessInfo(object): """ raise NotImplementedError() + @property + def project_is_domain(self): + """Return if a project act as a domain. + + :returns: bool + """ + raise NotImplementedError() + class AccessInfoV2(AccessInfo): """An object for encapsulating raw v2 auth token from identity service.""" @@ -528,6 +536,10 @@ class AccessInfoV2(AccessInfo): except KeyError: pass + @property + def project_is_domain(self): + return False + @property def project_domain_id(self): return None @@ -658,6 +670,10 @@ class AccessInfoV3(AccessInfo): def project_id(self): return self._project['id'] + @_missingproperty + def project_is_domain(self): + return self._data['token']['is_domain'] + @_missingproperty def project_domain_id(self): return self._project['domain']['id'] diff --git a/keystoneauth1/fixture/v3.py b/keystoneauth1/fixture/v3.py index cd4a67fa..2fbcd582 100644 --- a/keystoneauth1/fixture/v3.py +++ b/keystoneauth1/fixture/v3.py @@ -63,7 +63,7 @@ class Token(dict): trust_id=None, trust_impersonation=None, trustee_user_id=None, trustor_user_id=None, oauth_access_token_id=None, oauth_consumer_id=None, audit_id=None, audit_chain_id=None, - is_admin_project=None): + is_admin_project=None, project_is_domain=None): super(Token, self).__init__() self.user_id = user_id or uuid.uuid4().hex @@ -99,7 +99,8 @@ class Token(dict): self.set_project_scope(id=project_id, name=project_name, domain_id=project_domain_id, - domain_name=project_domain_name) + domain_name=project_domain_name, + is_domain=project_is_domain) if domain_id or domain_name: self.set_domain_scope(id=domain_id, name=domain_name) @@ -213,6 +214,14 @@ class Token(dict): def project_id(self, value): self.root.setdefault('project', {})['id'] = value + @property + def project_is_domain(self): + return self.root.get('is_domain') + + @project_is_domain.setter + def project_is_domain(self, value): + self.root['is_domain'] = value + @property def project_name(self): return self.root.get('project', {}).get('name') @@ -390,12 +399,15 @@ class Token(dict): return service def set_project_scope(self, id=None, name=None, domain_id=None, - domain_name=None): + domain_name=None, is_domain=None): self.project_id = id or uuid.uuid4().hex self.project_name = name or uuid.uuid4().hex self.project_domain_id = domain_id or uuid.uuid4().hex self.project_domain_name = domain_name or uuid.uuid4().hex + if is_domain is not None: + self.project_is_domain = is_domain + def set_domain_scope(self, id=None, name=None): self.domain_id = id or uuid.uuid4().hex self.domain_name = name or uuid.uuid4().hex diff --git a/keystoneauth1/tests/unit/access/test_v3_access.py b/keystoneauth1/tests/unit/access/test_v3_access.py index 4054c2e8..6dfca997 100644 --- a/keystoneauth1/tests/unit/access/test_v3_access.py +++ b/keystoneauth1/tests/unit/access/test_v3_access.py @@ -44,6 +44,7 @@ class AccessV3Test(utils.TestCase): self.assertFalse(auth_ref.domain_scoped) self.assertFalse(auth_ref.project_scoped) + self.assertIsNone(auth_ref.project_is_domain) self.assertEqual(token.user_domain_id, auth_ref.user_domain_id) self.assertEqual(token.user_domain_name, auth_ref.user_domain_name) @@ -110,6 +111,7 @@ class AccessV3Test(utils.TestCase): self.assertTrue(auth_ref.domain_scoped) self.assertFalse(auth_ref.project_scoped) + self.assertIsNone(auth_ref.project_is_domain) self.assertEqual(token.audit_id, auth_ref.audit_id) self.assertEqual(token.audit_chain_id, auth_ref.audit_chain_id) @@ -155,6 +157,53 @@ class AccessV3Test(utils.TestCase): self.assertFalse(auth_ref.domain_scoped) self.assertTrue(auth_ref.project_scoped) + self.assertIsNone(auth_ref.project_is_domain) + + self.assertEqual(token.audit_id, auth_ref.audit_id) + self.assertEqual(token.audit_chain_id, auth_ref.audit_chain_id) + + def test_building_project_as_domain_scoped_accessinfo(self): + token = fixture.V3Token() + token.set_project_scope(is_domain=True) + + service = token.add_service(type='identity') + service.add_standard_endpoints(public='http://url') + + token_id = uuid.uuid4().hex + + auth_ref = access.create(body=token, auth_token=token_id) + + self.assertIn('methods', auth_ref._data['token']) + self.assertIn('catalog', auth_ref._data['token']) + self.assertTrue(auth_ref.has_service_catalog()) + self.assertTrue(auth_ref._data['token']['catalog']) + + self.assertEqual(token_id, auth_ref.auth_token) + self.assertEqual(token.user_name, auth_ref.username) + self.assertEqual(token.user_id, auth_ref.user_id) + + self.assertEqual(token.role_ids, auth_ref.role_ids) + self.assertEqual(token.role_names, auth_ref.role_names) + + self.assertIsNone(auth_ref.domain_name) + self.assertIsNone(auth_ref.domain_id) + + self.assertEqual(token.project_name, auth_ref.project_name) + self.assertEqual(token.project_id, auth_ref.project_id) + + self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) + self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) + + self.assertEqual(token.project_domain_id, auth_ref.project_domain_id) + self.assertEqual(token.project_domain_name, + auth_ref.project_domain_name) + + self.assertEqual(token.user_domain_id, auth_ref.user_domain_id) + self.assertEqual(token.user_domain_name, auth_ref.user_domain_name) + + self.assertFalse(auth_ref.domain_scoped) + self.assertTrue(auth_ref.project_scoped) + self.assertTrue(auth_ref.project_is_domain) self.assertEqual(token.audit_id, auth_ref.audit_id) self.assertEqual(token.audit_chain_id, auth_ref.audit_chain_id) diff --git a/keystoneauth1/tests/unit/test_fixtures.py b/keystoneauth1/tests/unit/test_fixtures.py index 55296594..81996698 100644 --- a/keystoneauth1/tests/unit/test_fixtures.py +++ b/keystoneauth1/tests/unit/test_fixtures.py @@ -164,6 +164,34 @@ class V3TokenTests(utils.TestCase): self.assertEqual(project_name, token.project_name) self.assertEqual(project_name, token['token']['project']['name']) + self.assertIsNone(token.get('token', {}).get('is_domain')) + + project_domain = token['token']['project']['domain'] + + self.assertEqual(project_domain_id, token.project_domain_id) + self.assertEqual(project_domain_id, project_domain['id']) + self.assertEqual(project_domain_name, token.project_domain_name) + self.assertEqual(project_domain_name, project_domain['name']) + + def test_project_as_domain_scoped(self): + project_id = uuid.uuid4().hex + project_name = uuid.uuid4().hex + project_domain_id = uuid.uuid4().hex + project_domain_name = uuid.uuid4().hex + project_is_domain = True + + token = fixture.V3Token(project_id=project_id, + project_name=project_name, + project_domain_id=project_domain_id, + project_domain_name=project_domain_name, + project_is_domain=project_is_domain) + + self.assertEqual(project_id, token.project_id) + self.assertEqual(project_id, token['token']['project']['id']) + self.assertEqual(project_name, token.project_name) + self.assertEqual(project_name, token['token']['project']['name']) + self.assertEqual(project_is_domain, token['token']['is_domain']) + project_domain = token['token']['project']['domain'] self.assertEqual(project_domain_id, token.project_domain_id)