diff options
author | Jamie Lennox <jamielennox@gmail.com> | 2016-06-21 12:26:25 +1000 |
---|---|---|
committer | Jamie Lennox <jamielennox@gmail.com> | 2016-07-08 12:30:25 +1000 |
commit | d3af1d06b4046c25c199bf1c389a9e440a634bc6 (patch) | |
tree | 29dd74acabaf936d05d56894c7b493f9a7c03acf /oslo_context | |
parent | ae6f152447f4b915a2ca72b554a6157a18c857ea (diff) | |
download | oslo-context-d3af1d06b4046c25c199bf1c389a9e440a634bc6.tar.gz |
Add is_admin_project to context
is_admin_project is provided by keystonemiddleware and used by
oslo.policy to enforce that a project scoped token exists in the admin
project.
To make this usable we add the ability to read the X-Is-Admin-Project
header from the environment, and add it to the outputted policy values.
Note the value is added to keystonemiddleware in the depend review
however it must work even with older auth_token middlewares so is fine
to merge prior to a middleware release.
Closes-Bug: #1577996
Depends-On: Ic680e6eaa683926914cf4b2152ec3bb67c6601ff
Change-Id: Ie48fedb8092e33e9645a37ea3fe44b88d34ad3b8
Diffstat (limited to 'oslo_context')
-rw-r--r-- | oslo_context/context.py | 21 | ||||
-rw-r--r-- | oslo_context/tests/test_context.py | 37 |
2 files changed, 54 insertions, 4 deletions
diff --git a/oslo_context/context.py b/oslo_context/context.py index bbf26a4..09da29e 100644 --- a/oslo_context/context.py +++ b/oslo_context/context.py @@ -71,11 +71,16 @@ class RequestContext(object): read_only=False, show_deleted=False, request_id=None, resource_uuid=None, overwrite=True, roles=None, user_name=None, project_name=None, domain_name=None, - user_domain_name=None, project_domain_name=None): + user_domain_name=None, project_domain_name=None, + is_admin_project=True): """Initialize the RequestContext :param overwrite: Set to False to ensure that the greenthread local copy of the index is not overwritten. + :param is_admin_project: Whether the specified project is specified in + the token as the admin project. Defaults to + True for backwards compatibility. + :type is_admin_project: bool """ self.auth_token = auth_token self.user = user @@ -91,6 +96,7 @@ class RequestContext(object): self.project_domain = project_domain self.project_domain_name = project_domain_name self.is_admin = is_admin + self.is_admin_project = is_admin_project self.read_only = read_only self.show_deleted = show_deleted self.resource_uuid = resource_uuid @@ -121,7 +127,8 @@ class RequestContext(object): 'user_domain_id': self.user_domain, 'project_id': self.tenant, 'project_domain_id': self.project_domain, - 'roles': self.roles} + 'roles': self.roles, + 'is_admin_project': self.is_admin_project} def to_dict(self): """Return a dictionary of context attributes.""" @@ -144,7 +151,8 @@ class RequestContext(object): 'request_id': self.request_id, 'resource_uuid': self.resource_uuid, 'roles': self.roles, - 'user_identity': user_idt} + 'user_identity': user_idt, + 'is_admin_project': self.is_admin_project} def get_logging_values(self): """Return a dictionary of logging specific context attributes.""" @@ -194,6 +202,13 @@ class RequestContext(object): roles = [r.strip() for r in roles.split(',')] if roles else [] kwargs['roles'] = roles + if 'is_admin_project' not in kwargs: + # NOTE(jamielennox): we default is_admin_project to true because if + # nothing is provided we have to assume it is the admin project to + # make old policy continue to work. + is_admin_proj_str = environ.get('HTTP_X_IS_ADMIN_PROJECT', 'true') + kwargs['is_admin_project'] = is_admin_proj_str.lower() == 'true' + return cls(**kwargs) diff --git a/oslo_context/tests/test_context.py b/oslo_context/tests/test_context.py index 6829416..2141c8d 100644 --- a/oslo_context/tests/test_context.py +++ b/oslo_context/tests/test_context.py @@ -241,6 +241,22 @@ class ContextTest(test_base.BaseTestCase): ctx = context.RequestContext.from_environ(environ=environ) self.assertEqual(['abc', 'def', 'ghi'], ctx.roles) + def test_environ_admin_project(self): + environ = {} + ctx = context.RequestContext.from_environ(environ=environ) + self.assertIs(True, ctx.is_admin_project) + self.assertIs(True, ctx.to_policy_values()['is_admin_project']) + + environ = {'HTTP_X_IS_ADMIN_PROJECT': 'True'} + ctx = context.RequestContext.from_environ(environ=environ) + self.assertIs(True, ctx.is_admin_project) + self.assertIs(True, ctx.to_policy_values()['is_admin_project']) + + environ = {'HTTP_X_IS_ADMIN_PROJECT': 'False'} + ctx = context.RequestContext.from_environ(environ=environ) + self.assertIs(False, ctx.is_admin_project) + self.assertIs(False, ctx.to_policy_values()['is_admin_project']) + def test_from_function_and_args(self): ctx = context.RequestContext(user="user1") arg = [] @@ -390,6 +406,7 @@ class ContextTest(test_base.BaseTestCase): project_domain = uuid.uuid4().hex roles = [uuid.uuid4().hex, uuid.uuid4().hex, uuid.uuid4().hex] + # default is_admin_project is True ctx = context.RequestContext(user=user, user_domain=user_domain, tenant=tenant, @@ -400,4 +417,22 @@ class ContextTest(test_base.BaseTestCase): 'user_domain_id': user_domain, 'project_id': tenant, 'project_domain_id': project_domain, - 'roles': roles}, ctx.to_policy_values()) + 'roles': roles, + 'is_admin_project': True}, + ctx.to_policy_values()) + + # is_admin_project False gets passed through + ctx = context.RequestContext(user=user, + user_domain=user_domain, + tenant=tenant, + project_domain=project_domain, + roles=roles, + is_admin_project=False) + + self.assertEqual({'user_id': user, + 'user_domain_id': user_domain, + 'project_id': tenant, + 'project_domain_id': project_domain, + 'roles': roles, + 'is_admin_project': False}, + ctx.to_policy_values()) |