{
16 |
17 | Marker markerToMatch;
18 |
19 | @Override
20 | public void start() {
21 | if (markerToMatch != null) {
22 | super.start();
23 | } else {
24 | addError(String.format("The marker property must be set for [%s]",
25 | getName()));
26 | }
27 | }
28 |
29 | public FilterReply decide(ILoggingEvent event) {
30 | Marker marker = event.getMarker();
31 | if (!isStarted()) {
32 | return FilterReply.NEUTRAL;
33 | }
34 |
35 | if (marker == null) {
36 | return onMismatch;
37 | }
38 |
39 | if (markerToMatch.contains(marker)) {
40 | return onMatch;
41 | }
42 | return onMismatch;
43 | }
44 |
45 | public void setMarker(String markerStr) {
46 | if (markerStr != null) {
47 | markerToMatch = MarkerFactory.getMarker(markerStr);
48 | }
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/filter/SecurityMarkerFilter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.filter;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import org.owasp.security.logging.SecurityMarkers;
7 | import org.slf4j.Marker;
8 |
9 | import ch.qos.logback.classic.spi.ILoggingEvent;
10 | import ch.qos.logback.core.filter.AbstractMatcherFilter;
11 | import ch.qos.logback.core.spi.FilterReply;
12 |
13 | /**
14 | * Filters logging for SECURITY markers. If a logging event has a SECURITY
15 | * marker attached to it, it will pass the filter. This is useful to route
16 | * security related events to a separate log file.
17 | *
18 | * The default behavior of this filter is to deny all non-security events and
19 | * pass security events to the rest of the filter chain. If acceptAll is true,
20 | * then all security related events will pass this filter, regardless of other
21 | * filters on the filter chain. To enable acceptAll, configure the filter as
22 | * follows:
23 | *
24 | *
25 | * {@code
26 | *
27 | * true
28 | *
29 | * }
30 | *
31 | *
32 | * @author August Detlefsen [augustd@codemagi.com]
33 | */
34 | public class SecurityMarkerFilter extends AbstractMatcherFilter {
35 |
36 | public static final List markersToMatch = new ArrayList(3);
37 | static {
38 | markersToMatch.add(SecurityMarkers.SECURITY_SUCCESS);
39 | markersToMatch.add(SecurityMarkers.SECURITY_FAILURE);
40 | markersToMatch.add(SecurityMarkers.SECURITY_AUDIT);
41 | }
42 |
43 | private boolean acceptAll = false;
44 |
45 | public FilterReply decide(ILoggingEvent event) {
46 | if (!isStarted()) {
47 | return FilterReply.NEUTRAL;
48 | }
49 |
50 | // make sure the event has a marker
51 | Marker eventMarker = event.getMarker();
52 |
53 | if (eventMarker == null) {
54 | return FilterReply.DENY;
55 | }
56 |
57 | if (eventMarker.hasReferences()) {
58 | // check for events with multiple markers
59 | for (Marker marker : markersToMatch) {
60 | if (eventMarker.contains(marker)) {
61 | return acceptAll ? FilterReply.ACCEPT : FilterReply.NEUTRAL;
62 | }
63 | }
64 | } else {
65 | // handle simple case of an event with a single marker
66 | if (markersToMatch.contains(eventMarker)) {
67 | return acceptAll ? FilterReply.ACCEPT : FilterReply.NEUTRAL;
68 | }
69 | }
70 |
71 | // no match found for security markers
72 | return FilterReply.DENY;
73 | }
74 |
75 | public void setAcceptAll(String input) {
76 | if (input != null) {
77 | acceptAll = Boolean.valueOf(input);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/SecurityLoggingLayout.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout;
2 |
3 | import org.owasp.security.logging.mdc.MDCFilter;
4 | import org.slf4j.MDC;
5 |
6 | import ch.qos.logback.classic.spi.ILoggingEvent;
7 | import ch.qos.logback.core.LayoutBase;
8 |
9 | /**
10 | *
11 | * Layout for security related logging
12 | *
13 | */
14 | public class SecurityLoggingLayout extends LayoutBase {
15 |
16 | private static final String LINE_SEP = System.getProperty("line.separator");
17 | private String prefix = "Security";
18 |
19 | public String doLayout(ILoggingEvent event) {
20 | StringBuilder sbuf = new StringBuilder(128);
21 | if (prefix != null) {
22 | sbuf.append(prefix).append(": ");
23 | }
24 | sbuf.append(event.getTimeStamp()
25 | - event.getLoggerContextVO().getBirthTime());
26 | sbuf.append(' ');
27 | sbuf.append(event.getLevel());
28 | sbuf.append(' ');
29 | sbuf.append(event.getMarker());
30 | sbuf.append(' ');
31 | sbuf.append(event.getLoggerName());
32 | sbuf.append(" - ");
33 | sbuf.append(MDC.get(MDCFilter.LOGIN_ID));
34 | sbuf.append('@');
35 | sbuf.append(MDC.get(MDCFilter.IPADDRESS));
36 | sbuf.append(' ');
37 | sbuf.append(event.getFormattedMessage());
38 | sbuf.append(LINE_SEP);
39 | return sbuf.toString();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/cef/CEFLoggingLayout.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.cef;
2 |
3 | import ch.qos.logback.classic.spi.ILoggingEvent;
4 | import ch.qos.logback.core.LayoutBase;
5 |
6 | public class CEFLoggingLayout extends LayoutBase {
7 |
8 | public String doLayout(ILoggingEvent event) {
9 | Prefix prefix = new Prefix();
10 | prefix.name = event.getMessage();
11 | return prefix.toString();
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/cef/Prefix.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.cef;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Set;
6 |
7 | /**
8 | * prefix of the CEF logging format example :
9 | *
10 | * Sep 19 08:26:10 host CEF:0|security|threatmanager|1.0|100|worm successfully
11 | * stopped|10|src=10.0.0.1 dst=2.1.2.2 spt=1232
12 | *
13 | * @author sytze
14 | *
15 | */
16 | public class Prefix {
17 |
18 | private final static String CEF_PREFIX = "CEF:";
19 |
20 | /**
21 | * version of the CEF format
22 | */
23 | int version;
24 |
25 | /**
26 | * device that sends the logging events
27 | */
28 | Device device = new Device();
29 |
30 | /**
31 | * represents the type of event, for instance for intrusion detection
32 | */
33 | String signatureId = "signatureId";
34 |
35 | /**
36 | * human-readable description of the event
37 | */
38 | String name = "name";
39 |
40 | /**
41 | * severity/importance of the event, range 0 - 10. 10 is the most important
42 | */
43 | int severity;
44 |
45 | /**
46 | * key/value pairs with extra
47 | */
48 | Map extension = new ExtensionMap();
49 |
50 | class Device {
51 | String vendor = "vendor", product = "product", version = "version";
52 |
53 | public String toString() {
54 | return vendor + "|" + product + "|" + version;
55 | }
56 | }
57 |
58 | public String toString() {
59 | return CEF_PREFIX + version + "|" + device + "|" + signatureId + "|"
60 | + name + "|" + severity + "|" + extension;
61 | }
62 |
63 | class ExtensionMap extends HashMap {
64 |
65 | /**
66 | *
67 | */
68 | private static final long serialVersionUID = 1499695924597182375L;
69 |
70 | public ExtensionMap() {
71 | put("extension", "value");
72 | }
73 |
74 | /**
75 | * TODO : encoding, multi-line
76 | */
77 | public String toString() {
78 | Set keys = this.keySet();
79 | StringBuilder builder = new StringBuilder();
80 | for (Object key : keys) {
81 | builder.append(key);
82 | builder.append('=');
83 | builder.append(get(key));
84 | builder.append(' ');
85 | }
86 | return builder.toString();
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/cef/SyslogHeader.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.cef;
2 |
3 | public class SyslogHeader {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/rich/RichContext.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.rich;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.UnsupportedEncodingException;
6 | import java.net.InetAddress;
7 | import java.net.NetworkInterface;
8 | import java.net.UnknownHostException;
9 | import java.security.InvalidKeyException;
10 | import java.security.NoSuchAlgorithmException;
11 | import java.util.Enumeration;
12 | import java.util.jar.Attributes;
13 | import java.util.jar.Manifest;
14 |
15 | import javax.crypto.Mac;
16 | import javax.crypto.SecretKey;
17 | import javax.crypto.spec.SecretKeySpec;
18 |
19 | import org.apache.commons.codec.binary.Hex;
20 |
21 | import ch.qos.logback.classic.spi.LoggingEvent;
22 |
23 | public class RichContext {
24 |
25 | private long pid;
26 | private long clientTime;
27 | private String applicationName;
28 | private String inetAddress;
29 |
30 | public RichContext(LoggingEvent event) {
31 | pid = getPID();
32 | clientTime = event.getTimeStamp();
33 | applicationName = getApplicationName();
34 | inetAddress = getLocalHostLANAddress();
35 | }
36 |
37 | public static long getPID() {
38 | String processName = java.lang.management.ManagementFactory
39 | .getRuntimeMXBean().getName();
40 | return Long.parseLong(processName.split("@")[0]);
41 | }
42 |
43 | public String getApplicationName() {
44 |
45 | try (InputStream manifestStream = Thread.currentThread()
46 | .getContextClassLoader()
47 | .getResourceAsStream("META-INF/MANIFEST.MF")) {
48 | Manifest manifest = new Manifest(manifestStream);
49 | Attributes attrs = manifest.getMainAttributes();
50 |
51 | // does this work for all java applications ?
52 | String appName = attrs.getValue("Implementation-Title");
53 | if (appName == null) {
54 | appName = "UNKNOWN";
55 | }
56 | return appName;
57 | } catch (IOException E) {
58 | // handle
59 | }
60 | return null;
61 | }
62 |
63 | public static String getHMAC(String msg) {
64 | String macKey = System.getProperty("hmac.key", "HMAC KEY");
65 |
66 | Mac mac;
67 | char[] checksum = "".toCharArray();
68 | try {
69 | mac = Mac.getInstance("HmacSHA256");
70 | // get the bytes of the hmac key and data string
71 | byte[] secretByte = macKey.getBytes("UTF-8");
72 | byte[] dataBytes = msg.getBytes("UTF-8");
73 | SecretKey secret = new SecretKeySpec(secretByte, "HMACSHA256");
74 |
75 | mac.init(secret);
76 | byte[] doFinal = mac.doFinal(dataBytes);
77 | checksum = Hex.encodeHex(doFinal);
78 | } catch (NoSuchAlgorithmException e) {
79 | // TODO Auto-generated catch block
80 | e.printStackTrace();
81 | } catch (InvalidKeyException e) {
82 | // TODO Auto-generated catch block
83 | e.printStackTrace();
84 | } catch (UnsupportedEncodingException e) {
85 | // TODO Auto-generated catch block
86 | e.printStackTrace();
87 | }
88 | return String.copyValueOf(checksum);
89 |
90 | }
91 |
92 | private static String getLocalHostLANAddress() {
93 | try {
94 | InetAddress candidateAddress = null;
95 | // Iterate all NICs (network interface cards)...
96 | for (Enumeration ifaces = NetworkInterface
97 | .getNetworkInterfaces(); ifaces.hasMoreElements();) {
98 | NetworkInterface iface = (NetworkInterface) ifaces
99 | .nextElement();
100 | // Iterate all IP addresses assigned to each card...
101 | for (Enumeration inetAddrs = iface
102 | .getInetAddresses(); inetAddrs.hasMoreElements();) {
103 | InetAddress inetAddr = (InetAddress) inetAddrs
104 | .nextElement();
105 | if (!inetAddr.isLoopbackAddress()) {
106 |
107 | if (inetAddr.isSiteLocalAddress()) {
108 | return inetAddr.toString();
109 | } else if (candidateAddress == null) {
110 | candidateAddress = inetAddr;
111 | }
112 | }
113 | }
114 | }
115 | if (candidateAddress != null) {
116 | return candidateAddress.toString();
117 | }
118 | InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
119 | if (jdkSuppliedAddress == null) {
120 | throw new UnknownHostException(
121 | "The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
122 | }
123 | return jdkSuppliedAddress.toString();
124 | } catch (Exception e) {
125 | return "";
126 | }
127 | }
128 |
129 | @Override
130 | public String toString() {
131 | String message = "[pid=" + pid + ", applicationName=" + applicationName
132 | + ", clientTime=" + clientTime + ", clientIp=" + inetAddress
133 | + "]";
134 | String signedMessage = message + getHMAC(message);
135 | return signedMessage;
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/rich/RichMDCFilter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.rich;
2 |
3 | import ch.qos.logback.classic.helpers.MDCInsertingServletFilter;
4 | import jakarta.servlet.ServletRequest;
5 |
6 | public class RichMDCFilter extends MDCInsertingServletFilter {
7 |
8 | // TODO : implement
9 | void insertIntoMDC(ServletRequest request) {
10 | // super.insertIntoMDC(request);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/layout/rich/RichSecurityLoggingLayout.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.rich;
2 |
3 | import ch.qos.logback.classic.spi.LoggingEvent;
4 | import ch.qos.logback.core.LayoutBase;
5 |
6 | public class RichSecurityLoggingLayout extends LayoutBase {
7 |
8 | public String doLayout(LoggingEvent event) {
9 | RichContext rctx = new RichContext(event);
10 | return rctx.toString();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/CRLFConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.spi.ILoggingEvent;
4 | import ch.qos.logback.core.pattern.CompositeConverter;
5 | import org.owasp.security.logging.Utils;
6 |
7 | /**
8 | * This converter is used to encode any carriage returns and line feeds to
9 | * prevent log injection attacks
10 | *
11 | * It is not possible to replace the actual formatted message, instead this
12 | * converter returns a masked version of the message that can be accessed using
13 | * the conversionWord specified in the conversionRule definition in logback.xml.
14 | *
15 | * @author August Detlefsen [augustd@codemagi.com]
16 | */
17 | public class CRLFConverter extends CompositeConverter {
18 |
19 | @Override
20 | protected String transform(ILoggingEvent event, String in) {
21 | return Utils.replaceCRLFWithUnderscore(in);
22 | }
23 |
24 | /**
25 | * Override start method because the superclass ReplacingCompositeConverter
26 | * requires at least two options and this class has none.
27 | */
28 | @Override
29 | public void start() {
30 | started = true;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/CRLFThrowableConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
4 | import ch.qos.logback.classic.spi.IThrowableProxy;
5 |
6 | /**
7 | * This converter is used to encode any carriage returns and line feeds to
8 | * prevent log injection attacks in exception messages
9 | *
10 | * This converter uses a CRLFThrowableProxy that acts as a proxy to intercept
11 | * calls to IThrowable.getMessage to replace the characters in the message
12 | */
13 | public class CRLFThrowableConverter extends ThrowableProxyConverter {
14 |
15 | @Override
16 | protected String throwableProxyToString(IThrowableProxy tp) {
17 | return super.throwableProxyToString(new CRLFThrowableProxy(tp));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/CRLFThrowableProxy.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.spi.IThrowableProxy;
4 | import ch.qos.logback.classic.spi.StackTraceElementProxy;
5 | import org.owasp.security.logging.Utils;
6 |
7 | /**
8 | * Throwable proxy that replaces CR/LF chars in the message to avoid log injection
9 | * in exception messages.
10 | * Calls to getMessage are intercepted to replace CR and LF in the message
11 | * Calls to getCause are intercepted to ensure all exceptions in the stack are treated
12 | * All other other methods are directly sent through the proxied instance.
13 | */
14 | public class CRLFThrowableProxy implements IThrowableProxy {
15 | private final IThrowableProxy proxied;
16 |
17 | public CRLFThrowableProxy(IThrowableProxy proxied) {
18 | this.proxied = proxied;
19 | }
20 |
21 | @Override
22 | public String getMessage() {
23 | if (proxied.getMessage() == null) {
24 | return null;
25 | }
26 | return Utils.replaceCRLFWithUnderscore(proxied.getMessage());
27 | }
28 |
29 | @Override
30 | public IThrowableProxy getCause() {
31 | if (proxied.getCause() == null) {
32 | return null;
33 | }
34 | if (proxied.getCause() == proxied || proxied.getCause() == this) {
35 | return this;
36 | }
37 | return new CRLFThrowableProxy(proxied.getCause());
38 | }
39 |
40 | @Override
41 | public String getClassName() {
42 | return proxied.getClassName();
43 | }
44 |
45 | @Override
46 | public StackTraceElementProxy[] getStackTraceElementProxyArray() {
47 | return proxied.getStackTraceElementProxyArray();
48 | }
49 |
50 | @Override
51 | public int getCommonFrames() {
52 | return proxied.getCommonFrames();
53 | }
54 |
55 | @Override
56 | public IThrowableProxy[] getSuppressed() {
57 | return proxied.getSuppressed();
58 | }
59 |
60 | @Override
61 | public boolean isCyclic() {
62 | return proxied.isCyclic();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/DefinedRegexMaskingConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import java.util.HashMap;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.Set;
7 | import java.util.regex.Pattern;
8 |
9 | import ch.qos.logback.classic.pattern.ClassicConverter;
10 | import ch.qos.logback.classic.spi.ILoggingEvent;
11 | /**
12 | * Masking configured values in logs. To configure in you logback file here is an example:
13 | * Step 1 add conversion word:
14 | *
15 | * <conversionRule conversionWord="maskedMsg" converterClass="org.owasp.security.logging.mask.DefinedRegexMaskingConverter" />
16 | *
17 | * Step 2 add to the pattern like this. There 4 pre-defined values for CompleteMask, MaskLastFour, MaskFirstFour, emailMasking
18 | *
19 | * %maskedMsg{password|signature
20 | * username,
21 | * orderNumber|giftCardNum|,
22 | * email
23 | * }
24 | *
25 | * @author Rahul Agarwal
26 | *
27 | */
28 | public class DefinedRegexMaskingConverter extends ClassicConverter {
29 | private Map patternMap = new HashMap<>();
30 | private static final String MASK = "*****";
31 |
32 | @Override
33 | public String convert(ILoggingEvent logEvent) {
34 | String message = logEvent.getMessage();
35 | Set patternSet = patternMap.keySet();
36 |
37 | if (message!=null && !message.equals("")) {
38 | for (Pattern pattern : patternSet) {
39 | message = pattern.matcher(message).replaceAll(patternMap.get(pattern));
40 | }
41 | }
42 |
43 | return message;
44 | }
45 |
46 | @Override
47 | public void start() {
48 | List options = getOptionList();
49 | if (options != null && !options.isEmpty()) {
50 | // 0 = CompleteMask
51 | patternMap.put(Pattern.compile("(?x)([\"]?(" + options.get(0) + ")[\"]?\\s*[:=]{1}\\s*[\"]?)(?:[^\"\\n]+)"), "$1" + MASK);
52 |
53 | // 1 = MaskLastFour
54 | patternMap.put(Pattern.compile("(?x)([\"]?(" + options.get(1) + ")[\"]?[:=]{1}[\"]?[\\w.+/=]+)(?:[\\w.+/=]{4})"), "$1" + MASK);
55 |
56 | // 2 = MaskFirstFour
57 | patternMap.put(Pattern.compile("(?x)([\"]?(" + options.get(2) + ")[\"]?[:=]{1}[\"]?)(?:[\\w.+/=]+(?=\\w{4}))"), "$1" + MASK);
58 |
59 | // 3 = emailMasking
60 | patternMap.put(Pattern.compile("(?x)([\"]?(" + options.get(3) + ")[\"]?\\s*[:=]{1}\\s*[\"]?[\\w.]+(?=@[\\w.]+))(?:@[\\w.]+)"), "$1" + MASK);
61 | }
62 | super.start();
63 | }
64 | }
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/LUHNMaskingConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.pattern.ClassicConverter;
4 | import ch.qos.logback.classic.spi.ILoggingEvent;
5 |
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | public class LUHNMaskingConverter extends ClassicConverter {
10 |
11 | private static final String CREDIT_CARD_PATTERN = "s*\\d{1,5}\\s*(?:-*\\s*,*\\d{1,5}\\s*){1,4}";
12 | private static final Pattern pattern = Pattern.compile(CREDIT_CARD_PATTERN);
13 |
14 | @Override
15 | public String convert(ILoggingEvent iLoggingEvent) {
16 | return mask(iLoggingEvent.getFormattedMessage());
17 | }
18 |
19 | private String mask(String formattedMessage) {
20 | Matcher matcher = pattern.matcher(formattedMessage);
21 | while (matcher.find()) {
22 | String found = matcher.group();
23 | String cardNumber = removeSpecials(found);
24 | if (luhnCheck(cardNumber)) {
25 | int length = cardNumber.length();
26 | StringBuilder builder = new StringBuilder();
27 | builder.append(cardNumber.substring(0, 4));
28 | builder.append("**MASKED**");
29 | builder.append(cardNumber.substring(length-4,length));
30 | formattedMessage = formattedMessage.replaceAll(found, builder.toString());
31 | }
32 | }
33 | return formattedMessage;
34 | }
35 |
36 | private String removeSpecials(String cardNumber) {
37 | cardNumber = cardNumber.replaceAll("[^\\d ]", "").replaceAll("\\s", "");
38 | return cardNumber;
39 | }
40 |
41 | private boolean luhnCheck(String cardNumber) {
42 | int sum = 0;
43 | boolean doubled = false;
44 | for (int i = cardNumber.length() - 1; i >= 0; --i) {
45 | int digit = Integer.parseInt(cardNumber.substring(i, i + 1));
46 | int addend;
47 | if (doubled) {
48 | addend = digit * 2;
49 | if (addend > 9) {
50 | addend -= 9;
51 | }
52 | } else {
53 | addend = digit;
54 | }
55 | sum += addend;
56 | doubled = !doubled;
57 | }
58 | return sum % 10 == 0;
59 | }
60 | }
61 | ;
62 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/MaskingConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import org.owasp.security.logging.SecurityMarkers;
4 |
5 | import ch.qos.logback.classic.spi.ILoggingEvent;
6 | import ch.qos.logback.core.pattern.ReplacingCompositeConverter;
7 |
8 | import org.slf4j.Marker;
9 | import org.slf4j.helpers.MessageFormatter;
10 |
11 | /**
12 | * This converter is used to output a masked version of the formatted message in
13 | * contexts where the logging of confidential information is undesirable.
14 | *
15 | * It is not possible to replace the actual formatted message, instead this
16 | * converter returns a masked version of the message that can be accessed using
17 | * the conversionWord specified in the conversionRule definition in logback.xml.
18 | *
19 | * @author August Detlefsen [augustd@codemagi.com]
20 | * @author Sytze van Koningsveld
21 | */
22 | public class MaskingConverter extends
23 | ReplacingCompositeConverter {
24 |
25 | public static final String MASKED_PASSWORD = "********";
26 |
27 | @Override
28 | public String convert(ILoggingEvent event) {
29 | Marker eventMarker = event.getMarker();
30 |
31 | Object[] args = event.getArgumentArray();
32 | if (eventMarker != null
33 | && eventMarker.contains(SecurityMarkers.CONFIDENTIAL)) {
34 | for (int i = 0; i < args.length; i++) {
35 | args[i] = MASKED_PASSWORD;
36 | }
37 | }
38 |
39 | String maskedMessage = MessageFormatter.arrayFormat(event.getMessage(),
40 | args).getMessage();
41 |
42 | return maskedMessage;
43 | }
44 |
45 | /**
46 | * Override start method because the superclass ReplacingCompositeConverter
47 | * requires at least two options and this class has none.
48 | */
49 | @Override
50 | public void start() {
51 | started = true;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/NLFConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.spi.ILoggingEvent;
4 | import ch.qos.logback.core.pattern.CompositeConverter;
5 | import org.owasp.security.logging.Utils;
6 |
7 | /**
8 | * This converter is used to encode any carriage returns, line feeds and backspaces to
9 | * prevent log injection attacks
10 | *
11 | * It is not possible to replace the actual formatted message, instead this
12 | * converter returns a masked version of the message that can be accessed using
13 | * the conversionWord specified in the conversionRule definition in logback.xml.
14 | *
15 | */
16 | public class NLFConverter extends CompositeConverter {
17 |
18 | @Override
19 | protected String transform(ILoggingEvent event, String in) {
20 | return Utils.escapeNLFChars(in);
21 | }
22 |
23 | /**
24 | * Override start method because the superclass ReplacingCompositeConverter
25 | * requires at least two options and this class has none.
26 | */
27 | @Override
28 | public void start() {
29 | started = true;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/NLFThrowableConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
4 | import ch.qos.logback.classic.spi.IThrowableProxy;
5 |
6 | /**
7 | * This converter is used to encode any carriage returns and line feeds to
8 | * prevent log injection attacks in exception messages
9 | *
10 | * This converter uses a NLFThrowableProxy that acts as a proxy to intercept
11 | * calls to IThrowable.getMessage to replace the characters in the message
12 | */
13 | public class NLFThrowableConverter extends ThrowableProxyConverter {
14 |
15 | @Override
16 | protected String throwableProxyToString(IThrowableProxy tp) {
17 | return super.throwableProxyToString(new NLFThrowableProxy(tp));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/NLFThrowableProxy.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.spi.IThrowableProxy;
4 | import ch.qos.logback.classic.spi.StackTraceElementProxy;
5 | import org.owasp.security.logging.Utils;
6 |
7 | /**
8 | * Throwable proxy that replaces NLF (newline function) chars in the message to avoid log injection
9 | * in exception messages.
10 | * Calls to getMessage are intercepted to replace NLF in the message
11 | * Calls to getCause are intercepted to ensure all exceptions in the stack are treated
12 | * All other other methods are directly sent through the proxied instance.
13 | */
14 | public class NLFThrowableProxy implements IThrowableProxy {
15 | private final IThrowableProxy proxied;
16 |
17 | public NLFThrowableProxy(IThrowableProxy proxied) {
18 | this.proxied = proxied;
19 | }
20 |
21 | @Override
22 | public String getMessage() {
23 | if (proxied.getMessage() == null) {
24 | return null;
25 | }
26 | return Utils.replaceCRLFWithUnderscore(proxied.getMessage());
27 | }
28 |
29 | @Override
30 | public IThrowableProxy getCause() {
31 | if (proxied.getCause() == null) {
32 | return null;
33 | }
34 | if (proxied.getCause() == proxied || proxied.getCause() == this) {
35 | return this;
36 | }
37 | return new NLFThrowableProxy(proxied.getCause());
38 | }
39 |
40 | @Override
41 | public String getClassName() {
42 | return proxied.getClassName();
43 | }
44 |
45 | @Override
46 | public StackTraceElementProxy[] getStackTraceElementProxyArray() {
47 | return proxied.getStackTraceElementProxyArray();
48 | }
49 |
50 | @Override
51 | public int getCommonFrames() {
52 | return proxied.getCommonFrames();
53 | }
54 |
55 | @Override
56 | public IThrowableProxy[] getSuppressed() {
57 | return proxied.getSuppressed();
58 | }
59 |
60 | @Override
61 | public boolean isCyclic() {
62 | return proxied.isCyclic();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/main/java/org/owasp/security/logging/mask/SSNMaskingConverter.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.pattern.ClassicConverter;
4 | import ch.qos.logback.classic.spi.ILoggingEvent;
5 |
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | /**
10 | * Masks social security numbers in log messages. SSNs consist of digits separated
11 | * by dashes in the form ###-##-####.
12 | *
13 | * The following famous/test SSNs are not masked:
14 | *
15 | * - 219-09-9999 (Social Security Board pamphlet)
16 | *
- 078-05-1120 (Woolworth wallets: Mrs. Hilda Schrader Whitcher)
17 | *
- matches starting with 000 or 666
18 | *
- matches containing 00 as the middle two digits
19 | *
- matches containing 0000 as the final four digits
20 | *
21 | *
22 | * @author augustd
23 | */
24 | public class SSNMaskingConverter extends ClassicConverter {
25 |
26 | private static final Pattern SSN_PATTERN = Pattern.compile("((?!219-09-9999|078-05-1120)(?!666|000|9\\d{2})\\d{3}-(?!00)\\d{2}-(?!0{4})\\d{4})");
27 |
28 | @Override
29 | public String convert(ILoggingEvent iLoggingEvent) {
30 | return mask(iLoggingEvent.getFormattedMessage());
31 | }
32 |
33 | private String mask(String formattedMessage) {
34 | Matcher matcher = SSN_PATTERN.matcher(formattedMessage);
35 | while (matcher.find()) {
36 | String found = matcher.group();
37 | StringBuilder builder = new StringBuilder();
38 | builder.append("***-**-");
39 | builder.append(found.substring(7));
40 | formattedMessage = formattedMessage.replaceAll(found, builder.toString());
41 | }
42 | return formattedMessage;
43 | }
44 | }
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/SecurityMarkersTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging;
2 |
3 | import static org.hamcrest.CoreMatchers.is;
4 | import static org.junit.Assert.assertFalse;
5 | import static org.junit.Assert.assertThat;
6 | import static org.junit.Assert.assertTrue;
7 | import static org.mockito.Mockito.verify;
8 |
9 | import org.junit.After;
10 | import org.junit.Before;
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 | import org.mockito.ArgumentCaptor;
14 | import org.mockito.Captor;
15 | import org.mockito.Mock;
16 | import org.mockito.junit.MockitoJUnitRunner;
17 | import org.slf4j.LoggerFactory;
18 | import org.slf4j.Marker;
19 |
20 | import ch.qos.logback.classic.Level;
21 | import ch.qos.logback.classic.Logger;
22 | import ch.qos.logback.classic.spi.ILoggingEvent;
23 | import ch.qos.logback.classic.spi.LoggingEvent;
24 | import ch.qos.logback.core.Appender;
25 |
26 | @RunWith(MockitoJUnitRunner.class)
27 | public class SecurityMarkersTest {
28 |
29 | private static final Logger LOGGER = (Logger) LoggerFactory
30 | .getLogger(SecurityMarkersTest.class);
31 |
32 | @Mock
33 | private Appender mockAppender;
34 |
35 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
36 | @Captor
37 | private ArgumentCaptor captorLoggingEvent;
38 |
39 | @Before
40 | public void setup() {
41 | LOGGER.addAppender(mockAppender);
42 | }
43 |
44 | @After
45 | public void teardown() {
46 | LOGGER.detachAppender(mockAppender);
47 | }
48 |
49 | @Test
50 | public void getMarkersTest() {
51 | Marker test1 = SecurityMarkers.SECURITY_AUDIT;
52 | System.out.println("getMarkersTest(): test1: " + test1);
53 | assertTrue(test1.contains(SecurityMarkers.SECURITY_AUDIT));
54 | assertFalse(test1.contains(SecurityMarkers.CONFIDENTIAL));
55 |
56 | Marker test2 = SecurityMarkers.getMarker(
57 | SecurityMarkers.SECURITY_AUDIT,
58 | SecurityMarkers.SECURITY_FAILURE);
59 | System.out.println("getMarkersTest(): test2: " + test2);
60 | assertTrue(test2.contains(SecurityMarkers.SECURITY_AUDIT));
61 | assertTrue(test2.contains(SecurityMarkers.SECURITY_FAILURE));
62 |
63 | Marker test3 = SecurityMarkers.getMarker(
64 | SecurityMarkers.SECURITY_AUDIT, SecurityMarkers.CONFIDENTIAL);
65 | System.out.println("getMarkersTest(): test3: " + test3);
66 | assertTrue(test3.contains(SecurityMarkers.SECURITY_AUDIT));
67 | assertTrue(test3.contains(SecurityMarkers.CONFIDENTIAL));
68 | assertFalse(test3.contains(SecurityMarkers.SECURITY_FAILURE));
69 | }
70 |
71 | @Test
72 | public void confidentialTest() {
73 | Marker confidential = SecurityMarkers.CONFIDENTIAL;
74 | confidential.add(SecurityMarkers.SECURITY_AUDIT);
75 | String userid = "myId";
76 | String password = "password";
77 | LOGGER.info(confidential, "userid={}, password='{}'", userid, password);
78 |
79 | // Now verify our logging interactions
80 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
81 |
82 | // Get the logging event from the captor
83 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
84 |
85 | // Check log level is correct
86 | assertThat(loggingEvent.getLevel(), is(Level.INFO));
87 |
88 | // check that markers are proper
89 | Marker test = loggingEvent.getMarker();
90 | assertTrue(test.contains(SecurityMarkers.SECURITY_AUDIT));
91 | assertTrue(test.contains(SecurityMarkers.CONFIDENTIAL));
92 |
93 | // cleanup for following tests
94 | confidential.remove(SecurityMarkers.SECURITY_AUDIT);
95 | }
96 |
97 | @Test
98 | public void multiMarkerTest() {
99 | Marker marker = SecurityMarkers.getMarker(
100 | SecurityMarkers.SECURITY_SUCCESS, SecurityMarkers.CONFIDENTIAL);
101 | LOGGER.info(marker, "Multi-marker test");
102 |
103 | // Now verify our logging interactions
104 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
105 |
106 | // Get the logging event from the captor
107 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
108 |
109 | // Check log level is correct
110 | assertThat(loggingEvent.getLevel(), is(Level.INFO));
111 |
112 | // Check the message being logged is correct
113 | assertThat(loggingEvent.getFormattedMessage(), is("Multi-marker test"));
114 |
115 | // check that markers are proper
116 | Marker test = loggingEvent.getMarker();
117 | assertTrue(test.contains(SecurityMarkers.SECURITY_SUCCESS));
118 | assertTrue(test.contains(SecurityMarkers.CONFIDENTIAL));
119 | assertFalse(test.contains(SecurityMarkers.EVENT_FAILURE));
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/SecurityTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging;
2 |
3 | import static org.mockito.Mockito.verify;
4 |
5 | import org.junit.After;
6 | import org.junit.Before;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.mockito.ArgumentCaptor;
10 | import org.mockito.Captor;
11 | import org.mockito.Mock;
12 | import org.mockito.junit.MockitoJUnitRunner;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import ch.qos.logback.classic.Logger;
16 | import ch.qos.logback.classic.LoggerContext;
17 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
18 | import ch.qos.logback.classic.spi.ILoggingEvent;
19 | import ch.qos.logback.classic.spi.LoggingEvent;
20 | import ch.qos.logback.core.rolling.RollingFileAppender;
21 |
22 | @RunWith(MockitoJUnitRunner.class)
23 | public class SecurityTest {
24 |
25 | LoggerContext loggerContext = (LoggerContext) LoggerFactory
26 | .getILoggerFactory();
27 | Logger LOGGER;
28 |
29 | @Mock
30 | private RollingFileAppender mockAppender = new RollingFileAppender();
31 |
32 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
33 | @Captor
34 | private ArgumentCaptor captorLoggingEvent;
35 |
36 | @Before
37 | public void setup() {
38 | // mockAppender = new RollingFileAppender();
39 | mockAppender.setContext(loggerContext);
40 | mockAppender.setFile("testFile.log");
41 |
42 | PatternLayoutEncoder encoder = new PatternLayoutEncoder();
43 | encoder.setContext(loggerContext);
44 | encoder.setPattern("%-4relative [%thread] %-5level %logger{35} - %msg%n");
45 | encoder.start();
46 |
47 | mockAppender.setEncoder(encoder);
48 | mockAppender.start();
49 | LOGGER = loggerContext.getLogger("Main");
50 | LOGGER.addAppender(mockAppender);
51 |
52 | }
53 |
54 | @After
55 | public void teardown() {
56 | LOGGER.detachAppender(mockAppender);
57 | }
58 |
59 | @Test
60 | public void injectionTest() {
61 |
62 | LOGGER.info("This message contains \r\n line feeds");
63 |
64 | // Now verify our logging interactions
65 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
66 |
67 | // Get the logging event from the captor
68 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
69 |
70 | System.out.println("MESSAGE: " + loggingEvent.getFormattedMessage());
71 | // assertThat(loggingEvent.getFormattedMessage(),
72 | // is("This message contains line feeds"));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/filter/ExcludeClassifiedMarkerFilterTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.filter;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertTrue;
5 |
6 | import org.junit.Test;
7 | import org.owasp.security.logging.SecurityMarkers;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import ch.qos.logback.classic.Logger;
11 | import ch.qos.logback.classic.LoggerContext;
12 | import ch.qos.logback.classic.spi.ILoggingEvent;
13 | import ch.qos.logback.classic.spi.LoggingEvent;
14 | import ch.qos.logback.core.Appender;
15 | import ch.qos.logback.core.spi.FilterReply;
16 | import org.junit.After;
17 | import org.junit.Before;
18 | import org.junit.runner.RunWith;
19 | import org.mockito.ArgumentCaptor;
20 | import org.mockito.Captor;
21 | import static org.mockito.Mockito.verify;
22 | import org.mockito.Spy;
23 | import org.mockito.junit.MockitoJUnitRunner;
24 | import org.slf4j.Marker;
25 |
26 | /**
27 | *
28 | * @author August Detlefsen [augustd@codemagi.com]
29 | */
30 | @RunWith(MockitoJUnitRunner.class)
31 | public class ExcludeClassifiedMarkerFilterTest {
32 |
33 | LoggerContext loggerContext = (LoggerContext) LoggerFactory
34 | .getILoggerFactory();
35 |
36 | Logger LOGGER = (Logger) LoggerFactory.getLogger("CONSOLE");
37 |
38 | @Spy
39 | private final Appender mockAppender = LOGGER
40 | .getAppender("NOT_CLASSIFIED_CONSOLE");
41 |
42 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
43 | @Captor
44 | private ArgumentCaptor captorLoggingEvent;
45 |
46 | @Before
47 | public void setUp() {
48 | LOGGER.addAppender(mockAppender);
49 | }
50 |
51 | @After
52 | public void teardown() {
53 | LOGGER.detachAppender(mockAppender);
54 | }
55 |
56 | @Test
57 | public void testAppenderNormalEvent() {
58 | LOGGER.info("This statement is NOT confidential");
59 |
60 | // Now verify our logging interactions
61 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
62 |
63 | // Get the logging event from the captor
64 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
65 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
66 |
67 | // check the filter chain decision for this event
68 | assertEquals(FilterReply.NEUTRAL,
69 | mockAppender.getFilterChainDecision(loggingEvent));
70 | }
71 |
72 | @Test
73 | public void testAppenderSecurityEvent() {
74 | LOGGER.info(SecurityMarkers.SECURITY_SUCCESS,
75 | "This statement is a security event");
76 |
77 | // Now verify our logging interactions
78 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
79 |
80 | // Get the logging event from the captor
81 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
82 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
83 |
84 | // check the filter chain decision for this event
85 | assertEquals(FilterReply.NEUTRAL,
86 | mockAppender.getFilterChainDecision(loggingEvent));
87 | }
88 |
89 | @Test
90 | public void testAppenderConfidentialEvent() {
91 | LOGGER.info(SecurityMarkers.CONFIDENTIAL,
92 | "This statement is confidential");
93 |
94 | // Now verify our logging interactions
95 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
96 |
97 | // Get the logging event from the captor
98 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
99 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
100 |
101 | // check the filter chain decision for this event
102 | assertEquals(FilterReply.DENY,
103 | mockAppender.getFilterChainDecision(loggingEvent));
104 | }
105 |
106 | @Test
107 | public void testAppenderRestrictedEvent() {
108 | LOGGER.info(SecurityMarkers.RESTRICTED, "This statement is restricted");
109 |
110 | // Now verify our logging interactions
111 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
112 |
113 | // Get the logging event from the captor
114 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
115 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
116 |
117 | // check the filter chain decision for this event
118 | assertEquals(FilterReply.DENY,
119 | mockAppender.getFilterChainDecision(loggingEvent));
120 | }
121 |
122 | @Test
123 | public void testAppenderSecretEvent() {
124 | LOGGER.info(SecurityMarkers.SECRET, "This statement is secret");
125 |
126 | // Now verify our logging interactions
127 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
128 |
129 | // Get the logging event from the captor
130 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
131 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
132 |
133 | // check the filter chain decision for this event
134 | assertEquals(FilterReply.DENY,
135 | mockAppender.getFilterChainDecision(loggingEvent));
136 | }
137 |
138 | @Test
139 | public void testAppenderTopSecretEvent() {
140 | LOGGER.info(SecurityMarkers.TOP_SECRET, "This statement is top secret");
141 |
142 | // Now verify our logging interactions
143 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
144 |
145 | // Get the logging event from the captor
146 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
147 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
148 |
149 | // check the filter chain decision for this event
150 | assertEquals(FilterReply.DENY,
151 | mockAppender.getFilterChainDecision(loggingEvent));
152 | }
153 |
154 | @Test
155 | public void testAppenderMultipleEvent() {
156 | Marker multi = SecurityMarkers.getMarker(
157 | SecurityMarkers.SECURITY_AUDIT, SecurityMarkers.CONFIDENTIAL);
158 | LOGGER.info(multi,
159 | "This statement contains multiple markers: audit and confidential");
160 |
161 | // Now verify our logging interactions
162 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
163 |
164 | // Get the logging event from the captor
165 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
166 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
167 |
168 | // check the filter chain decision for this event
169 | assertEquals(FilterReply.DENY,
170 | mockAppender.getFilterChainDecision(loggingEvent));
171 | }
172 |
173 | @Test
174 | public void testRaw() {
175 | // create a new marker filter
176 | ExcludeClassifiedMarkerFilter mkt = new ExcludeClassifiedMarkerFilter();
177 | mkt.setContext(loggerContext);
178 | mkt.start();
179 |
180 | assertTrue(mkt.isStarted());
181 |
182 | // test a logging event with no markers
183 | ILoggingEvent nulEvent = new LoggingEvent();
184 | assertEquals(FilterReply.NEUTRAL, mkt.decide(nulEvent));
185 |
186 | // test a logging event with the CONFIDENTIAL marker
187 | LoggingEvent confidentialEvent = new LoggingEvent();
188 | confidentialEvent.addMarker(SecurityMarkers.CONFIDENTIAL);
189 | assertEquals(FilterReply.DENY, mkt.decide(confidentialEvent));
190 |
191 | // test a logging event with the RESTRICTED marker
192 | LoggingEvent restrictedEvent = new LoggingEvent();
193 | restrictedEvent.addMarker(SecurityMarkers.RESTRICTED);
194 | assertEquals(FilterReply.DENY, mkt.decide(restrictedEvent));
195 |
196 | // test a logging event with the SECRET marker
197 | LoggingEvent secretEvent = new LoggingEvent();
198 | secretEvent.addMarker(SecurityMarkers.SECRET);
199 | assertEquals(FilterReply.DENY, mkt.decide(secretEvent));
200 |
201 | // test a logging event with the TOP_SECRET marker
202 | LoggingEvent topSecretEvent = new LoggingEvent();
203 | topSecretEvent.addMarker(SecurityMarkers.TOP_SECRET);
204 | assertEquals(FilterReply.DENY, mkt.decide(topSecretEvent));
205 |
206 | // test a logging event without the CONFIDENTIAL marker
207 | LoggingEvent normalEvent = new LoggingEvent();
208 | normalEvent.addMarker(SecurityMarkers.EVENT_SUCCESS);
209 | assertEquals(FilterReply.NEUTRAL, mkt.decide(nulEvent));
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/filter/MarkerFilterTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.filter;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertTrue;
5 |
6 | import org.junit.Test;
7 | import org.owasp.security.logging.SecurityMarkers;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import ch.qos.logback.classic.Logger;
11 | import ch.qos.logback.classic.LoggerContext;
12 | import ch.qos.logback.classic.spi.ILoggingEvent;
13 | import ch.qos.logback.classic.spi.LoggingEvent;
14 | import ch.qos.logback.core.spi.FilterReply;
15 |
16 | public class MarkerFilterTest {
17 |
18 | @Test
19 | public void testDecideILoggingEvent() {
20 | LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
21 |
22 | // create a new marker filter
23 | MarkerFilter mkt = new MarkerFilter();
24 | mkt.setContext(lc);
25 | mkt.setMarker(SecurityMarkers.CONFIDENTIAL_MARKER_NAME);
26 | mkt.setOnMatch(FilterReply.ACCEPT);
27 | mkt.setOnMismatch(FilterReply.DENY);
28 | mkt.start();
29 | assertTrue(mkt.isStarted());
30 |
31 | // test a logging event with no markers
32 | ILoggingEvent nulEvent = new LoggingEvent();
33 | assertEquals(FilterReply.DENY, mkt.decide(nulEvent));
34 |
35 | // test a logging event with the CONFIDENTIAL marker
36 | LoggingEvent confidentialEvent = new LoggingEvent();
37 | confidentialEvent.addMarker(SecurityMarkers.CONFIDENTIAL);
38 | assertEquals(FilterReply.ACCEPT, mkt.decide(confidentialEvent));
39 |
40 | // test a logging event without the CONFIDENTIAL marker
41 | LoggingEvent normalEvent = new LoggingEvent();
42 | normalEvent.addMarker(SecurityMarkers.EVENT_SUCCESS);
43 | assertEquals(FilterReply.DENY, mkt.decide(nulEvent));
44 |
45 | Logger LOGGER = lc.getLogger(MarkerFilterTest.class);
46 | LOGGER.debug(SecurityMarkers.TOP_SECRET, "You should not see this!");
47 | LOGGER.debug(SecurityMarkers.CONFIDENTIAL,
48 | "Look at this confidential information!");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/filter/SecurityMarkerFilterTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.filter;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertTrue;
5 | import static org.mockito.Mockito.verify;
6 |
7 | import org.junit.After;
8 | import org.junit.Before;
9 | import org.junit.Test;
10 | import org.junit.runner.RunWith;
11 | import org.mockito.ArgumentCaptor;
12 | import org.mockito.Captor;
13 | import org.mockito.Spy;
14 | import org.mockito.junit.MockitoJUnitRunner;
15 | import org.owasp.security.logging.SecurityMarkers;
16 | import org.slf4j.LoggerFactory;
17 | import org.slf4j.Marker;
18 |
19 | import ch.qos.logback.classic.Logger;
20 | import ch.qos.logback.classic.LoggerContext;
21 | import ch.qos.logback.classic.spi.ILoggingEvent;
22 | import ch.qos.logback.classic.spi.LoggingEvent;
23 | import ch.qos.logback.core.Appender;
24 | import ch.qos.logback.core.spi.FilterReply;
25 |
26 | /**
27 | *
28 | * @author August Detlefsen [augustd@codemagi.com]
29 | */
30 | @RunWith(MockitoJUnitRunner.class)
31 | public class SecurityMarkerFilterTest {
32 |
33 | LoggerContext loggerContext = (LoggerContext) LoggerFactory
34 | .getILoggerFactory();
35 |
36 | Logger LOGGER = (Logger) LoggerFactory.getLogger("CONSOLE");
37 |
38 | @Spy
39 | private final Appender mockAppender = LOGGER
40 | .getAppender("SECURITY_CONSOLE");
41 |
42 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
43 | @Captor
44 | private ArgumentCaptor captorLoggingEvent;
45 |
46 | @Before
47 | public void setUp() {
48 | LOGGER.addAppender(mockAppender);
49 | }
50 |
51 | @After
52 | public void teardown() {
53 | LOGGER.detachAppender(mockAppender);
54 | }
55 |
56 | @Test
57 | public void testAppenderNormalEvent() {
58 | LOGGER.info("This statement is NOT a security event");
59 |
60 | // Now verify our logging interactions
61 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
62 |
63 | // Get the logging event from the captor
64 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
65 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
66 |
67 | // check the filter chain decision for this event
68 | assertEquals(FilterReply.DENY,
69 | mockAppender.getFilterChainDecision(loggingEvent));
70 | }
71 |
72 | @Test
73 | public void testAppenderSecuritySuccess() {
74 | LOGGER.info(SecurityMarkers.SECURITY_SUCCESS,
75 | "This statement is a security success");
76 |
77 | // Now verify our logging interactions
78 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
79 |
80 | // Get the logging event from the captor
81 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
82 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
83 |
84 | // check the filter chain decision for this event
85 | assertEquals(FilterReply.ACCEPT,
86 | mockAppender.getFilterChainDecision(loggingEvent));
87 | }
88 |
89 | @Test
90 | public void testAppenderSecurityFailure() {
91 | LOGGER.info(SecurityMarkers.SECURITY_FAILURE,
92 | "This statement is a security failure");
93 |
94 | // Now verify our logging interactions
95 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
96 |
97 | // Get the logging event from the captor
98 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
99 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
100 |
101 | // check the filter chain decision for this event
102 | assertEquals(FilterReply.ACCEPT,
103 | mockAppender.getFilterChainDecision(loggingEvent));
104 | }
105 |
106 | @Test
107 | public void testAppenderSecurityAudit() {
108 | LOGGER.info(SecurityMarkers.SECURITY_AUDIT,
109 | "This statement is a security audit");
110 |
111 | // Now verify our logging interactions
112 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
113 |
114 | // Get the logging event from the captor
115 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
116 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
117 |
118 | // check the filter chain decision for this event
119 | assertEquals(FilterReply.ACCEPT,
120 | mockAppender.getFilterChainDecision(loggingEvent));
121 | }
122 |
123 | @Test
124 | public void testAppenderMultipleEvent() {
125 | Marker multi = SecurityMarkers.getMarker(
126 | SecurityMarkers.SECURITY_AUDIT, SecurityMarkers.CONFIDENTIAL);
127 | LOGGER.info(multi,
128 | "This statement contains multiple markers: security audit and confidential");
129 |
130 | // Now verify our logging interactions
131 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
132 |
133 | // Get the logging event from the captor
134 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
135 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
136 |
137 | // check the filter chain decision for this event
138 | assertEquals(FilterReply.ACCEPT,
139 | mockAppender.getFilterChainDecision(loggingEvent));
140 | }
141 |
142 | @Test
143 | public void testAppenderMultipleNonSecurityEvent() {
144 | Marker multi = SecurityMarkers.getMarker(SecurityMarkers.EVENT_SUCCESS,
145 | SecurityMarkers.CONFIDENTIAL);
146 | System.out.println("MARKER: " + multi);
147 | LOGGER.info(multi,
148 | "This statement contains multiple markers: event success and confidential");
149 |
150 | // Now verify our logging interactions
151 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
152 |
153 | // Get the logging event from the captor
154 | LoggingEvent loggingEvent = captorLoggingEvent.getValue();
155 | System.out.println("testAppender(): loggingEvent: " + loggingEvent);
156 |
157 | // check the filter chain decision for this event
158 | assertEquals(FilterReply.DENY,
159 | mockAppender.getFilterChainDecision(loggingEvent));
160 | }
161 |
162 | @Test
163 | public void testRaw() {
164 | // create a new marker filter
165 | SecurityMarkerFilter mkt = new SecurityMarkerFilter();
166 | mkt.setContext(loggerContext);
167 | mkt.start();
168 |
169 | assertTrue(mkt.isStarted());
170 |
171 | // test a logging event with no markers
172 | ILoggingEvent nulEvent = new LoggingEvent();
173 | assertEquals(FilterReply.DENY, mkt.decide(nulEvent));
174 |
175 | // test a logging event with the CONFIDENTIAL marker
176 | LoggingEvent confidentialEvent = new LoggingEvent();
177 | confidentialEvent.addMarker(SecurityMarkers.SECURITY_SUCCESS);
178 | assertEquals(FilterReply.NEUTRAL, mkt.decide(confidentialEvent));
179 |
180 | // test a logging event with the RESTRICTED marker
181 | LoggingEvent restrictedEvent = new LoggingEvent();
182 | restrictedEvent.addMarker(SecurityMarkers.SECURITY_FAILURE);
183 | assertEquals(FilterReply.NEUTRAL, mkt.decide(restrictedEvent));
184 |
185 | // test a logging event with the SECRET marker
186 | LoggingEvent secretEvent = new LoggingEvent();
187 | secretEvent.addMarker(SecurityMarkers.SECURITY_AUDIT);
188 | assertEquals(FilterReply.NEUTRAL, mkt.decide(secretEvent));
189 | }
190 |
191 | @Test
192 | public void testRawAcceptAll() {
193 | // create a new marker filter
194 | SecurityMarkerFilter mkt = new SecurityMarkerFilter();
195 | mkt.setContext(loggerContext);
196 | mkt.setAcceptAll("true");
197 | mkt.start();
198 |
199 | assertTrue(mkt.isStarted());
200 |
201 | // test a logging event with no markers
202 | ILoggingEvent nulEvent = new LoggingEvent();
203 | assertEquals(FilterReply.DENY, mkt.decide(nulEvent));
204 |
205 | // test a logging event with the CONFIDENTIAL marker
206 | LoggingEvent confidentialEvent = new LoggingEvent();
207 | confidentialEvent.addMarker(SecurityMarkers.SECURITY_SUCCESS);
208 | assertEquals(FilterReply.ACCEPT, mkt.decide(confidentialEvent));
209 |
210 | // test a logging event with the RESTRICTED marker
211 | LoggingEvent restrictedEvent = new LoggingEvent();
212 | restrictedEvent.addMarker(SecurityMarkers.SECURITY_FAILURE);
213 | assertEquals(FilterReply.ACCEPT, mkt.decide(restrictedEvent));
214 |
215 | // test a logging event with the SECRET marker
216 | LoggingEvent secretEvent = new LoggingEvent();
217 | secretEvent.addMarker(SecurityMarkers.SECURITY_AUDIT);
218 | assertEquals(FilterReply.ACCEPT, mkt.decide(secretEvent));
219 | }
220 |
221 | }
222 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/layout/cef/CEFLoggingLayoutTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.cef;
2 |
3 | import org.junit.Test;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import ch.qos.logback.classic.Level;
7 | import ch.qos.logback.classic.Logger;
8 | import ch.qos.logback.classic.LoggerContext;
9 | import ch.qos.logback.classic.spi.ILoggingEvent;
10 | import ch.qos.logback.classic.spi.LoggingEvent;
11 |
12 | public class CEFLoggingLayoutTest {
13 |
14 | private Logger logger = ((LoggerContext) LoggerFactory.getILoggerFactory())
15 | .getLogger("test");
16 |
17 | @Test
18 | public void test() {
19 | CEFLoggingLayout layout = new CEFLoggingLayout();
20 | ILoggingEvent event = new LoggingEvent("Wifi connection tampered with",
21 | logger, Level.DEBUG, "Someother", (Throwable) null,
22 | (Object[]) null);
23 | System.out.println(layout.doLayout(event));
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/layout/rich/RichContextTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.layout.rich;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertTrue;
5 |
6 | import org.junit.Test;
7 |
8 | import ch.qos.logback.classic.spi.LoggingEvent;
9 |
10 | public class RichContextTest {
11 |
12 | private LoggingEvent event = new LoggingEvent();
13 | {
14 | event.setTimeStamp(999);
15 | }
16 | private RichContext ctx = new RichContext(event);
17 |
18 | @Test
19 | public void testGetPID() {
20 | assertTrue(RichContext.getPID() > 0);
21 | }
22 |
23 | // @Test
24 | public void testGetApplicationName() {
25 | assertEquals("JUnit", ctx.getApplicationName());
26 | }
27 |
28 | @Test
29 | public void testToString() {
30 | System.out.println(ctx.toString());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/BaseConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 adetlefsen.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.owasp.security.logging.mask;
17 |
18 | import ch.qos.logback.classic.Level;
19 | import ch.qos.logback.classic.Logger;
20 | import ch.qos.logback.classic.LoggerContext;
21 | import ch.qos.logback.classic.PatternLayout;
22 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
23 | import ch.qos.logback.classic.spi.ILoggingEvent;
24 | import ch.qos.logback.classic.spi.LoggingEvent;
25 | import ch.qos.logback.core.rolling.RollingFileAppender;
26 |
27 | import static org.hamcrest.CoreMatchers.is;
28 | import org.junit.After;
29 | import static org.junit.Assert.assertThat;
30 | import org.junit.Before;
31 | import org.mockito.ArgumentCaptor;
32 | import org.mockito.Captor;
33 | import org.mockito.Mock;
34 | import static org.mockito.Mockito.verify;
35 | import org.mockito.Spy;
36 | import org.slf4j.LoggerFactory;
37 |
38 | /**
39 | *
40 | * @author adetlefsen
41 | */
42 | public abstract class BaseConverterTest {
43 |
44 | LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
45 |
46 | Logger LOGGER = (Logger)LoggerFactory.getLogger("CONSOLE");
47 |
48 | PatternLayoutEncoder encoder;
49 | PatternLayout layout;
50 |
51 | abstract String getConverterClass();
52 |
53 | @Spy
54 | protected RollingFileAppender mockAppender = new RollingFileAppender();
55 |
56 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
57 | @Captor
58 | protected ArgumentCaptor captorLoggingEvent;
59 |
60 | @Before
61 | public void setUp() {
62 | PatternLayout.defaultConverterMap.put("testmask", getConverterClass());
63 | encoder = new PatternLayoutEncoder();
64 | encoder.setContext(loggerContext);
65 | encoder.setPattern("[%thread] %-5level -masked- %testmask%n");
66 | encoder.start();
67 |
68 | mockAppender.setContext(loggerContext);
69 | mockAppender.setEncoder(encoder);
70 | mockAppender.start();
71 |
72 | LOGGER.addAppender(mockAppender);
73 | }
74 |
75 | @After
76 | public void teardown() {
77 | LOGGER.detachAppender(mockAppender);
78 | }
79 |
80 | protected String log(String message) {
81 | LOGGER.info(message);
82 | return getLayoutMessage();
83 | }
84 |
85 | protected String log(String pattern, String ... parameter) {
86 | LOGGER.info(pattern, parameter);
87 | return getLayoutMessage();
88 | }
89 |
90 | protected String getLayoutMessage() {
91 | // Now verify our logging interactions
92 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
93 | // Get the logging event from the captor
94 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
95 | // Check log level is correct
96 | assertThat(loggingEvent.getLevel(), is(Level.INFO));
97 | // Check the message being logged is correct
98 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
99 | System.out.println("layoutMessage: " + layoutMessage);
100 | return layoutMessage;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/CRLFConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License");
3 | * you may not use this file except in compliance with the License.
4 | * You may obtain a copy of the License at
5 | *
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 | package org.owasp.security.logging.mask;
15 |
16 | //import ch.qos.logback.classic.PatternLayoutEncoder;
17 | import ch.qos.logback.classic.Level;
18 | import ch.qos.logback.classic.Logger;
19 | import ch.qos.logback.classic.LoggerContext;
20 | import ch.qos.logback.classic.PatternLayout;
21 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
22 | import ch.qos.logback.classic.spi.ILoggingEvent;
23 | import ch.qos.logback.classic.spi.LoggingEvent;
24 | import ch.qos.logback.core.rolling.RollingFileAppender;
25 | import static org.hamcrest.CoreMatchers.is;
26 |
27 | import org.junit.After;
28 |
29 | import static org.junit.Assert.assertThat;
30 | import static org.junit.Assert.assertTrue;
31 |
32 | import org.junit.Before;
33 | import org.junit.Test;
34 | import org.junit.runner.RunWith;
35 | import org.mockito.ArgumentCaptor;
36 | import org.mockito.Captor;
37 | import org.mockito.Mock;
38 |
39 | import static org.mockito.Mockito.verify;
40 |
41 | import org.mockito.junit.MockitoJUnitRunner;
42 | import org.slf4j.LoggerFactory;
43 |
44 | /**
45 | *
46 | * @author August Detlefsen [augustd@codemagi.com]
47 | */
48 | @RunWith(MockitoJUnitRunner.class)
49 | public class CRLFConverterTest {
50 |
51 | LoggerContext loggerContext = (LoggerContext) LoggerFactory
52 | .getILoggerFactory();
53 |
54 | Logger LOGGER;
55 |
56 | PatternLayoutEncoder encoder;
57 |
58 | PatternLayout layout;
59 |
60 | @Mock
61 | private RollingFileAppender mockAppender = new RollingFileAppender();
62 |
63 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
64 | @Captor
65 | private ArgumentCaptor captorLoggingEvent;
66 |
67 | @Before
68 | public void setUp() {
69 | PatternLayout.defaultConverterMap.put("crlf",
70 | CRLFConverter.class.getName());
71 | // layout = new PatternLayout();
72 |
73 | encoder = new PatternLayoutEncoder();
74 | encoder.setContext(loggerContext);
75 | encoder.setPattern("%-4relative [%thread] %-5level %logger{35} - %crlf(%msg)%n");
76 | encoder.start();
77 |
78 | // Layout layout = new PatternLayout();
79 | // layout.setEncoder(encoder);
80 |
81 | mockAppender.setContext(loggerContext);
82 | mockAppender.setEncoder(encoder);
83 | mockAppender.start();
84 |
85 | LOGGER = (Logger) LoggerFactory.getLogger("CONSOLE");
86 | LOGGER.addAppender(mockAppender);
87 | }
88 |
89 | @After
90 | public void teardown() {
91 | LOGGER.detachAppender(mockAppender);
92 | }
93 |
94 | @Test
95 | public void test() {
96 | LOGGER.info("This message contains \r\n line feeds");
97 |
98 | // Now verify our logging interactions
99 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
100 |
101 | // Get the logging event from the captor
102 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
103 |
104 | // Check log level is correct
105 | assertThat(loggingEvent.getLevel(), is(Level.INFO));
106 |
107 | // Check the message being logged is correct
108 | // assertThat(loggingEvent.getFormattedMessage(),
109 | // is("This message contains __ line feeds"));'
110 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
111 | assertTrue(layoutMessage
112 | .contains("This message contains __ line feeds"));
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/CRLFThrowableConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License");
3 | * you may not use this file except in compliance with the License.
4 | * You may obtain a copy of the License at
5 | *
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 | package org.owasp.security.logging.mask;
15 |
16 | import ch.qos.logback.classic.Level;
17 | import ch.qos.logback.classic.Logger;
18 | import ch.qos.logback.classic.LoggerContext;
19 | import ch.qos.logback.classic.PatternLayout;
20 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
21 | import ch.qos.logback.classic.spi.ILoggingEvent;
22 | import ch.qos.logback.classic.spi.LoggingEvent;
23 | import ch.qos.logback.core.rolling.RollingFileAppender;
24 | import org.junit.After;
25 | import org.junit.Before;
26 | import org.junit.Test;
27 | import org.junit.runner.RunWith;
28 | import org.mockito.ArgumentCaptor;
29 | import org.mockito.Captor;
30 | import org.mockito.Mock;
31 | import org.mockito.junit.MockitoJUnitRunner;
32 | import org.slf4j.LoggerFactory;
33 |
34 | import static org.hamcrest.CoreMatchers.is;
35 | import static org.junit.Assert.assertThat;
36 | import static org.junit.Assert.assertTrue;
37 | import static org.mockito.Mockito.verify;
38 | import static org.slf4j.Logger.ROOT_LOGGER_NAME;
39 |
40 | /**
41 | *
42 | */
43 | @RunWith(MockitoJUnitRunner.class)
44 | public class CRLFThrowableConverterTest {
45 |
46 | private LoggerContext loggerContext = (LoggerContext) LoggerFactory
47 | .getILoggerFactory();
48 |
49 | private Logger LOGGER;
50 |
51 | private PatternLayoutEncoder encoder;
52 |
53 | private PatternLayout layout;
54 |
55 | @Mock
56 | private RollingFileAppender mockAppender = new RollingFileAppender<>();
57 |
58 | @Captor
59 | private ArgumentCaptor captorLoggingEvent;
60 |
61 | @Before
62 | public void setUp() {
63 | PatternLayout.defaultConverterMap.put("ex",
64 | CRLFThrowableConverter.class.getName());
65 |
66 | encoder = new PatternLayoutEncoder();
67 | encoder.setContext(loggerContext);
68 | encoder.setPattern("%-4relative [%thread] %-5level %logger{35} - %msg %ex%n");
69 | encoder.start();
70 |
71 | mockAppender.setContext(loggerContext);
72 | mockAppender.setEncoder(encoder);
73 | mockAppender.start();
74 |
75 | LOGGER = (Logger) LoggerFactory.getLogger(ROOT_LOGGER_NAME);
76 | LOGGER.addAppender(mockAppender);
77 | }
78 |
79 | @After
80 | public void tearDown() {
81 | LOGGER.detachAppender(mockAppender);
82 | }
83 |
84 | @Test
85 | public void test_with_1_exception() {
86 | try {
87 | throw new IllegalArgumentException("This message contains \r\n line feeds");
88 | } catch (IllegalArgumentException ex) {
89 | LOGGER.error("", ex);
90 | }
91 |
92 | // Now verify our logging interactions
93 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
94 |
95 | // Get the logging event from the captor
96 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
97 |
98 | // Check log level is correct
99 | assertThat(loggingEvent.getLevel(), is(Level.ERROR));
100 |
101 | // Check the message being logged is correct
102 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
103 | assertTrue(layoutMessage
104 | .contains("This message contains __ line feeds"));
105 | }
106 |
107 | @Test
108 | public void test_with_nested_exception() {
109 | try {
110 | try {
111 | throw new IllegalArgumentException("This message contains \r\n line feeds");
112 | } catch (IllegalArgumentException ex) {
113 | // replace message with line feeds to ensure the message is correctly replaced in first exception
114 | throw new RuntimeException("Invalid argument", ex);
115 | }
116 | } catch (RuntimeException ex) {
117 | LOGGER.error("", ex);
118 | }
119 |
120 | // Now verify our logging interactions
121 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
122 |
123 | // Get the logging event from the captor
124 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
125 |
126 | // Check log level is correct
127 | assertThat(loggingEvent.getLevel(), is(Level.ERROR));
128 |
129 | // Check the message being logged is correct
130 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
131 | assertTrue(layoutMessage
132 | .contains("This message contains __ line feeds"));
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/DefinedRegexMaskingConverterTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import org.junit.Before;
9 | import org.junit.Test;
10 |
11 | import ch.qos.logback.classic.spi.LoggingEvent;
12 | /**
13 | * Test regex masking convertor
14 | * @author Rahul Agarwal
15 | *
16 | */
17 | public class DefinedRegexMaskingConverterTest {
18 | private DefinedRegexMaskingConverter mc;
19 |
20 | @Before
21 | public void init(){
22 | mc = new DefinedRegexMaskingConverter();
23 | List optionsList = new ArrayList<>();
24 | //full mask
25 | optionsList.add("password|signature");
26 | //mask last 4
27 | optionsList.add("username");
28 | //mask first 4
29 | optionsList.add("orderNumber|giftCardNum");
30 | //email
31 | optionsList.add("email|customerEmail");
32 |
33 | mc.setOptionList(optionsList);
34 | mc.start();
35 | }
36 |
37 | @Test
38 | public void testCompleteMask(){
39 | //blank message
40 | String masked = mc.convert(getEvent(""));
41 | assertEquals("", masked);
42 |
43 | //equal separator
44 | masked = mc.convert(getEvent("password=abc123"));
45 | assertEquals("password=*****", masked);
46 |
47 | //colon seprator
48 | masked = mc.convert(getEvent("password:abc123"));
49 | assertEquals("password:*****", masked);
50 |
51 | //json
52 | masked = mc.convert(getEvent("\"password\":\"abc123\""));
53 | assertEquals("\"password\":\"*****\"", masked);
54 |
55 | //multiple
56 | masked = mc.convert(getEvent("\"password\":\"abc123\",signature=foo"));
57 | assertEquals("\"password\":\"*****\",signature=*****", masked);
58 | }
59 |
60 | @Test
61 | public void testLast4Mask(){
62 | //equal separator
63 | String masked = mc.convert(getEvent("username=abc123"));
64 | assertEquals("username=ab*****", masked);
65 |
66 | //colon seprator
67 | masked = mc.convert(getEvent("username:abc123"));
68 | assertEquals("username:ab*****", masked);
69 |
70 | //json
71 | masked = mc.convert(getEvent("\"username\":\"abc123\""));
72 | assertEquals("\"username\":\"ab*****\"", masked);
73 |
74 | //multiple
75 | masked = mc.convert(getEvent("\"username\":\"abc123\",signature=foo"));
76 | assertEquals("\"username\":\"ab*****\",signature=*****", masked);
77 | }
78 |
79 | @Test
80 | public void testFirst4Mask(){
81 | //equal separator
82 | String masked = mc.convert(getEvent("orderNumber=77887765567abc123"));
83 | assertEquals("orderNumber=*****c123", masked);
84 |
85 | //colon seprator
86 | masked = mc.convert(getEvent("orderNumber:abc123"));
87 | assertEquals("orderNumber:*****c123", masked);
88 |
89 | //json
90 | masked = mc.convert(getEvent("\"orderNumber\":\"abc123\""));
91 | assertEquals("\"orderNumber\":\"*****c123\"", masked);
92 |
93 | //multiple
94 | masked = mc.convert(getEvent("\"orderNumber\":\"abc123\",signature=foo"));
95 | assertEquals("\"orderNumber\":\"*****c123\",signature=*****", masked);
96 | }
97 |
98 | @Test
99 | public void testEmail(){
100 | //equal separator
101 | String masked = mc.convert(getEvent("email=foo@bar.com"));
102 | assertEquals("email=foo*****", masked);
103 |
104 | //colon seprator
105 | masked = mc.convert(getEvent("email:foo@bar.com.sg"));
106 | assertEquals("email:foo*****", masked);
107 |
108 | //json
109 | masked = mc.convert(getEvent("\"email\":\"foo.baz@bar.com\""));
110 | assertEquals("\"email\":\"foo.baz*****\"", masked);
111 |
112 | //multiple
113 | masked = mc.convert(getEvent("\"email\":\"foo@bar.com.sg\",signature=foo"));
114 | assertEquals("\"email\":\"foo*****\",signature=*****", masked);
115 | }
116 |
117 | private LoggingEvent getEvent(String message) {
118 | LoggingEvent event = new LoggingEvent();
119 | event.setMessage(message);
120 | return event;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/LUHNMaskingConverterTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import ch.qos.logback.classic.spi.ILoggingEvent;
4 | import ch.qos.logback.classic.spi.LoggingEvent;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import static org.assertj.core.api.Assertions.assertThat;
9 |
10 | public class LUHNMaskingConverterTest {
11 |
12 | @Before
13 | public void setUp() throws Exception {
14 | }
15 |
16 | @Test
17 | public void should_satisfy_convert_with_masked_string() {
18 | ILoggingEvent iLoggingEvent = new LoggingEvent();
19 | ((LoggingEvent) iLoggingEvent).setMessage(getXML());
20 | String formatted = new LUHNMaskingConverter().convert(iLoggingEvent);
21 | assertThat(formatted).isNotNull().isXmlEqualTo(expectedXml());
22 | }
23 |
24 | private String expectedXml() {
25 | return "" +
26 | "" +
27 | "4111**MASKED**1111" +
28 | "3782**MASKED**0005" +
29 | "3787**MASKED**1000" +
30 | "5610**MASKED**8250" +
31 | "3056**MASKED**5904" +
32 | "5105**MASKED**5100" +
33 | "4222**MASKED**2222" +
34 | "3566**MASKED**0505" +
35 | "TEXT Vlaues" +
36 | "lorem lipsm lpisn" +
37 | "1546955340104" +
38 | "1546955347298" +
39 | "";
40 | }
41 |
42 | private String getXML() {
43 | return "" +
44 | "" +
45 | "4111 1111 1111 1111" +
46 | "3782-8224-6310-005" +
47 | "3787,3449,3671,000" +
48 | "5610591081018250" +
49 | "30569309025904" +
50 | "5105105105105100" +
51 | "4222222222222" +
52 | "3566002020360505" +
53 | "TEXT Vlaues" +
54 | "lorem lipsm lpisn" +
55 | "1546955340104" +
56 | "1546955347298" +
57 | "";
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/MaskingConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License");
3 | * you may not use this file except in compliance with the License.
4 | * You may obtain a copy of the License at
5 | *
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 | package org.owasp.security.logging.mask;
15 |
16 | import ch.qos.logback.classic.Level;
17 | import ch.qos.logback.classic.Logger;
18 | import ch.qos.logback.classic.LoggerContext;
19 | import ch.qos.logback.classic.PatternLayout;
20 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
21 | import ch.qos.logback.classic.spi.ILoggingEvent;
22 | import ch.qos.logback.classic.spi.LoggingEvent;
23 | import ch.qos.logback.core.rolling.RollingFileAppender;
24 | import static org.hamcrest.CoreMatchers.is;
25 |
26 | import org.junit.After;
27 |
28 | import static org.junit.Assert.assertFalse;
29 | import static org.junit.Assert.assertThat;
30 | import static org.junit.Assert.assertTrue;
31 |
32 | import org.junit.Before;
33 | import org.junit.Test;
34 | import org.junit.runner.RunWith;
35 | import org.mockito.ArgumentCaptor;
36 | import org.mockito.Captor;
37 | import org.mockito.Mock;
38 |
39 | import static org.mockito.Mockito.verify;
40 |
41 | import org.mockito.junit.MockitoJUnitRunner;
42 | import org.owasp.security.logging.SecurityMarkers;
43 | import org.slf4j.LoggerFactory;
44 | import org.slf4j.Marker;
45 |
46 | /**
47 | *
48 | * @author August Detlefsen [augustd@codemagi.com]
49 | */
50 | @RunWith(MockitoJUnitRunner.class)
51 | public class MaskingConverterTest {
52 |
53 | LoggerContext loggerContext = (LoggerContext) LoggerFactory
54 | .getILoggerFactory();
55 |
56 | Logger LOGGER = (Logger) LoggerFactory.getLogger("CONSOLE");
57 |
58 | PatternLayoutEncoder encoder;
59 |
60 | @Mock
61 | private RollingFileAppender mockAppender = new RollingFileAppender();
62 |
63 | // Captor is genericised with ch.qos.logback.classic.spi.LoggingEvent
64 | @Captor
65 | private ArgumentCaptor captorLoggingEvent;
66 |
67 | @Before
68 | public void setUp() {
69 | PatternLayout.defaultConverterMap.put("mask",
70 | MaskingConverter.class.getName());
71 |
72 | encoder = new PatternLayoutEncoder();
73 | encoder.setContext(loggerContext);
74 | encoder.setPattern("%-4relative [%thread] %-5level %logger{35} - %mask%n");
75 | encoder.start();
76 |
77 | mockAppender.setContext(loggerContext);
78 | mockAppender.setEncoder(encoder);
79 | mockAppender.start();
80 |
81 | LOGGER.addAppender(mockAppender);
82 | }
83 |
84 | @After
85 | public void teardown() {
86 | LOGGER.detachAppender(mockAppender);
87 | }
88 |
89 | @Test
90 | public void test() {
91 | String userid = "myId";
92 | String password = "secret";
93 | LOGGER.info(SecurityMarkers.CONFIDENTIAL, "userid={}, password='{}'",
94 | userid, password);
95 |
96 | // Now verify our logging interactions
97 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
98 |
99 | // Get the logging event from the captor
100 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
101 |
102 | // Check log level is correct
103 | assertThat(loggingEvent.getLevel(), is(Level.INFO));
104 |
105 | // Check the message being logged is correct
106 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
107 | assertTrue(layoutMessage.contains("userid="
108 | + MaskingConverter.MASKED_PASSWORD + ", password='"
109 | + MaskingConverter.MASKED_PASSWORD + "'"));
110 | assertFalse(layoutMessage.contains("secret"));
111 | }
112 |
113 | /**
114 | * Test that masking works for combinations of markers and not just
115 | * SecurityMarkers.CONFIDENTIAL
116 | *
117 | * @see https://github.com/javabeanz/owasp-security-logging/issues/19
118 | */
119 | @Test
120 | public void markerTest() {
121 | Marker multiMarker = SecurityMarkers.getMarker(SecurityMarkers.CONFIDENTIAL, SecurityMarkers.SECURITY_FAILURE);
122 |
123 | String ssn = "123-45-6789";
124 | LOGGER.info(multiMarker, "ssn={}", ssn);
125 |
126 | // Now verify our logging interactions
127 | verify(mockAppender).doAppend(captorLoggingEvent.capture());
128 |
129 | // Get the logging event from the captor
130 | final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
131 |
132 | // Check the message being logged is correct
133 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
134 | assertTrue(layoutMessage.contains("ssn=" + MaskingConverter.MASKED_PASSWORD));
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/mask/SSNMaskingConverterTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.mask;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertFalse;
6 | import static org.junit.Assert.assertTrue;
7 | import org.junit.runner.RunWith;
8 | import org.mockito.junit.MockitoJUnitRunner;
9 |
10 | @RunWith(MockitoJUnitRunner.class)
11 | public class SSNMaskingConverterTest extends BaseConverterTest {
12 |
13 | @Override
14 | String getConverterClass() {
15 | return SSNMaskingConverter.class.getName();
16 | }
17 |
18 | @Test
19 | public void testMask() {
20 | String layoutMessage = log("This message contains SSN 123-45-6789");
21 | System.out.println("testMask() layoutMessage: " + layoutMessage);
22 | assertFalse(layoutMessage.contains("123-45-6789"));
23 | assertTrue(layoutMessage.contains("***-**-6789"));
24 | }
25 |
26 | @Test
27 | public void testMaskWithParameter() {
28 | String layoutMessage = log("This message contains SSN {}", "123-45-6789");
29 | System.out.println("testMaskWithParameter() layoutMessage: " + layoutMessage);
30 | assertFalse(layoutMessage.contains("123-45-6789"));
31 | assertTrue(layoutMessage.contains("***-**-6789"));
32 | }
33 |
34 | @Test
35 | public void testMaskWithMultiParameter() {
36 | String layoutMessage = log("For user {} SSN is {}", "Joe Roberts", "123-45-6789");
37 | System.out.println("testMaskWithMultiParameter() layoutMessage: " + layoutMessage);
38 | assertFalse(layoutMessage.contains("123-45-6789"));
39 | assertTrue(layoutMessage.contains("Joe Roberts"));
40 | assertTrue(layoutMessage.contains("***-**-6789"));
41 | }
42 |
43 | @Test
44 | public void testNonMask() {
45 | String layoutMessage = log("This message contains non-SSN 078-05-1120");
46 | System.out.println("testNonMask() layoutMessage: " + layoutMessage);
47 | assertFalse(layoutMessage.contains("***-**-1120"));
48 | assertTrue(layoutMessage.contains("078-05-1120"));
49 | }
50 |
51 | @Test
52 | public void testNonMaskWithParameter() {
53 | String layoutMessage = log("This message contains non-SSN {}", "078-05-1120");
54 | System.out.println("testNonMaskWithParameter() layoutMessage: " + layoutMessage);
55 | assertFalse(layoutMessage.contains("***-**-1120"));
56 | assertTrue(layoutMessage.contains("078-05-1120"));
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/util/ExtendedIntervalLoggingTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.util;
2 |
3 | import java.lang.management.ManagementFactory;
4 | import java.lang.management.OperatingSystemMXBean;
5 |
6 | import org.junit.Test;
7 | import org.owasp.security.logging.SecurityMarkers;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import com.sun.management.UnixOperatingSystemMXBean;
12 |
13 | public class ExtendedIntervalLoggingTest {
14 |
15 | private static final Logger logger = LoggerFactory.getLogger(ExtendedIntervalLoggingTest.class);
16 |
17 | @Test
18 | public void doExtendedTest() {
19 |
20 | logger.info("extended test started");
21 |
22 | IntervalLoggerController wd = SecurityLoggingFactory.getControllerInstance();
23 |
24 | // Add support for security markers
25 | wd.setStatusMessageView( new DefaultIntervalLoggerView() {
26 | @Override
27 | public void logMessage( String message ) {
28 | logger.info( SecurityMarkers.RESTRICTED, message );
29 | }
30 | });
31 |
32 | // Add a new property to the list of current properties
33 | DefaultIntervalLoggerModel model = new DefaultIntervalLoggerModel();
34 | model.addProperty( new DefaultIntervalProperty("OpenFiles") {
35 | public void refresh() {
36 | // restricted class, display open file handle count on *nix if we can.
37 | OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
38 | if(os instanceof UnixOperatingSystemMXBean)
39 | value = Long.toString(((UnixOperatingSystemMXBean) os).getOpenFileDescriptorCount());
40 | }
41 | }
42 | );
43 |
44 | // Remove default property from middle of the list like ThreadNew
45 | IntervalProperty[] properties = model.getProperties();
46 | for ( IntervalProperty i : properties ) {
47 | if( i.getName().equals("ThreadNew") )
48 | model.removeProperty(i);
49 | }
50 |
51 | wd.setStatusMessageModel(model);
52 |
53 | // Update interval to every 3 seconds
54 | wd.start(3000);
55 |
56 | // wait around.
57 | long exit_time = System.currentTimeMillis() + (1000*30);
58 |
59 | while( exit_time > System.currentTimeMillis() ) {
60 |
61 | Thread.yield();
62 |
63 | try {
64 | Thread.sleep(100);
65 | } catch (InterruptedException e) {
66 | // TODO Auto-generated catch block
67 | e.printStackTrace();
68 | }
69 | }
70 |
71 | wd.stop();
72 |
73 | logger.info( "extended test finished");
74 |
75 |
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/util/SecurityUtilLoggingTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.util;
2 |
3 | import org.junit.Test;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | public class SecurityUtilLoggingTest {
8 |
9 | private static final Logger logger = LoggerFactory.getLogger(SecurityUtilLoggingTest.class);
10 |
11 | @Test
12 | public void doBareBonesTest() {
13 |
14 | System.out.println("Print some sample command line arguments.");
15 |
16 | String[] fakeargs = new String[4];
17 | fakeargs[0] = "arg0";
18 | fakeargs[1] = "arg1";
19 | fakeargs[2] = "arg2";
20 | fakeargs[3] = "arg3";
21 | SecurityUtil.logCommandLineArguments(fakeargs);
22 |
23 | System.out.println("Print shell environment variables.");
24 | SecurityUtil.logShellEnvironmentVariables();
25 |
26 | System.out.println("Print Java system properties.");
27 | SecurityUtil.logJavaSystemProperties();
28 |
29 | logger.info( "barebones test finished");
30 |
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/util/SimpleIntervalLoggingTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.util;
2 |
3 | import org.junit.Test;
4 | import org.slf4j.LoggerFactory;
5 | import org.slf4j.Logger;
6 |
7 |
8 | public class SimpleIntervalLoggingTest {
9 |
10 | private static final Logger logger = LoggerFactory.getLogger(SimpleIntervalLoggingTest.class);
11 |
12 | @Test
13 | public void doBareBonesTest() {
14 |
15 | logger.info("barebones test started");
16 |
17 | IntervalLoggerController wd = SecurityLoggingFactory.getControllerInstance();
18 |
19 | wd.start();
20 |
21 | // Wait around to see a few status messages logged.
22 | long exit_time = System.currentTimeMillis() + (1000*30);
23 |
24 | while( exit_time > System.currentTimeMillis() ) {
25 | Thread.yield();
26 | try { Thread.sleep(100); } catch (InterruptedException e) {}
27 | }
28 |
29 | wd.stop();
30 |
31 | logger.info( "barebones test finished");
32 |
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/util/StreamRedirectionTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.util;
2 |
3 | import org.junit.Test;
4 | import org.owasp.security.logging.SecurityMarkers;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | public class StreamRedirectionTest {
9 |
10 | private static final Logger logger = LoggerFactory.getLogger(StreamRedirectionTest.class);
11 |
12 | @Test
13 | public void doTest() {
14 |
15 | System.out.println("Messages not going to SLF4j. So sad.");
16 |
17 | SecurityUtil.bindSystemStreamsToSLF4J();
18 |
19 | System.out.println("Whoot, now I'm printing to SLF4J.");
20 |
21 | logger.error(SecurityMarkers.CONFIDENTIAL, "simple unclassified logging message.");
22 |
23 | System.out.flush();
24 |
25 | SecurityUtil.unbindSystemStreams();
26 |
27 | System.out.println("Stream restored. Messages not going to SLF4J. Sad yet again.");
28 |
29 | System.out.flush();
30 |
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/java/org/owasp/security/logging/util/StreamRedirectionWithCustomLoggersTest.java:
--------------------------------------------------------------------------------
1 | package org.owasp.security.logging.util;
2 |
3 | import ch.qos.logback.classic.Level;
4 | import ch.qos.logback.classic.LoggerContext;
5 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
6 | import ch.qos.logback.classic.spi.ILoggingEvent;
7 | import ch.qos.logback.core.read.ListAppender;
8 | import static org.hamcrest.CoreMatchers.is;
9 | import org.junit.After;
10 | import static org.junit.Assert.assertThat;
11 | import static org.junit.Assert.assertTrue;
12 | import org.junit.Before;
13 |
14 | import org.junit.Test;
15 | import org.junit.runner.RunWith;
16 | import org.mockito.junit.MockitoJUnitRunner;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | /**
21 | * @author Jens Piegsa
22 | * @author August Detlefsen
23 | */
24 | @RunWith(MockitoJUnitRunner.class)
25 | public class StreamRedirectionWithCustomLoggersTest {
26 |
27 | LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
28 |
29 | ch.qos.logback.classic.Logger LOGGER = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("BLANK");
30 | ch.qos.logback.classic.Logger ROOT_LOGGER = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
31 |
32 | private ListAppender mockAppender;
33 |
34 | PatternLayoutEncoder encoder;
35 |
36 | @Before
37 | public void setUp() {
38 | encoder = new PatternLayoutEncoder();
39 | encoder.setContext(loggerContext);
40 | encoder.setPattern("%message");
41 | encoder.start();
42 |
43 | mockAppender = new ListAppender();
44 | mockAppender.start();
45 | mockAppender.list.clear();
46 |
47 | LOGGER.addAppender(mockAppender);
48 | }
49 |
50 | @After
51 | public void teardown() {
52 | mockAppender.list.clear();
53 | LOGGER.detachAppender(mockAppender);
54 | }
55 |
56 | @Test
57 | public void doSysOutTest() {
58 | System.out.println("***** doSysOutTest *****");
59 | System.out.println("message 1");
60 | System.err.println("message 2");
61 |
62 | SecurityUtil.bindSystemStreamsToSLF4J(LOGGER, ROOT_LOGGER);
63 |
64 | System.out.println("message 3");
65 | System.err.println("message 4");
66 |
67 | SecurityUtil.unbindSystemStreams();
68 |
69 | System.out.println("message 5");
70 | System.err.println("message 6");
71 |
72 | ILoggingEvent loggingEvent = mockAppender.list.get(mockAppender.list.size() - 1);
73 |
74 | // Check log level is correct
75 | assertThat(loggingEvent.getLevel(), is(Level.INFO));
76 |
77 | // check that message 3 was the last to be logged
78 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
79 | assertTrue(layoutMessage.contains("message 3"));
80 | System.out.println("layoutMessage: " + layoutMessage);
81 | }
82 |
83 | @Test
84 | public void doSysErrTest() {
85 | System.out.println("***** doSysErrTest *****");
86 | System.out.println("message 1");
87 | System.err.println("message 2");
88 |
89 | SecurityUtil.bindSystemStreamsToSLF4J(ROOT_LOGGER, LOGGER);
90 |
91 | System.err.println("message 3");
92 | System.out.println("message 4");
93 |
94 | SecurityUtil.unbindSystemStreams();
95 |
96 | System.out.println("message 5");
97 | System.err.println("message 6");
98 |
99 | ILoggingEvent loggingEvent = mockAppender.list.get(mockAppender.list.size() - 1);
100 |
101 | // Check log level is correct
102 | assertThat(loggingEvent.getLevel(), is(Level.ERROR));
103 |
104 | // check that message 3 was the last to be logged
105 | String layoutMessage = encoder.getLayout().doLayout(loggingEvent);
106 | assertTrue(layoutMessage.contains("message 3"));
107 | System.out.println("layoutMessage: " + layoutMessage);
108 | }
109 |
110 | @Test
111 | public void doTest() {
112 | System.out.println("***** doTest *****");
113 | System.out.println("message 1");
114 | System.err.println("message 2");
115 |
116 | SecurityUtil.bindSystemStreamsToSLF4J(LOGGER, LOGGER);
117 |
118 | System.out.println("message 3");
119 | System.err.println("message 4");
120 |
121 | SecurityUtil.unbindSystemStreams();
122 |
123 | System.out.println("message 5");
124 | System.err.println("message 6");
125 |
126 | assertThat(mockAppender.list.size(), is(2));
127 |
128 | ILoggingEvent systemEvent = mockAppender.list.get(0);
129 |
130 | // Check log level is correct
131 | assertThat(systemEvent.getLevel(), is(Level.INFO));
132 |
133 | // check that message 3 was the last to be logged
134 | String layoutMessage = encoder.getLayout().doLayout(systemEvent);
135 | assertTrue(layoutMessage.contains("message 3"));
136 | System.out.println("layoutMessage: " + layoutMessage);
137 |
138 | ILoggingEvent errorEvent = mockAppender.list.get(1);
139 |
140 | // Check log level is correct
141 | assertThat(errorEvent.getLevel(), is(Level.ERROR));
142 |
143 | // check that message 3 was the last to be logged
144 | layoutMessage = encoder.getLayout().doLayout(errorEvent);
145 | assertTrue(layoutMessage.contains("message 4"));
146 | System.out.println("layoutMessage: " + layoutMessage);
147 |
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/resources/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Implementation-Vendor: JUnit
3 | Implementation-Title: JUnit
4 | Implementation-Version: 4.12
5 | Implementation-Vendor-Id: junit
6 | Built-By: jenkins
7 | Build-Jdk: 1.6.0_45
8 | Created-By: Apache Maven 3.0.4
9 | Archiver-Version: Plexus Archiver
10 |
11 |
--------------------------------------------------------------------------------
/owasp-security-logging-logback/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | STDOUT %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %ex %n
7 |
8 |
9 |
10 |
12 |
13 |
15 |
16 |
18 |
19 |
21 |
22 |
23 |
24 |
25 | APP %date [%thread] [%marker] %-5level U:%X{userId} - %crlf(%mask) %ex %n
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | NOT CLASSIFIED %date [%thread] [%marker] %-5level - %msg %ex %n
34 |
35 |
36 |
37 |
39 |
40 |
41 | true
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | CONFIDENTIAL
52 | ACCEPT
53 | DENY
54 |
55 |
56 | CONFIDENTIAL %date [%thread] [%marker] %-5level U:%X{userId} - %crlf(%msg) %ex %n
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | org.owasp
6 | security-logging
7 | 1.2.0
8 | pom
9 | OWASP Security Logging
10 | The OWASP Security Logging project provides developers and ops personnel with APIs for logging security-related events.
11 | https://www.owasp.org/index.php/OWASP_Security_Logging_Project
12 |
13 |
14 | The Apache License, Version 2.0
15 | http://www.apache.org/licenses/LICENSE-2.0.txt
16 |
17 |
18 |
19 |
20 | August Detlefsen
21 | augustd@codemagi.com
22 | CodeMagi, Inc.
23 | http://www.codemagi.com
24 |
25 |
26 |
27 | owasp-security-logging-common
28 | owasp-security-logging-log4j
29 | owasp-security-logging-logback
30 |
31 |
32 | scm:git:git@github.com:javabeanz/owasp-security-logging.git
33 | scm:git:git@github.com:javabeanz/owasp-security-logging.git
34 | https://github.com/javabeanz/owasp-security-logging
35 |
36 |
37 | UTF-8
38 |
39 |
40 |
41 |
42 | org.slf4j
43 | slf4j-api
44 | 2.0.7
45 |
46 |
47 | junit
48 | junit
49 | 4.13.1
50 | test
51 |
52 |
53 | org.mockito
54 | mockito-core
55 | 5.4.0
56 | test
57 |
58 |
59 | org.hamcrest
60 | hamcrest-core
61 | 1.3
62 | test
63 |
64 |
65 | jakarta.servlet
66 | jakarta.servlet-api
67 | 5.0.0
68 | provided
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-compiler-plugin
78 | 3.11.0
79 |
80 | 1.8
81 | 1.8
82 |
83 |
84 |
85 |
86 |
87 |
88 | org.jacoco
89 | jacoco-maven-plugin
90 | 0.8.10
91 |
92 |
93 |
94 | prepare-agent
95 |
96 |
97 |
98 | report
99 | test
100 |
101 | report
102 |
103 |
104 |
105 |
106 |
107 | com.buschmais.jqassistant
108 | jqassistant-maven-plugin
109 | 1.11.1
110 |
111 |
112 | default-cli
113 | test
114 |
115 | scan
116 | analyze
117 |
118 |
119 | INFO
120 | MAJOR
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | release
130 |
131 |
132 |
133 | org.apache.maven.plugins
134 | maven-source-plugin
135 | 3.0.1
136 |
137 |
138 | attach-sources
139 |
140 | jar
141 |
142 |
143 |
144 |
145 |
146 | org.apache.maven.plugins
147 | maven-javadoc-plugin
148 | 3.0.0
149 |
150 |
151 | attach-javadocs
152 |
153 | jar
154 |
155 |
156 |
157 |
158 |
159 | org.apache.maven.plugins
160 | maven-gpg-plugin
161 | 1.6
162 |
163 |
164 | sign-artifacts
165 | deploy
166 |
167 | sign
168 |
169 |
170 |
171 |
172 |
173 | org.sonatype.plugins
174 | nexus-staging-maven-plugin
175 | 1.6.8
176 | true
177 |
178 | ossrh
179 | https://oss.sonatype.org/
180 | true
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 | ossrh
190 | https://oss.sonatype.org/content/repositories/snapshots
191 |
192 |
193 | ossrh
194 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
195 |
196 |
197 |
198 |
--------------------------------------------------------------------------------