def _get_policy_data(self, service): file_policy_data = {} mgr_policy_data = {} policy_data = {} # Check whether policy file exists. if os.path.isfile(self.path): try: with open(self.path, 'r') as policy_file: file_policy_data = policy_file.read() file_policy_data = json.loads(file_policy_data) except (IOError, ValueError) as e: msg = "Failed to read policy file for service. " if isinstance(e, IOError): msg += "Please check that policy path exists." else: msg += "JSON may be improperly formatted." LOG.debug(msg) file_policy_data = {} # Check whether policy actions are defined in code. Nova and Keystone, # for example, define their default policy actions in code. mgr = stevedore.named.NamedExtensionManager( 'oslo.policy.policies', names=[service], on_load_failure_callback=None, invoke_on_load=True, warn_on_missing_entrypoint=False) if mgr: policy_generator = {policy.name: policy.obj for policy in mgr} if policy_generator and service in policy_generator: for rule in policy_generator[service]: mgr_policy_data[rule.name] = str(rule.check) # If data from both file and code exist, combine both together. if file_policy_data and mgr_policy_data: # Add the policy actions from code first. for action, rule in mgr_policy_data.items(): policy_data[action] = rule # Overwrite with any custom policy actions defined in policy.json. for action, rule in file_policy_data.items(): policy_data[action] = rule elif file_policy_data: policy_data = file_policy_data elif mgr_policy_data: policy_data = mgr_policy_data else: error_message = 'Policy file for {0} service neither found in '\ 'code nor at {1}.'.format(service, self.path) raise rbac_exceptions.RbacParsingException(error_message) try: policy_data = json.dumps(policy_data) except ValueError: error_message = 'Policy file for {0} service is invalid.'.format( service) raise rbac_exceptions.RbacParsingException(error_message) return policy_data
def get_rules(self): rules = policy.Rules() # Check whether policy file exists and attempt to read it. for path in self.policy_files[self.service]: try: with open(path, 'r') as fp: for k, v in policy.Rules.load(fp.read()).items(): if k not in rules: rules[k] = v # If the policy name and rule are the same, no # ambiguity, so no reason to warn. elif str(v) != str(rules[k]): msg = ("The same policy name: %s was found in " "multiple policies files for service %s. " "This can lead to policy rule ambiguity. " "Using rule: %s; Rule from file: %s") LOG.warning(msg, k, self.service, rules[k], v) except (ValueError, IOError): LOG.warning("Failed to read policy file '%s' for service %s.", path, self.service) # Check whether policy actions are defined in code. Nova and Keystone, # for example, define their default policy actions in code. mgr = stevedore.named.NamedExtensionManager( 'oslo.policy.policies', names=[self.service], invoke_on_load=True, warn_on_missing_entrypoint=False) if mgr: policy_generator = {plc.name: plc.obj for plc in mgr} if self.service in policy_generator: for rule in policy_generator[self.service]: if rule.name not in rules: if CONF.patrole.validate_deprecated_rules: # NOTE (sergey.vilgelm): # The `DocumentedRuleDefault` object has no # `deprecated_rule` attribute in Pike if getattr(rule, 'deprecated_rule', False): rule = self._handle_deprecated_rule(rule) rules[rule.name] = rule.check elif str(rule.check) != str(rules[rule.name]): msg = ("The same policy name: %s was found in the " "policies files and in the code for service " "%s. This can lead to policy rule ambiguity. " "Using rule: %s; Rule from code: %s") LOG.warning(msg, rule.name, self.service, rules[rule.name], rule.check) if not rules: msg = ( 'Policy files for {0} service were not found among the ' 'registered in-code policies or in any of the possible policy ' 'files: {1}.'.format(self.service, [ loc % self.service for loc in CONF.patrole.custom_policy_files ])) raise rbac_exceptions.RbacParsingException(msg) return rules
def _try_rule(self, apply_rule, target, access_data, o): if apply_rule not in self.rules: message = "Policy action: {0} not found in policy file: {1}."\ .format(apply_rule, self.path) LOG.debug(message) raise rbac_exceptions.RbacParsingException(message) else: rule = self.rules[apply_rule] return rule(target, access_data, o)
def _try_rule(self, apply_rule, target, access_data, o): if apply_rule not in self.rules: message = ("Policy action \"{0}\" not found in policy file: {1} or" " among registered policy in code defaults for service." ).format(apply_rule, self.path) LOG.debug(message) raise rbac_exceptions.RbacParsingException(message) else: rule = self.rules[apply_rule] return rule(target, access_data, o)
def _try_rule(self, apply_rule, target, access_data, o): if apply_rule not in self.rules: message = ('Policy action "{0}" not found in policy files: ' '{1} or among registered policy in code defaults for ' '{2} service.').format(apply_rule, self.policy_files[self.service], self.service) LOG.debug(message) raise rbac_exceptions.RbacParsingException(message) else: rule = self.rules[apply_rule] return rule(target, access_data, o)
def allowed(self, rule_name, roles): """Checks if a given rule in a policy is allowed with given role. :param string rule_name: Rule to be checked using provided requirements file specified by ``[patrole].custom_requirements_file``. Must be a key present in this file, under the appropriate component. :param List[string] roles: Roles to validate against custom requirements file. :returns: True if ``role`` is allowed to perform ``rule_name``, else False. :rtype: bool :raises RbacParsingException: If ``rule_name`` does not exist among the keyed policy names in the custom requirements file. """ if not self.roles_dict: raise lib_exc.InvalidConfiguration( "Roles dictionary parsed from requirements YAML file is " "empty. Ensure the requirements YAML file is correctly " "formatted.") try: requirement_roles = self.roles_dict[rule_name] except KeyError: raise rbac_exceptions.RbacParsingException( "'%s' rule name is not defined in the requirements YAML file: " "%s" % (rule_name, self.filepath)) for role_reqs in requirement_roles: required_roles = [ role for role in role_reqs if not role.startswith("!") ] forbidden_roles = [ role[1:] for role in role_reqs if role.startswith("!") ] # User must have all required roles required_passed = all([r in roles for r in required_roles]) # User must not have any forbidden roles forbidden_passed = all([r not in forbidden_roles for r in roles]) if required_passed and forbidden_passed: return True return False
def _get_policy_data(self): file_policy_data = {} mgr_policy_data = {} policy_data = {} # Check whether policy file exists and attempt to read it. for path in self.policy_files[self.service]: try: with open(path, 'r') as fp: for k, v in json.load(fp).items(): if k not in file_policy_data: file_policy_data[k] = v else: # If the policy name and rule are the same, no # ambiguity, so no reason to warn. if v != file_policy_data[k]: LOG.warning( "The same policy name: %s was found in " "multiple policies files for service %s. " "This can lead to policy rule ambiguity. " "Using rule: %s", k, self.service, file_policy_data[k]) except (IOError, ValueError) as e: msg = "Failed to read policy file for service. " if isinstance(e, IOError): msg += "Please check that policy path exists." else: msg += "JSON may be improperly formatted." LOG.debug(msg) # Check whether policy actions are defined in code. Nova and Keystone, # for example, define their default policy actions in code. mgr = stevedore.named.NamedExtensionManager( 'oslo.policy.policies', names=[self.service], on_load_failure_callback=None, invoke_on_load=True, warn_on_missing_entrypoint=False) if mgr: policy_generator = {plc.name: plc.obj for plc in mgr} if policy_generator and self.service in policy_generator: for rule in policy_generator[self.service]: mgr_policy_data[rule.name] = str(rule.check) # If data from both file and code exist, combine both together. if file_policy_data and mgr_policy_data: # Add the policy actions from code first. for action, rule in mgr_policy_data.items(): policy_data[action] = rule # Overwrite with any custom policy actions defined in policy.json. for action, rule in file_policy_data.items(): policy_data[action] = rule elif file_policy_data: policy_data = file_policy_data elif mgr_policy_data: policy_data = mgr_policy_data else: error_message = ( 'Policy files for {0} service were not found among the ' 'registered in-code policies or in any of the possible policy ' 'files: {1}.'.format(self.service, [ loc % self.service for loc in CONF.patrole.custom_policy_files ])) raise rbac_exceptions.RbacParsingException(error_message) try: policy_data = json.dumps(policy_data) except (TypeError, ValueError): error_message = 'Policy files for {0} service are invalid.'.format( self.service) raise rbac_exceptions.RbacParsingException(error_message) return policy_data