diff --git a/Changelog.md b/Changelog.md index 80959a77e..3b8428290 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.5-public-preview] - To Be Decided ### Changes +- [INSTRUMENTATION] Support for Apache log4j 3.0.0-alpha1 (new version released on 21 June 2023) ## [1.0.4-public-preview] - 2023-06-20 ### Changes diff --git a/instrumentation-security/apache-log4j-3.0.0/build.gradle b/instrumentation-security/apache-log4j-3.0.0/build.gradle new file mode 100644 index 000000000..bc2e57321 --- /dev/null +++ b/instrumentation-security/apache-log4j-3.0.0/build.gradle @@ -0,0 +1,25 @@ +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.apache-log4j' } +} + +dependencies { + implementation(project(":newrelic-security-api")) + implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") + implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") + implementation("org.apache.logging.log4j:log4j-core:3.0.0-alpha1") +} + +verifyInstrumentation { + passes("org.apache.logging.log4j:log4j-core:[3.0.0-alpha1,)") +} + +site { + title 'Log4j' + type 'Framework' +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} diff --git a/instrumentation-security/apache-log4j-3.0.0/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor_Instrumentation.java b/instrumentation-security/apache-log4j-3.0.0/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor_Instrumentation.java new file mode 100644 index 000000000..9fbe296bf --- /dev/null +++ b/instrumentation-security/apache-log4j-3.0.0/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor_Instrumentation.java @@ -0,0 +1,25 @@ +package org.apache.logging.log4j.core.lookup; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.helper.Log4JStrSubstitutor; +import com.newrelic.api.agent.security.utils.UserDataTranslationHelper; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.logging.log4j.core.LogEvent; + +@Weave(type = MatchType.BaseClass, originalName = "org.apache.logging.log4j.core.lookup.StrSubstitutor") +public class StrSubstitutor_Instrumentation { + + protected String resolveVariable(final LogEvent event, final String variableName, final StringBuilder buf, + final int startPos, final int endPos) { + if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + Log4JStrSubstitutor substitutor = new Log4JStrSubstitutor(variableName, buf, startPos, endPos); + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(UserDataTranslationHelper.getAttributeName(Log4JStrSubstitutor.class.getName()), substitutor); + } + return Weaver.callOriginal(); + } + + +} diff --git a/instrumentation-security/apache-log4j-3.0.0/src/test/java/com/nr/instrumentation/security/log4j/Log4jTest.java b/instrumentation-security/apache-log4j-3.0.0/src/test/java/com/nr/instrumentation/security/log4j/Log4jTest.java new file mode 100644 index 000000000..f8c1ae050 --- /dev/null +++ b/instrumentation-security/apache-log4j-3.0.0/src/test/java/com/nr/instrumentation/security/log4j/Log4jTest.java @@ -0,0 +1,175 @@ +package com.nr.instrumentation.security.log4j; + +import com.newrelic.agent.security.introspec.InstrumentationTestConfig; +import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner; +import com.newrelic.agent.security.introspec.SecurityIntrospector; +import com.newrelic.api.agent.security.schema.helper.Log4JStrSubstitutor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.lookup.StrSubstitutor; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +@RunWith(SecurityInstrumentationTestRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@InstrumentationTestConfig(includePrefixes = "org.apache.logging.log4j.core", configName = "application_logging_context_data_enabled.yml") +public class Log4jTest { + private final Logger logger = LogManager.getLogger(Log4jTest.class); + private static final Map MAP = new HashMap<>(); + private final String SOURCE = " ${Key} "; + private final Log4JStrSubstitutor EXPECTED = new Log4JStrSubstitutor("Key", new StringBuilder(" value "), 1, 7); + + @BeforeClass + public static void setLogLevel() { + MAP.put("Key", "value"); + } + + @Test + public void testResolveVariable() { + Properties info = new Properties(); + info.setProperty("Key", "value"); + String str = StrSubstitutor.replace(SOURCE, info); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable1() { + String str = StrSubstitutor.replace(SOURCE, MAP); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable2() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(SOURCE); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actaul = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actaul); + } + + @Test + public void testResolveVariable3() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(SOURCE, 0, SOURCE.length()); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable4() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(SOURCE.toCharArray()); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable5() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(SOURCE.toCharArray(), 0, SOURCE.length()); + logger.error(str); + + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable6() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(new StringBuffer(SOURCE)); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable7() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(new StringBuffer(SOURCE), 0, SOURCE.length()); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable8() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(new StringBuilder(SOURCE)); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable9() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + String str = substitutor.replace(new StringBuilder(SOURCE), 0, SOURCE.length()); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable10() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + boolean str = substitutor.replaceIn(new StringBuilder(SOURCE)); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + @Test + public void testResolveVariable11() { + StrSubstitutor substitutor = new StrSubstitutor(MAP); + boolean str = substitutor.replaceIn(new StringBuilder(SOURCE), 1, SOURCE.length()-1); + logger.error(str); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + Log4JStrSubstitutor actual = introspector.getLog4JStrSubstitutor(); + assertLog4JStrSubstitutor(EXPECTED, actual); + } + + + private void assertLog4JStrSubstitutor(Log4JStrSubstitutor expected, Log4JStrSubstitutor actual) { + Assert.assertEquals("Invalid variable name", expected.getVariableName(), actual.getVariableName()); + Assert.assertEquals("Invalid buffer value", expected.getBuf().toString(), actual.getBuf().toString()); + Assert.assertEquals("Wrong Start position of variable", expected.getStartPos(), actual.getStartPos()); + Assert.assertEquals("Wrong end position of variable", expected.getEndPos(), actual.getEndPos()); + } +} \ No newline at end of file diff --git a/instrumentation-security/apache-log4j-3.0.0/src/test/resources/application_logging_context_data_enabled.yml b/instrumentation-security/apache-log4j-3.0.0/src/test/resources/application_logging_context_data_enabled.yml new file mode 100644 index 000000000..1212edc2e --- /dev/null +++ b/instrumentation-security/apache-log4j-3.0.0/src/test/resources/application_logging_context_data_enabled.yml @@ -0,0 +1,12 @@ +common: &default_settings + application_logging: + enabled: true + forwarding: + enabled: true + max_samples_stored: 10000 + context_data: + enabled: true + metrics: + enabled: true + local_decorating: + enabled: false diff --git a/instrumentation-security/apache-log4j-3.0.0/src/test/resources/application_logging_enabled.yml b/instrumentation-security/apache-log4j-3.0.0/src/test/resources/application_logging_enabled.yml new file mode 100644 index 000000000..583ffd2bb --- /dev/null +++ b/instrumentation-security/apache-log4j-3.0.0/src/test/resources/application_logging_enabled.yml @@ -0,0 +1,10 @@ +common: &default_settings + application_logging: + enabled: true + forwarding: + enabled: true + max_samples_stored: 10000 + metrics: + enabled: true + local_decorating: + enabled: false diff --git a/settings.gradle b/settings.gradle index d97187553..60b7618c1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -108,6 +108,7 @@ include 'instrumentation:graalvm-jsinjection-19.0.0' include 'instrumentation:graalvm-jsinjection-22.0.0' include 'instrumentation:apache-log4j-2.0' include 'instrumentation:apache-log4j-2.17.2' +include 'instrumentation:apache-log4j-3.0.0' include 'instrumentation:saxpath' include 'instrumentation:javax-xpath' include 'instrumentation:akka-http-core-2.11_10.0.11'