From 09baf361c8b2a4caff314249b4e9e3488a0153d9 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Tue, 17 Sep 2024 19:06:39 -0700 Subject: [PATCH 1/2] Ensure that LabKey's log4j2.xml file is used --- .../labkey/embedded/LabKeySpringBootClassLoader.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java b/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java index 137fbd0686..5c32e1ca2b 100644 --- a/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java +++ b/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java @@ -4,7 +4,9 @@ import java.io.IOException; import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.List; @@ -23,6 +25,14 @@ public LabKeySpringBootClassLoader() public LabKeySpringBootClassLoader(ClassLoader parent) { super(parent); + + // HACK: This ensures that the "embedded" URLs get added first, so our canonical log4j2.xml file is found even + // if dependencies include their own version. See Issue 51286. + if (parent instanceof URLClassLoader ucl) + { + Arrays.stream(ucl.getURLs()) + .forEach(this::addURL); + } } @Override @@ -50,7 +60,7 @@ public Enumeration getResources(String name) throws IOException // Eventually we should shift to only configuring and loading SLF4J and Log4J via Spring Boot and not // from inside the webapp. if (name.equalsIgnoreCase("META-INF/services/org.apache.logging.log4j.util.PropertySource") || - name.equalsIgnoreCase("META-INF/services/org.apache.logging.log4j.spi.Provider") || + name.equalsIgnoreCase("META-INF/services/org.apache.logging.log4j.spi.Provider") || name.equalsIgnoreCase("META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat")) { List urls = new ArrayList<>(); From c8295940327331272d4faea7396af321494c4182 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Wed, 18 Sep 2024 10:30:54 -0700 Subject: [PATCH 2/2] New and improved (?) approach. Add only URLs that resolve to a log4j2.xml file. Avoid ContentSecurityPolicyFilter and other classes we don't want. --- .../embedded/LabKeySpringBootClassLoader.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java b/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java index 5c32e1ca2b..3a8301817d 100644 --- a/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java +++ b/server/embedded/src/org/labkey/embedded/LabKeySpringBootClassLoader.java @@ -1,8 +1,10 @@ package org.labkey.embedded; +import org.jboss.logging.Logger; import org.labkey.bootstrap.LabKeyBootstrapClassLoader; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -17,6 +19,8 @@ */ public class LabKeySpringBootClassLoader extends LabKeyBootstrapClassLoader { + private static final Logger LOG = Logger.getLogger(LabKeySpringBootClassLoader.class); + public LabKeySpringBootClassLoader() { super(); @@ -26,12 +30,26 @@ public LabKeySpringBootClassLoader(ClassLoader parent) { super(parent); - // HACK: This ensures that the "embedded" URLs get added first, so our canonical log4j2.xml file is found even - // if dependencies include their own version. See Issue 51286. + // HACK: This ensures that the jar containing our canonical log4j2.xml file gets added first, so it's found + // even if dependencies include their own version. See Issue 51286. if (parent instanceof URLClassLoader ucl) { Arrays.stream(ucl.getURLs()) - .forEach(this::addURL); + .forEach(url -> { + // Test this url via a class loader with no parent; if URL resolves a log4j2.xml file, add it and log. + try (URLClassLoader loader = new URLClassLoader(new URL[]{url}, null); InputStream is = loader.getResourceAsStream("log4j2.xml")) + { + if (is != null) + { + addURL(url); + LOG.info("Added URL that resolves log4j2.xml to class loader: " + url); + } + } + catch (IOException e) + { + throw new RuntimeException(e); + } + }); } }