Skip to content

Commit

Permalink
NR-313392: Route detection support for Grails Framework
Browse files Browse the repository at this point in the history
  • Loading branch information
IshikaDawda committed Sep 26, 2024
1 parent 8691619 commit fd596ec
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,4 +22,16 @@ public static void gatherUrlMappings(Map<String, String> 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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String> 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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,37 @@
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 java.lang.reflect.Method;
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<String, Method> 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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@

@Weave(type = MatchType.ExactClass, originalName = "org.grails.core.DefaultGrailsControllerClass")
public abstract class DefaultGrailsController_Instrumentation {

private Map<String, Method> 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<ApplicationURLMapping> mappings = ConcurrentHashMap.newKeySet();

private static final Set<String> defaultHandlers = new HashSet<String>() {{
add("org.eclipse.jetty.jsp.JettyJspServlet");
add("org.eclipse.jetty.servlet.ServletHandler$Default404Servlet");
Expand All @@ -40,14 +44,19 @@ 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<ApplicationURLMapping> getApplicationURLMappings() {
return mappings;
}

private static Set<Integer> handlers = ConcurrentHashMap.newKeySet();

private static Set<RouteSegments> routeSegments = new TreeSet<>(new RouteComparator());

public static Set<Integer> getHandlersHash() {
return handlers;
}
Expand Down Expand Up @@ -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, "*");
}
Expand All @@ -106,6 +116,7 @@ public static List<String> 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;
Expand Down

0 comments on commit fd596ec

Please sign in to comment.