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:
		@@ -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": []
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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", {})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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"))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user