You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/03/28 07:46:37 UTC
[5/5] camel git commit: CAMEL-10885 Add mask option to log EIP
CAMEL-10885 Add mask option to log EIP
Introduced a StringFormatter interface to plugin a formatter into the Log EIP processor. MaskingStringFormatter is the implementation which masks sensitive information like password and passphrase for key=value, XML and JSON. If logEipMask is set to true on CamelContext or route, MaskingStringFormatter is enabled with default options.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/4dc64385
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/4dc64385
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/4dc64385
Branch: refs/heads/master
Commit: 4dc64385bb7fd362fd4028def621a03837df41b3
Parents: 7f5d742
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Fri Mar 17 17:18:13 2017 +0900
Committer: Claus Ibsen <da...@apache.org>
Committed: Tue Mar 28 09:46:16 2017 +0200
----------------------------------------------------------------------
.../org/apache/camel/RuntimeConfiguration.java | 14 ++
.../apache/camel/impl/DefaultCamelContext.java | 9 +
.../apache/camel/impl/DefaultRouteContext.java | 14 ++
.../org/apache/camel/model/LogDefinition.java | 8 +-
.../org/apache/camel/model/RouteDefinition.java | 48 +++++
.../apache/camel/processor/LogProcessor.java | 12 +-
.../camel/processor/MaskingStringFormatter.java | 181 +++++++++++++++++++
.../org/apache/camel/spi/StringFormatter.java | 34 ++++
.../apache/camel/processor/LogEipMaskTest.java | 86 +++++++++
.../processor/MaskingStringFormatterTest.java | 100 ++++++++++
.../blueprint/CamelContextFactoryBean.java | 10 +
.../xml/AbstractCamelContextFactoryBean.java | 5 +
.../camel/spring/CamelContextFactoryBean.java | 13 ++
.../spring/processor/SpringLogEipMaskTest.java | 67 +++++++
.../processor/logEipCustomFormatterTest.xml | 37 ++++
.../camel/spring/processor/logEipMaskTest.xml | 41 +++++
16 files changed, 677 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/RuntimeConfiguration.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/RuntimeConfiguration.java b/camel-core/src/main/java/org/apache/camel/RuntimeConfiguration.java
index 7264ec0..d605b43 100644
--- a/camel-core/src/main/java/org/apache/camel/RuntimeConfiguration.java
+++ b/camel-core/src/main/java/org/apache/camel/RuntimeConfiguration.java
@@ -67,6 +67,20 @@ public interface RuntimeConfiguration {
Boolean isMessageHistory();
/**
+ * Sets whether security mask for Log EIP is enabled or not (default is disabled).
+ *
+ * @param logEipMask <tt>true</tt> if mask is enabled
+ */
+ void setLogEipMask(Boolean logEipMask);
+
+ /**
+ * Gets whether security mask for Log EIP is enabled or not.
+ *
+ * @return <tt>true</tt> if mask is enabled
+ */
+ Boolean isLogEipMask();
+
+ /**
* Sets whether to log exhausted message body with message history.
*
* @param logExhaustedMessageBody whether message body should be logged
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index a171645..c81d981 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -240,6 +240,7 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
private Boolean autoStartup = Boolean.TRUE;
private Boolean trace = Boolean.FALSE;
private Boolean messageHistory = Boolean.TRUE;
+ private Boolean logEipMask = Boolean.FALSE;
private Boolean logExhaustedMessageBody = Boolean.FALSE;
private Boolean streamCache = Boolean.FALSE;
private Boolean handleFault = Boolean.FALSE;
@@ -2707,6 +2708,14 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
this.messageHistory = messageHistory;
}
+ public void setLogEipMask(Boolean useLogEipMask) {
+ this.logEipMask = useLogEipMask;
+ }
+
+ public Boolean isLogEipMask() {
+ return logEipMask != null && logEipMask;
+ }
+
public Boolean isLogExhaustedMessageBody() {
return logExhaustedMessageBody;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
index 594742e..3d6cadb 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
@@ -63,6 +63,7 @@ public class DefaultRouteContext implements RouteContext {
private boolean routeAdded;
private Boolean trace;
private Boolean messageHistory;
+ private Boolean logEipMask;
private Boolean logExhaustedMessageBody;
private Boolean streamCache;
private Boolean handleFault;
@@ -310,6 +311,19 @@ public class DefaultRouteContext implements RouteContext {
}
}
+ public void setLogEipMask(Boolean logEipMask) {
+ this.logEipMask = logEipMask;
+ }
+
+ public Boolean isLogEipMask() {
+ if (logEipMask != null) {
+ return logEipMask;
+ } else {
+ // fallback to the option from camel context
+ return getCamelContext().isLogEipMask();
+ }
+ }
+
public void setLogExhaustedMessageBody(Boolean logExhaustedMessageBody) {
this.logExhaustedMessageBody = logExhaustedMessageBody;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java b/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
index 7e6cd42..3d0b957 100644
--- a/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/LogDefinition.java
@@ -28,8 +28,10 @@ import org.apache.camel.Expression;
import org.apache.camel.LoggingLevel;
import org.apache.camel.Processor;
import org.apache.camel.processor.LogProcessor;
+import org.apache.camel.processor.MaskingStringFormatter;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.RouteContext;
+import org.apache.camel.spi.StringFormatter;
import org.apache.camel.util.CamelContextHelper;
import org.apache.camel.util.CamelLogger;
import org.apache.camel.util.ObjectHelper;
@@ -123,7 +125,11 @@ public class LogDefinition extends NoOutputDefinition<LogDefinition> {
LoggingLevel level = getLoggingLevel() != null ? getLoggingLevel() : LoggingLevel.INFO;
CamelLogger camelLogger = new CamelLogger(logger, level, getMarker());
- return new LogProcessor(exp, camelLogger);
+ StringFormatter formatter = routeContext.getCamelContext().getRegistry().lookupByNameAndType("logEipFormatter", StringFormatter.class);
+ if (formatter == null && routeContext.isLogEipMask()) {
+ formatter = new MaskingStringFormatter();
+ }
+ return new LogProcessor(exp, camelLogger, formatter);
}
@Override
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
index 48f10a5..5e3fffb 100644
--- a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -77,6 +77,7 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
private String streamCache;
private String trace;
private String messageHistory;
+ private String logEipMask;
private String handleFault;
private String delayer;
private String autoStartup;
@@ -478,6 +479,27 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
}
/**
+ * Enable security mask in Log EIP for this route.
+ *
+ * @return the builder
+ */
+ public RouteDefinition logEipMask() {
+ setLogEipMask("true");
+ return this;
+ }
+
+ /**
+ * Sets whether security mask in Log EIP is enabled for this route.
+ *
+ * @param logEipMask whether to enable security mask in Log EIP (true or false), the value can be a property placeholder
+ * @return the builder
+ */
+ public RouteDefinition logEipMask(String logEipMask) {
+ setLogEipMask(logEipMask);
+ return this;
+ }
+
+ /**
* Disable message history for this route.
*
* @return the builder
@@ -875,6 +897,21 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
}
/**
+ * Whether security mask for Log EIP is enabled on this route.
+ */
+ public String getLogEipMask() {
+ return logEipMask;
+ }
+
+ /**
+ * Whether security mask for Log EIP is enabled on this route.
+ */
+ @XmlAttribute @Metadata(defaultValue = "false")
+ public void setLogEipMask(String logEipMask) {
+ this.logEipMask = logEipMask;
+ }
+
+ /**
* Whether handle fault is enabled on this route.
*/
public String getHandleFault() {
@@ -1132,6 +1169,17 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
}
}
+ // configure Log EIP mask
+ if (logEipMask != null) {
+ Boolean isLogEipMask = CamelContextHelper.parseBoolean(camelContext, getLogEipMask());
+ if (isLogEipMask != null) {
+ routeContext.setLogEipMask(isLogEipMask);
+ if (isLogEipMask) {
+ log.debug("Security mask for Log EIP is enabled on route: {}", getId());
+ }
+ }
+ }
+
// configure stream caching
if (streamCache != null) {
Boolean isStreamCache = CamelContextHelper.parseBoolean(camelContext, getStreamCache());
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/processor/LogProcessor.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/LogProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/LogProcessor.java
index 2304afc..eaff482 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/LogProcessor.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/LogProcessor.java
@@ -22,6 +22,7 @@ import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.Traceable;
import org.apache.camel.spi.IdAware;
+import org.apache.camel.spi.StringFormatter;
import org.apache.camel.support.ServiceSupport;
import org.apache.camel.util.AsyncProcessorHelper;
import org.apache.camel.util.CamelLogger;
@@ -36,10 +37,12 @@ public class LogProcessor extends ServiceSupport implements AsyncProcessor, Trac
private String id;
private final Expression expression;
private final CamelLogger logger;
+ private final StringFormatter formatter;
- public LogProcessor(Expression expression, CamelLogger logger) {
+ public LogProcessor(Expression expression, CamelLogger logger, StringFormatter formatter) {
this.expression = expression;
this.logger = logger;
+ this.formatter = formatter;
}
public void process(Exchange exchange) throws Exception {
@@ -51,6 +54,9 @@ public class LogProcessor extends ServiceSupport implements AsyncProcessor, Trac
try {
if (logger.shouldLog()) {
String msg = expression.evaluate(exchange, String.class);
+ if (formatter != null) {
+ msg = formatter.format(msg);
+ }
logger.doLog(msg);
}
} catch (Exception e) {
@@ -87,6 +93,10 @@ public class LogProcessor extends ServiceSupport implements AsyncProcessor, Trac
return logger;
}
+ public StringFormatter getLogFormatter() {
+ return formatter;
+ }
+
@Override
protected void doStart() throws Exception {
// noop
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/processor/MaskingStringFormatter.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/MaskingStringFormatter.java b/camel-core/src/main/java/org/apache/camel/processor/MaskingStringFormatter.java
new file mode 100644
index 0000000..4d2ef6f
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/processor/MaskingStringFormatter.java
@@ -0,0 +1,181 @@
+/**
+ * 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.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.Future;
+import java.util.regex.Pattern;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.spi.ExchangeFormatter;
+import org.apache.camel.spi.StringFormatter;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.util.MessageHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+
+/**
+ * The {@link StringFormatter} 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 MaskingStringFormatter implements StringFormatter {
+
+ 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 MaskingStringFormatter() {
+ this(DEFAULT_KEYWORDS, true, true, true);
+ }
+
+ public MaskingStringFormatter(boolean maskKeyValue, boolean maskXml, boolean maskJson) {
+ this(DEFAULT_KEYWORDS, maskKeyValue, maskXml, maskJson);
+ }
+
+ public MaskingStringFormatter(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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/main/java/org/apache/camel/spi/StringFormatter.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/StringFormatter.java b/camel-core/src/main/java/org/apache/camel/spi/StringFormatter.java
new file mode 100644
index 0000000..c76e63e
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/StringFormatter.java
@@ -0,0 +1,34 @@
+/**
+ * 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.spi;
+
+import org.apache.camel.Exchange;
+
+/**
+ * A plugin used to format a log String, for example to mask security information
+ * like password or passphrase.
+ */
+public interface StringFormatter {
+
+ /**
+ * Format a given string.
+ *
+ * @param source the source string
+ * @return formatted string
+ */
+ String format(String source);
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/test/java/org/apache/camel/processor/LogEipMaskTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/LogEipMaskTest.java b/camel-core/src/test/java/org/apache/camel/processor/LogEipMaskTest.java
new file mode 100644
index 0000000..a230aef
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/processor/LogEipMaskTest.java
@@ -0,0 +1,86 @@
+/**
+ * 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 org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.StringFormatter;
+import org.apache.camel.util.jndi.JndiTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LogEipMaskTest {
+
+ protected MockStringFormatter globalFormatter;
+ protected JndiRegistry registry;
+
+ protected CamelContext createCamelContext() throws Exception {
+ registry = new JndiRegistry(JndiTest.createInitialContext());
+ globalFormatter = new MockStringFormatter();
+ CamelContext context = new DefaultCamelContext(registry);
+ context.addRoutes(createRouteBuilder());
+ return context;
+ }
+
+ @Test
+ public void testLogEipMask() throws Exception {
+ CamelContext context = createCamelContext();
+ MockEndpoint mock = context.getEndpoint("mock:foo", MockEndpoint.class);
+ mock.expectedMessageCount(1);
+ context.setLogEipMask(true);
+ context.start();
+ context.createProducerTemplate().sendBody("direct:foo", "mask password=\"my passw0rd!\"");
+ context.createProducerTemplate().sendBody("direct:noMask", "no-mask password=\"my passw0rd!\"");
+ mock.assertIsSatisfied();
+ context.stop();
+ }
+
+ @Test
+ public void testCustomFormatter() throws Exception {
+ CamelContext context = createCamelContext();
+ registry.bind("logEipFormatter", globalFormatter);
+ context.start();
+ context.createProducerTemplate().sendBody("direct:foo", "mock password=\"my passw0rd!\"");
+ Assert.assertEquals("Got mock password=\"my passw0rd!\"", globalFormatter.received);
+ context.stop();
+ }
+
+ public static class MockStringFormatter implements StringFormatter {
+ private String received;
+ @Override
+ public String format(String source) {
+ received = source;
+ return source;
+ }
+ }
+
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:foo").routeId("foo").log("Got ${body}").to("mock:foo");
+ from("direct:noMask").routeId("noMask").logEipMask("false").log("Got ${body}").to("mock:noMask");
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/camel-core/src/test/java/org/apache/camel/processor/MaskingStringFormatterTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/MaskingStringFormatterTest.java b/camel-core/src/test/java/org/apache/camel/processor/MaskingStringFormatterTest.java
new file mode 100644
index 0000000..aadb5a2
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/processor/MaskingStringFormatterTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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 org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.impl.DefaultMessage;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class MaskingStringFormatterTest {
+
+ @Test
+ public void testDefaultOption() throws Exception {
+ MaskingStringFormatter formatter = new MaskingStringFormatter();
+ String answer = formatter.format("key=value, myPassword=foo,\n myPassphrase=\"foo bar\", secretKey='!@#$%^&*() -+[]{};:'");
+ Assert.assertEquals("key=value, myPassword=\"xxxxx\",\n myPassphrase=\"xxxxx\", secretKey=\"xxxxx\"", answer);
+
+ answer = formatter.format("<xmlPassword>\n foo bar \n</xmlPassword>\n<user password=\"asdf qwert\"/>");
+ Assert.assertEquals("<xmlPassword>\n xxxxx \n</xmlPassword>\n<user password=\"xxxxx\"/>", answer);
+
+ answer = formatter.format("{\"key\" : \"value\", \"My Password\":\"foo\", \"My SecretPassphrase\" : \"foo bar\", \"My SecretKey2\" : \"!@#$%^&*() -+[]{};:'\"}");
+ Assert.assertEquals("{\"key\" : \"value\", \"My Password\":\"xxxxx\", \"My SecretPassphrase\" : \"xxxxx\", \"My SecretKey2\" : \"xxxxx\"}", answer);
+ }
+
+ @Test
+ public void testDisableKeyValueMask() throws Exception {
+ MaskingStringFormatter formatter = new MaskingStringFormatter(false, true, true);
+ String answer = formatter.format("key=value, myPassword=foo,\n myPassphrase=\"foo bar\", secretKey='!@#$%^&*() -+[]{};:'");
+ Assert.assertEquals("key=value, myPassword=foo,\n myPassphrase=\"foo bar\", secretKey='!@#$%^&*() -+[]{};:'", answer);
+
+ answer = formatter.format("<xmlPassword>\n foo bar \n</xmlPassword>\n<user password=\"asdf qwert\"/>");
+ Assert.assertEquals("<xmlPassword>\n xxxxx \n</xmlPassword>\n<user password=\"asdf qwert\"/>", answer);
+
+ answer = formatter.format("{\"key\" : \"value\", \"My Password\":\"foo\", \"My SecretPassphrase\" : \"foo bar\", \"My SecretKey2\" : \"!@#$%^&*() -+[]{};:'\"}");
+ Assert.assertEquals("{\"key\" : \"value\", \"My Password\":\"xxxxx\", \"My SecretPassphrase\" : \"xxxxx\", \"My SecretKey2\" : \"xxxxx\"}", answer);
+ }
+
+ @Test
+ public void testDisableXmlElementMask() throws Exception {
+ MaskingStringFormatter formatter = new MaskingStringFormatter(true, false, true);
+ String answer = formatter.format("key=value, myPassword=foo,\n myPassphrase=\"foo bar\", secretKey='!@#$%^&*() -+[]{};:'");
+ Assert.assertEquals("key=value, myPassword=\"xxxxx\",\n myPassphrase=\"xxxxx\", secretKey=\"xxxxx\"", answer);
+
+ answer = formatter.format("<xmlPassword>\n foo bar \n</xmlPassword>\n<user password=\"asdf qwert\"/>");
+ Assert.assertEquals("<xmlPassword>\n foo bar \n</xmlPassword>\n<user password=\"xxxxx\"/>", answer);
+
+ answer = formatter.format("{\"key\" : \"value\", \"My Password\":\"foo\", \"My SecretPassphrase\" : \"foo bar\", \"My SecretKey2\" : \"!@#$%^&*() -+[]{};:'\"}");
+ Assert.assertEquals("{\"key\" : \"value\", \"My Password\":\"xxxxx\", \"My SecretPassphrase\" : \"xxxxx\", \"My SecretKey2\" : \"xxxxx\"}", answer);
+ }
+
+ @Test
+ public void testDisableJsonMask() throws Exception {
+ MaskingStringFormatter formatter = new MaskingStringFormatter(true, true, false);
+ String answer = formatter.format("key=value, myPassword=foo,\n myPassphrase=\"foo\u3000bar\", secretKey='!@#$%^&*() -+[]{};:'");
+ Assert.assertEquals("key=value, myPassword=\"xxxxx\",\n myPassphrase=\"xxxxx\", secretKey=\"xxxxx\"", answer);
+
+ answer = formatter.format("<xmlPassword>\n foo bar \n</xmlPassword>\n<user password=\"asdf qwert\"/>");
+ Assert.assertEquals("<xmlPassword>\n xxxxx \n</xmlPassword>\n<user password=\"xxxxx\"/>", answer);
+
+ answer = formatter.format("{\"key\" : \"value\", \"My Password\":\"foo\", \"My SecretPassphrase\" : \"foo bar\", \"My SecretKey2\" : \"!@#$%^&*() -+[]{};:'\"}");
+ Assert.assertEquals("{\"key\" : \"value\", \"My Password\":\"foo\", \"My SecretPassphrase\" : \"foo bar\", \"My SecretKey2\" : \"!@#$%^&*() -+[]{};:'\"}", answer);
+ }
+
+ @Test
+ public void testCustomMaskString() throws Exception {
+ MaskingStringFormatter formatter = new MaskingStringFormatter();
+ formatter.setMaskString("**********");
+ String answer = formatter.format("key=value, myPassword=foo,\n myPassphrase=\"foo\u3000bar\", secretKey='!@#$%^&*() -+[]{};:'");
+ Assert.assertEquals("key=value, myPassword=\"**********\",\n myPassphrase=\"**********\", secretKey=\"**********\"", answer);
+
+ answer = formatter.format("<xmlPassword>\n foo bar \n</xmlPassword>\n<user password=\"asdf qwert\"/>");
+ Assert.assertEquals("<xmlPassword>\n ********** \n</xmlPassword>\n<user password=\"**********\"/>", answer);
+
+ answer = formatter.format("{\"key\" : \"value\", \"My Password\":\"foo\", \"My SecretPassphrase\" : \"foo bar\", \"My SecretKey2\" : \"!@#$%^&*() -+[]{};:'\"}");
+ Assert.assertEquals("{\"key\" : \"value\", \"My Password\":\"**********\", \"My SecretPassphrase\" : \"**********\", \"My SecretKey2\" : \"**********\"}", answer);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
index ecc74f1..f4f9c5c 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
@@ -93,6 +93,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
@XmlAttribute
private String messageHistory;
@XmlAttribute
+ private String logEipMask;
+ @XmlAttribute
private String logExhaustedMessageBody;
@XmlAttribute
private String streamCache = "false";
@@ -536,6 +538,14 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
this.messageHistory = messageHistory;
}
+ public String getLogEipMask() {
+ return logEipMask;
+ }
+
+ public void setLogEipMask(String logEipMask) {
+ this.logEipMask = logEipMask;
+ }
+
public String getLogExhaustedMessageBody() {
return logExhaustedMessageBody;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 912e1af..fc92daa 100644
--- a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -727,6 +727,8 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
public abstract String getMessageHistory();
+ public abstract String getLogEipMask();
+
public abstract String getLogExhaustedMessageBody();
public abstract String getStreamCache();
@@ -822,6 +824,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
if (getMessageHistory() != null) {
ctx.setMessageHistory(CamelContextHelper.parseBoolean(getContext(), getMessageHistory()));
}
+ if (getLogEipMask() != null) {
+ ctx.setLogEipMask(CamelContextHelper.parseBoolean(getContext(), getLogEipMask()));
+ }
if (getLogExhaustedMessageBody() != null) {
ctx.setLogExhaustedMessageBody(CamelContextHelper.parseBoolean(getContext(), getLogExhaustedMessageBody()));
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
index 70a319e..be304eb 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
@@ -101,6 +101,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
private String trace;
@XmlAttribute @Metadata(defaultValue = "true")
private String messageHistory;
+ @XmlAttribute @Metadata(defaultValue = "false")
+ private String logEipMask;
@XmlAttribute
private String logExhaustedMessageBody;
@XmlAttribute
@@ -635,6 +637,17 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
this.messageHistory = messageHistory;
}
+ public String getLogEipMask() {
+ return logEipMask;
+ }
+
+ /**
+ * Sets whether security mask for Log EIP is enabled or not.
+ */
+ public void setLogEipMask(String logEipMask) {
+ this.logEipMask = logEipMask;
+ }
+
public String getLogExhaustedMessageBody() {
return logExhaustedMessageBody;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringLogEipMaskTest.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringLogEipMaskTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringLogEipMaskTest.java
new file mode 100644
index 0000000..6bf1a70
--- /dev/null
+++ b/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringLogEipMaskTest.java
@@ -0,0 +1,67 @@
+/**
+ * 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.spring.processor;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.processor.LogEipMaskTest;
+import org.apache.camel.spi.StringFormatter;
+import org.apache.camel.spring.SpringCamelContext;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;
+
+public class SpringLogEipMaskTest {
+
+ @Test
+ public void testLogEipMask() throws Exception {
+ final AbstractXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("org/apache/camel/spring/processor/logEipMaskTest.xml");
+ SpringCamelContext context = SpringCamelContext.springCamelContext(applicationContext);
+ MockEndpoint mock = context.getEndpoint("mock:foo", MockEndpoint.class);
+ mock.expectedMessageCount(1);
+ context.setLogEipMask(true);
+ context.start();
+ context.createProducerTemplate().sendBody("direct:foo", "mask password=\"my passw0rd!\"");
+ context.createProducerTemplate().sendBody("direct:noMask", "no-mask password=\"my passw0rd!\"");
+ mock.assertIsSatisfied();
+ context.stop();
+ }
+
+ @Test
+ public void testCustomFormatter() throws Exception {
+ final AbstractXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("org/apache/camel/spring/processor/logEipCustomFormatterTest.xml");
+ SpringCamelContext context = SpringCamelContext.springCamelContext(applicationContext);
+ context.start();
+ MockStringFormatter customFormatter = applicationContext.getBean("logEipFormatter", MockStringFormatter.class);
+ context.createProducerTemplate().sendBody("direct:foo", "mock password=\"my passw0rd!\"");
+ Assert.assertEquals("Got mock password=\"my passw0rd!\"", customFormatter.received);
+ context.stop();
+ }
+
+ public static class MockStringFormatter implements StringFormatter {
+ private String received;
+ @Override
+ public String format(String source) {
+ received = source;
+ return source;
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipCustomFormatterTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipCustomFormatterTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipCustomFormatterTest.xml
new file mode 100644
index 0000000..dc90e35
--- /dev/null
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipCustomFormatterTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+ ">
+
+ <bean id="logEipFormatter" class="org.apache.camel.spring.processor.SpringLogEipMaskTest.MockStringFormatter"/>
+
+ <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+ <route id="foo">
+ <from uri="direct:foo"/>
+ <log message="Got ${body}"/>
+ <to uri="mock:foo"/>
+ </route>
+
+ </camelContext>
+
+</beans>
http://git-wip-us.apache.org/repos/asf/camel/blob/4dc64385/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipMaskTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipMaskTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipMaskTest.xml
new file mode 100644
index 0000000..577847d
--- /dev/null
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/logEipMaskTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+ ">
+
+ <camelContext logEipMask="true" xmlns="http://camel.apache.org/schema/spring">
+
+ <route id="foo">
+ <from uri="direct:foo"/>
+ <log message="Got ${body}"/>
+ <to uri="mock:foo"/>
+ </route>
+
+ <route id="noMask" logEipMask="false">
+ <from uri="direct:noMask"/>
+ <log message="Got ${body}"/>
+ <to uri="mock:noMask"/>
+ </route>
+
+ </camelContext>
+
+</beans>