From e68ff3edf50b334668dd5563e746a491a58935ff Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sat, 11 Dec 2021 16:05:14 -0700 Subject: [PATCH] LOG4J2-3208 - Disable JNDI by default --- .../log4j/core/appender/mom/JmsManager.java | 13 ++-- .../log4j/core/lookup/Interpolator.java | 19 ++++-- .../logging/log4j/core/net/JndiManager.java | 54 +++++++++++----- .../core/selector/JndiContextSelector.java | 6 ++ .../core/appender/mom/JmsAppenderTest.java | 6 ++ .../routing/RoutingAppenderWithJndiTest.java | 10 ++- .../log4j/core/lookup/InterpolatorTest.java | 3 + .../core/lookup/JndiDisabledLookupTest.java | 64 +++++++++++++++++++ .../log4j/core/lookup/JndiLookupTest.java | 6 ++ .../core/lookup/JndiRestrictedLookupTest.java | 1 + src/site/xdoc/manual/appenders.xml | 3 + src/site/xdoc/manual/configuration.xml.vm | 8 +++ src/site/xdoc/manual/logsep.xml | 3 + src/site/xdoc/manual/lookups.xml | 5 ++ 14 files changed, 172 insertions(+), 29 deletions(-) create mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java index ad57358..671cd5d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java @@ -125,10 +125,15 @@ public class JmsManager extends AbstractManager { @Override public JmsManager createManager(final String name, final JmsManagerConfiguration data) { - try { - return new JmsManager(name, data); - } catch (final Exception e) { - logger().error("Error creating JmsManager using JmsManagerConfiguration [{}]", data, e); + if (JndiManager.isIsJndiEnabled()) { + try { + return new JmsManager(name, data); + } catch (final Exception e) { + logger().error("Error creating JmsManager using JmsManagerConfiguration [{}]", data, e); + return null; + } + } else { + logger().error("JNDI has not been enabled. The log4j2.enableJndi property must be set to true"); return null; } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java index f0c40f5..827b77e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java @@ -26,6 +26,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.ConfigurationAware; import org.apache.logging.log4j.core.config.plugins.util.PluginManager; import org.apache.logging.log4j.core.config.plugins.util.PluginType; +import org.apache.logging.log4j.core.net.JndiManager; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.ReflectionUtil; import org.apache.logging.log4j.status.StatusLogger; @@ -77,7 +78,9 @@ public class Interpolator extends AbstractConfigurationAwareLookup { for (final Map.Entry> entry : plugins.entrySet()) { try { final Class clazz = entry.getValue().getPluginClass().asSubclass(StrLookup.class); - strLookupMap.put(entry.getKey().toLowerCase(), ReflectionUtil.instantiate(clazz)); + if (!clazz.getName().equals(JndiLookup.class.getName()) || JndiManager.isIsJndiEnabled()) { + strLookupMap.put(entry.getKey().toLowerCase(), ReflectionUtil.instantiate(clazz)); + } } catch (final Throwable t) { handleError(entry.getKey(), t); } @@ -106,12 +109,14 @@ public class Interpolator extends AbstractConfigurationAwareLookup { strLookupMap.put("lower", new LowerLookup()); strLookupMap.put("upper", new UpperLookup()); // JNDI - try { - // [LOG4J2-703] We might be on Android - strLookupMap.put(LOOKUP_KEY_JNDI, - Loader.newCheckedInstanceOf("org.apache.logging.log4j.core.lookup.JndiLookup", StrLookup.class)); - } catch (final LinkageError | Exception e) { - handleError(LOOKUP_KEY_JNDI, e); + if (JndiManager.isIsJndiEnabled()) { + try { + // [LOG4J2-703] We might be on Android + strLookupMap.put(LOOKUP_KEY_JNDI, + Loader.newCheckedInstanceOf("org.apache.logging.log4j.core.lookup.JndiLookup", StrLookup.class)); + } catch (final LinkageError | Exception e) { + handleError(LOOKUP_KEY_JNDI, e); + } } // JMX input args try { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java index 2d7604f..d946cd1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java @@ -73,6 +73,10 @@ public class JndiManager extends AbstractManager { private final DirContext context; + public static boolean isIsJndiEnabled() { + return PropertiesUtil.getProperties().getBooleanProperty("log4j2.enableJndi", false); + } + private JndiManager(final String name, final DirContext context, final List allowedHosts, final List allowedClasses, final List allowedProtocols) { super(null, name); @@ -82,6 +86,14 @@ public class JndiManager extends AbstractManager { this.allowedProtocols = allowedProtocols; } + private JndiManager(final String name) { + super(null, name); + this.context = null; + this.allowedProtocols = null; + this.allowedClasses = null; + this.allowedHosts = null; + } + /** * Gets the default JndiManager using the default {@link javax.naming.InitialContext}. * @@ -194,7 +206,10 @@ public class JndiManager extends AbstractManager { @Override protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { - return JndiCloser.closeSilently(this.context); + if (context != null) { + return JndiCloser.closeSilently(this.context); + } + return true; } /** @@ -207,6 +222,9 @@ public class JndiManager extends AbstractManager { */ @SuppressWarnings("unchecked") public synchronized T lookup(final String name) throws NamingException { + if (context == null) { + return null; + } try { URI uri = new URI(name); if (uri.getScheme() != null) { @@ -261,21 +279,25 @@ public class JndiManager extends AbstractManager { @Override public JndiManager createManager(final String name, final Properties data) { - String hosts = data != null ? data.getProperty(ALLOWED_HOSTS) : null; - String classes = data != null ? data.getProperty(ALLOWED_CLASSES) : null; - String protocols = data != null ? data.getProperty(ALLOWED_PROTOCOLS) : null; - List allowedHosts = new ArrayList<>(); - List allowedClasses = new ArrayList<>(); - List allowedProtocols = new ArrayList<>(); - addAll(hosts, allowedHosts, permanentAllowedHosts, ALLOWED_HOSTS, data); - addAll(classes, allowedClasses, permanentAllowedClasses, ALLOWED_CLASSES, data); - addAll(protocols, allowedProtocols, permanentAllowedProtocols, ALLOWED_PROTOCOLS, data); - try { - return new JndiManager(name, new InitialDirContext(data), allowedHosts, allowedClasses, - allowedProtocols); - } catch (final NamingException e) { - LOGGER.error("Error creating JNDI InitialContext.", e); - return null; + if (isIsJndiEnabled()) { + String hosts = data != null ? data.getProperty(ALLOWED_HOSTS) : null; + String classes = data != null ? data.getProperty(ALLOWED_CLASSES) : null; + String protocols = data != null ? data.getProperty(ALLOWED_PROTOCOLS) : null; + List allowedHosts = new ArrayList<>(); + List allowedClasses = new ArrayList<>(); + List allowedProtocols = new ArrayList<>(); + addAll(hosts, allowedHosts, permanentAllowedHosts, ALLOWED_HOSTS, data); + addAll(classes, allowedClasses, permanentAllowedClasses, ALLOWED_CLASSES, data); + addAll(protocols, allowedProtocols, permanentAllowedProtocols, ALLOWED_PROTOCOLS, data); + try { + return new JndiManager(name, new InitialDirContext(data), allowedHosts, allowedClasses, + allowedProtocols); + } catch (final NamingException e) { + LOGGER.error("Error creating JNDI InitialContext.", e); + return null; + } + } else { + return new JndiManager(name); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java index 09bd0a6..43afdb7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java @@ -93,6 +93,12 @@ public class JndiContextSelector implements NamedContextSelector { private static final StatusLogger LOGGER = StatusLogger.getLogger(); + public JndiContextSelector() { + if (!JndiManager.isIsJndiEnabled()) { + throw new IllegalStateException("JNDI must be enabled by setting log4j2.enableJndi=true"); + } + } + @Override public void shutdown(String fqcn, ClassLoader loader, boolean currentContext, boolean allContexts) { LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get(); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java index 9216ef8..daf2d0e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java @@ -49,6 +49,7 @@ import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.message.StringMapMessage; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -83,6 +84,11 @@ public class JmsAppenderTest { @Rule public RuleChain rules = RuleChain.outerRule(jndiRule).around(ctx); + @BeforeClass + public static void beforeClass() throws Exception { + System.setProperty("log4j2.enableJndi", "true"); + } + public JmsAppenderTest() throws Exception { // this needs to set up before LoggerContextRule given(connectionFactory.createConnection()).willReturn(connection); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java index 02a8a79..4ed02f2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java @@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.appender.routing; import java.io.File; import java.util.Collections; +import java.util.Map; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; @@ -29,6 +30,7 @@ import org.apache.logging.log4j.message.StructuredDataMessage; import org.apache.logging.log4j.test.appender.ListAppender; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.RuleChain; @@ -47,8 +49,12 @@ public class RoutingAppenderWithJndiTest { public static LoggerContextRule loggerContextRule = new LoggerContextRule("log4j-routing-by-jndi.xml"); @ClassRule - public static RuleChain rules = RuleChain.outerRule(new JndiRule(Collections.emptyMap())) - .around(loggerContextRule); + public static RuleChain rules = RuleChain.outerRule(new JndiRule(initBindings())).around(loggerContextRule); + + private static Map initBindings() { + System.setProperty("log4j2.enableJndi", "true"); + return Collections.emptyMap(); + } @Before public void before() throws NamingException { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java index 9e55563..7ce5fa7 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.junit.JndiRule; +import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.ExternalResource; @@ -48,12 +49,14 @@ public class InterpolatorTest { protected void before() throws Throwable { System.setProperty(TESTKEY, TESTVAL); System.setProperty(TESTKEY2, TESTVAL); + System.setProperty("log4j2.enableJndi", "true"); } @Override protected void after() { System.clearProperty(TESTKEY); System.clearProperty(TESTKEY2); + System.clearProperty("log4j2.enableJndi"); } }).around(new JndiRule( JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME, TEST_CONTEXT_NAME)); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java new file mode 100644 index 0000000..eb44bc6 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiDisabledLookupTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.lookup; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.junit.JndiRule; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * JndiDisabledLookupTest + * + * Verifies the Lookups are disabled without the log4j2.enableJndi property set to true. + */ +public class JndiDisabledLookupTest { + + private static final String TEST_CONTEXT_RESOURCE_NAME = "logging/context-name"; + private static final String TEST_CONTEXT_NAME = "app-1"; + private static final String TEST_INTEGRAL_NAME = "int-value"; + private static final int TEST_INTEGRAL_VALUE = 42; + private static final String TEST_STRINGS_NAME = "string-collection"; + private static final Collection TEST_STRINGS_COLLECTION = Arrays.asList("one", "two", "three"); + + @Rule + public JndiRule jndiRule = new JndiRule(createBindings()); + + private Map createBindings() { + final Map map = new HashMap<>(); + map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME, TEST_CONTEXT_NAME); + map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_INTEGRAL_NAME, TEST_INTEGRAL_VALUE); + map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_STRINGS_NAME, TEST_STRINGS_COLLECTION); + return map; + } + + @Test + public void testLookup() { + final StrLookup lookup = new JndiLookup(); + + String contextName = lookup.lookup(TEST_CONTEXT_RESOURCE_NAME); + assertNull(contextName); + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java index c2e34e3..530d1ee 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.logging.log4j.junit.JndiRule; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -42,6 +43,11 @@ public class JndiLookupTest { @Rule public JndiRule jndiRule = new JndiRule(createBindings()); + @BeforeClass + public static void beforeClass() { + System.setProperty("log4j2.enableJndi", "true"); + } + private Map createBindings() { final Map map = new HashMap<>(); map.put(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME, TEST_CONTEXT_NAME); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java index 032c9c4..5a6d0ac 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/JndiRestrictedLookupTest.java @@ -54,6 +54,7 @@ public class JndiRestrictedLookupTest { public static void beforeClass() { System.setProperty("log4j2.allowedLdapClasses", Level.class.getName()); System.setProperty("log4j2.allowedJndiProtocols", "dns"); + System.setProperty("log4j2.enableJndi", "true"); } @Test diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index 267f54f..bcf6232 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -1527,6 +1527,9 @@ public class ConnectionFactory {

The JMS Appender sends the formatted log event to a JMS Destination.

+

The JMS Appender requires JNDI support so as of release 2.15.1 this appender will not function unless + log4j2.enableJndi=truelog4j2.enableJndi=true is configured as a system property or environment + variable. See the enableJndi system property.

Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. Starting in Log4j 2.1, these appenders were combined into the JMS Appender which makes no distinction between queues diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm index 402a96c..69737de 100644 --- a/src/site/xdoc/manual/configuration.xml.vm +++ b/src/site/xdoc/manual/configuration.xml.vm @@ -1960,6 +1960,14 @@ public class AwesomeTest { before falling back to the default class loader. + + log4j2.enableJndi + LOG4J_ENABLE_JNDI + false + + When true, Log4j components that use JNDI are enabled. When false, the default, they are disabled. + + log4j2.allowedLdapClasses LOG4J_ALLOWED_LDAP_CLASSES diff --git a/src/site/xdoc/manual/logsep.xml b/src/site/xdoc/manual/logsep.xml index 55b59eb..6d8694a 100644 --- a/src/site/xdoc/manual/logsep.xml +++ b/src/site/xdoc/manual/logsep.xml @@ -111,6 +111,9 @@ to use JNDI to locate each web application's LoggerContext. Be sure to set the isLog4jContextSelectorNamed context parameter to true and also set the log4jContextName and log4jConfiguration context parameters. + Note that the JndiContextSelector will not work unless log4j2.enableJndi=true is set as a + system property or environment variable. See the + enableJndi system property.

diff --git a/src/site/xdoc/manual/lookups.xml b/src/site/xdoc/manual/lookups.xml index cc6a66f..70024ff 100644 --- a/src/site/xdoc/manual/lookups.xml +++ b/src/site/xdoc/manual/lookups.xml @@ -266,6 +266,11 @@ +

+ As of Log4j 2.15.1 JNDI operations require that log4j2.enableJndi=true be set as a system + property or the corresponding environment variable for this lookup to function. See the + enableJndi system property. +

The JndiLookup allows variables to be retrieved via JNDI. By default the key will be prefixed with java:comp/env/, however if the key contains a ":" no prefix will be added. -- 2.27.0