Skip to content

Commit 962b9d6

Browse files
Updating Log4J Implementation
Translating the existing Log4J implementation into the updated logging class structures. Tests for the common aspects are also being provided. Additional class 'Log4JLoggerFactory.java' is being provided which is a Service Provider Interface (SPI) contribution at runtime through the log4j.xml file content. This will need more tests.
1 parent ec72299 commit 962b9d6

File tree

11 files changed

+1255
-0
lines changed

11 files changed

+1255
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* OWASP Enterprise Security API (ESAPI)
3+
*
4+
* This file is part of the Open Web Application Security Project (OWASP)
5+
* Enterprise Security API (ESAPI) project. For details, please see
6+
* <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
7+
*
8+
* Copyright (c) 2007 - The OWASP Foundation
9+
*
10+
* The ESAPI is published by OWASP under the BSD license. You should read and accept the
11+
* LICENSE before you use, modify, and/or redistribute this software.
12+
*
13+
* @created 2018
14+
*/
15+
package org.owasp.esapi.logging.log4j;
16+
17+
import org.apache.log4j.Logger;
18+
import org.owasp.esapi.Logger.EventType;
19+
/**
20+
* Contract for translating an ESAPI log event into an Log4J log event.
21+
*
22+
*/
23+
public interface Log4JLogBridge {
24+
/**
25+
* Translation for the provided ESAPI level, type, and message to the specified Log4J Logger.
26+
* @param logger Logger to receive the translated message.
27+
* @param esapiLevel ESAPI level of event.
28+
* @param type ESAPI event type
29+
* @param message ESAPI event message content.
30+
*/
31+
void log(Logger logger, int esapiLevel, EventType type, String message) ;
32+
/**
33+
* Translation for the provided ESAPI level, type, message, and Throwable to the specified Log4J Logger.
34+
* @param logger Logger to receive the translated message.
35+
* @param esapiLevel ESAPI level of event.
36+
* @param type ESAPI event type
37+
* @param message ESAPI event message content.
38+
* @param throwable ESAPI event Throwable content
39+
*/
40+
void log(Logger logger, int esapiLevel, EventType type, String message, Throwable throwable) ;
41+
42+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* OWASP Enterprise Security API (ESAPI)
3+
*
4+
* This file is part of the Open Web Application Security Project (OWASP)
5+
* Enterprise Security API (ESAPI) project. For details, please see
6+
* <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
7+
*
8+
* Copyright (c) 2007 - The OWASP Foundation
9+
*
10+
* The ESAPI is published by OWASP under the BSD license. You should read and accept the
11+
* LICENSE before you use, modify, and/or redistribute this software.
12+
*
13+
* @created 2018
14+
*/
15+
16+
package org.owasp.esapi.logging.log4j;
17+
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
21+
import org.apache.log4j.Logger;
22+
import org.owasp.esapi.Logger.EventType;
23+
import org.owasp.esapi.logging.appender.LogAppender;
24+
import org.owasp.esapi.logging.cleaning.LogScrubber;
25+
26+
/**
27+
* Implementation which is intended to bridge the ESAPI Logging API into LOG4J supported Object structures.
28+
*
29+
*/
30+
public class Log4JLogBridgeImpl implements Log4JLogBridge {
31+
/** Configuration providing associations between esapi log levels and LOG4J levels.*/
32+
private final Map<Integer,Log4JLogLevelHandler> esapiSlfLevelMap;
33+
/** Cleaner used for log content.*/
34+
private final LogScrubber scrubber;
35+
/** Appender used for assembling default message content for all logs.*/
36+
private final LogAppender appender;
37+
38+
/**
39+
* Constructor.
40+
* @param logScrubber Log message cleaner.
41+
* @param esapiSlfHandlerMap Map identifying ESAPI -> LOG4J log level associations.
42+
*/
43+
public Log4JLogBridgeImpl(LogAppender messageAppender, LogScrubber logScrubber, Map<Integer, Log4JLogLevelHandler> esapiSlfHandlerMap) {
44+
//Defensive copy to prevent external mutations.
45+
this.esapiSlfLevelMap = new HashMap<>(esapiSlfHandlerMap);
46+
this.scrubber = logScrubber;
47+
this.appender = messageAppender;
48+
}
49+
@Override
50+
public void log(Logger logger, int esapiLevel, EventType type, String message) {
51+
Log4JLogLevelHandler handler = esapiSlfLevelMap.get(esapiLevel);
52+
if (handler == null) {
53+
throw new IllegalArgumentException("Unable to lookup LOG4J level mapping for esapi value of " + esapiLevel);
54+
}
55+
if (handler.isEnabled(logger)) {
56+
String fullMessage = appender.appendTo(logger.getName(), type, message);
57+
String cleanString = scrubber.cleanMessage(fullMessage);
58+
59+
handler.log(logger, cleanString);
60+
}
61+
}
62+
@Override
63+
public void log(Logger logger, int esapiLevel, EventType type, String message, Throwable throwable) {
64+
Log4JLogLevelHandler handler = esapiSlfLevelMap.get(esapiLevel);
65+
if (handler == null) {
66+
throw new IllegalArgumentException("Unable to lookup LOG4J level mapping for esapi value of " + esapiLevel);
67+
}
68+
if (handler.isEnabled(logger)) {
69+
String fullMessage = appender.appendTo(logger.getName(), type, message);
70+
String cleanString = scrubber.cleanMessage(fullMessage);
71+
72+
handler.log(logger, cleanString, throwable);
73+
}
74+
}
75+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/**
2+
* OWASP Enterprise Security API (ESAPI)
3+
*
4+
* This file is part of the Open Web Application Security Project (OWASP)
5+
* Enterprise Security API (ESAPI) project. For details, please see
6+
* <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
7+
*
8+
* Copyright (c) 2007 - The OWASP Foundation
9+
*
10+
* The ESAPI is published by OWASP under the BSD license. You should read and accept the
11+
* LICENSE before you use, modify, and/or redistribute this software.
12+
*
13+
* @created 2018
14+
*/
15+
package org.owasp.esapi.logging.log4j;
16+
17+
import java.io.IOException;
18+
import java.io.InputStream;
19+
import java.io.OutputStream;
20+
import java.io.PrintStream;
21+
import java.util.ArrayList;
22+
import java.util.HashMap;
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
import org.apache.log4j.LogManager;
27+
import org.apache.log4j.PropertyConfigurator;
28+
import org.owasp.esapi.ESAPI;
29+
import org.owasp.esapi.LogFactory;
30+
import org.owasp.esapi.Logger;
31+
import org.owasp.esapi.codecs.HTMLEntityCodec;
32+
import org.owasp.esapi.logging.appender.LogAppender;
33+
import org.owasp.esapi.logging.appender.LogPrefixAppender;
34+
import org.owasp.esapi.logging.cleaning.CodecLogScrubber;
35+
import org.owasp.esapi.logging.cleaning.CompositeLogScrubber;
36+
import org.owasp.esapi.logging.cleaning.LogScrubber;
37+
import org.owasp.esapi.logging.cleaning.NewlineLogScrubber;
38+
import org.owasp.esapi.logging.java.JavaLogFactory;
39+
import org.owasp.esapi.reference.DefaultSecurityConfiguration;
40+
/**
41+
* LogFactory implementation which creates Log4J supporting Loggers.
42+
*
43+
*/
44+
public class Log4JLogFactory implements LogFactory {
45+
/** Immune characters for the codec log scrubber for JAVA context.*/
46+
private static final char[] IMMUNE_LOG4J_HTML = {',', '.', '-', '_', ' ' };
47+
/** Codec being used to clean messages for logging.*/
48+
private static final HTMLEntityCodec HTML_CODEC = new HTMLEntityCodec();
49+
/** Log appender instance.*/
50+
private static LogAppender Log4J_LOG_APPENDER;
51+
/** Log cleaner instance.*/
52+
private static LogScrubber Log4J_LOG_SCRUBBER;
53+
/** Bridge class for mapping esapi -> log4j log levels.*/
54+
private static Log4JLogBridge LOG_BRIDGE;
55+
56+
static {
57+
boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_ENCODING_REQUIRED);
58+
Log4J_LOG_SCRUBBER = createLogScrubber(encodeLog);
59+
60+
boolean logClientInfo = true;
61+
boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME);
62+
String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME);
63+
boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP);
64+
Log4J_LOG_APPENDER = createLogAppender(logClientInfo, logServerIp, logApplicationName, appName);
65+
66+
Map<Integer, Log4JLogLevelHandler> levelLookup = new HashMap<>();
67+
levelLookup.put(Logger.ALL, Log4JLogLevelHandlers.TRACE);
68+
levelLookup.put(Logger.TRACE, Log4JLogLevelHandlers.TRACE);
69+
levelLookup.put(Logger.DEBUG, Log4JLogLevelHandlers.DEBUG);
70+
levelLookup.put(Logger.INFO, Log4JLogLevelHandlers.INFO);
71+
levelLookup.put(Logger.ERROR, Log4JLogLevelHandlers.ERROR);
72+
levelLookup.put(Logger.WARNING, Log4JLogLevelHandlers.WARN);
73+
levelLookup.put(Logger.FATAL, Log4JLogLevelHandlers.FATAL);
74+
//LEVEL.OFF not used. If it's off why would we try to log it?
75+
76+
LOG_BRIDGE = new Log4JLogBridgeImpl(Log4J_LOG_APPENDER, Log4J_LOG_SCRUBBER, levelLookup);
77+
78+
try (InputStream stream = Log4JLogFactory.class.getClassLoader().
79+
getResourceAsStream("log4j.xml")) {
80+
PropertyConfigurator.configure(stream);
81+
} catch (IOException ioe) {
82+
System.err.print(new IOException("Failed to load log4j.xml.", ioe));
83+
}
84+
85+
OutputStream nullOutputStream = new OutputStream() {
86+
@Override
87+
public void write(int b) throws IOException {
88+
//No Op
89+
}
90+
};
91+
92+
System.setOut(new PrintStream(nullOutputStream));
93+
}
94+
95+
/**
96+
* Populates the default log scrubber for use in factory-created loggers.
97+
* @param requiresEncoding {@code true} if encoding is required for log content.
98+
* @return LogScrubber instance.
99+
*/
100+
/*package*/ static LogScrubber createLogScrubber(boolean requiresEncoding) {
101+
List<LogScrubber> messageScrubber = new ArrayList<>();
102+
messageScrubber.add(new NewlineLogScrubber());
103+
104+
if (requiresEncoding) {
105+
messageScrubber.add(new CodecLogScrubber(HTML_CODEC, IMMUNE_LOG4J_HTML));
106+
}
107+
108+
return new CompositeLogScrubber(messageScrubber);
109+
110+
}
111+
112+
/**
113+
* Populates the default log appender for use in factory-created loggers.
114+
* @param appName
115+
* @param logApplicationName
116+
* @param logServerIp
117+
* @param logClientInfo
118+
*
119+
* @return LogAppender instance.
120+
*/
121+
/*package*/ static LogAppender createLogAppender(boolean logClientInfo, boolean logServerIp, boolean logApplicationName, String appName) {
122+
return new LogPrefixAppender(logClientInfo, logServerIp, logApplicationName, appName);
123+
}
124+
125+
126+
@Override
127+
public Logger getLogger(String moduleName) {
128+
org.apache.log4j.Logger log4JLogger = org.apache.log4j.Logger.getLogger(moduleName);
129+
return new Log4JLogger(log4JLogger, LOG_BRIDGE, Logger.ALL);
130+
}
131+
132+
@Override
133+
public Logger getLogger(@SuppressWarnings("rawtypes") Class clazz) {
134+
org.apache.log4j.Logger log4JLogger = org.apache.log4j.Logger.getLogger(clazz);
135+
return new Log4JLogger(log4JLogger, LOG_BRIDGE, Logger.ALL);
136+
}
137+
138+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* OWASP Enterprise Security API (ESAPI)
3+
*
4+
* This file is part of the Open Web Application Security Project (OWASP)
5+
* Enterprise Security API (ESAPI) project. For details, please see
6+
* <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
7+
*
8+
* Copyright (c) 2007 - The OWASP Foundation
9+
*
10+
* The ESAPI is published by OWASP under the BSD license. You should read and accept the
11+
* LICENSE before you use, modify, and/or redistribute this software.
12+
*
13+
* @created 2018
14+
*/
15+
package org.owasp.esapi.logging.log4j;
16+
17+
import org.apache.log4j.Logger;
18+
19+
/**
20+
* Contract used to isolate translations for each SLF4J Logging Level.
21+
*
22+
* @see Log4JLogLevelHandlers
23+
* @see Log4JLogBridgeImpl
24+
*
25+
*/
26+
interface Log4JLogLevelHandler {
27+
/** Check if the logging level is enabled for the specified logger.*/
28+
boolean isEnabled(Logger logger);
29+
/**
30+
* Calls the appropriate log level event on the specified logger.
31+
* @param logger Logger to invoke.
32+
* @param msg Message to log.
33+
*/
34+
void log(Logger logger, String msg);
35+
/**
36+
* Calls the appropriate log level event on the specified logger.
37+
* @param logger Logger to invoke
38+
* @param msg Message to log
39+
* @param th Throwable to log.
40+
*/
41+
void log(Logger logger, String msg, Throwable th);
42+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* OWASP Enterprise Security API (ESAPI)
3+
*
4+
* This file is part of the Open Web Application Security Project (OWASP)
5+
* Enterprise Security API (ESAPI) project. For details, please see
6+
* <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
7+
*
8+
* Copyright (c) 2007 - The OWASP Foundation
9+
*
10+
* The ESAPI is published by OWASP under the BSD license. You should read and accept the
11+
* LICENSE before you use, modify, and/or redistribute this software.
12+
*
13+
* @created 2018
14+
*/
15+
16+
package org.owasp.esapi.logging.log4j;
17+
18+
19+
import org.apache.log4j.Level;
20+
import org.apache.log4j.Logger;
21+
22+
/**
23+
* Enumeration capturing the propagation of Log4J level events.
24+
*
25+
*/
26+
public enum Log4JLogLevelHandlers implements Log4JLogLevelHandler {
27+
FATAL(Level.FATAL),
28+
ERROR(Level.ERROR),
29+
WARN(Level.WARN),
30+
INFO(Level.INFO),
31+
DEBUG(Level.DEBUG),
32+
TRACE(Level.TRACE),
33+
ALL(Level.ALL);
34+
35+
private final Level level;
36+
37+
private Log4JLogLevelHandlers(Level lvl) {
38+
this.level = lvl;
39+
}
40+
41+
@Override
42+
public boolean isEnabled(Logger logger) {
43+
return logger.isEnabledFor(level);
44+
}
45+
46+
@Override
47+
public void log(Logger logger, String msg) {
48+
logger.log(level, msg);
49+
}
50+
51+
@Override
52+
public void log(Logger logger, String msg, Throwable th) {
53+
logger.log(level, msg, th);
54+
}
55+
}

0 commit comments

Comments
 (0)