def _build_match_rule(action, target, pluralized): """Create the rule to match for a given action. The policy rule to be matched is built in the following way: 1) add entries for matching permission on objects 2) add an entry for the specific action (e.g.: create_network) 3) add an entry for attributes of a resource for which the action is being executed (e.g.: create_network:shared) 4) add an entry for sub-attributes of a resource for which the action is being executed (e.g.: create_router:external_gateway_info:network_id) """ match_rule = policy.RuleCheck('rule', action) registered_rule = _ENFORCER.registered_rules.get(action) if registered_rule and registered_rule.scope_types: match_rule.scope_types = registered_rule.scope_types resource, enforce_attr_based_check = get_resource_and_action( action, pluralized) if enforce_attr_based_check: # assigning to variable with short name for improving readability res_map = attributes.RESOURCES if resource in res_map: for attribute_name in res_map[resource]: if _is_attribute_explicitly_set(attribute_name, res_map[resource], target, action): attribute = res_map[resource][attribute_name] if 'enforce_policy' in attribute: attr_rule = policy.RuleCheck( 'rule', '%s:%s' % (action, attribute_name)) # Build match entries for sub-attributes if _should_validate_sub_attributes( attribute, target[attribute_name]): attr_rule = policy.AndCheck([ attr_rule, _build_subattr_match_rule( attribute_name, attribute, action, target) ]) attribute_value = target[attribute_name] if isinstance(attribute_value, list): subattr_rule = _build_list_of_subattrs_rule( attribute_name, attribute_value, action) if subattr_rule: attr_rule = policy.AndCheck( [attr_rule, subattr_rule]) match_rule = policy.AndCheck([match_rule, attr_rule]) return match_rule
def test_rule_true(self): enforcer = ENFORCER check = policy.RuleCheck('rule', 'spam') self.assertEqual(check('target', 'creds', enforcer), True) enforcer.rules['spam'].assert_called_once_with('target', 'creds', enforcer)
def _build_list_of_subattrs_rule(attr_name, attribute_value, action): rules = [] for sub_attr in attribute_value: if isinstance(sub_attr, dict): for k in sub_attr: rules.append(policy.RuleCheck( 'rule', '%s:%s:%s' % (action, attr_name, k))) if rules: return policy.AndCheck(rules)
def test_process_rules(self): action = "create_" + FAKE_RESOURCE_NAME # Construct RuleChecks for an action, attribute and subattribute match_rule = oslo_policy.RuleCheck('rule', action) attr_rule = oslo_policy.RuleCheck( 'rule', '%s:%ss' % (action, FAKE_RESOURCE_NAME)) sub_attr_rules = [oslo_policy.RuleCheck( 'rule', '%s:%s:%s' % (action, 'attr', 'sub_attr_1'))] # Build an AndCheck from the given RuleChecks # Make the checks nested to better check the recursion sub_attr_rules = oslo_policy.AndCheck(sub_attr_rules) attr_rule = oslo_policy.AndCheck( [attr_rule, sub_attr_rules]) match_rule = oslo_policy.AndCheck([match_rule, attr_rule]) # Assert that the rules are correctly extracted from the match_rule rules = policy._process_rules_list([], match_rule) self.assertEqual(['create_fake_resource', 'create_fake_resource:fake_resources', 'create_fake_resource:attr:sub_attr_1'], rules)
def _build_match_rule(action, target, pluralized): """Create the rule to match for a given action. The policy rule to be matched is built in the following way: 1) add entries for matching permission on objects 2) add an entry for the specific action (e.g.: create_network) 3) add an entry for attributes of a resource for which the action is being executed (e.g.: create_network:shared) 4) add an entry for sub-attributes of a resource for which the action is being executed (e.g.: create_router:external_gateway_info:network_id) """ match_rule = policy.RuleCheck('rule', action) resource, is_write = get_resource_and_action(action, pluralized) # Attribute-based checks shall not be enforced on GETs if is_write: # assigning to variable with short name for improving readability res_map = attributes.RESOURCE_ATTRIBUTE_MAP if resource in res_map: for attribute_name in res_map[resource]: if _is_attribute_explicitly_set(attribute_name, res_map[resource], target, action): attribute = res_map[resource][attribute_name] if 'enforce_policy' in attribute: attr_rule = policy.RuleCheck( 'rule', '%s:%s' % (action, attribute_name)) # Build match entries for sub-attributes if _should_validate_sub_attributes( attribute, target[attribute_name]): attr_rule = policy.AndCheck([ attr_rule, _build_subattr_match_rule( attribute_name, attribute, action, target) ]) match_rule = policy.AndCheck([match_rule, attr_rule]) return match_rule
def _build_subattr_match_rule(attr_name, attr, action, target): """Create the rule to match for sub-attribute policy checks.""" # TODO(salv-orlando): Instead of relying on validator info, introduce # typing for API attributes # Expect a dict as type descriptor validate = attr['validate'] key = [k for k in validate.keys() if k.startswith('type:dict')] if not key: LOG.warning("Unable to find data type descriptor for attribute %s", attr_name) return data = validate[key[0]] if not isinstance(data, dict): LOG.debug( "Attribute type descriptor is not a dict. Unable to " "generate any sub-attr policy rule for %s.", attr_name) return sub_attr_rules = [ policy.RuleCheck('rule', '%s:%s:%s' % (action, attr_name, sub_attr_name)) for sub_attr_name in data if sub_attr_name in target[attr_name] ] return policy.AndCheck(sub_attr_rules)
def test_log_rule_list(self, mock_debug, mock_is_e): policy.log_rule_list(oslo_policy.RuleCheck('rule', 'create_')) self.assertTrue(mock_is_e.called) self.assertTrue(mock_debug.called)
def test_rule_missing(self): check = policy.RuleCheck('rule', 'spam') self.assertEqual(check('target', 'creds', ENFORCER), False)