Source code for edumfa.lib.eventhandler.responsemangler
# -*- coding: utf-8 -*-## License: AGPLv3# This file is part of eduMFA. eduMFA is a fork of privacyIDEA which was forked from LinOTP.# Copyright (c) 2024 eduMFA Project-Team# Previous authors by privacyIDEA project:## 2019 Cornelius Kölbel <cornelius.koelbel@netknights.it>## (c) 2019. Cornelius Kölbel## This code is free software; you can redistribute it and/or# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE# License as published by the Free Software Foundation; either# version 3 of the License, or any later version.## This code is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU AFFERO GENERAL PUBLIC LICENSE for more details.## You should have received a copy of the GNU Affero General Public# License along with this program. If not, see <http://www.gnu.org/licenses/>.#__doc__="""This is the event handler module that can mangle the JSON response.We can add or delete key or even subtrees in the JSON response of a request.The key is identified by a JSON Pointer(see https://tools.ietf.org/html/rfc6901)"""fromedumfa.lib.eventhandler.baseimportBaseEventHandlerfromedumfa.lib.utilsimportis_truefromedumfa.libimport_importjsonimportlogginglog=logging.getLogger(__name__)
[docs]classResponseManglerEventHandler(BaseEventHandler):""" An Eventhandler needs to return a list of actions, which it can handle. It also returns a list of allowed action and conditions It returns an identifier, which can be used in the eventhandlig definitions """identifier="ResponseMangler"description="This event handler can mangle the JSON response."@propertydefallowed_positions(cls):""" This returns the allowed positions of the event handler definition. The ResponseMangler can only be located at the "post" position :return: list of allowed positions """return["post"]@propertydefactions(cls):""" This method returns a dictionary of allowed actions and possible options in this handler module. :return: dict with actions """actions={ACTION_TYPE.DELETE:{"JSON pointer":{"type":"str","required":True,"description":_("The JSON pointer (key) that should be deleted. Please ""specify in the format '/detail/message'.")}},ACTION_TYPE.SET:{"JSON pointer":{"type":"str","required":True,"description":_("The JSON pointer (key) that should be set. ""Please specify in the format '/detail/message'.")},"type":{"type":"str","required":True,"description":_("The type of the value."),"value":["string","integer","bool"]},"value":{"type":"str","required":True,"description":_("The value of the JSON key that should be set.")}}}returnactions
[docs]defdo(self,action,options=None):""" This method executes the defined action in the given event. :param action: :param options: Contains the flask parameters g, request, response and the handler_def configuration :type options: dict :return: """ret=Trueresponse=options.get("response")try:content=self._get_response_content(response)exceptException:# The body could not be decoded to JSON. Actually this would be# a BadRequest, but we refrain from importing from werkzeug, here.log.info("The body could not be decoded to JSON.")# Early existreturnrethandler_def=options.get("handler_def")handler_options=handler_def.get("options",{})json_pointer=handler_options.get("JSON pointer","")value=handler_options.get("value")type=handler_options.get("type")comp=json_pointer.split("/")comp=[xforxincompifx]ifaction.lower()==ACTION_TYPE.DELETE:try:iflen(comp)==1:del(content[comp[0]])eliflen(comp)==2:del(content[comp[0]][comp[1]])eliflen(comp)==3:del(content[comp[0]][comp[1]][comp[2]])else:log.warning("JSON pointer length of {0!s} not supported.".format(len(comp)))options.get("response").data=json.dumps(content)exceptKeyError:log.warning("Can not delete response JSON Pointer {0!s}.".format(json_pointer))elifaction.lower()==ACTION_TYPE.SET:try:iftype=="integer":value=int(value)eliftype=="bool":value=is_true(value)exceptValueError:log.warning("Failed to convert value")iflen(comp)==1:content[comp[0]]=valueeliflen(comp)==2:content[comp[0]]=content.get(comp[0])or{}content[comp[0]][comp[1]]=valueeliflen(comp)==3:content[comp[0]]=content.get(comp[0])or{}content[comp[0]][comp[1]]=content[comp[0]].get(comp[1])or{}content[comp[0]][comp[1]][comp[2]]=valueelse:log.warning("JSON pointer of length {0!s} not supported.".format(len(comp)))options.get("response").data=json.dumps(content)returnret