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
This commit is contained in:
Jamie Lennox 2016-05-10 14:10:52 +10:00
parent 118c9629e5
commit ed75863807
5 changed files with 78 additions and 1 deletions

View File

@ -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'])

View File

@ -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')

View File

@ -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)

View File

@ -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)

View File

@ -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'])