From 73f54c55807fdca273aa27421239c000e76f74e0 Mon Sep 17 00:00:00 2001 From: idawda Date: Tue, 24 Dec 2024 17:27:12 +0530 Subject: [PATCH] NR-353483: Fix instrumentation verifier failure for Apache Struts 2 support --- .../apache-struts2-7.0/build.gradle | 28 ++++++++++ .../apache/struts2/StrutsHelper.java | 52 +++++++++++++++++++ .../config/Configuration_Instrumentation.java | 24 +++++++++ .../DefaultActionMapper_Instrumentation.java | 18 +++++++ .../apache-struts2/build.gradle | 2 +- settings.gradle | 1 + 6 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 instrumentation-security/apache-struts2-7.0/build.gradle create mode 100644 instrumentation-security/apache-struts2-7.0/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java create mode 100644 instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/config/Configuration_Instrumentation.java create mode 100644 instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java diff --git a/instrumentation-security/apache-struts2-7.0/build.gradle b/instrumentation-security/apache-struts2-7.0/build.gradle new file mode 100644 index 000000000..960e51354 --- /dev/null +++ b/instrumentation-security/apache-struts2-7.0/build.gradle @@ -0,0 +1,28 @@ +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.struts:struts2-core:7.0.0'){transitive = false} + implementation("jakarta.servlet:jakarta.servlet-api:5.0.0"){transitive = false} +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.apache-struts2-7.0' } +} + +verifyInstrumentation { + passes 'org.apache.struts:struts2-core:[7.0.0,)' + excludeRegex '.*[-atlassian|BETA].*' +} + + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +site { + title 'Struts2' + type 'Framework' +} diff --git a/instrumentation-security/apache-struts2-7.0/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java b/instrumentation-security/apache-struts2-7.0/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java new file mode 100644 index 000000000..95846fe2a --- /dev/null +++ b/instrumentation-security/apache-struts2-7.0/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java @@ -0,0 +1,52 @@ +package com.newrelic.agent.security.instrumentation.apache.struts2; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper; +import com.newrelic.api.agent.security.schema.ApplicationURLMapping; +import com.newrelic.api.agent.security.schema.Framework; +import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.struts2.config.ConfigurationManager; +import org.apache.struts2.config.RuntimeConfiguration; +import org.apache.struts2.config.entities.ActionConfig; +import org.apache.struts2.dispatcher.mapper.ActionMapping; + +import java.util.Map; + +public class StrutsHelper { + + private static final String APACHE_STRUTS2 = "APACHE-STRUTS2-7.0"; + + public static void gatherURLMappings(RuntimeConfiguration runtimeConfig) { + try { + Map> namespaces = runtimeConfig.getActionConfigs(); + for (Map.Entry> namespace : namespaces.entrySet()) { + String url = namespace.getKey(); + for (ActionConfig actionConfig : namespace.getValue().values()) { + String mapping = StringUtils.appendIfMissing(url, URLMappingsHelper.SEPARATOR) + actionConfig.getName(); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, mapping, actionConfig.getClassName())); + } + } + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, APACHE_STRUTS2, e.getMessage()), e, StrutsHelper.class.getName()); + } + } + + public static void setRoute(ActionMapping mapping, ConfigurationManager configManager) { + if (!NewRelicSecurity.isHookProcessingActive()){ + return; + } + try { + if (mapping != null && mapping.getNamespace() != null && configManager.getConfiguration() != null && configManager.getConfiguration().getRuntimeConfiguration() != null){ + ActionConfig actionConfig = configManager.getConfiguration().getRuntimeConfiguration().getActionConfig(mapping.getNamespace(), mapping.getName()); + if (actionConfig != null){ + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(StringUtils.appendIfMissing(mapping.getNamespace(), URLMappingsHelper.SEPARATOR) + actionConfig.getName()); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.APACHE_STRUTS2); + } + } + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, APACHE_STRUTS2, e.getMessage()), e, StrutsHelper.class.getName()); + } + } +} diff --git a/instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/config/Configuration_Instrumentation.java b/instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/config/Configuration_Instrumentation.java new file mode 100644 index 000000000..92f1f3d7d --- /dev/null +++ b/instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/config/Configuration_Instrumentation.java @@ -0,0 +1,24 @@ +package org.apache.struts2.config; + +import com.newrelic.agent.security.instrumentation.apache.struts2.StrutsHelper; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import java.util.List; + +@Weave(type = MatchType.Interface, originalName = "org.apache.struts2.config.Configuration") +public abstract class Configuration_Instrumentation { + + abstract public RuntimeConfiguration getRuntimeConfiguration(); + + public List reloadContainer(List containerProviders) throws ConfigurationException { + List returnVal; + try { + returnVal = Weaver.callOriginal(); + } finally { + StrutsHelper.gatherURLMappings(getRuntimeConfiguration()); + } + return returnVal; + } +} diff --git a/instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java b/instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java new file mode 100644 index 000000000..ebb1f1d6f --- /dev/null +++ b/instrumentation-security/apache-struts2-7.0/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java @@ -0,0 +1,18 @@ +package org.apache.struts2.dispatcher.mapper; + +import com.newrelic.agent.security.instrumentation.apache.struts2.StrutsHelper; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.struts2.config.ConfigurationManager; + +@Weave(originalName = "org.apache.struts2.dispatcher.mapper.ActionMapper", type = MatchType.Interface) +public class DefaultActionMapper_Instrumentation { + + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + ActionMapping mapping = Weaver.callOriginal(); + StrutsHelper.setRoute(mapping, configManager); + return mapping; + } +} diff --git a/instrumentation-security/apache-struts2/build.gradle b/instrumentation-security/apache-struts2/build.gradle index dfdbd95e5..953544204 100644 --- a/instrumentation-security/apache-struts2/build.gradle +++ b/instrumentation-security/apache-struts2/build.gradle @@ -11,7 +11,7 @@ jar { } verifyInstrumentation { - passesOnly 'org.apache.struts:struts2-core:[2.1.2,)' + passes 'org.apache.struts:struts2-core:[2.1.2,7.0.0)' excludeRegex 'org.apache.struts:struts2-core:2.3.15.1-atlassian-[4-5]$' } diff --git a/settings.gradle b/settings.gradle index afec08f66..3fcb7e2e3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -175,6 +175,7 @@ include 'instrumentation:resteasy-3' include 'instrumentation:resteasy-4' include 'instrumentation:jersey' include 'instrumentation:apache-struts2' +include 'instrumentation:apache-struts2-7.0' include 'instrumentation:spring-webflux' include 'instrumentation:spring-webmvc-3.1.0' include 'instrumentation:spring-webmvc-5.3.0'