From 149bbc2f8da5512312567de53fe636681e46199a Mon Sep 17 00:00:00 2001 From: idawda Date: Wed, 25 Sep 2024 17:14:28 +0530 Subject: [PATCH] NR-313390: Route detection support for Apache Struts2 Framework --- .../apache-struts2/build.gradle | 2 +- .../apache/struts2/StrutsHelper.java | 28 ++++++++++++++++--- .../DefaultActionMapper_Instrumentation.java | 19 +++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 instrumentation-security/apache-struts2/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java diff --git a/instrumentation-security/apache-struts2/build.gradle b/instrumentation-security/apache-struts2/build.gradle index c6d47ff7e..dfdbd95e5 100644 --- a/instrumentation-security/apache-struts2/build.gradle +++ b/instrumentation-security/apache-struts2/build.gradle @@ -3,6 +3,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation('org.apache.struts:struts2-core:6.1.2') + implementation("javax.servlet:javax.servlet-api:4.0.1") } jar { @@ -10,7 +11,6 @@ jar { } verifyInstrumentation { - passesOnly 'org.apache.struts.xwork:xwork-core:[0,)' passesOnly 'org.apache.struts:struts2-core:[2.1.2,)' excludeRegex 'org.apache.struts:struts2-core:2.3.15.1-atlassian-[4-5]$' } diff --git a/instrumentation-security/apache-struts2/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java b/instrumentation-security/apache-struts2/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java index 4a278c1cd..6b509fe1d 100644 --- a/instrumentation-security/apache-struts2/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java +++ b/instrumentation-security/apache-struts2/src/main/java/com/newrelic/agent/security/instrumentation/apache/struts2/StrutsHelper.java @@ -3,29 +3,49 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.instrumentation.helpers.*; +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 com.opensymphony.xwork2.config.ConfigurationManager; import com.opensymphony.xwork2.config.RuntimeConfiguration; import com.opensymphony.xwork2.config.entities.ActionConfig; +import org.apache.struts2.dispatcher.mapper.ActionMapping; + import java.util.Map; public class StrutsHelper { - private static final String SEPARATOR = "/"; - private static final String WILDCARD = "*"; private static final String APACHE_STRUTS2 = "APACHE-STRUTS2"; + 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, SEPARATOR) + actionConfig.getName(); - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, mapping, actionConfig.getClassName())); + String mapping = StringUtils.appendIfMissing(url, URLMappingsHelper.SEPARATOR) + actionConfig.getName(); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, mapping, actionConfig.getClassName())); } } } catch (Exception ignored){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, APACHE_STRUTS2, ignored.getMessage()), ignored, 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 ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, APACHE_STRUTS2, ignored.getMessage()), ignored, StrutsHelper.class.getName()); + } + } } diff --git a/instrumentation-security/apache-struts2/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java b/instrumentation-security/apache-struts2/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java new file mode 100644 index 000000000..f0a304b2b --- /dev/null +++ b/instrumentation-security/apache-struts2/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper_Instrumentation.java @@ -0,0 +1,19 @@ +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 com.opensymphony.xwork2.config.ConfigurationManager; + +import javax.servlet.http.HttpServletRequest; + +@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; + } +}