aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas <>2021-03-25 15:24:48 +0100
committerThomas <>2021-03-25 15:24:48 +0100
commit44a005e0e68e882a50d9bc061ca8daef4d84efa0 (patch)
treef411eb5e7133d2dea3c163f3733000788260f6d7
parent56bbd2ea411e050a300b89f47d8787968d244546 (diff)
downloadmoa-sig-44a005e0e68e882a50d9bc061ca8daef4d84efa0.tar.gz
moa-sig-44a005e0e68e882a50d9bc061ca8daef4d84efa0.tar.bz2
moa-sig-44a005e0e68e882a50d9bc061ca8daef4d84efa0.zip
add masking pattern to clear personal information from certificate logging
-rw-r--r--moaSig/moa-sig-lib/build.gradle6
-rw-r--r--moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/logging/IaikLog.java56
-rw-r--r--moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/IaikLoggerMaskingTest.java182
-rw-r--r--moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/MemoryLoggingAppender.java56
4 files changed, 295 insertions, 5 deletions
diff --git a/moaSig/moa-sig-lib/build.gradle b/moaSig/moa-sig-lib/build.gradle
index 9602ee1..4f13db2 100644
--- a/moaSig/moa-sig-lib/build.gradle
+++ b/moaSig/moa-sig-lib/build.gradle
@@ -13,7 +13,6 @@ dependencies {
api fileTree(dir: '../libs', include: '*.jar')
api group: 'at.gv.egovernment.moa.sig', name: 'tsl-lib', version: '2.0.4.1'
- api 'log4j:log4j:1.2.17'
api 'commons-logging:commons-logging:1.2'
api 'commons-io:commons-io:2.8.0'
api 'commons-codec:commons-codec:1.15'
@@ -30,6 +29,11 @@ dependencies {
api group: 'org.apache.pdfbox', name: 'preflight-app', version: '2.0.23'
api group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
api group: 'org.apache.httpcomponents', name: 'httpclient-cache', version: '4.5.13'
+
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-migrationsupport', version: '5.7.1'
+ testImplementation group: 'org.junit.platform', name: 'junit-platform-engine', version: '1.7.1'
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.1'
+ testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
}
task releases(type: Copy) {
diff --git a/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/logging/IaikLog.java b/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/logging/IaikLog.java
index f477588..e4a3921 100644
--- a/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/logging/IaikLog.java
+++ b/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/logging/IaikLog.java
@@ -23,6 +23,13 @@
package at.gv.egovernment.moa.spss.server.logging;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,6 +50,24 @@ public class IaikLog implements iaik.logging.Log {
/** The node ID to use. */
private String nodeId;
+ public static final String X509_INFO_CLEARING_PATTERN = "(?!serialNumber)(=)(.*?)(,|\"|$)";
+
+ private static Pattern multilinePattern;
+ private static List<String> maskPatterns = new ArrayList<>();
+
+ /**
+ * Add masking pattern into logger.
+ *
+ * @param maskPattern
+ */
+ public static void addMaskPattern(String maskPattern) {
+ maskPatterns.add(maskPattern);
+ multilinePattern = Pattern.compile(
+ maskPatterns.stream()
+ .collect(Collectors.joining("|")), Pattern.MULTILINE
+ );
+}
+
/**
* Create a new <code>IaikLog</code>.
*
@@ -83,7 +108,7 @@ public class IaikLog implements iaik.logging.Log {
*/
@Override
public void info(TransactionId transactionId, Object message, Throwable t) {
- final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, message);
+ final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, maskMessage(message));
log.info(msg.toString(), t);
}
@@ -101,7 +126,7 @@ public class IaikLog implements iaik.logging.Log {
*/
@Override
public void warn(TransactionId transactionId, Object message, Throwable t) {
- final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, message);
+ final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, maskMessage(message));
log.warn(msg.toString(), t);
}
@@ -119,7 +144,7 @@ public class IaikLog implements iaik.logging.Log {
*/
@Override
public void error(TransactionId transactionId, Object message, Throwable t) {
- final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, message);
+ final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, maskMessage(message));
log.error(msg.toString(), t);
}
@@ -137,7 +162,7 @@ public class IaikLog implements iaik.logging.Log {
*/
@Override
public void fatal(TransactionId transactionId, Object message, Throwable t) {
- final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, message);
+ final IaikLogMsg msg = new IaikLogMsg(transactionId, nodeId, maskMessage(message));
log.error(msg.toString(), t);
}
@@ -158,4 +183,27 @@ public class IaikLog implements iaik.logging.Log {
return nodeId;
}
+
+ private String maskMessage(Object message) {
+ String msg = message != null ? message.toString() : "<null>";
+
+ if (multilinePattern == null) {
+ return msg;
+
+ }
+
+ StringBuilder sb = new StringBuilder(msg);
+ Matcher matcher = multilinePattern.matcher(sb);
+ while (matcher.find()) {
+ IntStream.rangeClosed(1, matcher.groupCount()).forEach(
+ group -> {
+ if (matcher.group(group) != null) {
+ IntStream.range(matcher.start(group),
+ matcher.end(group)).forEach(i -> sb.setCharAt(i, '*')); // replace each character with asterisk
+ }
+ });
+ }
+ return sb.toString();
+}
+
}
diff --git a/moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/IaikLoggerMaskingTest.java b/moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/IaikLoggerMaskingTest.java
new file mode 100644
index 0000000..b3bf0e8
--- /dev/null
+++ b/moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/IaikLoggerMaskingTest.java
@@ -0,0 +1,182 @@
+package test.at.gv.egovernment.moa.spss.logger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egovernment.moa.spss.server.logging.IaikLog;
+import at.gv.egovernment.moa.spss.server.logging.TransactionId;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+
+@RunWith(BlockJUnit4ClassRunner.class)
+public class IaikLoggerMaskingTest {
+
+ private IaikLog log;
+ private TransactionId transId;
+
+ private MemoryLoggingAppender memoryAppender = null;
+
+ private static final String LOGMSG_1 =
+ "Signature OK from signer: serialNumber=882486130371,givenName=XXXĤáčęk,SN=XXXMûstérfřău,CN=XXXĤáčęk XXXMûstérfřău,C=AT";
+
+ private static final String LOGMSG_2 =
+ "storing cert \"serialNumber=882486130371,givenName=XXXĤáčęk,SN=XXXMûstérfřău,CN=XXXĤáčęk XXXMûstérfřău,C=AT\" to: /data/eID/springboot-authhandler/config/moa-spss/certstore/subjectdn/518D25DA7380CF1967B5014DDB74E862E5E52827/9E1D7A221A7D1A522A9E169FA6F9A2E81EEAB643";
+
+ @Before
+ public void initialize() {
+ log = new IaikLog(RandomStringUtils.randomAlphabetic(5));
+ transId = new TransactionId(RandomStringUtils.randomAlphanumeric(5));
+
+ // setup log appender
+ if (memoryAppender == null) {
+ final Logger logger = (Logger) LoggerFactory.getLogger("iaik.server");
+ memoryAppender = new MemoryLoggingAppender();
+ memoryAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
+ logger.setLevel(Level.DEBUG);
+ logger.addAppender(memoryAppender);
+ memoryAppender.start();
+
+ } else {
+ memoryAppender.reset();
+
+ }
+
+ }
+
+ @Test
+ public void certificateMaskingInfoLevelMorePatterns() {
+ // patterns
+ IaikLog.addMaskPattern("(C=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(CN=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(SN=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(serialNumber=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(givenName=)(.*?)(,|$)");
+
+ //test
+ log.info(transId, LOGMSG_1, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+ @Test
+ public void certificateMaskingInfoLevelOnePattern() {
+ // Patterns
+ IaikLog.addMaskPattern(IaikLog.X509_INFO_CLEARING_PATTERN);
+
+ //test
+ log.info(transId, LOGMSG_1, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+ @Test
+ public void certificateMaskingSecondMessage() {
+ // Patterns
+ IaikLog.addMaskPattern(IaikLog.X509_INFO_CLEARING_PATTERN);
+
+ //test
+ log.info(transId, LOGMSG_2, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+ @Test
+ public void certificateMaskingWarnLevelMorePatterns() {
+ // patterns
+ IaikLog.addMaskPattern("(C=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(CN=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(SN=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(serialNumber=)(.*?)(,|$)");
+ IaikLog.addMaskPattern("(givenName=)(.*?)(,|$)");
+
+ //test
+ log.warn(transId, LOGMSG_1, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+ @Test
+ public void certificateMaskingWarnLevelOnePattern() {
+ // Patterns
+ IaikLog.addMaskPattern(IaikLog.X509_INFO_CLEARING_PATTERN);
+
+ //test
+ log.warn(transId, LOGMSG_1, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+
+ @Test
+ public void certificateMaskingErrorLevelOnePattern() {
+ // Patterns
+ IaikLog.addMaskPattern(IaikLog.X509_INFO_CLEARING_PATTERN);
+
+ //test
+ log.error(transId, LOGMSG_1, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+ @Test
+ public void certificateMaskingFatalLevelOnePattern() {
+ // Patterns
+ IaikLog.addMaskPattern(IaikLog.X509_INFO_CLEARING_PATTERN);
+
+ //test
+ log.fatal(transId, LOGMSG_1, null);
+
+ //verify log
+ verifyLogMessge(Arrays.asList("882486130371", "ûsté", "XĤáčę", "AT"));
+
+ }
+
+ @Test
+ public void randomMessage() {
+ // Patterns
+ IaikLog.addMaskPattern(IaikLog.X509_INFO_CLEARING_PATTERN);
+ String msg = RandomStringUtils.randomAlphanumeric(25);
+
+ //test
+ log.info(transId, msg, null);
+
+ //verify log
+ Arrays.asList(msg)
+ .stream().forEach(
+ el -> assertTrue("find wrong element", memoryAppender.getLoggedEvents().get(0).getMessage().contains(el)));
+
+ }
+
+
+ private void verifyLogMessge(List<String> checks) {
+ assertEquals("no log", 1, memoryAppender.getSize());
+ checks.stream().forEach(
+ el -> assertFalse("find wrong element", memoryAppender.getLoggedEvents().get(0).getMessage().contains(el)));
+
+ }
+
+}
diff --git a/moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/MemoryLoggingAppender.java b/moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/MemoryLoggingAppender.java
new file mode 100644
index 0000000..e1c6fce
--- /dev/null
+++ b/moaSig/moa-sig-lib/src/test/java/test/at/gv/egovernment/moa/spss/logger/MemoryLoggingAppender.java
@@ -0,0 +1,56 @@
+package test.at.gv.egovernment.moa.spss.logger;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+/**
+ * In-Memory Logging-Appender to check log messages.
+ *
+ * @author tlenz
+ *
+ */
+public class MemoryLoggingAppender extends ListAppender<ILoggingEvent> {
+
+ public void reset() {
+ this.list.clear();
+ }
+
+ public boolean contains(String string, Level level) {
+ return this.list.stream()
+ .anyMatch(event -> event.getMessage().toString().contains(string)
+ && event.getLevel().equals(level));
+ }
+
+ public int countEventsForLogger(String loggerName) {
+ return (int) this.list.stream()
+ .filter(event -> event.getLoggerName().contains(loggerName))
+ .count();
+ }
+
+ public List<ILoggingEvent> search(String string) {
+ return this.list.stream()
+ .filter(event -> event.getMessage().toString().contains(string))
+ .collect(Collectors.toList());
+ }
+
+ public List<ILoggingEvent> search(String string, Level level) {
+ return this.list.stream()
+ .filter(event -> event.getMessage().toString().contains(string)
+ && event.getLevel().equals(level))
+ .collect(Collectors.toList());
+ }
+
+ public int getSize() {
+ return this.list.size();
+ }
+
+ public List<ILoggingEvent> getLoggedEvents() {
+ return Collections.unmodifiableList(this.list);
+ }
+
+}