/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.processor; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; import org.apache.camel.spi.MaskingFormatter; /** * The {@link MaskingFormatter} that searches the specified keywards in the source * and replace its value with mask string. By default passphrase, password and secretKey * are used as keywards to replace its value. */ public class DefaultMaskingFormatter implements MaskingFormatter { private static final Set<String> DEFAULT_KEYWORDS = new HashSet<String>(Arrays.asList("passphrase", "password", "secretKey")); private Set<String> keywords; private boolean maskKeyValue; private boolean maskXmlElement; private boolean maskJson; private String maskString = "xxxxx"; private Pattern keyValueMaskPattern; private Pattern xmlElementMaskPattern; private Pattern jsonMaskPattern; public DefaultMaskingFormatter() { this(DEFAULT_KEYWORDS, true, true, true); } public DefaultMaskingFormatter(boolean maskKeyValue, boolean maskXml, boolean maskJson) { this(DEFAULT_KEYWORDS, maskKeyValue, maskXml, maskJson); } public DefaultMaskingFormatter(Set<String> keywords, boolean maskKeyValue, boolean maskXmlElement, boolean maskJson) { this.keywords = keywords; setMaskKeyValue(maskKeyValue); setMaskXmlElement(maskXmlElement); setMaskJson(maskJson); } public String format(String source) { if (keywords == null || keywords.isEmpty()) { return source; } String answer = source; if (maskKeyValue) { answer = keyValueMaskPattern.matcher(answer).replaceAll("$1\"" + maskString + "\""); } if (maskXmlElement) { answer = xmlElementMaskPattern.matcher(answer).replaceAll("$1" + maskString + "$3"); } if (maskJson) { answer = jsonMaskPattern.matcher(answer).replaceAll("$1\"" + maskString + "\""); } return answer; } public boolean isMaskKeyValue() { return maskKeyValue; } public void setMaskKeyValue(boolean maskKeyValue) { this.maskKeyValue = maskKeyValue; if (maskKeyValue) { keyValueMaskPattern = createKeyValueMaskPattern(keywords); } else { keyValueMaskPattern = null; } } public boolean isMaskXmlElement() { return maskXmlElement; } public void setMaskXmlElement(boolean maskXml) { this.maskXmlElement = maskXml; if (maskXml) { xmlElementMaskPattern = createXmlElementMaskPattern(keywords); } else { xmlElementMaskPattern = null; } } public boolean isMaskJson() { return maskJson; } public void setMaskJson(boolean maskJson) { this.maskJson = maskJson; if (maskJson) { jsonMaskPattern = createJsonMaskPattern(keywords); } else { jsonMaskPattern = null; } } public String getMaskString() { return maskString; } public void setMaskString(String maskString) { this.maskString = maskString; } protected Pattern createKeyValueMaskPattern(Set<String> keywords) { StringBuilder regex = createOneOfThemRegex(keywords); if (regex == null) { return null; } regex.insert(0, "([\\w]*(?:"); regex.append(")[\\w]*[\\s]*?=[\\s]*?)([\\S&&[^'\",\\}\\]\\)]]+[\\S&&[^,\\}\\]\\)>]]*?|\"[^\"]*?\"|'[^']*?')"); return Pattern.compile(regex.toString(), Pattern.CASE_INSENSITIVE); } protected Pattern createXmlElementMaskPattern(Set<String> keywords) { StringBuilder regex = createOneOfThemRegex(keywords); if (regex == null) { return null; } regex.insert(0, "(<([\\w]*(?:"); regex.append(")[\\w]*)(?:[\\s]+.+)*?>[\\s]*?)(?:[\\S&&[^<]]+(?:\\s+[\\S&&[^<]]+)*?)([\\s]*?</\\2>)"); return Pattern.compile(regex.toString(), Pattern.CASE_INSENSITIVE); } protected Pattern createJsonMaskPattern(Set<String> keywords) { StringBuilder regex = createOneOfThemRegex(keywords); if (regex == null) { return null; } regex.insert(0, "(\"(?:[^\"]|(?:\\\"))*?(?:"); regex.append(")(?:[^\"]|(?:\\\"))*?\"\\s*?\\:\\s*?)(?:\"(?:[^\"]|(?:\\\"))*?\")"); return Pattern.compile(regex.toString(), Pattern.CASE_INSENSITIVE); } protected StringBuilder createOneOfThemRegex(Set<String> keywords) { StringBuilder regex = new StringBuilder(); if (keywords == null || keywords.isEmpty()) { return null; } String[] strKeywords = keywords.toArray(new String[0]); regex.append(Pattern.quote(strKeywords[0])); if (strKeywords.length > 1) { for (int i = 1; i < strKeywords.length; i++) { regex.append('|'); regex.append(Pattern.quote(strKeywords[i])); } } return regex; } }