def wrapper(self, context, **kwargs): if not context['is_admin']: action = 'identity:%s' % f.__name__ creds = _build_policy_check_credentials(self, action, context, kwargs) # Now, build the target dict for policy check. We include: # # - Any query filter parameters # - Data from the main url (which will be in the kwargs # parameter) and would typically include the prime key # of a get/update/delete call # # First any query filter parameters target = dict() if filters: for item in filters: if item in context['query_string']: target[item] = context['query_string'][item] LOG.debug(_('RBAC: Adding query filter params (%s)'), ( ', '.join(['%s=%s' % (item, target[item]) for item in target]))) # Now any formal url parameters for key in kwargs: target[key] = kwargs[key] self.policy_api.enforce(creds, action, authorization.flatten(target)) LOG.debug(_('RBAC: Authorization granted')) else: LOG.warning(_('RBAC: Bypassing authorization')) return f(self, context, filters, **kwargs)
def check_protection(self, context, prep_info, target_attr=None): """Provide call protection for complex target attributes. As well as including the standard parameters from the original API call (which is passed in prep_info), this call will add in any additional entities or attributes (passed in target_attr), so that they can be referenced by policy rules. """ if 'is_admin' in context and context['is_admin']: LOG.warning(_('RBAC: Bypassing authorization')) else: action = 'identity:%s' % prep_info['f_name'] # TODO(henry-nash) need to log the target attributes as well creds = _build_policy_check_credentials(self, action, context, prep_info['input_attr']) # Build the dict the policy engine will check against from both the # parameters passed into the call we are protecting (which was # stored in the prep_info by protected()), plus the target # attributes provided. policy_dict = {} if target_attr: policy_dict = {'target': target_attr} policy_dict.update(prep_info['input_attr']) self.policy_api.enforce(creds, action, authorization.flatten(policy_dict)) LOG.debug(_('RBAC: Authorization granted'))
def inner(self, context, *args, **kwargs): if 'is_admin' in context and context['is_admin']: LOG.warning(_('RBAC: Bypassing authorization')) elif callback is not None: prep_info = {'f_name': f.__name__, 'input_attr': kwargs} callback(self, context, prep_info, *args, **kwargs) else: action = 'identity:%s' % f.__name__ creds = _build_policy_check_credentials(self, action, context, kwargs) policy_dict = {} # Check to see if we need to include the target entity in our # policy checks. We deduce this by seeing if the class has # specified a get_member() method and that kwargs contains the # appropriate entity id. if (hasattr(self, 'get_member_from_driver') and self.get_member_from_driver is not None): key = '%s_id' % self.member_name if key in kwargs: ref = self.get_member_from_driver(kwargs[key]) policy_dict['target'] = {self.member_name: ref} # TODO(henry-nash): Move this entire code to a member # method inside v3 Auth if context.get('subject_token_id') is not None: token_ref = self.token_api.get_token( context['subject_token_id']) policy_dict.setdefault('target', {}) policy_dict['target'].setdefault(self.member_name, {}) policy_dict['target'][self.member_name]['user_id'] = ( token_ref['user_id']) if 'domain' in token_ref['user']: policy_dict['target'][self.member_name].setdefault( 'user', {}) policy_dict['target'][self.member_name][ 'user'].setdefault('domain', {}) policy_dict['target'][self.member_name]['user'][ 'domain']['id'] = ( token_ref['user']['domain']['id']) # Add in the kwargs, which means that any entity provided as a # parameter for calls like create and update will be included. policy_dict.update(kwargs) self.policy_api.enforce(creds, action, authorization.flatten(policy_dict)) LOG.debug(_('RBAC: Authorization granted')) return f(self, context, *args, **kwargs)
def filter_by_attributes(cls, refs, hints): """Filters a list of references by filter values.""" def _attr_match(ref_attr, val_attr): """Matches attributes allowing for booleans as strings. We test explicitly for a value that defines it as 'False', which also means that the existence of the attribute with no value implies 'True' """ if type(ref_attr) is bool: return ref_attr == utils.attr_as_boolean(val_attr) else: return ref_attr == val_attr def _inexact_attr_match(filter, ref): """Applies an inexact filter to a result dict. :param filter: the filter in question :param ref: the dict to check :returns True if there is a match """ comparator = filter['comparator'] key = filter['name'] if key in ref: filter_value = filter['value'] target_value = ref[key] if not filter['case_sensitive']: # We only support inexact filters on strings so # it's OK to use lower() filter_value = filter_value.lower() target_value = target_value.lower() if comparator == 'contains': return (filter_value in target_value) elif comparator == 'startswith': return target_value.startswith(filter_value) elif comparator == 'endswith': return target_value.endswith(filter_value) else: # We silently ignore unsupported filters return True return False for filter in hints.filters(): if filter['comparator'] == 'equals': attr = filter['name'] value = filter['value'] refs = [r for r in refs if _attr_match( authorization.flatten(r).get(attr), value)] else: # It might be an inexact filter refs = [r for r in refs if _inexact_attr_match( filter, r)] return refs
def filter_by_attributes(cls, refs, hints): """Filters a list of references by filter values.""" def _attr_match(ref_attr, val_attr): """Matches attributes allowing for booleans as strings. We test explicitly for a value that defines it as 'False', which also means that the existence of the attribute with no value implies 'True' """ if type(ref_attr) is bool: return ref_attr == utils.attr_as_boolean(val_attr) else: return ref_attr == val_attr def _inexact_attr_match(filter, ref): """Applies an inexact filter to a result dict. :param filter: the filter in question :param ref: the dict to check :returns True if there is a match """ comparator = filter['comparator'] key = filter['name'] if key in ref: filter_value = filter['value'] target_value = ref[key] if not filter['case_sensitive']: # We only support inexact filters on strings so # it's OK to use lower() filter_value = filter_value.lower() target_value = target_value.lower() if comparator == 'contains': return (filter_value in target_value) elif comparator == 'startswith': return target_value.startswith(filter_value) elif comparator == 'endswith': return target_value.endswith(filter_value) else: # We silently ignore unsupported filters return True return False for filter in hints.filters(): if filter['comparator'] == 'equals': attr = filter['name'] value = filter['value'] refs = [ r for r in refs if _attr_match(authorization.flatten(r).get(attr), value) ] else: # It might be an inexact filter refs = [r for r in refs if _inexact_attr_match(filter, r)] return refs