diff options
author | Brian Waldon <bcwaldon@gmail.com> | 2012-01-16 15:28:49 -0800 |
---|---|---|
committer | Brian Waldon <bcwaldon@gmail.com> | 2012-01-16 16:07:40 -0800 |
commit | 85518a93ef01ae997ecfc0687d89ba87f7607f54 (patch) | |
tree | 9d7928af887d05d8b1052ea5c9cabee82247f4bb | |
parent | 1fd26203b29d6432325ae1365e3dcbecc9d97864 (diff) | |
download | nova-85518a93ef01ae997ecfc0687d89ba87f7607f54.tar.gz |
Add default policy rule
If a specific rule is not found, we will check the rule defined in FLAGS.policy_default_action.
Change-Id: Ib1b1aa4bbeec74bdb1562d0fc649d33838076f01
-rw-r--r-- | etc/nova/policy.json | 86 | ||||
-rw-r--r-- | nova/common/policy.py | 13 | ||||
-rw-r--r-- | nova/policy.py | 12 | ||||
-rw-r--r-- | nova/tests/test_policy.py | 38 | ||||
-rw-r--r-- | nova/volume/api.py | 7 |
5 files changed, 63 insertions, 93 deletions
diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 00140886bf..78003d2e32 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -1,95 +1,17 @@ { "admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]], + "default": [["rule:admin_or_owner"]], - "compute:create": [["rule:admin_or_owner"]], - "compute:create:attach_network": [["rule:admin_or_owner"]], - "compute:create:attach_volume": [["rule:admin_or_owner"]], - - "compute:get": [["rule:admin_or_owner"]], + "compute:create": [], + "compute:create:attach_network": [], + "compute:create:attach_volume": [], "compute:get_all" :[], - "compute:update": [["rule:admin_or_owner"]], - - "compute:get_instance_metadata": [["rule:admin_or_owner"]], - "compute:update_instance_metadata": [["rule:admin_or_owner"]], - "compute:delete_instance_metadata": [["rule:admin_or_owner"]], - - "compute:get_instance_faults": [["rule:admin_or_owner"]], - "compute:get_actions": [["rule:admin_or_owner"]], - "compute:get_diagnostics": [["rule:admin_or_owner"]], - - "compute:get_lock": [["rule:admin_or_owner"]], - "compute:lock": [["rule:admin_or_owner"]], - "compute:unlock": [["rule:admin_or_owner"]], - - "compute:get_ajax_console": [["rule:admin_or_owner"]], - "compute:get_vnc_console": [["rule:admin_or_owner"]], - "compute:get_console_output": [["rule:admin_or_owner"]], - - "compute:associate_floating_ip": [["rule:admin_or_owner"]], - "compute:reset_network": [["rule:admin_or_owner"]], - "compute:inject_network_info": [["rule:admin_or_owner"]], - "compute:add_fixed_ip": [["rule:admin_or_owner"]], - "compute:remove_fixed_ip": [["rule:admin_or_owner"]], - - "compute:attach_volume": [["rule:admin_or_owner"]], - "compute:detach_volume": [["rule:admin_or_owner"]], - - "compute:inject_file": [["rule:admin_or_owner"]], - - "compute:set_admin_password": [["rule:admin_or_owner"]], - - "compute:rescue": [["rule:admin_or_owner"]], - "compute:unrescue": [["rule:admin_or_owner"]], - - "compute:suspend": [["rule:admin_or_owner"]], - "compute:resume": [["rule:admin_or_owner"]], - - "compute:pause": [["rule:admin_or_owner"]], - "compute:unpause": [["rule:admin_or_owner"]], - - "compute:start": [["rule:admin_or_owner"]], - "compute:stop": [["rule:admin_or_owner"]], - - "compute:resize": [["rule:admin_or_owner"]], - "compute:confirm_resize": [["rule:admin_or_owner"]], - "compute:revert_resize": [["rule:admin_or_owner"]], - - "compute:rebuild": [["rule:admin_or_owner"]], - - "compute:reboot": [["rule:admin_or_owner"]], - - "compute:snapshot": [["rule:admin_or_owner"]], - "compute:backup": [["rule:admin_or_owner"]], - - "compute:add_security_group": [["rule:admin_or_owner"]], - "compute:remove_security_group": [["rule:admin_or_owner"]], - - "compute:delete": [["rule:admin_or_owner"]], - "compute:soft_delete": [["rule:admin_or_owner"]], - "compute:force_delete": [["rule:admin_or_owner"]], - "compute:restore": [["rule:admin_or_owner"]], - "volume:create": [], - "volume:get": [], "volume:get_all": [], "volume:get_volume_metadata": [], - "volume:delete": [], - "volume:update": [], - "volume:delete_volume_metadata": [], - "volume:update_volume_metadata": [], - - "volume:attach": [], - "volume:detach": [], - "volume:check_attach": [], - "volume:check_detach": [], - "volume:initialize_connection": [], - "volume:terminate_connection": [], - - "volume:create_snapshot": [], - "volume:delete_snapshot": [], "volume:get_snapshot": [], "volume:get_all_snapshots": [] } diff --git a/nova/common/policy.py b/nova/common/policy.py index b7cd3cf417..d8d29d6b05 100644 --- a/nova/common/policy.py +++ b/nova/common/policy.py @@ -104,13 +104,14 @@ def enforce(match_list, target_dict, credentials_dict): class Brain(object): """Implements policy checking.""" @classmethod - def load_json(cls, data): + def load_json(cls, data, default_rule=None): """Init a brain using json instead of a rules dictionary.""" rules_dict = json.loads(data) - return cls(rules=rules_dict) + return cls(rules=rules_dict, default_rule=default_rule) - def __init__(self, rules=None): + def __init__(self, rules=None, default_rule=None): self.rules = rules or {} + self.default_rule = default_rule def add_rule(self, key, match): self.rules[key] = match @@ -154,7 +155,11 @@ class Brain(object): try: new_match_list = self.rules[match] except KeyError: - return False + if self.default_rule and match != self.default_rule: + new_match_list = ('rule:%s' % self.default_rule,) + else: + return False + return self.check(new_match_list, target_dict, cred_dict) def _check_role(self, match, target_dict, cred_dict): diff --git a/nova/policy.py b/nova/policy.py index 1b3d77996b..22551d6a40 100644 --- a/nova/policy.py +++ b/nova/policy.py @@ -25,6 +25,8 @@ from nova import utils FLAGS = flags.FLAGS flags.DEFINE_string('policy_file', 'policy.json', _('JSON file representing policy')) +flags.DEFINE_string('policy_default_rule', 'default', + _('Rule checked when requested rule is not found')) _POLICY_PATH = None _POLICY_CACHE = {} @@ -48,7 +50,8 @@ def init(): def _set_brain(data): - policy.set_brain(policy.HttpBrain.load_json(data)) + default_rule = FLAGS.policy_default_rule + policy.set_brain(policy.HttpBrain.load_json(data, default_rule)) def enforce(context, action, target): @@ -69,10 +72,11 @@ def enforce(context, action, target): """ init() + match_list = ('rule:%s' % action,) - target_dict = target - credentials_dict = context.to_dict() + credentials = context.to_dict() + try: - policy.enforce(match_list, target_dict, credentials_dict) + policy.enforce(match_list, target, credentials) except policy.NotAuthorized: raise exception.PolicyNotAuthorized(action=action) diff --git a/nova/tests/test_policy.py b/nova/tests/test_policy.py index fd3a05e764..d65371ea11 100644 --- a/nova/tests/test_policy.py +++ b/nova/tests/test_policy.py @@ -25,6 +25,7 @@ from nova.common import policy as common_policy from nova import context from nova import exception from nova import flags +import nova.common.policy from nova import policy from nova import test @@ -137,3 +138,40 @@ class PolicyTestCase(test.TestCase): def test_early_OR_enforcement(self): action = "example:early_or_success" policy.enforce(self.context, action, self.target) + + +class DefaultPolicyTestCase(test.TestCase): + + def setUp(self): + super(DefaultPolicyTestCase, self).setUp() + policy.reset() + policy.init() + + self.rules = { + "default": [], + "example:exist": [["false:false"]] + } + + self._set_brain('default') + + self.context = context.RequestContext('fake', 'fake') + + def _set_brain(self, default_rule): + brain = nova.common.policy.HttpBrain(self.rules, default_rule) + nova.common.policy.set_brain(brain) + + def tearDown(self): + super(DefaultPolicyTestCase, self).setUp() + policy.reset() + + def test_policy_called(self): + self.assertRaises(exception.PolicyNotAuthorized, policy.enforce, + self.context, "example:exist", {}) + + def test_not_found_policy_calls_default(self): + policy.enforce(self.context, "example:noexist", {}) + + def test_default_not_found(self): + self._set_brain("default_noexist") + self.assertRaises(exception.PolicyNotAuthorized, policy.enforce, + self.context, "example:noexist", {}) diff --git a/nova/volume/api.py b/nova/volume/api.py index 6f5921f7ca..cc9cac019b 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -146,9 +146,10 @@ class API(base.Base): self.db.volume_update(context, volume['id'], fields) def get(self, context, volume_id): - check_policy(context, 'get', {'id': volume_id}) rv = self.db.volume_get(context, volume_id) - return dict(rv.iteritems()) + volume = dict(rv.iteritems()) + check_policy(context, 'get', volume) + return volume def get_all(self, context, search_opts={}): check_policy(context, 'get_all') @@ -262,7 +263,7 @@ class API(base.Base): def _create_snapshot(self, context, volume, name, description, force=False): - check_policy(context, 'create_snapshot') + check_policy(context, 'create_snapshot', volume) if ((not force) and (volume['status'] != "available")): raise exception.ApiError(_("Volume status must be available")) |