From ed7586380732842a0b52236a59499d191033ef11 Mon Sep 17 00:00:00 2001 From: Jamie Lennox Date: Tue, 10 May 2016 14:10:52 +1000 Subject: [PATCH] Expose is_admin_project in AccessInfo There is currently incomplete is_admin_project information in the token. We can expose this already via keystoneauth because we have to handle the default case where there is nothing in the token. The default feels backwards but to handle the historical situation where a deployment has not got the admin_project set all projects were in the admin project so it must default to true for policy enforcement. Adds the fixture handling as well for testing with this enabled. Change-Id: I58db52427a2bac6cd56794429559771499dc7f5a Closes-Bug: #1577996 --- keystoneauth1/access/access.py | 20 +++++++++++++++++++ keystoneauth1/fixture/v3.py | 18 ++++++++++++++++- .../tests/unit/access/test_v2_access.py | 6 ++++++ .../tests/unit/access/test_v3_access.py | 18 +++++++++++++++++ keystoneauth1/tests/unit/test_fixtures.py | 17 ++++++++++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/keystoneauth1/access/access.py b/keystoneauth1/access/access.py index cf834fbf..de299e3e 100644 --- a/keystoneauth1/access/access.py +++ b/keystoneauth1/access/access.py @@ -329,6 +329,18 @@ class AccessInfo(object): """ raise NotImplementedError() + @property + def is_admin_project(self): + """Return true if the current project scope is the admin project. + + For backwards compatibility purposes if there is nothing specified in + the token we always assume we are in the admin project, so this will + default to True. + + :returns boolean + """ + raise NotImplementedError() + @property def audit_id(self): """Return the audit ID if present. @@ -536,6 +548,10 @@ class AccessInfoV2(AccessInfo): def is_federated(self): return False + @property + def is_admin_project(self): + return True + @property def audit_id(self): try: @@ -576,6 +592,10 @@ class AccessInfoV3(AccessInfo): def is_federated(self): return 'OS-FEDERATION' in self._user + @property + def is_admin_project(self): + return self._data.get('token', {}).get('is_admin_project', True) + @_missingproperty def expires(self): return utils.parse_isotime(self._data['token']['expires_at']) diff --git a/keystoneauth1/fixture/v3.py b/keystoneauth1/fixture/v3.py index f7cc3ebe..cd4a67fa 100644 --- a/keystoneauth1/fixture/v3.py +++ b/keystoneauth1/fixture/v3.py @@ -62,7 +62,8 @@ class Token(dict): project_domain_name=None, domain_id=None, domain_name=None, 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): + oauth_consumer_id=None, audit_id=None, audit_chain_id=None, + is_admin_project=None): super(Token, self).__init__() self.user_id = user_id or uuid.uuid4().hex @@ -117,6 +118,9 @@ class Token(dict): if audit_chain_id: self.audit_chain_id = audit_chain_id + if is_admin_project is not None: + self.is_admin_project = is_admin_project + @property def root(self): return self.setdefault('token', {}) @@ -335,6 +339,18 @@ class Token(dict): def role_names(self): return [r['name'] for r in self.root.get('roles', [])] + @property + def is_admin_project(self): + return self.root.get('is_admin_project') + + @is_admin_project.setter + def is_admin_project(self, value): + self.root['is_admin_project'] = value + + @is_admin_project.deleter + def is_admin_project(self): + self.root.pop('is_admin_project', None) + def validate(self): project = self.root.get('project') domain = self.root.get('domain') diff --git a/keystoneauth1/tests/unit/access/test_v2_access.py b/keystoneauth1/tests/unit/access/test_v2_access.py index 8f7bb503..aabef671 100644 --- a/keystoneauth1/tests/unit/access/test_v2_access.py +++ b/keystoneauth1/tests/unit/access/test_v2_access.py @@ -210,3 +210,9 @@ class AccessV2Test(utils.TestCase): self.assertIsInstance(auth_ref, access.AccessInfoV2) self.assertEqual({'kerberos': principal}, auth_ref.bind) + + def test_is_admin_project(self): + token = fixture.V2Token() + auth_ref = access.create(body=token) + self.assertIsInstance(auth_ref, access.AccessInfoV2) + self.assertIs(True, auth_ref.is_admin_project) diff --git a/keystoneauth1/tests/unit/access/test_v3_access.py b/keystoneauth1/tests/unit/access/test_v3_access.py index 7e9792c3..4054c2e8 100644 --- a/keystoneauth1/tests/unit/access/test_v3_access.py +++ b/keystoneauth1/tests/unit/access/test_v3_access.py @@ -195,3 +195,21 @@ class AccessV3Test(utils.TestCase): self.assertIsInstance(auth_ref, access.AccessInfoV3) self.assertEqual({'kerberos': principal}, auth_ref.bind) + + def test_is_admin_project_unset(self): + token = fixture.V3Token() + auth_ref = access.create(body=token) + self.assertIsInstance(auth_ref, access.AccessInfoV3) + self.assertIs(True, auth_ref.is_admin_project) + + def test_is_admin_project_true(self): + token = fixture.V3Token(is_admin_project=True) + auth_ref = access.create(body=token) + self.assertIsInstance(auth_ref, access.AccessInfoV3) + self.assertIs(True, auth_ref.is_admin_project) + + def test_is_admin_project_false(self): + token = fixture.V3Token(is_admin_project=False) + auth_ref = access.create(body=token) + self.assertIsInstance(auth_ref, access.AccessInfoV3) + self.assertIs(False, auth_ref.is_admin_project) diff --git a/keystoneauth1/tests/unit/test_fixtures.py b/keystoneauth1/tests/unit/test_fixtures.py index 0b533d00..55296594 100644 --- a/keystoneauth1/tests/unit/test_fixtures.py +++ b/keystoneauth1/tests/unit/test_fixtures.py @@ -297,3 +297,20 @@ class V3TokenTests(utils.TestCase): self.assertEqual({name1: data1, name2: data2}, token['token']['bind']) + + def test_is_admin_project(self): + token = fixture.V3Token() + self.assertIsNone(token.is_admin_project) + self.assertNotIn('is_admin_project', token['token']) + + token.is_admin_project = True + self.assertIs(True, token.is_admin_project) + self.assertIs(True, token['token']['is_admin_project']) + + token.is_admin_project = False + self.assertIs(False, token.is_admin_project) + self.assertIs(False, token['token']['is_admin_project']) + + del token.is_admin_project + self.assertIsNone(token.is_admin_project) + self.assertNotIn('is_admin_project', token['token'])