diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 3970ce96aea9..02bf503cd752 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -1,4 +1,5 @@ { + "admin": [["role:admin"]], "admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]], "default": [["rule:admin_or_owner"]], diff --git a/nova/context.py b/nova/context.py index 66697b567a77..b6fd105eba5a 100644 --- a/nova/context.py +++ b/nova/context.py @@ -24,6 +24,7 @@ import copy from nova.openstack.common import local from nova.openstack.common import log as logging from nova.openstack.common import timeutils +from nova import policy from nova import utils @@ -66,9 +67,7 @@ class RequestContext(object): self.roles = roles or [] self.is_admin = is_admin if self.is_admin is None: - self.is_admin = 'admin' in [x.lower() for x in self.roles] - elif self.is_admin and 'admin' not in self.roles: - self.roles.append('admin') + self.is_admin = policy.check_admin_role(self.roles) self.read_deleted = read_deleted self.remote_address = remote_address if not timestamp: diff --git a/nova/policy.py b/nova/policy.py index 94bbbdd937c4..acfe830b9961 100644 --- a/nova/policy.py +++ b/nova/policy.py @@ -92,3 +92,23 @@ def enforce(context, action, target): policy.enforce(match_list, target, credentials, exception.PolicyNotAuthorized, action=action) + + +def check_admin_role(roles): + """Whether or not roles contains 'admin' role according to policy setting. + + """ + init() + + action = 'admin' + match_list = ('rule:%s' % action,) + target = {} + credentials = {'roles': roles} + + try: + policy.enforce(match_list, target, credentials, + exception.PolicyNotAuthorized, action=action) + except exception.PolicyNotAuthorized: + return False + + return True diff --git a/nova/tests/policy.json b/nova/tests/policy.json index 6fa0cf4b398a..a2d948323ff4 100644 --- a/nova/tests/policy.json +++ b/nova/tests/policy.json @@ -1,4 +1,5 @@ { + "admin": [["role:admin"], ["role:administrator"]], "compute:create": [], "compute:create:attach_network": [], "compute:create:attach_volume": [], diff --git a/nova/tests/test_context.py b/nova/tests/test_context.py index 977095910ed3..0915bf157f29 100644 --- a/nova/tests/test_context.py +++ b/nova/tests/test_context.py @@ -26,6 +26,12 @@ class ContextTestCase(test.TestCase): roles=['admin', 'weasel']) self.assertEquals(ctxt.is_admin, True) + def test_request_context_sets_is_admin_by_role(self): + ctxt = context.RequestContext('111', + '222', + roles=['administrator']) + self.assertEquals(ctxt.is_admin, True) + def test_request_context_sets_is_admin_upcase(self): ctxt = context.RequestContext('111', '222', diff --git a/nova/tests/test_policy.py b/nova/tests/test_policy.py index 41282005ae0d..a85d3e25cd46 100644 --- a/nova/tests/test_policy.py +++ b/nova/tests/test_policy.py @@ -49,6 +49,11 @@ class PolicyFileTestCase(test.TestCase): tmpfilename = os.path.join(tmpdir, 'policy') self.flags(policy_file=tmpfilename) + # NOTE(uni): context construction invokes policy check to determin + # is_admin or not. As a side-effect, policy reset is needed here + # to flush existing policy cache. + policy.reset() + action = "example:test" with open(tmpfilename, "w") as policyfile: policyfile.write("""{"example:test": []}""")