From 1ea18fd6bc69ecfdbffa2d526e4895d2b1cf4b2c Mon Sep 17 00:00:00 2001 From: idawda Date: Fri, 9 Aug 2024 16:39:04 +0530 Subject: [PATCH 1/3] NR-299885: Instrumentation support for GraphQL --- .../graphql-java-16.2/build.gradle | 22 +++++++++++++ .../java/graphql/GraphQL_Instrumentation.java | 32 +++++++++++++++++++ .../ParseAndValidate_Instrumentation.java | 9 ++++++ .../agent/security/schema/HttpRequest.java | 11 +++++++ .../schema/HttpRequestCustomDataTypeEnum.java | 8 +++++ settings.gradle | 3 +- 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 instrumentation-security/graphql-java-16.2/build.gradle create mode 100644 instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java create mode 100644 instrumentation-security/graphql-java-16.2/src/main/java/graphql/ParseAndValidate_Instrumentation.java create mode 100644 newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequestCustomDataTypeEnum.java diff --git a/instrumentation-security/graphql-java-16.2/build.gradle b/instrumentation-security/graphql-java-16.2/build.gradle new file mode 100644 index 000000000..2ac60f459 --- /dev/null +++ b/instrumentation-security/graphql-java-16.2/build.gradle @@ -0,0 +1,22 @@ +dependencies { + implementation(project(":newrelic-security-api")) + implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") + implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") + implementation("com.graphql-java:graphql-java:16.2") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.graphql-java-16.2' } +} + +verifyInstrumentation { + passesOnly('com.graphql-java:graphql-java:[16.0,)') + excludeRegex('com.graphql-java:graphql-java:(0.0.0|201|202).*') + excludeRegex('com.graphql-java:graphql-java:.*(vTEST|-beta|-alpha1|-nf-execution|-rc|-TEST).*') + exclude('com.graphql-java:graphql-java:15.0') +} + +site { + title 'GraphQL Java' + type 'Framework' +} diff --git a/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java b/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java new file mode 100644 index 000000000..235a47d4c --- /dev/null +++ b/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java @@ -0,0 +1,32 @@ +package graphql; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.HttpRequestCustomDataTypeEnum; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import graphql.execution.instrumentation.InstrumentationState; +import graphql.language.Document; +import graphql.schema.GraphQLSchema; + +import java.util.concurrent.CompletableFuture; + +@Weave(originalName = "graphql.GraphQL", type = MatchType.ExactClass) +public class GraphQL_Instrumentation { + + private CompletableFuture execute(ExecutionInput executionInput, Document document, GraphQLSchema graphQLSchema, InstrumentationState instrumentationState) { + try { + if (NewRelicSecurity.isHookProcessingActive()) { + HttpRequest request = NewRelicSecurity.getAgent().getSecurityMetaData().getRequest(); + if (executionInput.getQuery() != null && !executionInput.getQuery().isEmpty()) { + request.getCustomDataType().put("*.query", HttpRequestCustomDataTypeEnum.GRAPHQL_QUERY.name()); + } + if (executionInput.getQuery() != null && !executionInput.getVariables().isEmpty()) { + request.getCustomDataType().put("*.variables", HttpRequestCustomDataTypeEnum.GRAPHQL_VARIABLE.name()); + } + } + } catch (Exception ignored) {} + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/graphql-java-16.2/src/main/java/graphql/ParseAndValidate_Instrumentation.java b/instrumentation-security/graphql-java-16.2/src/main/java/graphql/ParseAndValidate_Instrumentation.java new file mode 100644 index 000000000..84c3ddf2b --- /dev/null +++ b/instrumentation-security/graphql-java-16.2/src/main/java/graphql/ParseAndValidate_Instrumentation.java @@ -0,0 +1,9 @@ +package graphql; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(originalName = "graphql.ParseAndValidate", type = MatchType.ExactClass) +public class ParseAndValidate_Instrumentation { + +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequest.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequest.java index 5b65ef0f6..f81bb66d8 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequest.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequest.java @@ -32,9 +32,13 @@ public class HttpRequest { private Map pathParameterMap; private boolean isRequestParsed; + private boolean isGrpc; + private String route; + private Map customDataType; + public HttpRequest() { this.clientIP = StringUtils.EMPTY; this.body = new StringBuilder(); @@ -50,6 +54,7 @@ public HttpRequest() { this.isRequestParsed = false; this.isGrpc = false; this.route = StringUtils.EMPTY; + this.customDataType = new HashMap<>(); } public HttpRequest(HttpRequest servletInfo) { @@ -67,6 +72,7 @@ public HttpRequest(HttpRequest servletInfo) { this.isRequestParsed = servletInfo.isRequestParsed; this.isGrpc = servletInfo.isGrpc; this.route = servletInfo.route; + this.customDataType = servletInfo.customDataType; } public String getMethod() { @@ -229,6 +235,11 @@ public void setRoute(String segment, boolean isAlreadyServlet) { this.route = Paths.get(this.route, formatedSegment).normalize().toString(); } } + + public Map getCustomDataType() { + return customDataType; + } + } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequestCustomDataTypeEnum.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequestCustomDataTypeEnum.java new file mode 100644 index 000000000..473eefc83 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/HttpRequestCustomDataTypeEnum.java @@ -0,0 +1,8 @@ +package com.newrelic.api.agent.security.schema; + +public enum HttpRequestCustomDataTypeEnum { + GRAPHQL_QUERY, + GRAPHQL_VARIABLE, + + NONE; +} diff --git a/settings.gradle b/settings.gradle index 5cbeccc44..d7bad818d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -209,4 +209,5 @@ include 'instrumentation:weblogic-12.2' include 'instrumentation:jedis-4.0.0' include 'instrumentation:jedis-3.0.0' include 'instrumentation:jedis-2.7.1_2.7.2' -include 'instrumentation:jedis-1.4.0' \ No newline at end of file +include 'instrumentation:jedis-1.4.0' +include 'instrumentation:graphql-java-16.2' \ No newline at end of file From 60a4bdbd1da727dffa319ee1b33957c805eb67fc Mon Sep 17 00:00:00 2001 From: idawda Date: Fri, 9 Aug 2024 18:37:46 +0530 Subject: [PATCH 2/3] NR-299885: Instrumentation support for GraphQL --- .../src/main/java/graphql/GraphQL_Instrumentation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java b/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java index 235a47d4c..bf6f1bbe8 100644 --- a/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java +++ b/instrumentation-security/graphql-java-16.2/src/main/java/graphql/GraphQL_Instrumentation.java @@ -22,7 +22,7 @@ private CompletableFuture execute(ExecutionInput executionInput if (executionInput.getQuery() != null && !executionInput.getQuery().isEmpty()) { request.getCustomDataType().put("*.query", HttpRequestCustomDataTypeEnum.GRAPHQL_QUERY.name()); } - if (executionInput.getQuery() != null && !executionInput.getVariables().isEmpty()) { + if (executionInput.getVariables() != null && !executionInput.getVariables().isEmpty()) { request.getCustomDataType().put("*.variables", HttpRequestCustomDataTypeEnum.GRAPHQL_VARIABLE.name()); } } From c1c18fa8ae07907ce84ebf13c3e495f589f8a6da Mon Sep 17 00:00:00 2001 From: idawda Date: Tue, 17 Sep 2024 12:29:23 +0530 Subject: [PATCH 3/3] Bump jsonVersion to 1.2.9 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9971d5819..14ae4b751 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # The agent version. agentVersion=1.4.1 -jsonVersion=1.2.5 +jsonVersion=1.2.9 # Updated exposed NR APM API version. nrAPIVersion=8.12.0