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; + } +} diff --git a/instrumentation-security/grails-1.3/src/main/java/com/newrelic/agent/security/instrumentation/grails13/GrailsHelper.java b/instrumentation-security/grails-1.3/src/main/java/com/newrelic/agent/security/instrumentation/grails13/GrailsHelper.java index 51c4a9496..51ffd541f 100644 --- a/instrumentation-security/grails-1.3/src/main/java/com/newrelic/agent/security/instrumentation/grails13/GrailsHelper.java +++ b/instrumentation-security/grails-1.3/src/main/java/com/newrelic/agent/security/instrumentation/grails13/GrailsHelper.java @@ -4,6 +4,7 @@ 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.utils.logging.LogLevel; import java.util.Map; @@ -21,4 +22,16 @@ public static void gatherUrlMappings(Map uri2viewMap, String han NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, GRAILS_13, ignored.getMessage()), ignored, GrailsHelper.class.getName()); } } + + public static void setRoute(String uri) { + if (!NewRelicSecurity.isHookProcessingActive()){ + return; + } + try { + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(uri); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.GRAILS); + } catch (Exception ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, GRAILS_13, ignored.getMessage()), ignored, GrailsHelper.class.getName()); + } + } } diff --git a/instrumentation-security/grails-1.3/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java b/instrumentation-security/grails-1.3/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java index e936a10c6..8d1b63808 100644 --- a/instrumentation-security/grails-1.3/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java +++ b/instrumentation-security/grails-1.3/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java @@ -19,4 +19,12 @@ public abstract class DefaultGrailsController_Instrumentation { public DefaultGrailsController_Instrumentation() { GrailsHelper.gatherUrlMappings(uri2viewMap, getClazz().getName()); } + + public String getViewByURI(String uri) { + String view = Weaver.callOriginal(); + if (view != null) { + GrailsHelper.setRoute(uri); + } + return view; + } } diff --git a/instrumentation-security/grails-2.0/src/main/java/com/newrelic/agent/security/instrumentation/grails2/GrailsHelper.java b/instrumentation-security/grails-2.0/src/main/java/com/newrelic/agent/security/instrumentation/grails2/GrailsHelper.java index c448abb85..32edabbb1 100644 --- a/instrumentation-security/grails-2.0/src/main/java/com/newrelic/agent/security/instrumentation/grails2/GrailsHelper.java +++ b/instrumentation-security/grails-2.0/src/main/java/com/newrelic/agent/security/instrumentation/grails2/GrailsHelper.java @@ -4,21 +4,33 @@ 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.utils.logging.LogLevel; import java.util.Map; public class GrailsHelper { - private static final String WILDCARD = "*"; private static final String GRAILS_20 = "GRAILS-2.0"; public static void gatherUrlMappings( Map uri2viewMap, String handler) { try { for (String path : uri2viewMap.keySet()) { - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, path, handler)); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, path, handler)); } } catch (Exception ignored){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, GRAILS_20, ignored.getMessage()), ignored, GrailsHelper.class.getName()); } } + + public static void setRoute(String uri) { + if (!NewRelicSecurity.isHookProcessingActive()){ + return; + } + try { + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(uri); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.GRAILS); + } catch (Exception ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, GRAILS_20, ignored.getMessage()), ignored, GrailsHelper.class.getName()); + } + } } diff --git a/instrumentation-security/grails-2.0/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java b/instrumentation-security/grails-2.0/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java index 8f88fb90b..cd8d5ed42 100644 --- a/instrumentation-security/grails-2.0/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java +++ b/instrumentation-security/grails-2.0/src/main/java/org/codehaus/groovy/grails/commons/DefaultGrailsController_Instrumentation.java @@ -21,4 +21,12 @@ public void initialize() { GrailsHelper.gatherUrlMappings(uri2viewMap, getClazz().getName()); } } + + public String getViewByURI(String uri) { + String view = Weaver.callOriginal(); + if (view != null) { + GrailsHelper.setRoute(uri); + } + return view; + } } diff --git a/instrumentation-security/grails-3.0/src/main/java/com/newrelic/agent/security/instrumentation/grails3/GrailsHelper.java b/instrumentation-security/grails-3.0/src/main/java/com/newrelic/agent/security/instrumentation/grails3/GrailsHelper.java index faec20690..b1823ac2b 100644 --- a/instrumentation-security/grails-3.0/src/main/java/com/newrelic/agent/security/instrumentation/grails3/GrailsHelper.java +++ b/instrumentation-security/grails-3.0/src/main/java/com/newrelic/agent/security/instrumentation/grails3/GrailsHelper.java @@ -4,6 +4,7 @@ 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; @@ -11,19 +12,29 @@ import java.util.Map; public class GrailsHelper { - private static final String WILDCARD = "*"; private static final String GRAILS_30 = "GRAILS-3.0"; + public static void gatherUrlMappings(Map actions, String handler, String controller) { try { String path = StringUtils.prependIfMissing(controller, StringUtils.SEPARATOR); for (String action : actions.keySet()) { String finalPath = StringUtils.appendIfMissing(path, StringUtils.SEPARATOR) + action; - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, finalPath, handler)); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, finalPath, handler)); } - // for default action mappings - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, path, handler)); } catch(Throwable ignored) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, GRAILS_30, ignored.getMessage()), ignored, GrailsHelper.class.getName()); } } + + public static void setRoute(String name, String action) { + if (!NewRelicSecurity.isHookProcessingActive()){ + return; + } + try { + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(StringUtils.appendIfMissing(name, URLMappingsHelper.SEPARATOR) + action); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.GRAILS); + } catch (Exception ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, GRAILS_30, ignored.getMessage()), ignored, GrailsHelper.class.getName()); + } + } } diff --git a/instrumentation-security/grails-3.0/src/main/java/org/grails/core/DefaultGrailsController_Instrumentation.java b/instrumentation-security/grails-3.0/src/main/java/org/grails/core/DefaultGrailsController_Instrumentation.java index a0f86b79e..cc62eccb4 100644 --- a/instrumentation-security/grails-3.0/src/main/java/org/grails/core/DefaultGrailsController_Instrumentation.java +++ b/instrumentation-security/grails-3.0/src/main/java/org/grails/core/DefaultGrailsController_Instrumentation.java @@ -11,12 +11,20 @@ @Weave(type = MatchType.ExactClass, originalName = "org.grails.core.DefaultGrailsControllerClass") public abstract class DefaultGrailsController_Instrumentation { + private Map actions = Weaver.callOriginal(); + abstract public Class getClazz(); + abstract public String getName(); @WeaveAllConstructors public DefaultGrailsController_Instrumentation() { GrailsHelper.gatherUrlMappings(actions, getClazz().getName(), getName()); } + + public Object invoke(Object controller, String action) throws Throwable { + GrailsHelper.setRoute(getName(), action); + return Weaver.callOriginal(); + } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/URLMappingsHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/URLMappingsHelper.java index ec9aefcdc..d38c4c8f7 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/URLMappingsHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/URLMappingsHelper.java @@ -17,9 +17,13 @@ public class URLMappingsHelper { public static final String SEPARATOR = "/"; + public static final String WILDCARD = "*"; + public static final String subResourceSegment = "/*"; + private static Set mappings = ConcurrentHashMap.newKeySet(); + private static final Set defaultHandlers = new HashSet() {{ add("org.eclipse.jetty.jsp.JettyJspServlet"); add("org.eclipse.jetty.servlet.ServletHandler$Default404Servlet"); @@ -40,6 +44,9 @@ public class URLMappingsHelper { add("weblogic.management.rest.JerseyServlet"); add("com.caucho.jsp.XtpServlet"); add("com.caucho.jsp.JspServlet"); + add("org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet"); + add("org.codehaus.groovy.grails.web.pages.GroovyPagesServlet"); + add("org.codehaus.groovy.grails.web.servlet.ErrorHandlingServlet"); }}; public static Set getApplicationURLMappings() { @@ -47,7 +54,9 @@ public static Set getApplicationURLMappings() { } private static Set handlers = ConcurrentHashMap.newKeySet(); + private static Set routeSegments = new TreeSet<>(new RouteComparator()); + public static Set getHandlersHash() { return handlers; } @@ -90,6 +99,7 @@ private static boolean isPathParam(String path) { StringUtils.equals(path,"*") || (StringUtils.startsWith(path, "{") && StringUtils.endsWith(path, "}")); } + private static boolean allowMultiSegments(String path) { return StringUtils.equals(path, "*"); } @@ -106,6 +116,7 @@ public static List getSegments(String endpoint) { } return segments; } + public static int getSegmentCount(String path){ Path normalizedPath = Paths.get(StringUtils.prependIfMissing(StringUtils.removeEnd(path, StringUtils.SEPARATOR), StringUtils.SEPARATOR)).normalize(); int i = 0;