killbill-memoizeit
Changes
profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ConfigMagicObfuscator.java 58(+58 -0)
profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java 192(+192 -0)
profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java 112(+112 -0)
profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ObfuscatorConverter.java 63(+63 -0)
profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/PatternObfuscator.java 81(+81 -0)
profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java 50(+50 -0)
profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java 219(+219 -0)
profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java 60(+60 -0)
profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java 70(+70 -0)
Details
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ConfigMagicObfuscator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ConfigMagicObfuscator.java
new file mode 100644
index 0000000..6ecd7ce
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ConfigMagicObfuscator.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.regex.Pattern;
+
+import com.google.common.collect.ImmutableList;
+
+// See ConfigurationObjectFactory
+public class ConfigMagicObfuscator extends Obfuscator {
+
+ private static final String[] DEFAULT_SENSITIVE_KEYS = {
+ "key",
+ "pass",
+ "password"
+ };
+
+ private final Collection<Pattern> patterns = new LinkedList<Pattern>();
+
+ public ConfigMagicObfuscator() {
+ this(ImmutableList.<Pattern>of());
+ }
+
+ public ConfigMagicObfuscator(final Collection<Pattern> extraPatterns) {
+ super();
+
+ for (final String sensitiveKey : DEFAULT_SENSITIVE_KEYS) {
+ this.patterns.add(buildPattern(sensitiveKey));
+ }
+ this.patterns.addAll(extraPatterns);
+ }
+
+ @Override
+ public String obfuscate(final String originalString) {
+ return obfuscate(originalString, patterns);
+ }
+
+ private Pattern buildPattern(final String key) {
+ return Pattern.compile("^Assigning value \\[([^\\]]*)\\] for \\[[^\\]]*" + key + "\\] on \\[[^\\]]*\\]$", DEFAULT_PATTERN_FLAGS);
+ }
+}
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java
new file mode 100644
index 0000000..88bda32
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * LuhnMaskingObfuscator replaces sequences of digits that pass the Luhn check
+ * with a masking string, leaving only the suffix containing the last four
+ * digits.
+ * <p/>
+ * Inspired from https://github.com/esamson/logback-luhn-mask (licensed under the Apache License, Version 2.0)
+ */
+public class LuhnMaskingObfuscator extends Obfuscator {
+
+ /**
+ * The minimum number of digits a credit card can have.
+ */
+ private static final int MIN_CC_DIGITS = 13;
+
+ public LuhnMaskingObfuscator() {
+ super();
+ }
+
+ @Override
+ public String obfuscate(final String originalString) {
+ return mask(originalString);
+ }
+
+ private String mask(final String formattedMessage) {
+ if (!hasEnoughDigits(formattedMessage)) {
+ return formattedMessage;
+ }
+
+ final int length = formattedMessage.length();
+ int unwrittenStart = 0;
+ int numberStart = -1;
+ int numberEnd;
+ int digitsSeen = 0;
+ final int[] last4pos = {-1, -1, -1, -1};
+ int pos;
+ char current;
+
+ final StringBuilder masked = new StringBuilder(formattedMessage.length());
+
+ for (pos = 0; pos < length; pos++) {
+ current = formattedMessage.charAt(pos);
+ if (isDigit(current)) {
+ digitsSeen++;
+
+ if (numberStart == -1) {
+ numberStart = pos;
+ }
+
+ last4pos[0] = last4pos[1];
+ last4pos[1] = last4pos[2];
+ last4pos[2] = last4pos[3];
+ last4pos[3] = pos;
+ } else if (digitsSeen > 0 && current != ' ' && current != '-') {
+ numberEnd = last4pos[3] + 1;
+ if ((digitsSeen >= MIN_CC_DIGITS)
+ && luhnCheck(stripSeparators(formattedMessage.substring(numberStart, numberEnd)))) {
+ masked.append(formattedMessage, unwrittenStart, numberStart);
+ masked.append(obfuscateConfidentialData(formattedMessage.substring(numberStart, numberEnd),
+ formattedMessage.substring(last4pos[0], numberEnd)));
+ masked.append(formattedMessage, last4pos[0], numberEnd);
+ unwrittenStart = numberEnd;
+ }
+ numberStart = -1;
+ digitsSeen = 0;
+ }
+ }
+
+ if (numberStart != -1 && (digitsSeen >= MIN_CC_DIGITS)
+ && luhnCheck(stripSeparators(formattedMessage.substring(numberStart, pos)))) {
+ masked.append(formattedMessage, unwrittenStart, numberStart);
+ masked.append(obfuscateConfidentialData(formattedMessage.substring(numberStart, pos),
+ formattedMessage.substring(last4pos[0], pos)));
+ masked.append(formattedMessage, last4pos[0], pos);
+ } else {
+ masked.append(formattedMessage, unwrittenStart, pos);
+ }
+
+ return masked.toString();
+ }
+
+ private boolean hasEnoughDigits(final CharSequence formattedMessage) {
+ int digits = 0;
+ final int length = formattedMessage.length();
+ char current;
+
+ for (int i = 0; i < length; i++) {
+ current = formattedMessage.charAt(i);
+ if (isDigit(current)) {
+ if (++digits == MIN_CC_DIGITS) {
+ return true;
+ }
+ } else if (digits > 0 && current != ' ' && current != '-') {
+ digits = 0;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Implementation of the [Luhn algorithm](http://en.wikipedia.org/wiki/Luhn_algorithm)
+ * to check if the given string is possibly a credit card number.
+ *
+ * @param cardNumber the number to check. It must only contain numeric characters
+ * @return `true` if the given string is a possible credit card number
+ */
+ @VisibleForTesting
+ boolean luhnCheck(final String cardNumber) {
+ int sum = 0;
+ int digit, addend;
+ boolean doubled = false;
+ for (int i = cardNumber.length() - 1; i >= 0; i--) {
+ digit = Integer.parseInt(cardNumber.substring(i, i + 1));
+ if (doubled) {
+ addend = digit * 2;
+ if (addend > 9) {
+ addend -= 9;
+ }
+ } else {
+ addend = digit;
+ }
+ sum += addend;
+ doubled = !doubled;
+ }
+ return (sum % 10) == 0;
+ }
+
+ /**
+ * Remove any ` ` and `-` characters from the given string.
+ *
+ * @param cardNumber the number to clean up
+ * @return if the given string contains no ` ` or `-` characters, the string
+ * itself is returned, otherwise a new string containing no ` ` or `-`
+ * characters is returned
+ */
+ @VisibleForTesting
+ String stripSeparators(final String cardNumber) {
+ final int length = cardNumber.length();
+ final char[] result = new char[length];
+ int count = 0;
+ char cur;
+ for (int i = 0; i < length; i++) {
+ cur = cardNumber.charAt(i);
+ if (!(cur == ' ' || cur == '-')) {
+ result[count++] = cur;
+ }
+ }
+ if (count == length) {
+ return cardNumber;
+ }
+ return new String(result, 0, count);
+ }
+
+ private static boolean isDigit(final char c) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java
new file mode 100644
index 0000000..68675e7
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+import com.google.common.annotations.VisibleForTesting;
+
+public abstract class Obfuscator {
+
+ protected static final int DEFAULT_PATTERN_FLAGS = Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL;
+
+ protected static final String MASK_LABEL = "MASKED";
+ protected static final int MASK_LABEL_LENGTH = MASK_LABEL.length();
+ protected static final char PAD_CHAR = '*';
+ protected static final int MASK_LOOKUPS_SIZE = 20;
+ protected final String[] MASK_LOOKUPS = new String[MASK_LOOKUPS_SIZE];
+
+ public Obfuscator() {
+ for (int i = 0; i < MASK_LOOKUPS.length; i++) {
+ MASK_LOOKUPS[i] = buildMask(i);
+ }
+ }
+
+ public abstract String obfuscate(final String originalString);
+
+ protected String obfuscate(final String originalString, final Iterable<Pattern> patterns) {
+ final StringBuilder obfuscatedStringBuilder = new StringBuilder(originalString);
+
+ for (final Pattern pattern : patterns) {
+ int currentOffset = 0;
+ // Create a matcher with a copy of the current obfuscated String
+ Matcher matcher = pattern.matcher(obfuscatedStringBuilder.toString());
+ while (matcher.find()) {
+ for (int groupNb = 1; groupNb <= matcher.groupCount(); groupNb++) {
+ final String confidentialData = matcher.group(groupNb);
+ final String obfuscatedConfidentialData = obfuscateConfidentialData(confidentialData);
+ obfuscatedStringBuilder.replace(currentOffset + matcher.start(groupNb), currentOffset + matcher.end(groupNb), obfuscatedConfidentialData);
+
+ // The original String is modified in place, which will confuse the Matcher if it becomes bigger
+ if (obfuscatedConfidentialData.length() > confidentialData.length()) {
+ currentOffset += obfuscatedConfidentialData.length() - confidentialData.length();
+ }
+ }
+ }
+ }
+
+ return obfuscatedStringBuilder.toString();
+ }
+
+ private String obfuscateConfidentialData(final CharSequence confidentialSequence) {
+ return obfuscateConfidentialData(confidentialSequence, null);
+ }
+
+ /**
+ * Get a mask string for masking the given `confidentialSequence`.
+ *
+ * @param confidentialSequence the string to be obfuscated
+ * @param unmasked the section of `confidentialSequence` to be left unmasked
+ * @return a mask string
+ */
+ @VisibleForTesting
+ String obfuscateConfidentialData(final CharSequence confidentialSequence, @Nullable final CharSequence unmasked) {
+ final int maskedLength = unmasked == null ? confidentialSequence.length() : confidentialSequence.length() - unmasked.length();
+ if (maskedLength < MASK_LOOKUPS_SIZE) {
+ return MASK_LOOKUPS[maskedLength];
+ } else {
+ return buildMask(maskedLength);
+ }
+ }
+
+ /**
+ * Create a masking string with the given length.
+ *
+ * @param maskedLength obfuscated String length
+ * @return a mask string
+ */
+ private String buildMask(final int maskedLength) {
+ final int pads = maskedLength - MASK_LABEL_LENGTH;
+ final StringBuilder mask = new StringBuilder(maskedLength);
+ if (pads <= 0) {
+ mask.append(MASK_LABEL);
+ } else {
+ for (int i = 0; i < pads / 2; i++) {
+ mask.append(PAD_CHAR);
+ }
+ mask.append(MASK_LABEL);
+ while (mask.length() < maskedLength) {
+ mask.append(PAD_CHAR);
+ }
+ }
+ return mask.toString();
+ }
+}
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ObfuscatorConverter.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ObfuscatorConverter.java
new file mode 100644
index 0000000..2b5f9e5
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/ObfuscatorConverter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import java.util.Collection;
+
+import ch.qos.logback.classic.pattern.ClassicConverter;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * ObfuscatorConverter attempts to mask sensitive data in the log files.
+ * <p/>
+ * To use, define a new conversion word in your Logback configuration, e.g.:
+ * <pre>
+ * <configuration>
+ * <conversionRule conversionWord="maskedMsg"
+ * converterClass="org.killbill.billing.server.log.obfuscators.ObfuscatorConverter" />
+ * <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ * <encoder>
+ * <pattern>%date [%thread] - %maskedMsg%n</pattern>
+ * </encoder>
+ * </appender>
+ * <root level="DEBUG">
+ * <appender-ref ref="STDOUT" />
+ * </root>
+ * </configuration>
+ * </pre>
+ */
+public class ObfuscatorConverter extends ClassicConverter {
+
+ private final Collection<Obfuscator> obfuscators = ImmutableList.<Obfuscator>of(new ConfigMagicObfuscator(),
+ new PatternObfuscator(),
+ new LuhnMaskingObfuscator());
+
+ @Override
+ public String convert(final ILoggingEvent event) {
+ String convertedMessage = event.getFormattedMessage();
+ for (final Obfuscator obfuscator : obfuscators) {
+ try {
+ convertedMessage = obfuscator.obfuscate(convertedMessage);
+ } catch (final RuntimeException e) {
+ // Ignore? Not sure the impact of importing a logger here
+ }
+ }
+ return convertedMessage;
+ }
+}
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/PatternObfuscator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/PatternObfuscator.java
new file mode 100644
index 0000000..f9a38a5
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/PatternObfuscator.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.regex.Pattern;
+
+import com.google.common.collect.ImmutableList;
+
+public class PatternObfuscator extends Obfuscator {
+
+ // Hide by default sensitive bank, PCI and PII data. For PANs, see LuhnMaskingObfuscator
+ private static final String[] DEFAULT_SENSITIVE_KEYS = {
+ "accountnumber",
+ "authenticationdata",
+ "bankaccountnumber",
+ "banknumber",
+ "bic",
+ "cardvalidationnum",
+ "cavv",
+ "ccvv",
+ "cvNumber",
+ "cvc",
+ "email",
+ "iban",
+ "name",
+ "number",
+ "password",
+ "xid"
+ };
+
+ private final Collection<Pattern> patterns = new LinkedList<Pattern>();
+
+ public PatternObfuscator() {
+ this(ImmutableList.<Pattern>of());
+ }
+
+ public PatternObfuscator(final Collection<Pattern> extraPatterns) {
+ super();
+
+ for (final String sensitiveKey : DEFAULT_SENSITIVE_KEYS) {
+ this.patterns.add(buildJSONPattern(sensitiveKey));
+ this.patterns.add(buildXMLPattern(sensitiveKey));
+ this.patterns.add(buildMultiValuesXMLPattern(sensitiveKey));
+ }
+ this.patterns.addAll(extraPatterns);
+ }
+
+ @Override
+ public String obfuscate(final String originalString) {
+ return obfuscate(originalString, patterns);
+ }
+
+ private Pattern buildJSONPattern(final String key) {
+ return Pattern.compile(key + "\":\\s*([^,{]+)", DEFAULT_PATTERN_FLAGS);
+ }
+
+ private Pattern buildXMLPattern(final String key) {
+ return Pattern.compile(key + ">([^<\\n]+)", DEFAULT_PATTERN_FLAGS);
+ }
+
+ private Pattern buildMultiValuesXMLPattern(final String key) {
+ return Pattern.compile(key + "</key>\\s*<value[^>]*>([^<\\n]+)</value>", DEFAULT_PATTERN_FLAGS);
+ }
+}
diff --git a/profiles/killbill/src/main/resources/logback.xml b/profiles/killbill/src/main/resources/logback.xml
index fc17204..3e86876 100644
--- a/profiles/killbill/src/main/resources/logback.xml
+++ b/profiles/killbill/src/main/resources/logback.xml
@@ -17,9 +17,11 @@
-->
<configuration>
+ <conversionRule conversionWord="maskedMsg" converterClass="org.killbill.billing.server.log.obfuscators.ObfuscatorConverter" />
+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
- <pattern>%date [%thread] %-5level %logger{36} - %msg%n%ex</pattern>
+ <pattern>%date [%thread] %-5level %logger{36} - %maskedMsg%n%ex</pattern>
</encoder>
</appender>
@@ -40,7 +42,7 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
- <pattern>%date [%thread] %msg%n%ex</pattern>
+ <pattern>%date [%thread] %maskedMsg%n%ex</pattern>
</encoder>
</appender>
</sift>
@@ -61,7 +63,7 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
- <pattern>%date [%thread] %msg%n%ex</pattern>
+ <pattern>%date [%thread] %maskedMsg%n%ex</pattern>
</encoder>
</appender>
</sift>
@@ -82,7 +84,7 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
- <pattern>%date [%thread] %msg%n%ex</pattern>
+ <pattern>%date [%thread] %maskedMsg%n%ex</pattern>
</encoder>
</appender>
</sift>
@@ -103,7 +105,7 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
- <pattern>%date [%thread] %msg%n%ex</pattern>
+ <pattern>%date [%thread] %maskedMsg%n%ex</pattern>
</encoder>
</appender>
</sift>
@@ -124,7 +126,7 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
- <pattern>%date [%thread] %msg%n%ex</pattern>
+ <pattern>%date [%thread] %maskedMsg%n%ex</pattern>
</encoder>
</appender>
</sift>
@@ -145,7 +147,7 @@
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
- <pattern>%date [%thread] %msg%n%ex</pattern>
+ <pattern>%date [%thread] %maskedMsg%n%ex</pattern>
</encoder>
</appender>
</sift>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java
new file mode 100644
index 0000000..382783a
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import org.killbill.billing.server.log.ServerTestSuiteNoDB;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestConfigMagicObfuscator extends ServerTestSuiteNoDB {
+
+ private final ConfigMagicObfuscator obfuscator = new ConfigMagicObfuscator();
+
+ @Test(groups = "fast")
+ public void testKey() throws Exception {
+ verify("Assigning value [pass2b78b7cef] for [org.killbill.billing.plugin.avatax.licenseKey] on [org.killbill.billing.plugins.avatax#getLicenseKey()]",
+ "Assigning value [***MASKED****] for [org.killbill.billing.plugin.avatax.licenseKey] on [org.killbill.billing.plugins.avatax#getLicenseKey()]");
+
+ verify("Assigning value [pass2b78b7cef] for [org.killbill.billing.plugin.avatax.apiKey] on [org.killbill.billing.plugins.avatax#getApiKey()]",
+ "Assigning value [***MASKED****] for [org.killbill.billing.plugin.avatax.apiKey] on [org.killbill.billing.plugins.avatax#getApiKey()]");
+ }
+
+ @Test(groups = "fast")
+ public void testPassword() throws Exception {
+ verify("Assigning value [pass2b78b7ce] for [org.killbill.dao.pass] on [org.killbill.commons.jdbi.guice.DaoConfig#getPass()]",
+ "Assigning value [***MASKED***] for [org.killbill.dao.pass] on [org.killbill.commons.jdbi.guice.DaoConfig#getPass()]");
+
+ verify("Assigning value [pass2b78b7ce] for [org.killbill.dao.password] on [org.killbill.commons.jdbi.guice.DaoConfig#getPassword()]",
+ "Assigning value [***MASKED***] for [org.killbill.dao.password] on [org.killbill.commons.jdbi.guice.DaoConfig#getPassword()]");
+ }
+
+ private void verify(final String input, final String output) {
+ final String obfuscated = obfuscator.obfuscate(input);
+ Assert.assertEquals(obfuscated, output, obfuscated);
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java
new file mode 100644
index 0000000..5795287
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import org.killbill.billing.server.log.ServerTestSuiteNoDB;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestLuhnMaskingObfuscator extends ServerTestSuiteNoDB {
+
+ private final LuhnMaskingObfuscator obfuscator = new LuhnMaskingObfuscator();
+
+ @Test(groups = "fast")
+ public void testStripSeparatorsSpaces() {
+ Assert.assertEquals(obfuscator.stripSeparators("5137 0049 8639 6403"), "5137004986396403");
+ }
+
+ @Test(groups = "fast")
+ public void testStripSeparatorsDashes() {
+ Assert.assertEquals(obfuscator.stripSeparators("5137-0049-8639-6403"), "5137004986396403");
+ }
+
+ @Test(groups = "fast")
+ public void testLuhnGood() {
+ Assert.assertTrue(obfuscator.luhnCheck("5137004986396403"));
+ }
+
+ @Test(groups = "fast")
+ public void testLuhnBad() {
+ Assert.assertFalse(obfuscator.luhnCheck("5137004986396404"));
+ }
+
+ @Test(groups = "fast")
+ public void testConvert() {
+ verify("try 5137 0049 8639 6404 and 5137 0049 8639 6403", "try 5137 0049 8639 6404 and ****MASKED*****6403");
+ }
+
+ @Test(groups = "fast")
+ public void testConvertCcNumberAtStartNonCcNumberAtEnd() {
+ verify("5137 0049 8639 6403 and 5137 0049 8639 6404", "****MASKED*****6403 and 5137 0049 8639 6404");
+ }
+
+ @Test(groups = "fast")
+ public void testConvertMultiple() {
+ verify("try 5137 0049 8639 6403 multiple 5137 0049 8639 6404 possible 4111-1111-1111 1111 card 4111111111111112 numbers", "try ****MASKED*****6403 multiple 5137 0049 8639 6404 possible ****MASKED*****1111 card 4111111111111112 numbers");
+ }
+
+ @Test(groups = "fast")
+ public void testLotsOfCcNumbers() {
+ verify("American Express"
+ + "378282246310005"
+ + "American Express"
+ + "371449635398431"
+ + "American Express Corporate"
+ + "378734493671000"
+ + "Australian BankCard"
+ + "5610591081018250"
+ + "Diners Club"
+ + "30569309025904"
+ + "Diners Club"
+ + "38520000023237"
+ + "Discover"
+ + "6011111111111117"
+ + "Discover"
+ + "6011000990139424"
+ + "JCB"
+ + "3530111333300000"
+ + "JCB"
+ + "3566002020360505"
+ + "MasterCard"
+ + "5555555555554444"
+ + "MasterCard"
+ + "5105105105105100"
+ + "Visa"
+ + "4111111111111111"
+ + "Visa"
+ + "4012888888881881"
+ + "Visa"
+ + "4222222222222"
+ + "Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number."
+ + "Processor-specific Cards"
+ + "Dankort (PBS)"
+ + "5019717010103742"
+ + "Switch/Solo (Paymentech)"
+ + "6331101999990016",
+ "American Express"
+ + "**MASKED***0005"
+ + "American Express"
+ + "**MASKED***8431"
+ + "American Express Corporate"
+ + "**MASKED***1000"
+ + "Australian BankCard"
+ + "***MASKED***8250"
+ + "Diners Club"
+ + "**MASKED**5904"
+ + "Diners Club"
+ + "**MASKED**3237"
+ + "Discover"
+ + "***MASKED***1117"
+ + "Discover"
+ + "***MASKED***9424"
+ + "JCB"
+ + "***MASKED***0000"
+ + "JCB"
+ + "***MASKED***0505"
+ + "MasterCard"
+ + "***MASKED***4444"
+ + "MasterCard"
+ + "***MASKED***5100"
+ + "Visa"
+ + "***MASKED***1111"
+ + "Visa"
+ + "***MASKED***1881"
+ + "Visa"
+ + "*MASKED**2222"
+ + "Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number."
+ + "Processor-specific Cards"
+ + "Dankort (PBS)"
+ + "***MASKED***3742"
+ + "Switch/Solo (Paymentech)"
+ + "***MASKED***0016");
+ }
+
+ @Test(groups = "fast")
+ public void testLotsOfNonCcNumbers() {
+ verify("American Express"
+ + "378282246310006"
+ + "American Express"
+ + "371449635398432"
+ + "American Express Corporate"
+ + "378734493671001"
+ + "Australian BankCard"
+ + "5610591081018251"
+ + "Diners Club"
+ + "30569309025905"
+ + "Diners Club"
+ + "38520000023238"
+ + "Discover"
+ + "6011111111111118"
+ + "Discover"
+ + "6011000990139425"
+ + "JCB"
+ + "3530111333300001"
+ + "JCB"
+ + "3566002020360506"
+ + "MasterCard"
+ + "5555555555554445"
+ + "MasterCard"
+ + "5105105105105102"
+ + "Visa"
+ + "4111111111111112"
+ + "Visa"
+ + "4012888888881882"
+ + "Visa"
+ + "4222222222223"
+ + "Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number."
+ + "Processor-specific Cards"
+ + "Dankort (PBS)"
+ + "5019717010103743"
+ + "Switch/Solo (Paymentech)"
+ + "6331101999990017",
+ "American Express"
+ + "378282246310006"
+ + "American Express"
+ + "371449635398432"
+ + "American Express Corporate"
+ + "378734493671001"
+ + "Australian BankCard"
+ + "5610591081018251"
+ + "Diners Club"
+ + "30569309025905"
+ + "Diners Club"
+ + "38520000023238"
+ + "Discover"
+ + "6011111111111118"
+ + "Discover"
+ + "6011000990139425"
+ + "JCB"
+ + "3530111333300001"
+ + "JCB"
+ + "3566002020360506"
+ + "MasterCard"
+ + "5555555555554445"
+ + "MasterCard"
+ + "5105105105105102"
+ + "Visa"
+ + "4111111111111112"
+ + "Visa"
+ + "4012888888881882"
+ + "Visa"
+ + "4222222222223"
+ + "Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number."
+ + "Processor-specific Cards"
+ + "Dankort (PBS)"
+ + "5019717010103743"
+ + "Switch/Solo (Paymentech)"
+ + "6331101999990017");
+ }
+
+ private void verify(final String input, final String output) {
+ final String obfuscated = obfuscator.obfuscate(input);
+ Assert.assertEquals(obfuscated, output, obfuscated);
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java
new file mode 100644
index 0000000..59bd626
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import java.util.regex.Pattern;
+
+import org.killbill.billing.server.log.ServerTestSuiteNoDB;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class TestObfuscator extends ServerTestSuiteNoDB {
+
+ private final Obfuscator obfuscator = new Obfuscator() {
+ @Override
+ public String obfuscate(final String originalString) {
+ return null;
+ }
+ };
+
+ @Test(groups = "fast")
+ public void testObfuscateWithOnePattern() throws Exception {
+ final Pattern pattern = Pattern.compile("number=([^;]+)");
+ final ImmutableList<Pattern> patterns = ImmutableList.<Pattern>of(pattern);
+ Assert.assertEquals(obfuscator.obfuscate("number=1234;number=12345;number=123456;number=1234567;number=12345678;number=123456789", patterns),
+ "number=MASKED;number=MASKED;number=MASKED;number=MASKED*;number=*MASKED*;number=*MASKED**");
+
+ }
+
+ @Test(groups = "fast")
+ public void testObfuscateWithMultiplePatterns() throws Exception {
+ final Pattern pattern1 = Pattern.compile("number=([^;]+)");
+ final Pattern pattern2 = Pattern.compile("numberB=([^;]+)");
+ final ImmutableList<Pattern> patterns = ImmutableList.<Pattern>of(pattern1, pattern2);
+ Assert.assertEquals(obfuscator.obfuscate("number=1234;numberB=12345;number=123456;numberB=1234567;number=12345678;numberB=123456789", patterns),
+ "number=MASKED;numberB=MASKED;number=MASKED;numberB=MASKED*;number=*MASKED*;numberB=*MASKED**");
+
+ }
+
+ @Test(groups = "fast")
+ public void testObfuscateConfidentialData() {
+ Assert.assertEquals(obfuscator.obfuscateConfidentialData("5137004986396403", "6403"), "***MASKED***");
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java
new file mode 100644
index 0000000..943a620
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import org.killbill.billing.server.log.ServerTestSuiteNoDB;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+public class TestObfuscatorConverter extends ServerTestSuiteNoDB {
+
+ private final ObfuscatorConverter converter = new ObfuscatorConverter();
+
+ @Test(groups = "fast")
+ public void testLogNonSensitiveData() throws Exception {
+ verify("Starting purchase call: \n" +
+ "<gateway>\n" +
+ "<card>tokenized</card>\n" +
+ "<bankAccountNumber></bankAccountNumber>\n" +
+ "<password></password>\n" +
+ "</gateway>",
+ "Starting purchase call: \n" +
+ "<gateway>\n" +
+ "<card>tokenized</card>\n" +
+ "<bankAccountNumber></bankAccountNumber>\n" +
+ "<password></password>\n" +
+ "</gateway>");
+ }
+
+ @Test(groups = "fast")
+ public void testLogSensitiveData() throws Exception {
+ verify("Starting purchase call: \n" +
+ "<gateway>\n" +
+ "<card>4111111111111111</card>\n" +
+ "<bankAccountNumber>482391823</bankAccountNumber>\n" +
+ "<password>supersecret</password>\n" +
+ "</gateway>",
+ "Starting purchase call: \n" +
+ "<gateway>\n" +
+ "<card>***MASKED***1111</card>\n" +
+ "<bankAccountNumber>*MASKED**</bankAccountNumber>\n" +
+ "<password>**MASKED***</password>\n" +
+ "</gateway>");
+ }
+
+ private void verify(final String input, final String output) {
+ final ILoggingEvent event = Mockito.mock(ILoggingEvent.class);
+ Mockito.when(event.getFormattedMessage()).thenReturn(input);
+
+ final String obfuscated = converter.convert(event);
+ Assert.assertEquals(obfuscated, output, obfuscated);
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java
new file mode 100644
index 0000000..6147466
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log.obfuscators;
+
+import org.killbill.billing.server.log.ServerTestSuiteNoDB;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestPatternObfuscator extends ServerTestSuiteNoDB {
+
+ private final PatternObfuscator obfuscator = new PatternObfuscator();
+
+ @Test(groups = "fast")
+ public void testAdyen() throws Exception {
+ verify("<ns:expiryMonth>04</expiryMonth>\n" +
+ "<ns:expiryYear>2015</expiryYear>\n" +
+ "<ns:holderName> test </holderName>\n" +
+ "<ns:number>5123456789012346</number>\n" +
+ "<ns2:shopperEmail>Bob@example.org</ns2:shopperEmail>\n" +
+ "<ns2:shopperIP>127.0.0.1</ns2:shopperIP>\n" +
+ "<ns2:shopperInteraction xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
+ "<ns2:shopperName>\n" +
+ " <firstName>Bob</firstName>\n" +
+ " <gender xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
+ " <infix xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
+ " <lastName>Smith</lastName>\n" +
+ "</ns2:shopperName>\n",
+ "<ns:expiryMonth>04</expiryMonth>\n" +
+ "<ns:expiryYear>2015</expiryYear>\n" +
+ "<ns:holderName>*MASKED*</holderName>\n" +
+ "<ns:number>*****MASKED*****</number>\n" +
+ "<ns2:shopperEmail>****MASKED*****</ns2:shopperEmail>\n" +
+ "<ns2:shopperIP>127.0.0.1</ns2:shopperIP>\n" +
+ "<ns2:shopperInteraction xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
+ "<ns2:shopperName>\n" +
+ " <firstName>MASKED</firstName>\n" +
+ " <gender xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
+ " <infix xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
+ " <lastName>MASKED</lastName>\n" +
+ "</ns2:shopperName>\n");
+ }
+
+ @Test(groups = "fast")
+ public void testCyberSource() throws Exception {
+ verify("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
+ " <s:Header>\n" +
+ " <wsse:Security s:mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n" +
+ " <wsse:UsernameToken>\n" +
+ " <wsse:Username/>\n" +
+ " <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\"/>\n" +
+ " </wsse:UsernameToken>\n" +
+ " </wsse:Security>\n" +
+ " </s:Header>\n" +
+ " <s:Body xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n" +
+ " <requestMessage xmlns=\"urn:schemas-cybersource-com:transaction-data-1.109\">\n" +
+ " <merchantID/>\n" +
+ " <merchantReferenceCode>e92a3bfd-0713-4396-a1e2-ff46cb051f8c</merchantReferenceCode>\n" +
+ " <clientLibrary>Ruby Active Merchant</clientLibrary>\n" +
+ " <clientLibraryVersion>1.47.0</clientLibraryVersion>\n" +
+ " <clientEnvironment>java</clientEnvironment>\n" +
+ "<billTo>\n" +
+ " <firstName>John</firstName>\n" +
+ " <lastName>Doe</lastName>\n" +
+ " <street1>5, oakriu road</street1>\n" +
+ " <street2>apt. 298</street2>\n" +
+ " <city>Gdio Foia</city>\n" +
+ " <state>FL</state>\n" +
+ " <postalCode>49302</postalCode>\n" +
+ " <country>US</country>\n" +
+ " <email>1428324461-test@tester.com</email>\n" +
+ "</billTo>\n" +
+ "<purchaseTotals>\n" +
+ " <currency>USD</currency>\n" +
+ " <grandTotalAmount>0.00</grandTotalAmount>\n" +
+ "</purchaseTotals>\n" +
+ "<card>\n" +
+ " <accountNumber>4242424242424242</accountNumber>\n" +
+ " <expirationMonth>12</expirationMonth>\n" +
+ " <expirationYear>2017</expirationYear>\n" +
+ " <cvNumber>1234</cvNumber>\n" +
+ " <cardType>001</cardType>\n" +
+ "</card>\n" +
+ "<subscription>\n" +
+ " <paymentMethod>credit card</paymentMethod>\n" +
+ "</subscription>\n" +
+ "<recurringSubscriptionInfo>\n" +
+ " <amount>0.00</amount>\n" +
+ " <frequency>on-demand</frequency>\n" +
+ " <approvalRequired>false</approvalRequired>\n" +
+ "</recurringSubscriptionInfo>\n" +
+ "<paySubscriptionCreateService run=\"true\"/>\n" +
+ "<businessRules>\n" +
+ "</businessRules>\n" +
+ " </requestMessage>\n" +
+ " </s:Body>\n" +
+ "</s:Envelope>",
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
+ " <s:Header>\n" +
+ " <wsse:Security s:mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n" +
+ " <wsse:UsernameToken>\n" +
+ " <wsse:Username/>\n" +
+ " <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\"/>\n" +
+ " </wsse:UsernameToken>\n" +
+ " </wsse:Security>\n" +
+ " </s:Header>\n" +
+ " <s:Body xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n" +
+ " <requestMessage xmlns=\"urn:schemas-cybersource-com:transaction-data-1.109\">\n" +
+ " <merchantID/>\n" +
+ " <merchantReferenceCode>e92a3bfd-0713-4396-a1e2-ff46cb051f8c</merchantReferenceCode>\n" +
+ " <clientLibrary>Ruby Active Merchant</clientLibrary>\n" +
+ " <clientLibraryVersion>1.47.0</clientLibraryVersion>\n" +
+ " <clientEnvironment>java</clientEnvironment>\n" +
+ "<billTo>\n" +
+ " <firstName>MASKED</firstName>\n" +
+ " <lastName>MASKED</lastName>\n" +
+ " <street1>5, oakriu road</street1>\n" +
+ " <street2>apt. 298</street2>\n" +
+ " <city>Gdio Foia</city>\n" +
+ " <state>FL</state>\n" +
+ " <postalCode>49302</postalCode>\n" +
+ " <country>US</country>\n" +
+ " <email>**********MASKED**********</email>\n" +
+ "</billTo>\n" +
+ "<purchaseTotals>\n" +
+ " <currency>USD</currency>\n" +
+ " <grandTotalAmount>0.00</grandTotalAmount>\n" +
+ "</purchaseTotals>\n" +
+ "<card>\n" +
+ " <accountNumber>*****MASKED*****</accountNumber>\n" +
+ " <expirationMonth>12</expirationMonth>\n" +
+ " <expirationYear>2017</expirationYear>\n" +
+ " <cvNumber>MASKED</cvNumber>\n" +
+ " <cardType>001</cardType>\n" +
+ "</card>\n" +
+ "<subscription>\n" +
+ " <paymentMethod>credit card</paymentMethod>\n" +
+ "</subscription>\n" +
+ "<recurringSubscriptionInfo>\n" +
+ " <amount>0.00</amount>\n" +
+ " <frequency>on-demand</frequency>\n" +
+ " <approvalRequired>false</approvalRequired>\n" +
+ "</recurringSubscriptionInfo>\n" +
+ "<paySubscriptionCreateService run=\"true\"/>\n" +
+ "<businessRules>\n" +
+ "</businessRules>\n" +
+ " </requestMessage>\n" +
+ " </s:Body>\n" +
+ "</s:Envelope>");
+ }
+
+ @Test(groups = "fast")
+ public void testLitle() throws Exception {
+ verify("<litleOnlineRequest merchantId=\\\"merchant_id\\\" version=\\\"8.18\\\" xmlns=\\\"http://www.litle.com/schema\\\"><authentication><user>login</user><password>password</password></authentication><sale id=\\\"615b9cb3-8580-4f57-bf69-9\\\" reportGroup=\\\"Default Report Group\\\"><orderId>615b9cb3-8580-4f57-bf69-9</orderId><amount>10000</amount><orderSource>ecommerce</orderSource><billToAddress><name>John Doe</name><email>1428325948-test@tester.com</email><addressLine1>5, oakriu road</addressLine1><addressLine2>apt. 298</addressLine2><city>Gdio Foia</city><state>FL</state><zip>49302</zip><country>US</country></billToAddress><shipToAddress/><card><type>VI</type><number>4242424242424242</number><expDate>1217</expDate><cardValidationNum>1234</cardValidationNum></card></sale></litleOnlineRequest>",
+ "<litleOnlineRequest merchantId=\\\"merchant_id\\\" version=\\\"8.18\\\" xmlns=\\\"http://www.litle.com/schema\\\"><authentication><user>login</user><password>*MASKED*</password></authentication><sale id=\\\"615b9cb3-8580-4f57-bf69-9\\\" reportGroup=\\\"Default Report Group\\\"><orderId>615b9cb3-8580-4f57-bf69-9</orderId><amount>10000</amount><orderSource>ecommerce</orderSource><billToAddress><name>*MASKED*</name><email>**********MASKED**********</email><addressLine1>5, oakriu road</addressLine1><addressLine2>apt. 298</addressLine2><city>Gdio Foia</city><state>FL</state><zip>49302</zip><country>US</country></billToAddress><shipToAddress/><card><type>VI</type><number>*****MASKED*****</number><expDate>1217</expDate><cardValidationNum>MASKED</cardValidationNum></card></sale></litleOnlineRequest>");
+ }
+
+ @Test(groups = "fast")
+ public void testJSON() throws Exception {
+ verify("{\n" +
+ " \"card\": {\n" +
+ " \"id\": \"card_483etw4er9fg4vF3sQdrt3FG\",\n" +
+ " \"object\": \"card\",\n" +
+ " \"banknumber\": 4111111111111111,\n" +
+ " \"last4\": \"0000\",\n" +
+ " \"brand\": \"Visa\",\n" +
+ " \"funding\": \"credit\",\n" +
+ " \"exp_month\": 6,\n" +
+ " \"exp_year\": 2019,\n" +
+ " \"fingerprint\": \"HOh74kZU387WlUvy\",\n" +
+ " \"country\": \"US\",\n" +
+ " \"name\": \"Bob Smith\",\n" +
+ " \"address_line1\": null,\n" +
+ " \"address_line2\": null,\n" +
+ " \"address_city\": null,\n" +
+ " \"address_state\": null,\n" +
+ " \"address_zip\": null,\n" +
+ " \"address_country\": null,\n" +
+ " \"dynamic_last4\": \"4242\",\n" +
+ " \"customer\": null,\n" +
+ " \"type\": \"Visa\"}\n" +
+ "}",
+ "{\n" +
+ " \"card\": {\n" +
+ " \"id\": \"card_483etw4er9fg4vF3sQdrt3FG\",\n" +
+ " \"object\": \"card\",\n" +
+ " \"banknumber\": *****MASKED*****,\n" +
+ " \"last4\": \"0000\",\n" +
+ " \"brand\": \"Visa\",\n" +
+ " \"funding\": \"credit\",\n" +
+ " \"exp_month\": 6,\n" +
+ " \"exp_year\": 2019,\n" +
+ " \"fingerprint\": \"HOh74kZU387WlUvy\",\n" +
+ " \"country\": \"US\",\n" +
+ " \"name\": **MASKED***,\n" +
+ " \"address_line1\": null,\n" +
+ " \"address_line2\": null,\n" +
+ " \"address_city\": null,\n" +
+ " \"address_state\": null,\n" +
+ " \"address_zip\": null,\n" +
+ " \"address_country\": null,\n" +
+ " \"dynamic_last4\": \"4242\",\n" +
+ " \"customer\": null,\n" +
+ " \"type\": \"Visa\"}\n" +
+ "}");
+
+ }
+
+ @Test(groups = "fast")
+ public void testPayU() throws Exception {
+ verify("<entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccvv</key>\n" +
+ " <value xsi:type=\"xsd:string\">1234</value>\n" +
+ "</entry>\n" +
+ "<entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccnum</key>\n" +
+ " <value xsi:type=\"xsd:string\">4111111111111111</value>\n" +
+ "</entry>\n" +
+ "<entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccexpmon</key>\n" +
+ " <value xsi:type=\"xsd:string\">12</value>\n" +
+ "</entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccexpyear</key>\n" +
+ " <value xsi:type=\"xsd:string\">2018</value>\n" +
+ "</entry>\n",
+ "<entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccvv</key>\n" +
+ " <value xsi:type=\"xsd:string\">MASKED</value>\n" +
+ "</entry>\n" +
+ "<entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccnum</key>\n" +
+ " <value xsi:type=\"xsd:string\">4111111111111111</value>\n" +
+ "</entry>\n" +
+ "<entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccexpmon</key>\n" +
+ " <value xsi:type=\"xsd:string\">12</value>\n" +
+ "</entry>\n" +
+ " <key xsi:type=\"xsd:string\">PayU.ccexpyear</key>\n" +
+ " <value xsi:type=\"xsd:string\">2018</value>\n" +
+ "</entry>\n"
+ );
+ }
+
+ private void verify(final String input, final String output) {
+ final String obfuscated = obfuscator.obfuscate(input);
+ Assert.assertEquals(obfuscated, output, obfuscated);
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java
new file mode 100644
index 0000000..f2328af
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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.killbill.billing.server.log;
+
+import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
+
+public abstract class ServerTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
+}