From bede7826300884fba1a64aae3b807ccbb419b5ca Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Tue, 24 Jul 2018 06:03:29 +0900 Subject: [PATCH] policy-in-code support in neutron-lib policy-in-code will be supported by the main neutron repo because the neutron API layer uses the policy code in the neutron repo. However, neutron_lib.context refers to its own policy enforcer, so we need a small code to support policy-in-code in neutron-lib side. Part of blueprint get-policy-from-neutron-lib Change-Id: I4923a069f4080dc53a8fb359f5a1518de06feb2f --- neutron_lib/_policy.py | 42 +++++++++++++++++++ neutron_lib/tests/etc/dummy_policy.json | 4 ++ neutron_lib/tests/unit/test__policy.py | 14 ++++++- .../policy-in-code-1e73cabebd41d66e.yaml | 8 ++++ setup.cfg | 6 +++ 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 neutron_lib/tests/etc/dummy_policy.json create mode 100644 releasenotes/notes/policy-in-code-1e73cabebd41d66e.yaml diff --git a/neutron_lib/_policy.py b/neutron_lib/_policy.py index 1bd16cc12..4c8b46e6a 100644 --- a/neutron_lib/_policy.py +++ b/neutron_lib/_policy.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import sys + from oslo_config import cfg from oslo_policy import policy @@ -19,6 +21,18 @@ _ADMIN_CTX_POLICY = 'context_is_admin' _ADVSVC_CTX_POLICY = 'context_is_advsvc' +_BASE_RULES = [ + policy.RuleDefault( + _ADMIN_CTX_POLICY, + 'role:admin', + description='Rule for cloud admin access'), + policy.RuleDefault( + _ADVSVC_CTX_POLICY, + 'role:advsvc', + description='Rule for advanced service role access'), +] + + def init(conf=cfg.CONF, policy_file=None): """Initialize the global enforcer if not already initialized. @@ -35,6 +49,7 @@ def init(conf=cfg.CONF, policy_file=None): global _ROLE_ENFORCER if not _ROLE_ENFORCER: _ROLE_ENFORCER = policy.Enforcer(conf, policy_file=policy_file) + _ROLE_ENFORCER.register_defaults(_BASE_RULES) _ROLE_ENFORCER.load_rules(True) @@ -65,3 +80,30 @@ def check_is_advsvc(context): enforcer) and False otherwise. """ return _check_rule(context, _ADVSVC_CTX_POLICY) + + +def list_rules(): + return _BASE_RULES + + +def get_enforcer(): + # NOTE(amotoki): This was borrowed from nova/policy.py. + # This method is for use by oslo.policy CLI scripts. Those scripts need the + # 'output-file' and 'namespace' options, but having those in sys.argv means + # loading the neutron config options will fail as those are not expected to + # be present. So we pass in an arg list with those stripped out. + conf_args = [] + # Start at 1 because cfg.CONF expects the equivalent of sys.argv[1:] + i = 1 + while i < len(sys.argv): + if sys.argv[i].strip('-') in ['namespace', 'output-file']: + i += 2 + continue + conf_args.append(sys.argv[i]) + i += 1 + + # 'project' must be 'neutron' so that get_enforcer looks at + # /etc/neutron/policy.json by default. + cfg.CONF(conf_args, project='neutron') + init() + return _ROLE_ENFORCER diff --git a/neutron_lib/tests/etc/dummy_policy.json b/neutron_lib/tests/etc/dummy_policy.json new file mode 100644 index 000000000..2e57efb43 --- /dev/null +++ b/neutron_lib/tests/etc/dummy_policy.json @@ -0,0 +1,4 @@ +{ + "context_is_admin": "role:dummy", + "context_is_advsvc": "role:dummy" +} diff --git a/neutron_lib/tests/unit/test__policy.py b/neutron_lib/tests/unit/test__policy.py index 4c49f910f..21af2d561 100644 --- a/neutron_lib/tests/unit/test__policy.py +++ b/neutron_lib/tests/unit/test__policy.py @@ -39,11 +39,16 @@ class TestPolicyEnforcer(base.BaseTestCase): self.assertTrue(policy.check_is_admin(ctx)) def test_check_is_admin_no_roles_no_admin(self): - policy.init(policy_file='no_policy.json') + policy.init(policy_file='dummy_policy.json') ctx = context.Context('me', 'my_project', roles=['user']).elevated() # With no admin role, elevated() should not work. self.assertFalse(policy.check_is_admin(ctx)) + def test_check_user_elevated_is_admin_with_default_policy(self): + policy.init(policy_file='no_policy.json') + ctx = context.Context('me', 'my_project', roles=['user']).elevated() + self.assertTrue(policy.check_is_admin(ctx)) + def test_check_is_advsvc_role(self): ctx = context.Context('me', 'my_project', roles=['advsvc']) self.assertTrue(policy.check_is_advsvc(ctx)) @@ -58,7 +63,12 @@ class TestPolicyEnforcer(base.BaseTestCase): self.assertFalse(policy.check_is_advsvc(ctx)) def test_check_is_advsvc_no_roles_no_advsvc(self): - policy.init(policy_file='no_policy.json') + policy.init(policy_file='dummy_policy.json') ctx = context.Context('me', 'my_project', roles=['advsvc']) # No advsvc role in the policy file, so cannot assume the role. self.assertFalse(policy.check_is_advsvc(ctx)) + + def test_check_is_advsvc_role_with_default_policy(self): + policy.init(policy_file='no_policy.json') + ctx = context.Context('me', 'my_project', roles=['advsvc']) + self.assertTrue(policy.check_is_advsvc(ctx)) diff --git a/releasenotes/notes/policy-in-code-1e73cabebd41d66e.yaml b/releasenotes/notes/policy-in-code-1e73cabebd41d66e.yaml new file mode 100644 index 000000000..be34f1489 --- /dev/null +++ b/releasenotes/notes/policy-in-code-1e73cabebd41d66e.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + policy-in-code support in neutron-lib is added. + The default policies for 'context_is_admin' and 'context_is_advsvc' are + now implemented as embeded policies. + (Note that the main policy-in-code support will be implemented + in the main neutron codebase.) diff --git a/setup.cfg b/setup.cfg index 76caaa7d1..e7c2316b9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,6 +22,12 @@ classifier = packages = neutron_lib +[entry_points] +oslo.policy.enforcer = + neutron_lib = neutron_lib._policy:get_enforcer +oslo.policy.policies = + neutron_lib = neutron_lib._policy:list_rules + [compile_catalog] directory = neutron_lib/locale domain = neutron_lib