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
This commit is contained in:
Brian Waldon
2012-01-16 15:28:49 -08:00
parent 1fd26203b2
commit 85518a93ef
5 changed files with 63 additions and 93 deletions

View File

@@ -1,95 +1,17 @@
{ {
"admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]], "admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]],
"default": [["rule:admin_or_owner"]],
"compute:create": [["rule:admin_or_owner"]], "compute:create": [],
"compute:create:attach_network": [["rule:admin_or_owner"]], "compute:create:attach_network": [],
"compute:create:attach_volume": [["rule:admin_or_owner"]], "compute:create:attach_volume": [],
"compute:get": [["rule:admin_or_owner"]],
"compute:get_all" :[], "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:create": [],
"volume:get": [],
"volume:get_all": [], "volume:get_all": [],
"volume:get_volume_metadata": [], "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_snapshot": [],
"volume:get_all_snapshots": [] "volume:get_all_snapshots": []
} }

View File

@@ -104,13 +104,14 @@ def enforce(match_list, target_dict, credentials_dict):
class Brain(object): class Brain(object):
"""Implements policy checking.""" """Implements policy checking."""
@classmethod @classmethod
def load_json(cls, data): def load_json(cls, data, default_rule=None):
"""Init a brain using json instead of a rules dictionary.""" """Init a brain using json instead of a rules dictionary."""
rules_dict = json.loads(data) 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.rules = rules or {}
self.default_rule = default_rule
def add_rule(self, key, match): def add_rule(self, key, match):
self.rules[key] = match self.rules[key] = match
@@ -154,7 +155,11 @@ class Brain(object):
try: try:
new_match_list = self.rules[match] new_match_list = self.rules[match]
except KeyError: 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) return self.check(new_match_list, target_dict, cred_dict)
def _check_role(self, match, target_dict, cred_dict): def _check_role(self, match, target_dict, cred_dict):

View File

@@ -25,6 +25,8 @@ from nova import utils
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
flags.DEFINE_string('policy_file', 'policy.json', flags.DEFINE_string('policy_file', 'policy.json',
_('JSON file representing policy')) _('JSON file representing policy'))
flags.DEFINE_string('policy_default_rule', 'default',
_('Rule checked when requested rule is not found'))
_POLICY_PATH = None _POLICY_PATH = None
_POLICY_CACHE = {} _POLICY_CACHE = {}
@@ -48,7 +50,8 @@ def init():
def _set_brain(data): 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): def enforce(context, action, target):
@@ -69,10 +72,11 @@ def enforce(context, action, target):
""" """
init() init()
match_list = ('rule:%s' % action,) match_list = ('rule:%s' % action,)
target_dict = target credentials = context.to_dict()
credentials_dict = context.to_dict()
try: try:
policy.enforce(match_list, target_dict, credentials_dict) policy.enforce(match_list, target, credentials)
except policy.NotAuthorized: except policy.NotAuthorized:
raise exception.PolicyNotAuthorized(action=action) raise exception.PolicyNotAuthorized(action=action)

View File

@@ -25,6 +25,7 @@ from nova.common import policy as common_policy
from nova import context from nova import context
from nova import exception from nova import exception
from nova import flags from nova import flags
import nova.common.policy
from nova import policy from nova import policy
from nova import test from nova import test
@@ -137,3 +138,40 @@ class PolicyTestCase(test.TestCase):
def test_early_OR_enforcement(self): def test_early_OR_enforcement(self):
action = "example:early_or_success" action = "example:early_or_success"
policy.enforce(self.context, action, self.target) 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", {})

View File

@@ -146,9 +146,10 @@ class API(base.Base):
self.db.volume_update(context, volume['id'], fields) self.db.volume_update(context, volume['id'], fields)
def get(self, context, volume_id): def get(self, context, volume_id):
check_policy(context, 'get', {'id': volume_id})
rv = self.db.volume_get(context, 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={}): def get_all(self, context, search_opts={}):
check_policy(context, 'get_all') check_policy(context, 'get_all')
@@ -262,7 +263,7 @@ class API(base.Base):
def _create_snapshot(self, context, volume, name, description, def _create_snapshot(self, context, volume, name, description,
force=False): force=False):
check_policy(context, 'create_snapshot') check_policy(context, 'create_snapshot', volume)
if ((not force) and (volume['status'] != "available")): if ((not force) and (volume['status'] != "available")):
raise exception.ApiError(_("Volume status must be available")) raise exception.ApiError(_("Volume status must be available"))