java - CXF Logging request & response with content filtering or masking soap fields -
i log incoming requests & responses particular endpoint, content filtering. i.e. when have request that:
<soap:envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"> <soap:body> <m:processphoto xmlns:m="http://www.w3schools.com/photos"> <m:name>apples</m:name> <m:description>photo apples in it</m:description> <!-- large encoded binary below --> <m:photo>anvzdcbhihjhbmrvbsb0zxh0dqpqdxn0igegcmfuzg9tihrlehqncmp1c3qgysbyyw5kb20gdgv4da0kanvzdcbhihjhbmrvbsb0zxh0dqpqdxn0igegcmfuzg9tihrlehqncmp1c3qgysbyyw5kb20gdgv4da0kanvzdcbhihjhbmrvbsb0zxh0dqp3b3csigkgzglkbid0ihrob3vnahqgdghhdcbhbnlvbmugd291bgqgymugaw50zxjlc3rlzcbpbibkzwnvzgluzyb0aglzlibjb25ncmf0cye=</m:photo> </m:processphoto> </soap:body> </soap:envelope>
i filter it, looks in logs that
<soap:envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"> <soap:body> <m:processphoto xmlns:m="http://www.w3schools.com/photos"> <m:name>apples</m:name> <m:description>photo apples in it</m:description> <m:photo>hidden</m:photo> </m:processphoto> </soap:body> </soap:envelope>
or removed m:photo element.
i found cxf has loggingininterceptor , loggingoutinterceptor , write own interceptors that. work do, question is: know better, out of box solution?
i had similar problem, needed mask passwords in input request. made small change existing loggininterceptor , overridden format method , added method mask password. here example
public class customlogininterceptor extends loggingininterceptor { @override protected string formatloggingmessage(loggingmessage loggingmessage) { string str = loggingmessage.tostring(); string output = maskpasswords(str); return(output); } private string maskpasswords(string str) { final string[] keys = { "password", "passwords" }; (string key : keys) { int beginindex = 0; int lastindex = -1; boolean emptypass = false; while (beginindex != -1 && (beginindex = stringutils.indexofignorecase(str, key, beginindex)) > 0) { beginindex = stringutils.indexof(str, ">", beginindex); if (beginindex != -1) { char ch = str.charat(beginindex - 1); if (ch == '/') { emptypass = true; } if (!emptypass) { lastindex = stringutils.indexof(str, "<", beginindex); if (lastindex != -1) { string overlay = "*"; string str2 = stringutils.substring(str, beginindex + 1, lastindex); if (str2 != null && str2.length() > 1) { overlay = stringutils.rightpad(overlay, str2.length(), "*"); str = stringutils.overlay(str, overlay, beginindex + 1, lastindex); } } } if (emptypass) { emptypass = false; lastindex = beginindex + 1; } else { if (lastindex != -1) { lastindex = stringutils .indexof(str, ">", lastindex); } } } beginindex = lastindex; } } return str; } }
and added custtom cxf logging bean in cxf-bean.xml
<bean id="kpininterceptor" class="com.kp.util.customlogininterceptor" /> <cxf:bus> <cxf:ininterceptors> <ref bean="kpininterceptor" /> </cxf:ininterceptors> <cxf:infaultinterceptors> <ref bean="kpininterceptor" /> </cxf:infaultinterceptors> </cxf:bus>
note i've used apache commons-lang3 jar string manipulation. can use response well
update
using patterns , making keys configurable using properties.
interceptor
public class customlogininterceptor extends loggingininterceptor { private static final string mask_pattern = "<\\s*{}\\s*>(.*)</\\s*{}\\s*>|<\\s*name\\s*>\\s*{}\\s*</\\s*name\\s*>\\s*<\\s*value\\s*>(.*)<"; private pattern pattern; private string[] keys; public void init() { stringbuilder builder = new stringbuilder(); (string str : keys) { builder.append(mask_pattern.replace("{}", str)); builder.append("|"); } builder.setlength(builder.length()-1); pattern = pattern.compile(builder.tostring(), pattern.case_insensitive | pattern.multiline); } public void setkeys(string[] keys) { this.keys = keys; } @override protected string formatloggingmessage(loggingmessage loggingmessage) { string output = maskpasswords(loggingmessage.tostring()); return(output); } private string maskpasswords(string str) { matcher matcher = pattern.matcher(str); final stringbuilder builder = new stringbuilder(str); while (matcher.find()) { int group = 1; while (group <= matcher.groupcount()) { if (matcher.group(group) != null) { (int = matcher.start(group); < matcher.end(group); i++) { builder.setcharat(i, '*'); } } group++; } } return builder.tostring(); } }
bean creation
<bean id="kpininterceptor" class="com.kp.util.customlogininterceptor" init-method="init"> <property name="keys"> <array value-type="java.lang.string"> <value>password</value> <value>accountid</value> </array> </property> </bean>
sample input
<?xml version="1.0" encoding="utf-8"?> <test> <hello>adffas</hello> <vsdsd>dfsdf</vsdsd> <password>sdfsfs</password> <sdfsfsf>sdfsfsf</sdfsfsf> <password>3434</password> <name>password</name> <value>sdfsfs</value> <password /> <name>password</name> <value /> <accountid>123456</accountid> <hello> <inner1> <password> <password>sdfsfs</password> </password> </inner> </hello> </test>
and output
<?xml version="1.0" encoding="utf-8"?> <test> <hello>adffas</hello> <vsdsd>dfsdf</vsdsd> <password>******</password> <sdfsfsf>sdfsfsf</sdfsfsf> <password>****</password> <name>password</name> <value>******</value> <password /> <name>password</name> <value /> <accountid>******</accountid> <hello> <inner1> <password> <password>******</password> </password> </inner> </hello> </test>
Comments
Post a Comment