File log4j-CVE-2020-9488.patch of Package log4j.22170
From 6851b5083ef9610bae320bf07e1f24d2aa08851b Mon Sep 17 00:00:00 2001
From: Matt Sicker <boards@gmail.com>
Date: Mon, 13 Apr 2020 17:59:43 -0500
Subject: [PATCH] [LOG4J2-2819] Add support for specifying an SSL configuration
for SmtpAppender
Signed-off-by: Matt Sicker <boards@gmail.com>
---
log4j-core/revapi.json | 29 +-
.../log4j/core/appender/SmtpAppender.java | 251 +++++++++++++++---
.../logging/log4j/core/net/SmtpManager.java | 31 ++-
.../log4j/core/appender/SmtpAppenderTest.java | 20 +-
4 files changed, 275 insertions(+), 56 deletions(-)
Index: apache-log4j-2.13.0-src/log4j-core/revapi.json
===================================================================
--- apache-log4j-2.13.0-src.orig/log4j-core/revapi.json
+++ apache-log4j-2.13.0-src/log4j-core/revapi.json
@@ -107,7 +107,34 @@
"new": "method <B extends org.apache.logging.log4j.core.appender.WriterAppender.Builder<B extends org.apache.logging.log4j.core.appender.WriterAppender.Builder<B>>> B org.apache.logging.log4j.core.appender.WriterAppender::newBuilder()",
"typeParameter": "B extends org.apache.logging.log4j.core.appender.WriterAppender.Builder<B extends org.apache.logging.log4j.core.appender.WriterAppender.Builder<B>>",
"justification": "LOG4J2-2491 - Allow all appenders to optionally carry a property array"
+ },
+ {
+ "code": "java.annotation.removed",
+ "old": "method org.apache.logging.log4j.core.appender.SmtpAppender org.apache.logging.log4j.core.appender.SmtpAppender::createAppender(org.apache.logging.log4j.core.config.Configuration, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, org.apache.logging.log4j.core.Layout<? extends java.io.Serializable>, org.apache.logging.log4j.core.Filter, java.lang.String)",
+ "new": "method org.apache.logging.log4j.core.appender.SmtpAppender org.apache.logging.log4j.core.appender.SmtpAppender::createAppender(org.apache.logging.log4j.core.config.Configuration, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, org.apache.logging.log4j.core.Layout<? extends java.io.Serializable>, org.apache.logging.log4j.core.Filter, java.lang.String)",
+ "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+ "justification": "Plugin is created through builder class now. No practical change here."
+ },
+ {
+ "code": "java.method.numberOfParametersChanged",
+ "old": "method org.apache.logging.log4j.core.net.SmtpManager org.apache.logging.log4j.core.net.SmtpManager::getSmtpManager(org.apache.logging.log4j.core.config.Configuration, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, boolean, java.lang.String, int)",
+ "new": "method org.apache.logging.log4j.core.net.SmtpManager org.apache.logging.log4j.core.net.SmtpManager::getSmtpManager(org.apache.logging.log4j.core.config.Configuration, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, boolean, java.lang.String, int, org.apache.logging.log4j.core.net.ssl.SslConfiguration)",
+ "justification": "LOG4J2-2819 - Add support for specifying an SSL configuration for SmtpAppender"
+ },
+ {
+ "code": "java.annotation.added",
+ "old": "parameter org.apache.logging.log4j.core.net.ssl.SslConfiguration org.apache.logging.log4j.core.net.ssl.SslConfiguration::createSSLConfiguration(java.lang.String, org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration, org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration, ===boolean===)",
+ "new": "parameter org.apache.logging.log4j.core.net.ssl.SslConfiguration org.apache.logging.log4j.core.net.ssl.SslConfiguration::createSSLConfiguration(java.lang.String, org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration, org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration, ===boolean===)",
+ "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginAttribute(\"verifyHostName\")",
+ "justification": "LOG4J2-TODO"
+ },
+ {
+ "code": "java.annotation.removed",
+ "old": "parameter org.apache.logging.log4j.core.net.ssl.SslConfiguration org.apache.logging.log4j.core.net.ssl.SslConfiguration::createSSLConfiguration(java.lang.String, org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration, org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration, ===boolean===)",
+ "new": "parameter org.apache.logging.log4j.core.net.ssl.SslConfiguration org.apache.logging.log4j.core.net.ssl.SslConfiguration::createSSLConfiguration(java.lang.String, org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration, org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration, ===boolean===)",
+ "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginElement(\"verifyHostName\")",
+ "justification": "LOG4J2-TODO"
}
]
}
-]
\ No newline at end of file
+]
Index: apache-log4j-2.13.0-src/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
===================================================================
--- apache-log4j-2.13.0-src.orig/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
+++ apache-log4j-2.13.0-src/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
@@ -17,8 +17,6 @@
package org.apache.logging.log4j.core.appender;
-import java.io.Serializable;
-
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
@@ -29,16 +27,20 @@ import org.apache.logging.log4j.core.con
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
-import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
import org.apache.logging.log4j.core.filter.ThresholdFilter;
import org.apache.logging.log4j.core.layout.HtmlLayout;
import org.apache.logging.log4j.core.net.SmtpManager;
+import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.util.Booleans;
+import java.io.Serializable;
+
/**
* Send an e-mail when a specific logging event occurs, typically on errors or
* fatal errors.
@@ -72,45 +74,212 @@ public final class SmtpAppender extends
}
/**
+ * @since 2.13.2
+ */
+ public static class Builder extends AbstractAppender.Builder<Builder>
+ implements org.apache.logging.log4j.core.util.Builder<SmtpAppender> {
+ @PluginBuilderAttribute
+ private String to;
+
+ @PluginBuilderAttribute
+ private String cc;
+
+ @PluginBuilderAttribute
+ private String bcc;
+
+ @PluginBuilderAttribute
+ private String from;
+
+ @PluginBuilderAttribute
+ private String replyTo;
+
+ @PluginBuilderAttribute
+ private String subject;
+
+ @PluginBuilderAttribute
+ private String smtpProtocol = "smtp";
+
+ @PluginBuilderAttribute
+ private String smtpHost;
+
+ @PluginBuilderAttribute
+ @ValidPort
+ private int smtpPort;
+
+ @PluginBuilderAttribute
+ private String smtpUsername;
+
+ @PluginBuilderAttribute(sensitive = true)
+ private String smtpPassword;
+
+ @PluginBuilderAttribute
+ private boolean smtpDebug;
+
+ @PluginBuilderAttribute
+ private int bufferSize = DEFAULT_BUFFER_SIZE;
+
+ @PluginElement("SSL")
+ private SslConfiguration sslConfiguration;
+
+ /**
+ * Comma-separated list of recipient email addresses.
+ */
+ public Builder setTo(final String to) {
+ this.to = to;
+ return this;
+ }
+
+ /**
+ * Comma-separated list of CC email addresses.
+ */
+ public Builder setCc(final String cc) {
+ this.cc = cc;
+ return this;
+ }
+
+ /**
+ * Comma-separated list of BCC email addresses.
+ */
+ public Builder setBcc(final String bcc) {
+ this.bcc = bcc;
+ return this;
+ }
+
+ /**
+ * Email address of the sender.
+ */
+ public Builder setFrom(final String from) {
+ this.from = from;
+ return this;
+ }
+
+ /**
+ * Comma-separated list of Reply-To email addresses.
+ */
+ public Builder setReplyTo(final String replyTo) {
+ this.replyTo = replyTo;
+ return this;
+ }
+
+ /**
+ * Subject template for the email messages.
+ * @see org.apache.logging.log4j.core.layout.PatternLayout
+ */
+ public Builder setSubject(final String subject) {
+ this.subject = subject;
+ return this;
+ }
+
+ /**
+ * Transport protocol to use for SMTP such as "smtp" or "smtps". Defaults to "smtp".
+ */
+ public Builder setSmtpProtocol(final String smtpProtocol) {
+ this.smtpProtocol = smtpProtocol;
+ return this;
+ }
+
+ /**
+ * Host name of SMTP server to send messages through.
+ */
+ public Builder setSmtpHost(final String smtpHost) {
+ this.smtpHost = smtpHost;
+ return this;
+ }
+
+ /**
+ * Port number of SMTP server to send messages through.
+ */
+ public Builder setSmtpPort(final int smtpPort) {
+ this.smtpPort = smtpPort;
+ return this;
+ }
+
+ /**
+ * Username to authenticate with SMTP server.
+ */
+ public Builder setSmtpUsername(final String smtpUsername) {
+ this.smtpUsername = smtpUsername;
+ return this;
+ }
+
+ /**
+ * Password to authenticate with SMTP server.
+ */
+ public Builder setSmtpPassword(final String smtpPassword) {
+ this.smtpPassword = smtpPassword;
+ return this;
+ }
+
+ /**
+ * Enables or disables mail session debugging on STDOUT. Disabled by default.
+ */
+ public Builder setSmtpDebug(final boolean smtpDebug) {
+ this.smtpDebug = smtpDebug;
+ return this;
+ }
+
+ /**
+ * Number of log events to buffer before sending an email. Defaults to {@value #DEFAULT_BUFFER_SIZE}.
+ */
+ public Builder setBufferSize(final int bufferSize) {
+ this.bufferSize = bufferSize;
+ return this;
+ }
+
+ /**
+ * Specifies an SSL configuration for smtps connections.
+ */
+ public Builder setSslConfiguration(final SslConfiguration sslConfiguration) {
+ this.sslConfiguration = sslConfiguration;
+ return this;
+ }
+
+ /**
+ * Specifies the layout used for the email message body. By default, this uses the
+ * {@linkplain HtmlLayout#createDefaultLayout() default HTML layout}.
+ */
+ @Override
+ public Builder setLayout(final Layout<? extends Serializable> layout) {
+ return super.setLayout(layout);
+ }
+
+ /**
+ * Specifies the filter used for this appender. By default, uses a {@link ThresholdFilter} with a level of
+ * ERROR.
+ */
+ @Override
+ public Builder setFilter(final Filter filter) {
+ return super.setFilter(filter);
+ }
+
+ @Override
+ public SmtpAppender build() {
+ if (getLayout() == null) {
+ setLayout(HtmlLayout.createDefaultLayout());
+ }
+ if (getFilter() == null) {
+ setFilter(ThresholdFilter.createFilter(null, null, null));
+ }
+ final SmtpManager smtpManager = SmtpManager.getSmtpManager(getConfiguration(), to, cc, bcc, from, replyTo,
+ subject, smtpProtocol, smtpHost, smtpPort, smtpUsername, smtpPassword, smtpDebug,
+ getFilter().toString(), bufferSize, sslConfiguration);
+ return new SmtpAppender(getName(), getFilter(), getLayout(), smtpManager, isIgnoreExceptions(), getPropertyArray());
+ }
+ }
+
+ /**
+ * @since 2.13.2
+ */
+ @PluginBuilderFactory
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
* Create a SmtpAppender.
- *
- * @param name
- * The name of the Appender.
- * @param to
- * The comma-separated list of recipient email addresses.
- * @param cc
- * The comma-separated list of CC email addresses.
- * @param bcc
- * The comma-separated list of BCC email addresses.
- * @param from
- * The email address of the sender.
- * @param replyTo
- * The comma-separated list of reply-to email addresses.
- * @param subject The subject of the email message.
- * @param smtpProtocol The SMTP transport protocol (such as "smtps", defaults to "smtp").
- * @param smtpHost
- * The SMTP hostname to send to.
- * @param smtpPortStr
- * The SMTP port to send to.
- * @param smtpUsername
- * The username required to authenticate against the SMTP server.
- * @param smtpPassword
- * The password required to authenticate against the SMTP server.
- * @param smtpDebug
- * Enable mail session debuging on STDOUT.
- * @param bufferSizeStr
- * How many log events should be buffered for inclusion in the
- * message?
- * @param layout
- * The layout to use (defaults to HtmlLayout).
- * @param filter
- * The Filter or null (defaults to ThresholdFilter, level of
- * ERROR).
- * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
- * they are propagated to the caller.
- * @return The SmtpAppender.
+ * @deprecated Use {@link #newBuilder()} to create and configure a {@link Builder} instance.
+ * @see Builder
*/
- @PluginFactory
public static SmtpAppender createAppender(
@PluginConfiguration final Configuration config,
@PluginAttribute("name") @Required final String name,
@@ -149,7 +318,7 @@ public final class SmtpAppender extends
final Configuration configuration = config != null ? config : new DefaultConfiguration();
final SmtpManager manager = SmtpManager.getSmtpManager(configuration, to, cc, bcc, from, replyTo, subject, smtpProtocol,
- smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(), bufferSize);
+ smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(), bufferSize, null);
if (manager == null) {
return null;
}
Index: apache-log4j-2.13.0-src/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
===================================================================
--- apache-log4j-2.13.0-src.orig/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
+++ apache-log4j-2.13.0-src/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
@@ -35,6 +35,7 @@ import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;
+import javax.net.ssl.SSLSocketFactory;
import org.apache.logging.log4j.LoggingException;
import org.apache.logging.log4j.core.Layout;
@@ -46,6 +47,7 @@ import org.apache.logging.log4j.core.imp
import org.apache.logging.log4j.core.impl.MutableLogEvent;
import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer;
import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.util.CyclicBuffer;
import org.apache.logging.log4j.core.util.NameUtil;
import org.apache.logging.log4j.core.util.NetUtils;
@@ -99,7 +101,8 @@ public class SmtpManager extends Abstrac
final String from, final String replyTo,
final String subject, String protocol, final String host,
final int port, final String username, final String password,
- final boolean isDebug, final String filterName, final int numElements) {
+ final boolean isDebug, final String filterName, final int numElements,
+ final SslConfiguration sslConfiguration) {
if (Strings.isEmpty(protocol)) {
protocol = "smtp";
}
@@ -144,7 +147,7 @@ public class SmtpManager extends Abstrac
final Serializer subjectSerializer = PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(subject).build();
return getManager(name, FACTORY, new FactoryData(to, cc, bcc, from, replyTo, subjectSerializer,
- protocol, host, port, username, password, isDebug, numElements));
+ protocol, host, port, username, password, isDebug, numElements, sslConfiguration));
}
/**
@@ -275,10 +278,12 @@ public class SmtpManager extends Abstrac
private final String password;
private final boolean isDebug;
private final int numElements;
+ private final SslConfiguration sslConfiguration;
public FactoryData(final String to, final String cc, final String bcc, final String from, final String replyTo,
final Serializer subjectSerializer, final String protocol, final String host, final int port,
- final String username, final String password, final boolean isDebug, final int numElements) {
+ final String username, final String password, final boolean isDebug, final int numElements,
+ final SslConfiguration sslConfiguration) {
this.to = to;
this.cc = cc;
this.bcc = bcc;
@@ -292,6 +297,7 @@ public class SmtpManager extends Abstrac
this.password = password;
this.isDebug = isDebug;
this.numElements = numElements;
+ this.sslConfiguration = sslConfiguration;
}
}
@@ -317,22 +323,31 @@ public class SmtpManager extends Abstrac
final String prefix = "mail." + data.protocol;
final Properties properties = PropertiesUtil.getSystemProperties();
- properties.put("mail.transport.protocol", data.protocol);
+ properties.setProperty("mail.transport.protocol", data.protocol);
if (properties.getProperty("mail.host") == null) {
// Prevent an UnknownHostException in Java 7
- properties.put("mail.host", NetUtils.getLocalHostname());
+ properties.setProperty("mail.host", NetUtils.getLocalHostname());
}
if (null != data.host) {
- properties.put(prefix + ".host", data.host);
+ properties.setProperty(prefix + ".host", data.host);
}
if (data.port > 0) {
- properties.put(prefix + ".port", String.valueOf(data.port));
+ properties.setProperty(prefix + ".port", String.valueOf(data.port));
}
final Authenticator authenticator = buildAuthenticator(data.username, data.password);
if (null != authenticator) {
- properties.put(prefix + ".auth", "true");
+ properties.setProperty(prefix + ".auth", "true");
+ }
+
+ if (data.protocol.equals("smtps")) {
+ final SslConfiguration sslConfiguration = data.sslConfiguration;
+ if (sslConfiguration != null) {
+ final SSLSocketFactory sslSocketFactory = sslConfiguration.getSslSocketFactory();
+ properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
+ properties.setProperty(prefix + ".ssl.checkserveridentity", Boolean.toString(sslConfiguration.isVerifyHostName()));
+ }
}
final Session session = Session.getInstance(properties, authenticator);
Index: apache-log4j-2.13.0-src/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
===================================================================
--- apache-log4j-2.13.0-src.orig/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
+++ apache-log4j-2.13.0-src/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
@@ -40,8 +40,6 @@ import static org.junit.Assert.*;
public class SmtpAppenderTest {
private static final String HOST = "localhost";
- private static final int PORTNUM = AvailablePortFinder.getNextAvailable();
- private static final String PORT = String.valueOf(PORTNUM);
@Test
public void testMessageFactorySetFrom() throws MessagingException {
@@ -114,9 +112,19 @@ public class SmtpAppenderTest {
final String subjectKey = getClass().getName();
final String subjectValue = "SubjectValue1";
ThreadContext.put(subjectKey, subjectValue);
- final SmtpAppender appender = SmtpAppender.createAppender(null, "Test", "to@example.com", "cc@example.com",
- "bcc@example.com", "from@example.com", "replyTo@example.com", "Subject Pattern %X{" + subjectKey + "}",
- null, HOST, PORT, null, null, "false", "3", null, null, "true");
+ final int smtpPort = AvailablePortFinder.getNextAvailable();
+ final SmtpAppender appender = SmtpAppender.newBuilder()
+ .setName("Test")
+ .setTo("to@example.com")
+ .setCc("cc@example.com")
+ .setBcc("bcc@example.com")
+ .setFrom("from@example.com")
+ .setReplyTo("replyTo@example.com")
+ .setSubject("Subject Pattern %X{" + subjectKey + "}")
+ .setSmtpHost(HOST)
+ .setSmtpPort(smtpPort)
+ .setBufferSize(3)
+ .build();
appender.start();
final LoggerContext context = LoggerContext.getContext();
@@ -125,7 +133,7 @@ public class SmtpAppenderTest {
root.setAdditive(false);
root.setLevel(Level.DEBUG);
- final SimpleSmtpServer server = SimpleSmtpServer.start(PORTNUM);
+ final SimpleSmtpServer server = SimpleSmtpServer.start(smtpPort);
root.debug("Debug message #1");
root.debug("Debug message #2");