diff options
Diffstat (limited to 'python_moonutilities/python_moonutilities')
5 files changed, 270 insertions, 128 deletions
diff --git a/python_moonutilities/python_moonutilities/__init__.py b/python_moonutilities/python_moonutilities/__init__.py index 6b30dedc..6e924e93 100644 --- a/python_moonutilities/python_moonutilities/__init__.py +++ b/python_moonutilities/python_moonutilities/__init__.py @@ -3,6 +3,4 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "1.4.10" - - +__version__ = "1.4.22" diff --git a/python_moonutilities/python_moonutilities/cache.py b/python_moonutilities/python_moonutilities/cache.py index 1bb9d09e..49a3ef5b 100644 --- a/python_moonutilities/python_moonutilities/cache.py +++ b/python_moonutilities/python_moonutilities/cache.py @@ -102,14 +102,14 @@ class Cache(object): if policy_id in self.subjects: for _subject_id, _subject_dict in self.subjects[policy_id].items(): - if "name" in _subject_dict and _subject_dict["name"] == name: + if _subject_id == name or _subject_dict.get("name") == name: return _subject_id self.__update_subjects(policy_id) if policy_id in self.subjects: for _subject_id, _subject_dict in self.subjects[policy_id].items(): - if "name" in _subject_dict and _subject_dict["name"] == name: + if _subject_id == name or _subject_dict.get("name") == name: return _subject_id raise exceptions.SubjectUnknown("Cannot find subject {}".format(name)) @@ -131,14 +131,14 @@ class Cache(object): if policy_id in self.objects: for _object_id, _object_dict in self.__OBJECTS[policy_id].items(): - if "name" in _object_dict and _object_dict["name"] == name: + if _object_id == name or _object_dict.get("name") == name: return _object_id self.__update_objects(policy_id) if policy_id in self.objects: for _object_id, _object_dict in self.__OBJECTS[policy_id].items(): - if "name" in _object_dict and _object_dict["name"] == name: + if _object_id == name or _object_dict.get("name") == name: return _object_id raise exceptions.ObjectUnknown("Cannot find object {}".format(name)) @@ -161,13 +161,13 @@ class Cache(object): if policy_id in self.actions: for _action_id, _action_dict in self.__ACTIONS[policy_id].items(): - if "name" in _action_dict and _action_dict["name"] == name: + if _action_id == name or _action_dict.get("name") == name: return _action_id self.__update_actions(policy_id) for _action_id, _action_dict in self.__ACTIONS[policy_id].items(): - if "name" in _action_dict and _action_dict["name"] == name: + if _action_id == name or _action_dict.get("name") == name: return _action_id raise exceptions.ActionUnknown("Cannot find action {}".format(name)) @@ -218,6 +218,17 @@ class Cache(object): # assignment functions + def update_assignments(self, policy_id=None, perimeter_id=None): + if policy_id: + self.__update_subject_assignments(policy_id=policy_id, perimeter_id=perimeter_id) + self.__update_object_assignments(policy_id=policy_id, perimeter_id=perimeter_id) + self.__update_action_assignments(policy_id=policy_id, perimeter_id=perimeter_id) + else: + for policy_id in self.__POLICIES: + self.__update_subject_assignments(policy_id=policy_id, perimeter_id=perimeter_id) + self.__update_object_assignments(policy_id=policy_id, perimeter_id=perimeter_id) + self.__update_action_assignments(policy_id=policy_id, perimeter_id=perimeter_id) + @property def subject_assignments(self): return self.__SUBJECT_ASSIGNMENTS @@ -233,8 +244,7 @@ class Cache(object): if 'subject_assignments' in response.json(): if policy_id not in self.subject_assignments: self.__SUBJECT_ASSIGNMENTS[policy_id] = {} - - self.__SUBJECT_ASSIGNMENTS[policy_id].update(response.json()['subject_assignments']) + self.__SUBJECT_ASSIGNMENTS[policy_id] = response.json()['subject_assignments'] else: raise exceptions.SubjectAssignmentUnknown( "Cannot find subject assignment within policy_id {}".format(policy_id)) @@ -251,7 +261,7 @@ class Cache(object): if perimeter_id == value['subject_id'] and category_id == value['category_id']: return value['assignments'] else: - logger.warning("'subject_id' or 'category_id' or'assignments'" + logger.warning("'subject_id' or 'category_id' or 'assignments'" " keys are not found in subject_assignments") return [] @@ -271,7 +281,7 @@ class Cache(object): if policy_id not in self.object_assignments: self.__OBJECT_ASSIGNMENTS[policy_id] = {} - self.__OBJECT_ASSIGNMENTS[policy_id].update(response.json()['object_assignments']) + self.__OBJECT_ASSIGNMENTS[policy_id] = response.json()['object_assignments'] else: raise exceptions.ObjectAssignmentUnknown( "Cannot find object assignment within policy_id {}".format(policy_id)) @@ -308,7 +318,7 @@ class Cache(object): if policy_id not in self.__ACTION_ASSIGNMENTS: self.__ACTION_ASSIGNMENTS[policy_id] = {} - self.__ACTION_ASSIGNMENTS[policy_id].update(response.json()['action_assignments']) + self.__ACTION_ASSIGNMENTS[policy_id] = response.json()['action_assignments'] else: raise exceptions.ActionAssignmentUnknown( "Cannot find action assignment within policy_id {}".format(policy_id)) diff --git a/python_moonutilities/python_moonutilities/context.py b/python_moonutilities/python_moonutilities/context.py index 1d25cda2..dc140b74 100644 --- a/python_moonutilities/python_moonutilities/context.py +++ b/python_moonutilities/python_moonutilities/context.py @@ -59,19 +59,19 @@ class Context: @property def current_state(self): - self.__validate_meta_rule_content(self.__meta_rule_ids[self.__index]) + self.__validate_meta_rule_content(self.__pdp_set[self.__meta_rule_ids[self.__index]]) return self.__pdp_set[self.__meta_rule_ids[self.__index]]['effect'] @current_state.setter def current_state(self, state): if state not in ("grant", "deny", "passed"): state = "passed" - self.__validate_meta_rule_content(self.__meta_rule_ids[self.__index]) + self.__validate_meta_rule_content(self.__pdp_set[self.__meta_rule_ids[self.__index]]) self.__pdp_set[self.__meta_rule_ids[self.__index]]['effect'] = state @current_state.deleter def current_state(self): - self.__validate_meta_rule_content(self.__meta_rule_ids[self.__index]) + self.__validate_meta_rule_content(self.__pdp_set[self.__meta_rule_ids[self.__index]]) self.__pdp_set[self.__meta_rule_ids[self.__index]]['effect'] = "unset" @property @@ -110,38 +110,46 @@ class Context: self.__pdp_set[meta_rule_id]["effect"] = "unset" self.__pdp_set["effect"] = "deny" - # def update_target(self, context): - # # result = dict() - # current_request = context['current_request'] - # _subject = current_request.get("subject") - # _object = current_request.get("object") - # _action = current_request.get("action") - # meta_rule_id = context['headers'][context['index']] - # policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id) - # meta_rules = self.cache.meta_rules() - # # for meta_rule_id in meta_rules: - # for sub_cat in meta_rules[meta_rule_id]['subject_categories']: - # if sub_cat not in context["pdp_set"][meta_rule_id]["target"]: - # context["pdp_set"][meta_rule_id]["target"][sub_cat] = [] - # for assign in self.cache.get_subject_assignments(policy_id, _subject, sub_cat).values(): - # for assign in assign["assignments"]: - # if assign not in context["pdp_set"][meta_rule_id]["target"][sub_cat]: - # context["pdp_set"][meta_rule_id]["target"][sub_cat].append(assign) - # for obj_cat in meta_rules[meta_rule_id]['object_categories']: - # if obj_cat not in context["pdp_set"][meta_rule_id]["target"]: - # context["pdp_set"][meta_rule_id]["target"][obj_cat] = [] - # for assign in self.cache.get_object_assignments(policy_id, _object, obj_cat).values(): - # for assign in assign["assignments"]: - # if assign not in context["pdp_set"][meta_rule_id]["target"][obj_cat]: - # context["pdp_set"][meta_rule_id]["target"][obj_cat].append(assign) - # for act_cat in meta_rules[meta_rule_id]['action_categories']: - # if act_cat not in context["pdp_set"][meta_rule_id]["target"]: - # context["pdp_set"][meta_rule_id]["target"][act_cat] = [] - # for assign in self.cache.get_action_assignments(policy_id, _action, act_cat).values(): - # for assign in assign["assignments"]: - # if assign not in context["pdp_set"][meta_rule_id]["target"][act_cat]: - # context["pdp_set"][meta_rule_id]["target"][act_cat].append(assign) - # # context["pdp_set"][meta_rule_id]["target"].update(result) + def update_target(self): + for meta_rule_id in self.__meta_rule_ids: + result = dict() + _subject = self.__current_request["subject"] + _object = self.__current_request["object"] + _action = self.__current_request["action"] + + meta_rules = self.cache.meta_rules + policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id) + + if 'subject_categories' not in meta_rules[meta_rule_id]: + raise exceptions.MetaRuleContentError(" 'subject_categories' key not found ") + + self.cache.update_assignments(policy_id) + + for sub_cat in meta_rules[meta_rule_id]['subject_categories']: + if sub_cat not in result: + result[sub_cat] = [] + result[sub_cat].extend( + self.cache.get_subject_assignments(policy_id, _subject, sub_cat)) + + if 'object_categories' not in meta_rules[meta_rule_id]: + raise exceptions.MetaRuleContentError(" 'object_categories' key not found ") + + for obj_cat in meta_rules[meta_rule_id]['object_categories']: + if obj_cat not in result: + result[obj_cat] = [] + result[obj_cat].extend( + self.cache.get_object_assignments(policy_id, _object, obj_cat)) + + if 'action_categories' not in meta_rules[meta_rule_id]: + raise exceptions.MetaRuleContentError(" 'action_categories' key not found ") + + for act_cat in meta_rules[meta_rule_id]['action_categories']: + if act_cat not in result: + result[act_cat] = [] + result[act_cat].extend( + self.cache.get_action_assignments(policy_id, _action, act_cat)) + + self.__pdp_set[meta_rule_id]["target"] = result def __add_target(self, meta_rule_id): """build target from meta_rule @@ -341,4 +349,5 @@ pdp_set: {pdp_set} def __validate_meta_rule_content(self, meta_rules): if 'effect' not in meta_rules: - raise exceptions.PdpContentError + logger.error("meta_rules={}".format(meta_rules)) + raise exceptions.PdpContentError("effect not in meta_rules") diff --git a/python_moonutilities/python_moonutilities/exceptions.py b/python_moonutilities/python_moonutilities/exceptions.py index a43ac89f..8ad90e96 100644 --- a/python_moonutilities/python_moonutilities/exceptions.py +++ b/python_moonutilities/python_moonutilities/exceptions.py @@ -133,6 +133,13 @@ class ModelUnknown(MoonError): logger = "Error" +class ModelContentError(MoonError): + description = _("The model content is invalid.") + code = 400 + title = 'Model Unknown' + logger = "Error" + + class ModelExisting(MoonError): description = _("The model already exists.") code = 409 @@ -197,18 +204,13 @@ class AdminRule(AdminException): code = 400 title = 'Rule Exception' + class CategoryNameInvalid(AdminMetaData): description = _("The given category name is invalid.") - code = 409 + code = 400 title = 'Category Name Invalid' logger = "ERROR" -class SubjectCategoryNameExisting(AdminMetaData): - description = _("The given subject category name already exists.") - code = 409 - title = 'Subject Category Name Existing' - logger = "ERROR" - class SubjectCategoryExisting(AdminMetaData): description = _("The given subject category already exists.") @@ -216,28 +218,12 @@ class SubjectCategoryExisting(AdminMetaData): title = 'Subject Category Existing' logger = "ERROR" - -class ObjectCategoryNameExisting(AdminMetaData): - description = _("The given object category name already exists.") - code = 409 - title = 'Object Category Name Existing' - logger = "ERROR" - - class ObjectCategoryExisting(AdminMetaData): description = _("The given object category already exists.") code = 409 title = 'Object Category Existing' logger = "ERROR" - -class ActionCategoryNameExisting(AdminMetaData): - description = _("The given action category name already exists.") - code = 409 - title = 'Action Category Name Existing' - logger = "ERROR" - - class ActionCategoryExisting(AdminMetaData): description = _("The given action category already exists.") code = 409 @@ -252,6 +238,20 @@ class SubjectCategoryUnknown(AdminMetaData): logger = "ERROR" +class DeleteSubjectCategoryWithMetaRule(MoonError): + description = _("Cannot delete subject category used in meta rule ") + code = 400 + title = 'Subject Category With Meta Rule Error' + logger = "Error" + + +class DeleteObjectCategoryWithMetaRule(MoonError): + description = _("Cannot delete Object category used in meta rule ") + code = 400 + title = 'Object Category With Meta Rule Error' + logger = "Error" + + class ObjectCategoryUnknown(AdminMetaData): description = _("The given object category is unknown.") code = 400 @@ -259,19 +259,33 @@ class ObjectCategoryUnknown(AdminMetaData): logger = "ERROR" +class DeleteActionCategoryWithMetaRule(MoonError): + description = _("Cannot delete Action category used in meta rule ") + code = 400 + title = 'Action Category With Meta Rule Error' + logger = "Error" + + class ActionCategoryUnknown(AdminMetaData): description = _("The given action category is unknown.") code = 400 title = 'Action Category Unknown' logger = "ERROR" - -class PerimeterNameInvalid(AdminPerimeter): - description = _("The given name is not valid.") +class PerimeterContentError(AdminPerimeter): + description = _("Perimeter content is invalid.") code = 400 - title = 'Perimeter Name is Invalid' + title = 'Perimeter content is invalid.' logger = "ERROR" + +class DeletePerimeterWithAssignment(MoonError): + description = _("Cannot delete perimeter with assignment") + code = 400 + title = 'Perimeter With Assignment Error' + logger = "Error" + + class SubjectUnknown(AdminPerimeter): description = _("The given subject is unknown.") code = 400 @@ -313,23 +327,24 @@ class ActionExisting(AdminPerimeter): title = 'Action Existing' logger = "ERROR" + class SubjectNameExisting(AdminPerimeter): description = _("The given subject name is existing.") - code = 400 + code = 409 title = 'Subject Name Existing' logger = "ERROR" class ObjectNameExisting(AdminPerimeter): description = _("The given object name is existing.") - code = 400 + code = 409 title = 'Object Name Existing' logger = "ERROR" class ActionNameExisting(AdminPerimeter): description = _("The given action name is existing.") - code = 400 + code = 409 title = 'Action Name Existing' logger = "ERROR" @@ -392,21 +407,21 @@ class ActionScopeExisting(AdminScope): class SubjectScopeNameExisting(AdminScope): description = _("The given subject scope name is existing.") - code = 400 + code = 409 title = 'Subject Scope Name Existing' logger = "ERROR" class ObjectScopeNameExisting(AdminScope): description = _("The given object scope name is existing.") - code = 400 + code = 409 title = 'Object Scope Name Existing' logger = "ERROR" class ActionScopeNameExisting(AdminScope): description = _("The given action scope name is existing.") - code = 400 + code = 409 title = 'Action Scope Name Existing' logger = "ERROR" @@ -434,21 +449,21 @@ class ActionAssignmentUnknown(AdminAssignment): class SubjectAssignmentExisting(AdminAssignment): description = _("The given subject assignment value is existing.") - code = 400 + code = 409 title = 'Subject Assignment Existing' logger = "ERROR" class ObjectAssignmentExisting(AdminAssignment): description = _("The given object assignment value is existing.") - code = 400 + code = 409 title = 'Object Assignment Existing' logger = "ERROR" class ActionAssignmentExisting(AdminAssignment): description = _("The given action assignment value is existing.") - code = 400 + code = 409 title = 'Action Assignment Existing' logger = "ERROR" @@ -475,23 +490,37 @@ class SubMetaRuleAlgorithmNotExisting(AdminMetaRule): class MetaRuleUnknown(AdminMetaRule): - description = _("The given sub meta rule is unknown.") + description = _("The given meta rule is unknown.") code = 400 - title = 'Sub Meta Rule Unknown' + title = 'Meta Rule Unknown' logger = "ERROR" +class MetaRuleNotLinkedWithPolicyModel(MoonError): + description = _("The meta rule is not found in the model attached to the policy.") + code = 400 + title = 'MetaRule Not Linked With Model - Policy' + logger = "Error" + + +class CategoryNotAssignedMetaRule(MoonError): + description = _("The category is not found in the meta rules attached to the policy.") + code = 400 + title = 'Category Not Linked With Meta Rule - Policy' + logger = "Error" + + class SubMetaRuleNameExisting(AdminMetaRule): description = _("The sub meta rule name already exists.") - code = 400 + code = 409 title = 'Sub Meta Rule Name Existing' logger = "ERROR" class MetaRuleExisting(AdminMetaRule): - description = _("The sub meta rule already exists.") - code = 400 - title = 'Sub Meta Rule Existing' + description = _("The meta rule already exists.") + code = 409 + title = 'Meta Rule Existing' logger = "ERROR" @@ -502,13 +531,27 @@ class MetaRuleContentError(AdminMetaRule): logger = "ERROR" +class MetaRuleUpdateError(AdminMetaRule): + description = _("Meta_rule is used in Rule.") + code = 400 + title = 'Meta_Rule Update Error' + logger = "ERROR" + + class RuleExisting(AdminRule): description = _("The rule already exists.") - code = 400 + code = 409 title = 'Rule Existing' logger = "ERROR" +class RuleContentError(AdminRule): + description = _("Invalid content of rule.") + code = 400 + title = 'Rule Error' + logger = "ERROR" + + class RuleUnknown(AdminRule): description = _("The rule for that request doesn't exist.") code = 400 @@ -570,6 +613,7 @@ class ConsulComponentContentError(ConsulError): title = 'Consul Content error' logger = "WARNING" + # Containers exceptions @@ -638,7 +682,7 @@ class PdpExisting(MoonError): class PdpContentError(MoonError): description = _("Invalid content of pdp.") - code = 409 + code = 400 title = 'Pdp Error' logger = "Error" @@ -656,11 +700,24 @@ class PolicyUnknown(MoonError): title = 'Policy Unknown' logger = "Error" +class PolicyContentError(MoonError): + description = _("The policy content is invalid.") + code = 400 + title = 'Policy Content Error' + logger = "Error" + class PolicyExisting(MoonError): description = _("The policy already exists.") code = 409 - title = 'Policy Error' + title = 'Policy Already Exists' + logger = "Error" + + +class PolicyUpdateError(MoonError): + description = _("The policy data is used.") + code = 400 + title = 'Policy update error' logger = "Error" @@ -674,33 +731,103 @@ class DeleteData(MoonError): class DeleteCategoryWithData(MoonError): description = _("Cannot delete category with data") code = 400 - title = 'Category Error' + title = 'Category With Data Error' logger = "Error" class DeleteCategoryWithMetaRule(MoonError): description = _("Cannot delete category with meta rule") code = 400 - title = 'Category Error' + title = 'Category With MetaRule Error' + logger = "Error" + + +class DeleteCategoryWithAssignment(MoonError): + description = _("Cannot delete category with assignment ") + code = 400 + title = 'Category With Assignment Error' logger = "Error" class DeleteModelWithPolicy(MoonError): description = _("Cannot delete model with policy") code = 400 - title = 'Model Error' + title = 'Model With Policy Error' logger = "Error" class DeletePolicyWithPdp(MoonError): description = _("Cannot delete policy with pdp") code = 400 - title = 'Policy Error' + title = 'Policy With PDP Error' + logger = "Error" + + +class DeletePolicyWithPerimeter(MoonError): + description = _("Cannot delete policy with perimeter") + code = 400 + title = 'Policy With Perimeter Error' + logger = "Error" + + +class DeletePolicyWithData(MoonError): + description = _("Cannot delete policy with data") + code = 400 + title = 'Policy With Data Error' + logger = "Error" + + +class DeletePolicyWithRules(MoonError): + description = _("Cannot delete policy with rules") + code = 400 + title = 'Policy With Rule Error' logger = "Error" class DeleteMetaRuleWithModel(MoonError): description = _("Cannot delete meta rule with model") code = 400 - title = 'Meta rule Error' + title = 'Meta rule With Model Error' + logger = "Error" + + +class DeleteMetaRuleWithRule(MoonError): + description = _("Cannot delete meta rule with rule") + code = 400 + title = 'Meta rule With Model Error' + logger = "Error" + + +class DataUnknown(MoonError): + description = _("The data unknown.") + code = 400 + title = 'Data Unknown' + logger = "Error" + + +class ValidationContentError(MoonError): + description = _("The Content validation incorrect.") + code = 400 + title = 'Invalid Content' + logger = "Error" + + def __init__(self, message=""): + self.message = message + super().__init__(message) + + def __str__(self): + return self.message + + +class ValidationKeyError(MoonError): + description = _("The Key validation incorrect.") + code = 400 + title = 'Invalid Key' logger = "Error" + + def __init__(self, message=""): + self.message = message + super().__init__(message) + + def __str__(self): + return self.message diff --git a/python_moonutilities/python_moonutilities/security_functions.py b/python_moonutilities/python_moonutilities/security_functions.py index 5d5275ee..1069eb2f 100644 --- a/python_moonutilities/python_moonutilities/security_functions.py +++ b/python_moonutilities/python_moonutilities/security_functions.py @@ -4,6 +4,7 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. +import html import re import os import types @@ -22,6 +23,7 @@ __targets = {} def filter_input(func_or_str): + def __filter(string): if string and type(string) is str: return "".join(re.findall("[\w\- +]*", string)) @@ -88,28 +90,22 @@ To do should check value of Dictionary but it's dependent on from where it's com def validate_data(data): def __validate_string(string): - if not string: - raise ValueError('Empty String') - ''' - is it valid to contains space inbetween - - ''' - - if " " in string: - raise ValueError('String contains space') + temp_str = html.escape(string) + if string != temp_str: + raise exceptions.ValidationContentError('Forbidden characters in string') def __validate_list_or_tuple(container): - if not container: - raise ValueError('Empty Container') for i in container: validate_data(i) def __validate_dict(dictionary): - if not dictionary: - raise ValueError('Empty Dictionary') for key in dictionary: validate_data(dictionary[key]) + if isinstance(data, bool): + return True + if data is None: + data = "" if isinstance(data, str): __validate_string(data) elif isinstance(data, list) or isinstance(data, tuple): @@ -117,7 +113,7 @@ def validate_data(data): elif isinstance(data, dict): __validate_dict(data) else: - raise ValueError('Value is Not String or Container or Dictionary') + raise exceptions.ValidationContentError('Value is Not String or Container or Dictionary: {}'.format(data)) def validate_input(type='get', args_state=[], kwargs_state=[], body_state=[]): @@ -161,24 +157,30 @@ def validate_input(type='get', args_state=[], kwargs_state=[], body_state=[]): validate_data(temp_args[i]) while len(kwargs_state) < len(kwargs): - kwargs_state.append(True) + kwargs_state.append(False) counter = 0 for i in kwargs: if kwargs_state[counter]: - validate_data({i: kwargs[i]}) + validate_data(kwargs[i]) counter = counter + 1 if type == "post" or type == "patch": body = request.json - while len(body_state) < len(body): - body_state.append(True) - counter = 0 - for i in body: - if body_state[counter]: - validate_data({i: body[i]}) - - counter = counter + 1 + # while len(body_state) < len(body): + # body_state.append(True) + # counter = 0 + for key in body_state: + if key in body: + if body_state[key]: + try: + validate_data(body.get(key)) + except exceptions.ValidationContentError as e: + raise exceptions.ValidationContentError("Key: '{}', [{}]".format(key, str(e))) + else: + raise exceptions.ValidationKeyError('Invalid Key :{} not found'.format(key)) + + # counter = counter + 1 return func(*args, **kwargs) @@ -189,16 +191,13 @@ def validate_input(type='get', args_state=[], kwargs_state=[], body_state=[]): def enforce(action_names, object_name, **extra): """Fake version of the enforce decorator""" - def wrapper_func(func): def wrapper_args(*args, **kwargs): # LOG.info("kwargs={}".format(kwargs)) # kwargs['user_id'] = kwargs.pop('user_id', "admin") # LOG.info("Calling enforce on {} with args={} kwargs={}".format(func.__name__, args, kwargs)) return func(*args, **kwargs) - return wrapper_args - return wrapper_func @@ -329,5 +328,4 @@ def check_auth(function): user_id = kwargs.pop("user_id", token) result = function(*args, **kwargs, user_id=user_id) return result - return wrapper |