diff --git a/.github/workflows/publish-release-to-maven.yml b/.github/workflows/publish-release-to-maven.yml index 3a2deecbf..1aae7301b 100644 --- a/.github/workflows/publish-release-to-maven.yml +++ b/.github/workflows/publish-release-to-maven.yml @@ -12,8 +12,8 @@ jobs: with: apm-repo: 'k2io/newrelic-java-agent' apm-source-ref: 'csec-dev' - csec-run-unittest: 'true' - csec-run-instrumentation-verify: 'true' + csec-run-unittest: 'false' + csec-run-instrumentation-verify: 'false' is-release: 'true' version-suffix: '' slack-notify: 'true' \ No newline at end of file diff --git a/Changelog.md b/Changelog.md index 4a1b5233d..3ec4c627e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,33 @@ Noteworthy changes to the agent are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.1] - 2024-8-14 +### Adds +- [PR-296](https://github.com/newrelic/csec-java-agent/pull/296) Apache Solr Support: The security agent now also supports Apache Solr Version 4.0.0 and above. [NR-288599](https://new-relic.atlassian.net/browse/NR-288599) +- [PR-275](https://github.com/newrelic/csec-java-agent/pull/275) The maximum permissible size for a request body for scan will be set at 500KB. [NR-174195](https://new-relic.atlassian.net/browse/NR-174195) +- [PR-306](https://github.com/newrelic/csec-java-agent/pull/306) Add csec prefix to all instrumentation Jar, this resolves CVE flagged by third party scanners on our instrumentation JARs. [NR-289249](https://new-relic.atlassian.net/browse/NR-289249) +- [PR-303](https://github.com/newrelic/csec-java-agent/pull/303) Honour OFF Flag, Handle Boolean values for config log_level. [NR-293102](https://new-relic.atlassian.net/browse/NR-293102) +- [PR-299](https://github.com/newrelic/csec-java-agent/pull/299) Support Authentication capabilities for Proxy Settings. [NR-283945](https://new-relic.atlassian.net/browse/NR-283945) +- [PR-313](https://github.com/newrelic/csec-java-agent/pull/313) Processing of the security agent will persist even if the creation of the security home directory encounters an issue. [NR-297206](https://new-relic.atlassian.net/browse/NR-297206) +- [PR-277](https://github.com/newrelic/csec-java-agent/pull/277) Improve Management of Log file size and its count. [NR-272900](https://new-relic.atlassian.net/browse/NR-272900) +- [PR-314](https://github.com/newrelic/csec-java-agent/pull/314) Report error to Error Inbox upon connection failure to Security Engine. [NR-299700](https://new-relic.atlassian.net/browse/NR-299700) +- [PR-316](https://github.com/newrelic/csec-java-agent/pull/316) Detailed IAST Scan metric reporting via HealthCheck. [NR-267166](https://new-relic.atlassian.net/browse/NR-267166) +- [PR-302](https://github.com/newrelic/csec-java-agent/pull/302) Detect API Endpoint of the Application for Vertx Framework. [NR-287771](https://new-relic.atlassian.net/browse/NR-287771) +- [PR-293](https://github.com/newrelic/csec-java-agent/pull/293), [PR-284](https://github.com/newrelic/csec-java-agent/pull/284), [PR-302](https://github.com/newrelic/csec-java-agent/pull/302) Detect route of an incoming request for mule server, play framework and Vertx Framework. [NR-283915](https://new-relic.atlassian.net/browse/NR-283915), [NR-265915](https://new-relic.atlassian.net/browse/NR-265915), [NR-287771](https://new-relic.atlassian.net/browse/NR-287771) + +### Changes +- [PR-265](https://github.com/newrelic/csec-java-agent/pull/265) Improve Secure Cookie event reporting to provide detailed vulnerability. [NR-273609](https://new-relic.atlassian.net/browse/NR-273609) +- [PR-283](https://github.com/newrelic/csec-java-agent/pull/283) Update IAST Header Parsing Minimum Expected Length Set to 8. [NR-282647](https://new-relic.atlassian.net/browse/NR-282647) +- [PR-308](https://github.com/newrelic/csec-java-agent/pull/308) Remove jackson-dataformat-properties to address [CVE-2023-3894](https://www.cve.org/CVERecord?id=CVE-2023-3894) and exclude transitive dependency junit to address [CVE-2020-15250](https://www.cve.org/CVERecord?id=CVE-2020-15250) [NR-295033](https://new-relic.atlassian.net/browse/NR-295033) + +### Fixes +- [PR-292](https://github.com/newrelic/csec-java-agent/pull/292) Fix for ClassNotFoundException observed in glassfish server [NR-262453](https://new-relic.atlassian.net/browse/NR-262453) +- [PR-286](https://github.com/newrelic/csec-java-agent/pull/286) Detect correct user class in Netty Reactor Server [NR-253551](https://new-relic.atlassian.net/browse/NR-253551) +- [PR-317](https://github.com/newrelic/csec-java-agent/pull/317) Add a workaround for an issue where New Relic Security Agent breaks the gRPC endpoints [#130](https://github.com/newrelic/csec-java-agent/issues/310). [NR-299709](https://new-relic.atlassian.net/browse/NR-299709) + +### Deprecations +- Status File Used for Debugging: This feature has been deprecated. All debugging capabilities have been moved to either Init Logging or [Error Inbox](https://docs.newrelic.com/docs/errors-inbox/errors-inbox/) and will be removed in a future agent release. [NR-293966](https://new-relic.atlassian.net/browse/NR-293966) + ## [1.4.0] - 2024-6-24 ### Changes - Json Version bump to 1.2.3 due to [NR-254157](https://new-relic.atlassian.net/browse/NR-254157) implementation. @@ -16,8 +43,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [PR-256](https://github.com/newrelic/csec-java-agent/pull/256), [PR-259](https://github.com/newrelic/csec-java-agent/pull/259), [PR-258](https://github.com/newrelic/csec-java-agent/pull/258) Feature to detect route of an incoming request for Jax-RS and Spring Framework. [NR-265913](https://new-relic.atlassian.net/browse/NR-265913), [NR-261653](https://new-relic.atlassian.net/browse/NR-261653), [NR-273605](https://new-relic.atlassian.net/browse/NR-273605) - [PR-126](https://github.com/newrelic/csec-java-agent/pull/126), [PR-127](https://github.com/newrelic/csec-java-agent/pull/127), [PR-128](https://github.com/newrelic/csec-java-agent/pull/128), [PR-129](https://github.com/newrelic/csec-java-agent/pull/129) Jedis Support : The security agent now also supports Jedis Version 1.4.0 and above. [NR-174176](https://new-relic.atlassian.net/browse/NR-174176) - [PR-287](https://github.com/newrelic/csec-java-agent/pull/287) Support for Proxy Settings for Connecting to the Security Engine, with known limitation of missing Authentication capabilities. + ### Fixes -- [PR-255](https://github.com/newrelic/csec-java-agent/pull/255) Handle InvalidPathException thrown by Paths.get method [NR-262452](https://new-relic.atlassian.net/browse/) +- [PR-255](https://github.com/newrelic/csec-java-agent/pull/255) Handle InvalidPathException thrown by Paths.get method [NR-262452](https://new-relic.atlassian.net/browse/NR-262452) - [PR-216](https://github.com/newrelic/csec-java-agent/pull/216) Extract Server Configuration to resolve IAST localhost connection with application for Glassfish Server. [NR-223808](https://new-relic.atlassian.net/browse/NR-223808) - [PR-214](https://github.com/newrelic/csec-java-agent/pull/214) Extract Server Configuration to resolve IAST localhost connection with application for Weblogic Server. [NR-223809](https://new-relic.atlassian.net/browse/NR-223809) - [PR-242](https://github.com/newrelic/csec-java-agent/pull/242) Fix for User Class detection in Play Framework [NR-264101](https://new-relic.atlassian.net/browse/NR-264101) diff --git a/gradle.properties b/gradle.properties index 8e99a4eca..904fdfffb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # The agent version. -agentVersion=1.4.0 -jsonVersion=1.2.3 +agentVersion=1.4.2 +jsonVersion=1.2.9 # Updated exposed NR APM API version. nrAPIVersion=8.12.0 diff --git a/gradle/script/java.gradle b/gradle/script/java.gradle index 38c9b374d..f7c6663cf 100644 --- a/gradle/script/java.gradle +++ b/gradle/script/java.gradle @@ -264,7 +264,7 @@ test { } dependencies { - testImplementation("junit:junit:4.12") + testImplementation("junit:junit:4.13.2") testImplementation("org.mockito:mockito-core:3.9.0") testImplementation("org.hamcrest:hamcrest-library:1.3") testImplementation(project(":test-annotations")) diff --git a/instrumentation-security-test/build.gradle b/instrumentation-security-test/build.gradle index 917a6071c..835fb8f6e 100644 --- a/instrumentation-security-test/build.gradle +++ b/instrumentation-security-test/build.gradle @@ -14,13 +14,15 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-agent:${nrAgentVersion}") - implementation 'org.apache.commons:commons-text:1.7' + implementation ('org.apache.commons:commons-text:1.10.0') implementation("com.newrelic.agent.java:agent-bridge:${nrAPIVersion}") implementation("com.newrelic.agent.java:agent-bridge-datastore:${nrAPIVersion}") implementation("commons-net:commons-net:3.9.0") implementation("org.mockftpserver:MockFtpServer:3.1.0") - api("org.apache.httpcomponents:httpclient:4.5.13") + api("org.apache.httpcomponents:httpclient:4.5.13"){ + exclude(module: 'commons-codec', group: 'commons-codec') + } api("org.nanohttpd:nanohttpd:2.3.1") } diff --git a/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/AkkaCoreUtils.java b/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/AkkaCoreUtils.java index 3a243a2a5..430dedb60 100644 --- a/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/AkkaCoreUtils.java +++ b/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/AkkaCoreUtils.java @@ -60,6 +60,9 @@ public static boolean acquireServletLockIfPossible() { } public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, String className, String methodName, Token token) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } try { token.linkAndExpire(); ServletHelper.executeBeforeExitingTransaction(); diff --git a/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/CsecAkkaHttpContextFunction.scala b/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/CsecAkkaHttpContextFunction.scala index 4a974e768..2ebd36c77 100644 --- a/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/CsecAkkaHttpContextFunction.scala +++ b/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/server/CsecAkkaHttpContextFunction.scala @@ -8,6 +8,7 @@ package akka.http.scaladsl.server import akka.Done +import akka.http.scaladsl.model.HttpEntity import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink import akka.util.ByteString @@ -55,15 +56,17 @@ class CsecContextWrapper(original: Function1[RequestContext, Future[RouteResult] override def apply(ctx: RequestContext): Future[RouteResult] = { try { - var httpRequest = ctx.request; + val httpRequest = ctx.request; val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = httpRequest.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + if (!httpRequest.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, ctx.materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, ctx.materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, httpRequest, body, NewRelic.getAgent.getTransaction.getToken); original.apply(ctx) } catch { diff --git a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala index f1d3534c5..76bef8435 100644 --- a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,14 @@ class AkkaAsyncRequestHandler(handler: HttpRequest ⇒ Future[HttpResponse])(imp val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) + AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val futureResponse: Future[HttpResponse] = handler.apply(param) futureResponse.flatMap(ResponseFutureHelper.wrapResponseAsync(NewRelic.getAgent.getTransaction.getToken, materializer)) diff --git a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java index 904e8fb83..cfd6c386c 100644 --- a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java +++ b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java @@ -63,6 +63,9 @@ public static boolean acquireServletLockIfPossible() { public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder response, String contentType, int responseCode, String className, String methodName, Token token) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } token.linkAndExpire(); if(!isServletLockAcquired || !NewRelicSecurity.isHookProcessingActive()){ diff --git a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala index 18dbe8b67..bb1f64a44 100644 --- a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,14 @@ class AkkaSyncRequestHandler(handler: HttpRequest ⇒ HttpResponse)(implicit mat val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val response: HttpResponse = handler.apply(param) ResponseFutureHelper.wrapResponseSync(response, materializer) diff --git a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java index e28c30ad5..deada6535 100644 --- a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java +++ b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java @@ -20,6 +20,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -65,7 +66,7 @@ public Future bindAndHandleSync( public Future singleRequest(HttpRequest httpRequest, HttpsConnectionContext connectionContext, ConnectionPoolSettings settings, LoggingAdapter log, Materializer fm) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -163,9 +164,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala index f1d3534c5..d6d0370cd 100644 --- a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,13 @@ class AkkaAsyncRequestHandler(handler: HttpRequest ⇒ Future[HttpResponse])(imp val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val futureResponse: Future[HttpResponse] = handler.apply(param) futureResponse.flatMap(ResponseFutureHelper.wrapResponseAsync(NewRelic.getAgent.getTransaction.getToken, materializer)) diff --git a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java index 064790902..124589903 100644 --- a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java +++ b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java @@ -63,6 +63,9 @@ public static boolean acquireServletLockIfPossible() { public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } token.linkAndExpire(); if(!isServletLockAcquired || !NewRelicSecurity.isHookProcessingActive()){ diff --git a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala index 18dbe8b67..f8b63323c 100644 --- a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,13 @@ class AkkaSyncRequestHandler(handler: HttpRequest ⇒ HttpResponse)(implicit mat val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val response: HttpResponse = handler.apply(param) ResponseFutureHelper.wrapResponseSync(response, materializer) diff --git a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java index ea8efb5ba..65d5da00b 100644 --- a/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java +++ b/instrumentation-security/akka-http-core-2.11_10.0.11/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java @@ -20,6 +20,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -66,7 +67,7 @@ public Future bindAndHandleSync( public Future singleRequestImpl(HttpRequest httpRequest, HttpsConnectionContext connectionContext, ConnectionPoolSettings poolSettings, LoggingAdapter loggingAdapter) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); @@ -167,9 +168,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala index f1d3534c5..d6d0370cd 100644 --- a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,13 @@ class AkkaAsyncRequestHandler(handler: HttpRequest ⇒ Future[HttpResponse])(imp val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val futureResponse: Future[HttpResponse] = handler.apply(param) futureResponse.flatMap(ResponseFutureHelper.wrapResponseAsync(NewRelic.getAgent.getTransaction.getToken, materializer)) diff --git a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java index 0a0d4fb68..fb29ea791 100644 --- a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java +++ b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java @@ -61,14 +61,18 @@ public static boolean acquireServletLockIfPossible() { return false; } - public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, String className, String methodName, Token token) { + public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } token.linkAndExpire(); if(!isServletLockAcquired || !NewRelicSecurity.isHookProcessingActive()){ return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(contentType); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(responseBody); + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(responseCode); LowSeverityHelper.addRrequestUriToEventFilter(NewRelicSecurity.getAgent().getSecurityMetaData().getRequest()); if(!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().getResponseContentType())) { diff --git a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala index 18dbe8b67..f8b63323c 100644 --- a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,13 @@ class AkkaSyncRequestHandler(handler: HttpRequest ⇒ HttpResponse)(implicit mat val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val response: HttpResponse = handler.apply(param) ResponseFutureHelper.wrapResponseSync(response, materializer) diff --git a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java index ea8efb5ba..65d5da00b 100644 --- a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java +++ b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java @@ -20,6 +20,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -66,7 +67,7 @@ public Future bindAndHandleSync( public Future singleRequestImpl(HttpRequest httpRequest, HttpsConnectionContext connectionContext, ConnectionPoolSettings poolSettings, LoggingAdapter loggingAdapter) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); @@ -167,9 +168,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala index 1e9b6e179..60a80405f 100644 --- a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala +++ b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala @@ -41,7 +41,7 @@ object ResponseFutureHelper { processingResult.onComplete { _ => { token.linkAndExpire() - AkkaCoreUtils.postProcessHttpRequest(isLockAquired, stringResponse, response.entity.contentType.toString(), this.getClass.getName, "apply", NewRelic.getAgent.getTransaction.getToken) + AkkaCoreUtils.postProcessHttpRequest(isLockAquired, stringResponse, response.entity.contentType.toString(), response.status.intValue(), this.getClass.getName, "apply", NewRelic.getAgent.getTransaction.getToken) } } @@ -68,7 +68,7 @@ object ResponseFutureHelper { } val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) - AkkaCoreUtils.postProcessHttpRequest(isLockAquired, stringResponse, httpResponse.entity.contentType.toString(), this.getClass.getName, "apply", NewRelic.getAgent.getTransaction.getToken()) + AkkaCoreUtils.postProcessHttpRequest(isLockAquired, stringResponse, httpResponse.entity.contentType.toString(), httpResponse.status.intValue(), this.getClass.getName, "apply", NewRelic.getAgent.getTransaction.getToken) } catch { case t: NewRelicSecurityException => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, AkkaCoreUtils.AKKA_HTTP_CORE_10_0_11, t.getMessage), t, classOf[AkkaCoreUtils].getName) diff --git a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala index e73c15e44..922fe6070 100644 --- a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaAsyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -26,11 +26,14 @@ class AkkaAsyncRequestHandler(handler: HttpRequest ⇒ Future[HttpResponse])(imp val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val futureResponse: Future[HttpResponse] = handler.apply(param) futureResponse.flatMap(ResponseFutureHelper.wrapResponseAsync(NewRelic.getAgent.getTransaction.getToken, materializer)) diff --git a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java index 88a5c57bd..0f36ab5e6 100644 --- a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java +++ b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaCoreUtils.java @@ -63,6 +63,9 @@ public static boolean acquireServletLockIfPossible() { public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } token.linkAndExpire(); if(!isServletLockAcquired || !NewRelicSecurity.isHookProcessingActive()){ return; diff --git a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala index 6e3cbf634..d0f99f329 100644 --- a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala +++ b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/AkkaSyncRequestHandler.scala @@ -8,7 +8,7 @@ package akka.http.scaladsl import akka.Done -import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} import akka.stream.Materializer import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink @@ -27,11 +27,14 @@ class AkkaSyncRequestHandler(handler: HttpRequest ⇒ HttpResponse)(implicit mat val body: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); - val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => - val chunk = byteString.utf8String - body.append(chunk) + + if (!param.entity.isInstanceOf[HttpEntity.Chunked]) { + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + body.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) } - val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) AkkaCoreUtils.preProcessHttpRequest(isLockAquired, param, body, NewRelic.getAgent.getTransaction.getToken); val response: HttpResponse = handler.apply(param) ResponseFutureHelper.wrapResponseSync(response, materializer) diff --git a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java index 623f578e7..41c69c12e 100644 --- a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java +++ b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/HttpExt_Instrumentation.java @@ -22,6 +22,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -74,7 +75,7 @@ public Future singleRequest(HttpRequest httpRequest, HttpsConnecti LoggingAdapter loggingAdapter) { final Segment segment = NewRelic.getAgent().getTransaction().startSegment("Akka", "singleRequest"); - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); @@ -176,9 +177,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection_Instrumentation.java b/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection_Instrumentation.java index 3b61abe30..6c7a53102 100644 --- a/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection_Instrumentation.java +++ b/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.LDAPOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -61,16 +62,16 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType caseType) { try { - return GenericHelper.acquireLockIfPossible(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(caseType, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } public SearchFuture searchAsync(Dn baseDn, String filter, SearchScope scope, String... attributes ) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(baseDn.getName(), filter, LDAPUtils.METHOD_SEARCH_ASYNC); @@ -90,7 +91,7 @@ public SearchFuture searchAsync(Dn baseDn, String filter, SearchScope scope, Str public SearchFuture searchAsync(String baseDn, String filter, SearchScope scope, String... attributes ) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(baseDn, filter, LDAPUtils.METHOD_SEARCH_ASYNC); @@ -109,7 +110,7 @@ public SearchFuture searchAsync(String baseDn, String filter, SearchScope scope, } public SearchFuture searchAsync( SearchRequest searchRequest ) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(searchRequest.getBase().getName(), searchRequest.getFilter().toString(), LDAPUtils.METHOD_SEARCH_ASYNC); diff --git a/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapConnection_Instrumentation.java b/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapConnection_Instrumentation.java index 12fe4c455..e8283a5fe 100644 --- a/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapConnection_Instrumentation.java +++ b/instrumentation-security/apache-ldap/src/main/java/org/apache/directory/ldap/client/api/LdapConnection_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.LDAPOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -61,16 +62,16 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType caseType) { try { - return GenericHelper.acquireLockIfPossible(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(caseType, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } public EntryCursor search(Dn baseDn, String filter, SearchScope scope, String... attributes ) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(baseDn.getName(), filter, LDAPUtils.METHOD_SEARCH); @@ -90,7 +91,7 @@ public EntryCursor search(Dn baseDn, String filter, SearchScope scope, String... public EntryCursor search( String baseDn, String filter, SearchScope scope, String... attributes ) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(baseDn, filter, LDAPUtils.METHOD_SEARCH); @@ -109,7 +110,7 @@ public EntryCursor search( String baseDn, String filter, SearchScope scope, Stri } public SearchCursor search(SearchRequest searchRequest ) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(searchRequest.getBase().getName(), searchRequest.getFilter().toString(), LDAPUtils.METHOD_SEARCH); diff --git a/instrumentation-security/apache-tomcat-10/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat10/HttpServletHelper.java b/instrumentation-security/apache-tomcat-10/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat10/HttpServletHelper.java index 4979cbab2..f27ae5e0c 100644 --- a/instrumentation-security/apache-tomcat-10/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat10/HttpServletHelper.java +++ b/instrumentation-security/apache-tomcat-10/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat10/HttpServletHelper.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.StringUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import jakarta.servlet.ServletContext; @@ -37,6 +38,10 @@ private static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if (StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/apache-tomcat-7/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat7/HttpServletHelper.java b/instrumentation-security/apache-tomcat-7/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat7/HttpServletHelper.java index 764334d19..c585c7b6c 100644 --- a/instrumentation-security/apache-tomcat-7/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat7/HttpServletHelper.java +++ b/instrumentation-security/apache-tomcat-7/src/main/java/com/newrelic/agent/security/instrumentation/apache/tomcat7/HttpServletHelper.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.StringUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import javax.servlet.ServletContext; @@ -36,6 +37,10 @@ private static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if (StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/async-http-client-2.0.0/src/main/java/com/newrelic/agent/security/instrumentation/org/asynchttpclient/AsynchttpHelper.java b/instrumentation-security/async-http-client-2.0.0/src/main/java/com/newrelic/agent/security/instrumentation/org/asynchttpclient/AsynchttpHelper.java index 94062e622..8088f8749 100644 --- a/instrumentation-security/async-http-client-2.0.0/src/main/java/com/newrelic/agent/security/instrumentation/org/asynchttpclient/AsynchttpHelper.java +++ b/instrumentation-security/async-http-client-2.0.0/src/main/java/com/newrelic/agent/security/instrumentation/org/asynchttpclient/AsynchttpHelper.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -36,15 +37,8 @@ public static boolean isLockAcquired() { return false; } - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttribName()); } public static void releaseLock() { diff --git a/instrumentation-security/async-http-client-2.0.0/src/main/java/org/asynchttpclient/AsyncHttpClient_Instrumentation.java b/instrumentation-security/async-http-client-2.0.0/src/main/java/org/asynchttpclient/AsyncHttpClient_Instrumentation.java index 9c12e6542..2a538a84b 100644 --- a/instrumentation-security/async-http-client-2.0.0/src/main/java/org/asynchttpclient/AsyncHttpClient_Instrumentation.java +++ b/instrumentation-security/async-http-client-2.0.0/src/main/java/org/asynchttpclient/AsyncHttpClient_Instrumentation.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -27,7 +28,7 @@ public abstract class AsyncHttpClient_Instrumentation { public ListenableFuture executeRequest(Request request, AsyncHandler handler) { URI uri = null; - boolean isLockAcquired = AsynchttpHelper.acquireLockIfPossible(); + boolean isLockAcquired = AsynchttpHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { try { diff --git a/instrumentation-security/build.gradle b/instrumentation-security/build.gradle index bd278a624..e4d65007e 100644 --- a/instrumentation-security/build.gradle +++ b/instrumentation-security/build.gradle @@ -23,6 +23,7 @@ subprojects { } jar { + archiveBaseName = "csec-${archiveBaseName.getOrNull()}" manifest { attributes 'Implementation-Vendor': 'New Relic', 'Implementation-Version': project.version } diff --git a/instrumentation-security/camel-xpath/src/main/java/org/apache/camel/builder/BuilderSupport_Instrumentation.java b/instrumentation-security/camel-xpath/src/main/java/org/apache/camel/builder/BuilderSupport_Instrumentation.java index 5be2a50df..4c4b94439 100644 --- a/instrumentation-security/camel-xpath/src/main/java/org/apache/camel/builder/BuilderSupport_Instrumentation.java +++ b/instrumentation-security/camel-xpath/src/main/java/org/apache/camel/builder/BuilderSupport_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -56,15 +57,15 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } public ValueBuilder xpath(String value, Class resultType, Namespaces namespaces) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(value, XPATHUtils.METHOD_XPATH); diff --git a/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SessionManager_Instrumentation.java b/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SessionManager_Instrumentation.java index 4a3fc9849..fef64e303 100644 --- a/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SessionManager_Instrumentation.java +++ b/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SessionManager_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -16,7 +17,7 @@ abstract class SessionManager_Instrumentation { abstract Configuration configuration(); public ResultSetFuture executeAsync(Statement statement) { - boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(statement.hashCode()); + boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, statement.hashCode()); ResultSetFuture result = null; AbstractOperation cqlOperation = null; diff --git a/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SimpleStatement_Instrumentation.java b/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SimpleStatement_Instrumentation.java index 09621a27f..2d8e68f24 100644 --- a/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SimpleStatement_Instrumentation.java +++ b/instrumentation-security/cassandra-datastax-3/src/main/java/com/datastax/driver/core/SimpleStatement_Instrumentation.java @@ -16,7 +16,7 @@ public abstract class SimpleStatement_Instrumentation { public SimpleStatement_Instrumentation(String query, Object... values) { - boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(hashCode()); + boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, hashCode()); try{ if(isLockAcquired){ @@ -41,7 +41,7 @@ public SimpleStatement_Instrumentation(String query, Object... values) { } public SimpleStatement_Instrumentation(String query, Map values){ - boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(hashCode()); + boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, hashCode()); try{ if(isLockAcquired){ diff --git a/instrumentation-security/cassandra-datastax-3/src/main/java/com/newrelic/agent/security/instrumentation/cassandra3/CassandraUtils.java b/instrumentation-security/cassandra-datastax-3/src/main/java/com/newrelic/agent/security/instrumentation/cassandra3/CassandraUtils.java index 8e886e480..f5f3343c4 100644 --- a/instrumentation-security/cassandra-datastax-3/src/main/java/com/newrelic/agent/security/instrumentation/cassandra3/CassandraUtils.java +++ b/instrumentation-security/cassandra-datastax-3/src/main/java/com/newrelic/agent/security/instrumentation/cassandra3/CassandraUtils.java @@ -29,9 +29,9 @@ public class CassandraUtils { public static final String NR_SEC_CASSANDRA_LOCK = "CASSANDRA_OPERATION_LOCK"; public static final String CASSANDRA_DATASTAX_3 = "CASSANDRA-DATASTAX-3"; - public static boolean acquireLockIfPossible(int hashcode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashcode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CASSANDRA_LOCK + hashcode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CASSANDRA_LOCK + hashcode); } catch (Exception ignored){ } return false; diff --git a/instrumentation-security/cassandra-datastax-4/src/main/java/com/datastax/driver/core/Session_Instrumentation.java b/instrumentation-security/cassandra-datastax-4/src/main/java/com/datastax/driver/core/Session_Instrumentation.java index 1fead9d5e..bf7e750b5 100644 --- a/instrumentation-security/cassandra-datastax-4/src/main/java/com/datastax/driver/core/Session_Instrumentation.java +++ b/instrumentation-security/cassandra-datastax-4/src/main/java/com/datastax/driver/core/Session_Instrumentation.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -17,7 +18,7 @@ public class Session_Instrumentation { public ResultT execute(RequestT request, GenericType resultType) { AbstractOperation cqlOperation = null; - boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(request.hashCode()); + boolean isLockAcquired = CassandraUtils.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, request.hashCode()); ResultT result = null; try { diff --git a/instrumentation-security/cassandra-datastax-4/src/main/java/com/newrelic/agent/security/instrumentation/cassandra4/CassandraUtils.java b/instrumentation-security/cassandra-datastax-4/src/main/java/com/newrelic/agent/security/instrumentation/cassandra4/CassandraUtils.java index bab7aba4e..be4ff6d1a 100644 --- a/instrumentation-security/cassandra-datastax-4/src/main/java/com/newrelic/agent/security/instrumentation/cassandra4/CassandraUtils.java +++ b/instrumentation-security/cassandra-datastax-4/src/main/java/com/newrelic/agent/security/instrumentation/cassandra4/CassandraUtils.java @@ -31,9 +31,9 @@ public class CassandraUtils { public static final String NR_SEC_CASSANDRA_LOCK = "CASSANDRA_OPERATION_LOCK"; public static final String CASSANDRA_DATASTAX_4 = "CASSANDRA-DATASTAX-4"; - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CASSANDRA_LOCK, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CASSANDRA_LOCK, hashCode); } catch (Exception ignored){ } return false; diff --git a/instrumentation-security/commons-jxpath/src/main/java/org/apache/commons/jxpath/ri/compiler/JXPathContextReferenceImpl_Instrumentation.java b/instrumentation-security/commons-jxpath/src/main/java/org/apache/commons/jxpath/ri/compiler/JXPathContextReferenceImpl_Instrumentation.java index f3902044c..b4abba71d 100644 --- a/instrumentation-security/commons-jxpath/src/main/java/org/apache/commons/jxpath/ri/compiler/JXPathContextReferenceImpl_Instrumentation.java +++ b/instrumentation-security/commons-jxpath/src/main/java/org/apache/commons/jxpath/ri/compiler/JXPathContextReferenceImpl_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,7 +19,7 @@ public class JXPathContextReferenceImpl_Instrumentation { public Object getValue(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_GETVALUE); @@ -37,7 +38,7 @@ public Object getValue(String xpath, Expression expr) { } public Iterator iterate(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_ITERATE); @@ -56,7 +57,7 @@ public Iterator iterate(String xpath, Expression expr) { } public void removePath(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_REMOVE_PATH); @@ -73,7 +74,7 @@ public void removePath(String xpath, Expression expr) { } public void removeAll(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_REMOVE_ALL); @@ -129,9 +130,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/dynamodb-1.11.390/src/main/java/com/amazonaws/services/dynamodbv2_1_11_390/AmazonDynamoDBClient_Instrumentation.java b/instrumentation-security/dynamodb-1.11.390/src/main/java/com/amazonaws/services/dynamodbv2_1_11_390/AmazonDynamoDBClient_Instrumentation.java index 5b45d9372..c5b72f8f1 100644 --- a/instrumentation-security/dynamodb-1.11.390/src/main/java/com/amazonaws/services/dynamodbv2_1_11_390/AmazonDynamoDBClient_Instrumentation.java +++ b/instrumentation-security/dynamodb-1.11.390/src/main/java/com/amazonaws/services/dynamodbv2_1_11_390/AmazonDynamoDBClient_Instrumentation.java @@ -16,6 +16,7 @@ import com.amazonaws.http.ExecutionContext; import com.amazonaws.http.HttpResponseHandler; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.newrelic.agent.security.instrumentation.dynamodb_1_11_390.DynamoDBUtil; @@ -36,7 +37,7 @@ public AmazonDynamoDBClient_Instrumentation(ClientConfiguration clientConfigurat private Response doInvoke(Request request, HttpResponseHandler> responseHandler, ExecutionContext executionContext, URI discoveredEndpoint) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(request.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, request.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(request, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-1.11.390/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_390/DynamoDBUtil.java b/instrumentation-security/dynamodb-1.11.390/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_390/DynamoDBUtil.java index 2766ce945..66a2d18af 100644 --- a/instrumentation-security/dynamodb-1.11.390/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_390/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-1.11.390/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_390/DynamoDBUtil.java @@ -25,6 +25,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -94,9 +95,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/dynamodb-1.11.453/src/main/java/com/amazonaws/services/dynamodbv2_1_11_453/AmazonDynamoDBClient_Instrumentation.java b/instrumentation-security/dynamodb-1.11.453/src/main/java/com/amazonaws/services/dynamodbv2_1_11_453/AmazonDynamoDBClient_Instrumentation.java index 840b4ea9f..6b4e8153b 100644 --- a/instrumentation-security/dynamodb-1.11.453/src/main/java/com/amazonaws/services/dynamodbv2_1_11_453/AmazonDynamoDBClient_Instrumentation.java +++ b/instrumentation-security/dynamodb-1.11.453/src/main/java/com/amazonaws/services/dynamodbv2_1_11_453/AmazonDynamoDBClient_Instrumentation.java @@ -16,6 +16,7 @@ import com.amazonaws.http.ExecutionContext; import com.amazonaws.http.HttpResponseHandler; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.newrelic.agent.security.instrumentation.dynamodb_1_11_453.DynamoDBUtil; @@ -35,7 +36,7 @@ public AmazonDynamoDBClient_Instrumentation(ClientConfiguration clientConfigurat private Response doInvoke(Request request, HttpResponseHandler> responseHandler, ExecutionContext executionContext, URI discoveredEndpoint, URI uriFromEndpointTrait) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(request.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, request.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(request, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-1.11.453/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_453/DynamoDBUtil.java b/instrumentation-security/dynamodb-1.11.453/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_453/DynamoDBUtil.java index d1d2bb4ac..0478947e0 100644 --- a/instrumentation-security/dynamodb-1.11.453/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_453/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-1.11.453/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_453/DynamoDBUtil.java @@ -25,6 +25,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -95,9 +96,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/dynamodb-1.11.459/src/main/java/com/amazonaws/services/dynamodbv2_1_11_459/AmazonDynamoDBClient_Instrumentation.java b/instrumentation-security/dynamodb-1.11.459/src/main/java/com/amazonaws/services/dynamodbv2_1_11_459/AmazonDynamoDBClient_Instrumentation.java index eece5aae0..dc82520ae 100644 --- a/instrumentation-security/dynamodb-1.11.459/src/main/java/com/amazonaws/services/dynamodbv2_1_11_459/AmazonDynamoDBClient_Instrumentation.java +++ b/instrumentation-security/dynamodb-1.11.459/src/main/java/com/amazonaws/services/dynamodbv2_1_11_459/AmazonDynamoDBClient_Instrumentation.java @@ -16,6 +16,7 @@ import com.amazonaws.http.ExecutionContext; import com.amazonaws.http.HttpResponseHandler; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.newrelic.agent.security.instrumentation.dynamodb_1_11_459.DynamoDBUtil; @@ -35,7 +36,7 @@ public AmazonDynamoDBClient_Instrumentation(ClientConfiguration clientConfigurat private Response doInvoke(Request request, HttpResponseHandler> responseHandler, ExecutionContext executionContext, URI discoveredEndpoint, URI uriFromEndpointTrait) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(request.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, request.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(request, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-1.11.459/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_459/DynamoDBUtil.java b/instrumentation-security/dynamodb-1.11.459/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_459/DynamoDBUtil.java index 352b50a1c..d981b6199 100644 --- a/instrumentation-security/dynamodb-1.11.459/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_459/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-1.11.459/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_459/DynamoDBUtil.java @@ -34,6 +34,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -104,9 +105,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/dynamodb-1.11.80/src/main/java/com/amazonaws/services/dynamodbv2_1_11_80/AmazonDynamoDBClient_Instrumentation.java b/instrumentation-security/dynamodb-1.11.80/src/main/java/com/amazonaws/services/dynamodbv2_1_11_80/AmazonDynamoDBClient_Instrumentation.java index 0464b2b1f..129f18b40 100644 --- a/instrumentation-security/dynamodb-1.11.80/src/main/java/com/amazonaws/services/dynamodbv2_1_11_80/AmazonDynamoDBClient_Instrumentation.java +++ b/instrumentation-security/dynamodb-1.11.80/src/main/java/com/amazonaws/services/dynamodbv2_1_11_80/AmazonDynamoDBClient_Instrumentation.java @@ -16,6 +16,7 @@ import com.amazonaws.http.ExecutionContext; import com.amazonaws.http.HttpResponseHandler; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.newrelic.agent.security.instrumentation.dynamodb_1_11_80.DynamoDBUtil; @@ -35,7 +36,7 @@ public AmazonDynamoDBClient_Instrumentation(ClientConfiguration clientConfigurat private Response doInvoke(Request request, HttpResponseHandler> responseHandler, ExecutionContext executionContext) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(request.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, request.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(request, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-1.11.80/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_80/DynamoDBUtil.java b/instrumentation-security/dynamodb-1.11.80/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_80/DynamoDBUtil.java index 13e1a39d8..44d708f95 100644 --- a/instrumentation-security/dynamodb-1.11.80/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_80/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-1.11.80/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_1_11_80/DynamoDBUtil.java @@ -25,6 +25,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -94,9 +95,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/dynamodb-2.1.0/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_210/DynamoDBUtil.java b/instrumentation-security/dynamodb-2.1.0/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_210/DynamoDBUtil.java index cab84ab53..1e59b670f 100644 --- a/instrumentation-security/dynamodb-2.1.0/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_210/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-2.1.0/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_210/DynamoDBUtil.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -96,7 +97,7 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { diff --git a/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java b/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java index 402aeac1b..f977f3aa9 100644 --- a/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java +++ b/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java @@ -8,6 +8,7 @@ package software.amazon.awssdk.core.client.handler; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -24,7 +25,7 @@ public class AsyncClientHandler_Instrumentation { public CompletableFuture execute( ClientExecutionParams executionParams) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } @@ -44,7 +45,7 @@ public Complet ClientExecutionParams executionParams, AsyncResponseTransformer asyncResponseTransformer) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java b/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java index 44c672ec0..412f6d137 100644 --- a/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java +++ b/instrumentation-security/dynamodb-2.1.0/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java @@ -8,6 +8,7 @@ package software.amazon.awssdk.core.client.handler; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -22,7 +23,7 @@ public class SyncClientHandler_Instrumentation { public OutputT execute( ClientExecutionParams executionParams) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } @@ -42,7 +43,7 @@ public ReturnT ClientExecutionParams executionParams, ResponseTransformer responseTransformer) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-2.1.2/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_212/DynamoDBUtil.java b/instrumentation-security/dynamodb-2.1.2/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_212/DynamoDBUtil.java index 1f85651cc..73f8d5691 100644 --- a/instrumentation-security/dynamodb-2.1.2/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_212/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-2.1.2/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_212/DynamoDBUtil.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -105,9 +106,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java b/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java index 11de52c85..0543f2a75 100644 --- a/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java +++ b/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java @@ -9,10 +9,10 @@ import com.newrelic.agent.security.instrumentation.dynamodb_212.DynamoDBUtil; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.agent.security.instrumentation.dynamodb_212.DynamoDBUtil; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SdkResponse; import software.amazon.awssdk.core.async.AsyncResponseTransformer; @@ -25,7 +25,7 @@ public class AsyncClientHandler_Instrumentation { public CompletableFuture execute( ClientExecutionParams executionParams) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } @@ -45,7 +45,7 @@ public Complet ClientExecutionParams executionParams, AsyncResponseTransformer asyncResponseTransformer) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java b/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java index 5f2c86e2f..8762c91b2 100644 --- a/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java +++ b/instrumentation-security/dynamodb-2.1.2/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java @@ -9,10 +9,10 @@ import com.newrelic.agent.security.instrumentation.dynamodb_212.DynamoDBUtil; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.agent.security.instrumentation.dynamodb_212.DynamoDBUtil; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SdkResponse; import software.amazon.awssdk.core.sync.ResponseTransformer; @@ -23,7 +23,7 @@ public class SyncClientHandler_Instrumentation { public OutputT execute( ClientExecutionParams executionParams) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } @@ -43,7 +43,7 @@ public ReturnT ClientExecutionParams executionParams, ResponseTransformer responseTransformer) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-2.15.34/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_215/DynamoDBUtil.java b/instrumentation-security/dynamodb-2.15.34/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_215/DynamoDBUtil.java index 2e26b9bbe..35c9cc87a 100644 --- a/instrumentation-security/dynamodb-2.15.34/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_215/DynamoDBUtil.java +++ b/instrumentation-security/dynamodb-2.15.34/src/main/java/com/newrelic/agent/security/instrumentation/dynamodb_215/DynamoDBUtil.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; @@ -110,9 +111,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java b/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java index 14c57f588..107928d21 100644 --- a/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java +++ b/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/AsyncClientHandler_Instrumentation.java @@ -9,10 +9,10 @@ import com.newrelic.agent.security.instrumentation.dynamodb_215.DynamoDBUtil; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.agent.security.instrumentation.dynamodb_215.DynamoDBUtil; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SdkResponse; import software.amazon.awssdk.core.async.AsyncResponseTransformer; @@ -25,7 +25,7 @@ public class AsyncClientHandler_Instrumentation { public CompletableFuture execute( ClientExecutionParams executionParams) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } @@ -45,7 +45,7 @@ public Complet ClientExecutionParams executionParams, AsyncResponseTransformer asyncResponseTransformer) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } diff --git a/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java b/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java index 5d38c0b9d..d312b10c5 100644 --- a/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java +++ b/instrumentation-security/dynamodb-2.15.34/src/main/java/software/amazon/awssdk/core/client/handler/SyncClientHandler_Instrumentation.java @@ -9,10 +9,10 @@ import com.newrelic.agent.security.instrumentation.dynamodb_215.DynamoDBUtil; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.agent.security.instrumentation.dynamodb_215.DynamoDBUtil; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SdkResponse; import software.amazon.awssdk.core.sync.ResponseTransformer; @@ -23,7 +23,7 @@ public class SyncClientHandler_Instrumentation { public OutputT execute( ClientExecutionParams executionParams) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } @@ -43,7 +43,7 @@ public ReturnT ClientExecutionParams executionParams, ResponseTransformer responseTransformer) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = DynamoDBUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = DynamoDBUtil.processDynamoDBRequest(executionParams, this.getClass().getName()); } diff --git a/instrumentation-security/exception-handler/src/main/java/java/lang/NullPointerException_Instrumentation.java b/instrumentation-security/exception-handler/src/main/java/java/lang/NullPointerException_Instrumentation.java deleted file mode 100644 index ab476454a..000000000 --- a/instrumentation-security/exception-handler/src/main/java/java/lang/NullPointerException_Instrumentation.java +++ /dev/null @@ -1,17 +0,0 @@ -package java.lang; - -import com.newrelic.api.agent.security.NewRelicSecurity; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.WeaveAllConstructors; - -@Weave(type = MatchType.ExactClass, originalName = "java.lang.NullPointerException") -public class NullPointerException_Instrumentation extends RuntimeException { - - @WeaveAllConstructors - public NullPointerException_Instrumentation() { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().reportApplicationRuntimeError(NewRelicSecurity.getAgent().getSecurityMetaData(), this); - } - } -} diff --git a/instrumentation-security/file-low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/io/File_Instrumentation.java b/instrumentation-security/file-low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/io/File_Instrumentation.java index 44f8b3183..989790c66 100644 --- a/instrumentation-security/file-low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/io/File_Instrumentation.java +++ b/instrumentation-security/file-low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/io/File_Instrumentation.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public abstract class File_Instrumentation { public abstract String getAbsolutePath(); public boolean exists() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); AbstractOperation operation = null; @@ -43,19 +44,12 @@ public boolean exists() { return returnVal; } - private static boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored) { - } - return false; + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } private static void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } diff --git a/instrumentation-security/file-operation/src/main/java/java/io/FileInputStream_Instrumentation.java b/instrumentation-security/file-operation/src/main/java/java/io/FileInputStream_Instrumentation.java index a4a9fb3cf..817531e2d 100644 --- a/instrumentation-security/file-operation/src/main/java/java/io/FileInputStream_Instrumentation.java +++ b/instrumentation-security/file-operation/src/main/java/java/io/FileInputStream_Instrumentation.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.FileHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public abstract class FileInputStream_Instrumentation { private void open(String name) throws FileNotFoundException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(name); @@ -37,17 +38,12 @@ private void open(String name) throws FileNotFoundException { registerExitOperation(isFileLockAcquired, operation); } - private boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } - private void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable e) {} + private static void releaseFileLock() { + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { diff --git a/instrumentation-security/file-operation/src/main/java/java/io/FileOutputStream_Instrumentation.java b/instrumentation-security/file-operation/src/main/java/java/io/FileOutputStream_Instrumentation.java index 1c9a794f5..ae6e2e885 100644 --- a/instrumentation-security/file-operation/src/main/java/java/io/FileOutputStream_Instrumentation.java +++ b/instrumentation-security/file-operation/src/main/java/java/io/FileOutputStream_Instrumentation.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.FileHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -23,7 +24,7 @@ public abstract class FileOutputStream_Instrumentation { private void open(String name, boolean append) throws FileNotFoundException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(name); @@ -38,17 +39,12 @@ private void open(String name, boolean append) registerExitOperation(isFileLockAcquired, operation); } - private boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } - private void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable e) {} + private static void releaseFileLock() { + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { diff --git a/instrumentation-security/file-operation/src/main/java/java/io/File_Instrumentation.java b/instrumentation-security/file-operation/src/main/java/java/io/File_Instrumentation.java index 8a76fc621..6c7372d77 100644 --- a/instrumentation-security/file-operation/src/main/java/java/io/File_Instrumentation.java +++ b/instrumentation-security/file-operation/src/main/java/java/io/File_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.FileHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,7 +19,7 @@ public abstract class File_Instrumentation { public boolean createNewFile() throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_CREATE_NEW_FILE, false, this); @@ -36,7 +37,7 @@ public boolean createNewFile() throws IOException { } public boolean delete() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_DELETE, false, this); @@ -54,7 +55,7 @@ public boolean delete() { } public void deleteOnExit() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_DELETE_ON_EXIT, false, this); @@ -70,7 +71,7 @@ public void deleteOnExit() { } public String[] list() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_LIST, false, this); @@ -88,7 +89,7 @@ public String[] list() { } public String[] list(FilenameFilter filter) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_LIST, false, this); @@ -106,7 +107,7 @@ public String[] list(FilenameFilter filter) { } public File[] listFiles() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_LISTFILES, false, this); @@ -124,7 +125,7 @@ public File[] listFiles() { } public File[] listFiles(FilenameFilter filter) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_LISTFILES, false, this); @@ -142,7 +143,7 @@ public File[] listFiles(FilenameFilter filter) { } public File[] listFiles(FileFilter filter) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_LISTFILES, false, this); @@ -160,7 +161,7 @@ public File[] listFiles(FileFilter filter) { } public boolean mkdir() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_MKDIR, false, this); @@ -178,7 +179,7 @@ public boolean mkdir() { } public boolean mkdirs() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_MKDIRS, false, this); @@ -196,7 +197,7 @@ public boolean mkdirs() { } public boolean renameTo(File_Instrumentation dest) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_RENAME_TO, false, this, dest); @@ -214,7 +215,7 @@ public boolean renameTo(File_Instrumentation dest) { } public boolean setReadOnly() { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_READ_ONLY, false, this); @@ -232,7 +233,7 @@ public boolean setReadOnly() { } public boolean setWritable(boolean writable, boolean ownerOnly) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_WRITABLE, false, this); @@ -250,7 +251,7 @@ public boolean setWritable(boolean writable, boolean ownerOnly) { } public boolean setWritable(boolean writable) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_WRITABLE, false, this); @@ -268,7 +269,7 @@ public boolean setWritable(boolean writable) { } public boolean setReadable(boolean readable, boolean ownerOnly) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_READABLE, false, this); @@ -286,7 +287,7 @@ public boolean setReadable(boolean readable, boolean ownerOnly) { } public boolean setReadable(boolean readable) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_READABLE, false, this); @@ -304,7 +305,7 @@ public boolean setReadable(boolean readable) { } public boolean setExecutable(boolean executable, boolean ownerOnly) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_EXECUTABLE, false, this); @@ -322,7 +323,7 @@ public boolean setExecutable(boolean executable, boolean ownerOnly) { } public boolean setExecutable(boolean executable) { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SET_EXECUTABLE, false, this); @@ -345,19 +346,12 @@ public boolean setExecutable(boolean executable) { public abstract String getAbsolutePath(); - private static boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored) { - } - return false; + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } private static void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } diff --git a/instrumentation-security/file-operation/src/main/java/java/io/RandomAccessFile_Instrumentation.java b/instrumentation-security/file-operation/src/main/java/java/io/RandomAccessFile_Instrumentation.java index 7f3760268..85517df32 100644 --- a/instrumentation-security/file-operation/src/main/java/java/io/RandomAccessFile_Instrumentation.java +++ b/instrumentation-security/file-operation/src/main/java/java/io/RandomAccessFile_Instrumentation.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.FileHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public abstract class RandomAccessFile_Instrumentation { private void open(String name, int mode) throws FileNotFoundException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(name); @@ -37,17 +38,12 @@ private void open(String name, int mode) throws FileNotFoundException { registerExitOperation(isFileLockAcquired, operation); } - private boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } - private void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable e) {} + private static void releaseFileLock() { + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { diff --git a/instrumentation-security/file-operation/src/main/java/java/nio/file/Files_Instrumentation.java b/instrumentation-security/file-operation/src/main/java/java/nio/file/Files_Instrumentation.java index 28181b03b..d2a88246b 100644 --- a/instrumentation-security/file-operation/src/main/java/java/nio/file/Files_Instrumentation.java +++ b/instrumentation-security/file-operation/src/main/java/java/nio/file/Files_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.FileHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -26,7 +27,7 @@ public static Path setPosixFilePermissions(Path path, Set perms) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if (isFileLockAcquired) { operation = preprocessSecurityHook(false, FileHelper.METHOD_NAME_SETPOSIXFILEPERMISSIONS, false, path.toFile()); @@ -43,19 +44,12 @@ public static Path setPosixFilePermissions(Path path, return returnVal; } - private static boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored) { - } - return false; + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } private static void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } diff --git a/instrumentation-security/file-operation/src/main/java/java/nio/file/spi/FileSystemProvider_Instrumentation.java b/instrumentation-security/file-operation/src/main/java/java/nio/file/spi/FileSystemProvider_Instrumentation.java index 81db76b0a..36b95a300 100644 --- a/instrumentation-security/file-operation/src/main/java/java/nio/file/spi/FileSystemProvider_Instrumentation.java +++ b/instrumentation-security/file-operation/src/main/java/java/nio/file/spi/FileSystemProvider_Instrumentation.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.FileHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -37,7 +38,7 @@ public abstract class FileSystemProvider_Instrumentation { public void copy(Path source, Path target, CopyOption... options) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.FILE_COPY, source, target); @@ -55,7 +56,7 @@ public void copy(Path source, Path target, CopyOption... options) public InputStream newInputStream(Path path, OpenOption... options) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; InputStream returnData; if(isFileLockAcquired) { @@ -75,7 +76,7 @@ public InputStream newInputStream(Path path, OpenOption... options) public OutputStream newOutputStream(Path path, OpenOption... options) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; OutputStream returnData; if(isFileLockAcquired) { @@ -97,7 +98,7 @@ public FileChannel newFileChannel(Path path, FileAttribute... attrs) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; FileChannel returnData; if(isFileLockAcquired) { @@ -120,7 +121,7 @@ public AsynchronousFileChannel newAsynchronousFileChannel(Path path, FileAttribute... attrs) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; AsynchronousFileChannel returnData; if(isFileLockAcquired) { @@ -140,7 +141,7 @@ public AsynchronousFileChannel newAsynchronousFileChannel(Path path, public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; SeekableByteChannel returnData; if(isFileLockAcquired) { @@ -159,7 +160,7 @@ public SeekableByteChannel newByteChannel(Path path, public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) throws IOException{ - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; DirectoryStream returnData; if(isFileLockAcquired) { @@ -178,7 +179,7 @@ public DirectoryStream newDirectoryStream(Path dir, public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.CREATE_DIRECTORY, dir); @@ -196,7 +197,7 @@ public void createDirectory(Path dir, FileAttribute... attrs) public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.CREATE_SYMBOLIC_LINK, link, target); @@ -212,7 +213,7 @@ public void createSymbolicLink(Path link, Path target, FileAttribute... attrs } public void createLink(Path link, Path existing) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.CREATE_LINK, link, existing); @@ -228,7 +229,7 @@ public void createLink(Path link, Path existing) throws IOException { } public void delete(Path path) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.DELETE, path); @@ -244,7 +245,7 @@ public void delete(Path path) throws IOException { } public boolean deleteIfExists(Path path) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; boolean returnData; if(isFileLockAcquired) { @@ -263,7 +264,7 @@ public boolean deleteIfExists(Path path) throws IOException { public void move(Path source, Path target, CopyOption... options) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.MOVE, source, target); @@ -281,7 +282,7 @@ public void move(Path source, Path target, CopyOption... options) public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException { - boolean isFileLockAcquired = acquireFileLockIfPossible(); + boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); AbstractOperation operation = null; if(isFileLockAcquired) { operation = preprocessSecurityHook(FileHelper.SET_ATTRIBUTE, path); @@ -295,17 +296,13 @@ public void setAttribute(Path path, String attribute, } registerExitOperation(operation, isFileLockAcquired); } - private void releaseFileLock() { - try { - FileHelper.releaseFileLock(); - } catch (Throwable ignored){} + + private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { + return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); } - private boolean acquireFileLockIfPossible() { - try { - return FileHelper.acquireFileLockIfPossible(); - } catch (Throwable ignored){} - return false; + private static void releaseFileLock() { + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } diff --git a/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java b/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java index 84d8f6bdf..7d7d7c6a4 100644 --- a/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java +++ b/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.JSInjectionOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -20,7 +21,7 @@ final class PolyglotContextImpl_Instrumentation { public Value eval(String languageId, Object sourceImpl) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(languageId, sourceImpl, JSEngineUtils.METHOD_EVAL); @@ -79,9 +80,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection) { try { - return GenericHelper.acquireLockIfPossible(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/graalvm-jsinjection-22.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java b/instrumentation-security/graalvm-jsinjection-22.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java index 12ac4f31f..43a5cc51c 100644 --- a/instrumentation-security/graalvm-jsinjection-22.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java +++ b/instrumentation-security/graalvm-jsinjection-22.0.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.JSInjectionOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -20,7 +21,7 @@ final class PolyglotContextImpl_Instrumentation { public Value eval(String languageId, org.graalvm.polyglot.Source source) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(languageId, source, JSEngineUtils.METHOD_EVAL); @@ -78,9 +79,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection) { try { - return GenericHelper.acquireLockIfPossible(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } 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..bf6f1bbe8 --- /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.getVariables() != 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/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcClientUtils.java b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcClientUtils.java index 1733cca6e..fb120f290 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcClientUtils.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcClientUtils.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -67,34 +68,15 @@ public static AbstractOperation preprocessSecurityHook(String uri, Metadata meta public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttrName()); } private static String getNrSecCustomAttrName() { return GrpcClientUtils.NR_SEC_CUSTOM_ATTRIB_NAME+Thread.currentThread().getId(); } - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(getNrSecCustomAttrName())) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttrName()); } - private static boolean isLockAcquired(String nrSecCustomAttrName) { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(nrSecCustomAttrName, Boolean.class)); - } catch (Throwable ignored) {} - return false; - } } diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcServerUtils.java b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcServerUtils.java index bcd9e3388..6a0f04108 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcServerUtils.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcServerUtils.java @@ -91,6 +91,9 @@ public static void preprocessSecurityHook(ServerStream_Instrumentat public static void postProcessSecurityHook(Metadata metadata, int statusCode, String className, String methodName) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive()) { return; } diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/processor/GrpcRequestThreadPool.java b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/processor/GrpcRequestThreadPool.java index 178defe2c..b20081e13 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/processor/GrpcRequestThreadPool.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/processor/GrpcRequestThreadPool.java @@ -35,8 +35,6 @@ public class GrpcRequestThreadPool { private final boolean allowCoreThreadTimeOut = false; private static final Object mutex = new Object(); - private static final AtomicBoolean isWaiting = new AtomicBoolean(false); - private GrpcRequestThreadPool() { LinkedBlockingQueue processQueue; // load the settings @@ -136,10 +134,6 @@ public BlockingQueue getQueue() { return this.executor.getQueue(); } - public AtomicBoolean isWaiting() { - return isWaiting; - } - public ThreadPoolExecutor getExecutor() { return executor; } diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/BindableService_Instrumentation.java b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/BindableService_Instrumentation.java new file mode 100644 index 000000000..2b4be8dd3 --- /dev/null +++ b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/BindableService_Instrumentation.java @@ -0,0 +1,32 @@ +package io.grpc; + +import com.newrelic.agent.security.instrumentation.grpc1220.GrpcUtils; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper; +import com.newrelic.api.agent.security.schema.ApplicationURLMapping; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(originalName = "io.grpc.BindableService", type = MatchType.Interface) +public class BindableService_Instrumentation { + public ServerServiceDefinition bindService() { + ServerServiceDefinition returnValue = Weaver.callOriginal(); + + try { + String handler = this.getClass().getName(); + for (ServerMethodDefinition serverMethod : returnValue.getMethods()) { + MethodDescriptor methodDescriptor = serverMethod.getMethodDescriptor(); + String url = methodDescriptor.getFullMethodName(); + String methodType = methodDescriptor.getType().name(); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(methodType, url, handler)); + } + } catch (Exception e){ + String message = "Instrumentation library: %s , error while getting app endpoints : %s"; + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(message, GrpcUtils.GRPC_1_22_0, e.getMessage()), e, this.getClass().getName()); + } + + return returnValue; + } +} diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ClientCall_Instrumentation.java b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ClientCall_Instrumentation.java index 0291a1817..47f49a1f1 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ClientCall_Instrumentation.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ClientCall_Instrumentation.java @@ -3,6 +3,7 @@ import com.newrelic.agent.security.instrumentation.grpc1220.GrpcClientUtils; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; @@ -20,7 +21,7 @@ public abstract class ClientCall_Instrumentation { MethodDescriptor methodDescriptor = null; public void start(ClientCall.Listener var1, Metadata var2) { - boolean isLockAcquired = GrpcClientUtils.acquireLockIfPossible(); + boolean isLockAcquired = GrpcClientUtils.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if (isLockAcquired) { diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java index 299f2885e..677671b37 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java @@ -7,6 +7,8 @@ import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.schema.Framework; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; @@ -32,6 +34,7 @@ public void onMessage(ReqT message) { if (isLockAcquired) { GrpcUtils.preProcessSecurityHook(message, GrpcUtils.Type.REQUEST, descriptorForType.getFullName()); } + ServletHelper.registerUserLevelCode(Framework.GRPC.name()); try { Weaver.callOriginal(); } finally { diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java index e1bc40df9..5b543db04 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java @@ -8,8 +8,13 @@ package io.grpc.internal; import com.newrelic.agent.security.instrumentation.grpc1220.GrpcServerUtils; +import com.newrelic.agent.security.instrumentation.grpc1220.GrpcUtils; import com.newrelic.agent.security.instrumentation.grpc1220.processor.MonitorGrpcRequestQueueThread; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.Framework; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.grpc.Context; @@ -29,6 +34,14 @@ private ServerStreamListener startCall(ServerStream_Instrumentatio stream.tokenForCsec = NewRelic.getAgent().getTransaction().getToken(); MonitorGrpcRequestQueueThread.submitNewTask(); boolean isLockAcquired = GrpcServerUtils.acquireLockIfPossible(); + try { + if (NewRelicSecurity.isHookProcessingActive()){ + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(methodDef.getMethodDescriptor().getFullMethodName()); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.GRPC); + } + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, GrpcUtils.GRPC_1_22_0, e.getMessage()), e, this.getClass().getName()); + } if (isLockAcquired) { GrpcServerUtils.preprocessSecurityHook(stream, methodDef, headers, this.getClass().getName()); } diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcClientUtils.java b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcClientUtils.java index 8e6adaee6..181f8f155 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcClientUtils.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcClientUtils.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -67,34 +68,14 @@ public static AbstractOperation preprocessSecurityHook(String uri, Metadata meta public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttrName()); } private static String getNrSecCustomAttrName() { return GrpcClientUtils.NR_SEC_CUSTOM_ATTRIB_NAME+Thread.currentThread().getId(); } - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(getNrSecCustomAttrName())) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), true); - return true; - } - } catch (Throwable ignored){} - return false; - } - - private static boolean isLockAcquired(String nrSecCustomAttrName) { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(nrSecCustomAttrName, Boolean.class)); - } catch (Throwable ignored) {} - return false; + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttrName()); } } diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcServerUtils.java b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcServerUtils.java index 4481b3f70..e4e9431d4 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcServerUtils.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcServerUtils.java @@ -95,6 +95,9 @@ public static void preprocessSecurityHook(ServerStream_Instrumentat public static void postProcessSecurityHook(Metadata metadata, int statusCode, String className, String methodName) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive()) { return; } diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/processor/GrpcRequestThreadPool.java b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/processor/GrpcRequestThreadPool.java index a2e8fceef..32e8eec98 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/processor/GrpcRequestThreadPool.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/processor/GrpcRequestThreadPool.java @@ -35,8 +35,6 @@ public class GrpcRequestThreadPool { private final boolean allowCoreThreadTimeOut = false; private static final Object mutex = new Object(); - private static final AtomicBoolean isWaiting = new AtomicBoolean(false); - private GrpcRequestThreadPool() { LinkedBlockingQueue processQueue; // load the settings @@ -136,10 +134,6 @@ public BlockingQueue getQueue() { return this.executor.getQueue(); } - public AtomicBoolean isWaiting() { - return isWaiting; - } - public ThreadPoolExecutor getExecutor() { return executor; } diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/BindableService_Instrumentation.java b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/BindableService_Instrumentation.java new file mode 100644 index 000000000..edeafd068 --- /dev/null +++ b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/BindableService_Instrumentation.java @@ -0,0 +1,32 @@ +package io.grpc; + +import com.newrelic.agent.security.instrumentation.grpc140.GrpcUtils; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper; +import com.newrelic.api.agent.security.schema.ApplicationURLMapping; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(originalName = "io.grpc.BindableService", type = MatchType.Interface) +public class BindableService_Instrumentation { + public ServerServiceDefinition bindService() { + ServerServiceDefinition returnValue = Weaver.callOriginal(); + + try { + String handler = this.getClass().getName(); + for (ServerMethodDefinition serverMethod : returnValue.getMethods()) { + MethodDescriptor methodDescriptor = serverMethod.getMethodDescriptor(); + String url = methodDescriptor.getFullMethodName(); + String methodType = methodDescriptor.getType().name(); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(methodType, url, handler)); + } + } catch (Exception e){ + String message = "Instrumentation library: %s , error while getting app endpoints : %s"; + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(message, GrpcUtils.GRPC_1_4_0, e.getMessage()), e, this.getClass().getName()); + } + + return returnValue; + } +} diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ClientCall_Instrumentation.java b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ClientCall_Instrumentation.java index ca4b45320..dd1b90d11 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ClientCall_Instrumentation.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ClientCall_Instrumentation.java @@ -3,6 +3,7 @@ import com.newrelic.agent.security.instrumentation.grpc140.GrpcClientUtils; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; @@ -20,7 +21,7 @@ public abstract class ClientCall_Instrumentation { MethodDescriptor methodDescriptor = null; public void start(ClientCall.Listener var1, Metadata var2) { - boolean isLockAcquired = GrpcClientUtils.acquireLockIfPossible(); + boolean isLockAcquired = GrpcClientUtils.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if (isLockAcquired) { diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java index 5347df9c1..b1b4b49b0 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java @@ -7,6 +7,8 @@ import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.schema.Framework; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; @@ -32,6 +34,7 @@ public void onMessage(ReqT message) { if (isLockAcquired) { GrpcUtils.preProcessSecurityHook(message, GrpcUtils.Type.REQUEST, descriptorForType.getFullName()); } + ServletHelper.registerUserLevelCode(Framework.GRPC.name()); try { Weaver.callOriginal(); } finally { diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java index b4228c8d3..a65812d3a 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java @@ -8,8 +8,13 @@ package io.grpc.internal; import com.newrelic.agent.security.instrumentation.grpc140.GrpcServerUtils; +import com.newrelic.agent.security.instrumentation.grpc140.GrpcUtils; import com.newrelic.agent.security.instrumentation.grpc140.processor.MonitorGrpcRequestQueueThread; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.Framework; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.grpc.Context; @@ -28,6 +33,14 @@ private ServerStreamListener startCall(ServerStream_Instrumentatio stream.tokenForCsec = NewRelic.getAgent().getTransaction().getToken(); MonitorGrpcRequestQueueThread.submitNewTask(); boolean isLockAcquired = GrpcServerUtils.acquireLockIfPossible(); + try { + if (NewRelicSecurity.isHookProcessingActive()){ + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(methodDef.getMethodDescriptor().getFullMethodName()); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.GRPC); + } + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, GrpcUtils.GRPC_1_4_0, e.getMessage()), e, this.getClass().getName()); + } if (isLockAcquired) { GrpcServerUtils.preprocessSecurityHook(stream, methodDef, headers, this.getClass().getName()); } diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcClientUtils.java b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcClientUtils.java index 30c9953b7..3145a0cad 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcClientUtils.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcClientUtils.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -67,33 +68,15 @@ public static AbstractOperation preprocessSecurityHook(String uri, Metadata meta public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttrName()); } private static String getNrSecCustomAttrName() { return GrpcClientUtils.NR_SEC_CUSTOM_ATTRIB_NAME+Thread.currentThread().getId(); } - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(getNrSecCustomAttrName())) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttrName()); } - private static boolean isLockAcquired(String nrSecCustomAttrName) { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(nrSecCustomAttrName, Boolean.class)); - } catch (Throwable ignored) {} - return false; - } } diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcServerUtils.java b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcServerUtils.java index 441865d70..90cb822dd 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcServerUtils.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcServerUtils.java @@ -90,6 +90,9 @@ public static void preprocessSecurityHook(ServerStream_Instrumentat public static void postProcessSecurityHook(Metadata metadata, int statusCode, String className, String methodName) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive()) { return; } diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/processor/GrpcRequestThreadPool.java b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/processor/GrpcRequestThreadPool.java index 1e23a656b..de3b95a28 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/processor/GrpcRequestThreadPool.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/processor/GrpcRequestThreadPool.java @@ -33,8 +33,6 @@ public class GrpcRequestThreadPool { private final boolean allowCoreThreadTimeOut = false; private static final Object mutex = new Object(); - private static final AtomicBoolean isWaiting = new AtomicBoolean(false); - private GrpcRequestThreadPool() { LinkedBlockingQueue processQueue; // load the settings @@ -134,10 +132,6 @@ public BlockingQueue getQueue() { return this.executor.getQueue(); } - public AtomicBoolean isWaiting() { - return isWaiting; - } - public ThreadPoolExecutor getExecutor() { return executor; } diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/BindableService_Instrumentation.java b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/BindableService_Instrumentation.java new file mode 100644 index 000000000..c1cb1f4e5 --- /dev/null +++ b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/BindableService_Instrumentation.java @@ -0,0 +1,32 @@ +package io.grpc; + +import com.newrelic.agent.security.instrumentation.grpc1400.GrpcUtils; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper; +import com.newrelic.api.agent.security.schema.ApplicationURLMapping; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(originalName = "io.grpc.BindableService", type = MatchType.Interface) +public class BindableService_Instrumentation { + public ServerServiceDefinition bindService() { + ServerServiceDefinition returnValue = Weaver.callOriginal(); + + try { + String handler = this.getClass().getName(); + for (ServerMethodDefinition serverMethod : returnValue.getMethods()) { + MethodDescriptor methodDescriptor = serverMethod.getMethodDescriptor(); + String url = methodDescriptor.getFullMethodName(); + String methodType = methodDescriptor.getType().name(); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(methodType, url, handler)); + } + } catch (Exception e){ + String message = "Instrumentation library: %s , error while getting app endpoints : %s"; + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(message, GrpcUtils.GRPC_1_40_0, e.getMessage()), e, this.getClass().getName()); + } + + return returnValue; + } +} diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ClientCall_Instrumentation.java b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ClientCall_Instrumentation.java index ebd0d6ec4..79ee376e0 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ClientCall_Instrumentation.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ClientCall_Instrumentation.java @@ -3,6 +3,7 @@ import com.newrelic.agent.security.instrumentation.grpc1400.GrpcClientUtils; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; @@ -20,7 +21,7 @@ public abstract class ClientCall_Instrumentation { MethodDescriptor csecMethodDescriptor = null; public void start(ClientCall.Listener var1, Metadata var2) { - boolean isLockAcquired = GrpcClientUtils.acquireLockIfPossible(); + boolean isLockAcquired = GrpcClientUtils.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if (isLockAcquired) { diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java index a26fb4170..406e6cca8 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/ServerCallListener_Instrumentation.java @@ -7,6 +7,8 @@ import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.schema.Framework; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; @@ -32,6 +34,7 @@ public void onMessage(ReqT message) { if (isLockAcquired) { GrpcUtils.preProcessSecurityHook(message, GrpcUtils.Type.REQUEST, descriptorForType.getFullName()); } + ServletHelper.registerUserLevelCode(Framework.GRPC.name()); try { Weaver.callOriginal(); } finally { diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java index f3e5ffaf1..a3d94e077 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/io/grpc/internal/ServerImpl_Instrumentation.java @@ -1,8 +1,13 @@ package io.grpc.internal; import com.newrelic.agent.security.instrumentation.grpc1400.GrpcServerUtils; +import com.newrelic.agent.security.instrumentation.grpc1400.GrpcUtils; import com.newrelic.agent.security.instrumentation.grpc1400.processor.MonitorGrpcRequestQueueThread; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.Framework; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.NewField; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -28,6 +33,14 @@ private void streamCreatedInternal(final ServerStream stream, final String metho private ServerMethodDefinition wrapMethod(ServerStream_Instrumentation stream, ServerMethodDefinition methodDef, StatsTraceContext statsTraceCtx) { stream.tokenForCsec = NewRelic.getAgent().getTransaction().getToken(); boolean isLockAcquired = GrpcServerUtils.acquireLockIfPossible(); + try { + if (NewRelicSecurity.isHookProcessingActive()){ + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(methodDef.getMethodDescriptor().getFullMethodName()); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.GRPC); + } + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, GrpcUtils.GRPC_1_40_0, e.getMessage()), e, this.getClass().getName()); + } if (isLockAcquired) { GrpcServerUtils.preprocessSecurityHook(stream, methodDef, headers, this.getClass().getName()); } diff --git a/instrumentation-security/http-async-client-4/src/main/java/com/newrelic/agent/security/instrumentation/httpasyncclient4/HttpAsyncClient4_Instrumentation.java b/instrumentation-security/http-async-client-4/src/main/java/com/newrelic/agent/security/instrumentation/httpasyncclient4/HttpAsyncClient4_Instrumentation.java index 86ec258c6..63391d32a 100644 --- a/instrumentation-security/http-async-client-4/src/main/java/com/newrelic/agent/security/instrumentation/httpasyncclient4/HttpAsyncClient4_Instrumentation.java +++ b/instrumentation-security/http-async-client-4/src/main/java/com/newrelic/agent/security/instrumentation/httpasyncclient4/HttpAsyncClient4_Instrumentation.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -39,7 +40,7 @@ public class HttpAsyncClient4_Instrumentation { public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsyncResponseConsumer responseConsumer, HttpContext context, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -65,7 +66,7 @@ public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsync } public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsyncResponseConsumer responseConsumer, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -91,7 +92,7 @@ public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsync } public Future execute(HttpHost target, HttpRequest request, HttpContext context, FutureCallback callback) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase @@ -119,7 +120,7 @@ public Future execute(HttpHost target, HttpRequest request, HttpCo } public Future execute(HttpHost target, HttpRequest request, FutureCallback callback) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase @@ -147,7 +148,7 @@ public Future execute(HttpHost target, HttpRequest request, Future } public Future execute(HttpUriRequest request, HttpContext context, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -167,7 +168,7 @@ public Future execute(HttpUriRequest request, HttpContext context, } public Future execute(HttpUriRequest request, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -255,9 +256,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/httpclient-3/src/main/java/com/newrelic/agent/security/instrumentation/httpclient3/HttpMethodBase_Instrumentation.java b/instrumentation-security/httpclient-3/src/main/java/com/newrelic/agent/security/instrumentation/httpclient3/HttpMethodBase_Instrumentation.java index 95745b0a5..785fae956 100644 --- a/instrumentation-security/httpclient-3/src/main/java/com/newrelic/agent/security/instrumentation/httpclient3/HttpMethodBase_Instrumentation.java +++ b/instrumentation-security/httpclient-3/src/main/java/com/newrelic/agent/security/instrumentation/httpclient3/HttpMethodBase_Instrumentation.java @@ -12,6 +12,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -30,7 +31,7 @@ public abstract class HttpMethodBase_Instrumentation { public abstract void setRequestHeader(String headerName, String headerValue); public int execute(HttpState state, HttpConnection conn) throws HttpException, IOException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -150,9 +151,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/HttpClient_Instrumentation.java b/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/HttpClient_Instrumentation.java index 0eda0fb4b..c383b4007 100644 --- a/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/HttpClient_Instrumentation.java +++ b/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/HttpClient_Instrumentation.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -34,7 +35,7 @@ public abstract class HttpClient_Instrumentation { public HttpResponse execute(HttpUriRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -54,7 +55,7 @@ public HttpResponse execute(HttpUriRequest request) throws Exception { } public HttpResponse execute(HttpUriRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -74,7 +75,7 @@ public HttpResponse execute(HttpUriRequest request, HttpContext context) throws } public HttpResponse execute(HttpHost target, HttpRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase @@ -102,7 +103,7 @@ public HttpResponse execute(HttpHost target, HttpRequest request) throws Excepti } public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase @@ -131,7 +132,7 @@ public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext co public T execute(HttpUriRequest request, ResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -152,7 +153,7 @@ public T execute(HttpUriRequest request, ResponseHandler res public T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -173,7 +174,7 @@ public T execute(HttpUriRequest request, ResponseHandler res public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase @@ -202,7 +203,7 @@ public T execute(HttpHost target, HttpRequest request, Response public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase @@ -304,9 +305,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpAsyncClient_Instrumentation.java b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpAsyncClient_Instrumentation.java index b837e1e7c..8c0e601cb 100644 --- a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpAsyncClient_Instrumentation.java +++ b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpAsyncClient_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -38,7 +39,7 @@ public Future execute( FutureCallback callback) { HttpRequest request = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(APACHE5_ASYNC_REQUEST_PRODUCER+requestProducer.hashCode(), HttpRequest.class); - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -68,9 +69,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpClient_Instrumentation.java b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpClient_Instrumentation.java index d8358d594..e5b1a090c 100644 --- a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpClient_Instrumentation.java +++ b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/HttpClient_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -29,7 +30,7 @@ public class HttpClient_Instrumentation { public HttpResponse execute(ClassicHttpRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -49,7 +50,7 @@ public HttpResponse execute(ClassicHttpRequest request) throws Exception { } public HttpResponse execute(ClassicHttpRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -69,7 +70,7 @@ public HttpResponse execute(ClassicHttpRequest request, HttpContext context) thr } public ClassicHttpResponse execute(HttpHost target, ClassicHttpRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -95,7 +96,7 @@ public ClassicHttpResponse execute(HttpHost target, ClassicHttpRequest request) } public HttpResponse execute(HttpHost target, ClassicHttpRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -122,7 +123,7 @@ public HttpResponse execute(HttpHost target, ClassicHttpRequest request, HttpCon public T execute(ClassicHttpRequest request, HttpClientResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -143,7 +144,7 @@ public T execute(ClassicHttpRequest request, HttpClientResponseHandler T execute(ClassicHttpRequest request, HttpContext context, HttpClientResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -164,7 +165,7 @@ public T execute(ClassicHttpRequest request, HttpContext context, HttpClient public T execute(HttpHost target, ClassicHttpRequest request, HttpClientResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -191,7 +192,7 @@ public T execute(HttpHost target, ClassicHttpRequest request, HttpClientResp public T execute(HttpHost target, ClassicHttpRequest request, HttpContext context, HttpClientResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -229,9 +230,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpClientImpl_Instrumentation.java b/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpClientImpl_Instrumentation.java index d7d163f48..a86fa1c53 100644 --- a/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpClientImpl_Instrumentation.java +++ b/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpClientImpl_Instrumentation.java @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -38,7 +39,7 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO @Trace private CompletableFuture> sendAsync(HttpRequest request, HttpResponse.BodyHandler responseHandler, HttpResponse.PushPromiseHandler pushPromiseHandler, Executor exchangeExecutor) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -91,9 +92,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { try { - return GenericHelper.acquireLockIfPossible(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); + return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/java-lang/src/main/java/java/lang/ProcessImpl_Instrumentation.java b/instrumentation-security/java-lang/src/main/java/java/lang/ProcessImpl_Instrumentation.java index c8d193236..57029faad 100644 --- a/instrumentation-security/java-lang/src/main/java/java/lang/ProcessImpl_Instrumentation.java +++ b/instrumentation-security/java-lang/src/main/java/java/lang/ProcessImpl_Instrumentation.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.ForkExecOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,8 +23,18 @@ static Process start(String[] cmdarray, ProcessBuilder.Redirect[] redirects, boolean redirectErrorStream) throws IOException { Process p = null; - AbstractOperation operation = preprocessSecurityHook(cmdarray, environment); - p = Weaver.callOriginal(); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SYSTEM_COMMAND, "SYSTEM_COMMAND_"); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSecurityHook(cmdarray, environment); + } + try { + p = Weaver.callOriginal(); + } finally { + if(isLockAcquired){ + GenericHelper.releaseLock("SYSTEM_COMMAND_"); + } + } registerExitOperation(operation); return p; } diff --git a/instrumentation-security/javax-jndi/src/main/java/javax/naming/Context_Instrumentation.java b/instrumentation-security/javax-jndi/src/main/java/javax/naming/Context_Instrumentation.java index 507e695cd..63c9611c3 100644 --- a/instrumentation-security/javax-jndi/src/main/java/javax/naming/Context_Instrumentation.java +++ b/instrumentation-security/javax-jndi/src/main/java/javax/naming/Context_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.utils.UserDataTranslationHelper; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,7 +19,7 @@ public abstract class Context_Instrumentation { public Object lookup(Name name) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); List operations = null; if(isLockAcquired) { operations = preprocessSecurityHook(name.getAll(), JNDIUtils.METHOD_LOOKUP); @@ -36,7 +37,7 @@ public Object lookup(Name name) throws NamingException { } public Object lookupLink(Name name) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); List operations = null; if(isLockAcquired) { operations = preprocessSecurityHook(name.getAll(), JNDIUtils.METHOD_LOOKUP); @@ -54,7 +55,7 @@ public Object lookupLink(Name name) throws NamingException { } public Object lookup(String name) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(name, JNDIUtils.METHOD_LOOKUP); @@ -72,7 +73,7 @@ public Object lookup(String name) throws NamingException { } public Object lookupLink(String name) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(name, JNDIUtils.METHOD_LOOKUP); @@ -99,8 +100,8 @@ private void registerExitOperation(boolean isLockAcquired, List search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(name.toString(), filterExpr); @@ -39,7 +40,7 @@ public NamingEnumeration search(Name name, String filterExpr, Obje } public NamingEnumeration search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(name, filterExpr); @@ -58,7 +59,7 @@ public NamingEnumeration search(String name, String filterExpr, Ob } public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(name, filter); @@ -82,7 +83,7 @@ public NamingEnumeration search(String name, String filter, Search SearchControls cons) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(name.toString(), filter); @@ -139,9 +140,9 @@ private void releaseLock() { } } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { try { - return GenericHelper.acquireLockIfPossible(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(ldap, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/javax-xpath/src/main/java/com/sun/org/apache/xpath/internal/XPath_Instrumentation.java b/instrumentation-security/javax-xpath/src/main/java/com/sun/org/apache/xpath/internal/XPath_Instrumentation.java index 777896065..72e3f93cf 100644 --- a/instrumentation-security/javax-xpath/src/main/java/com/sun/org/apache/xpath/internal/XPath_Instrumentation.java +++ b/instrumentation-security/javax-xpath/src/main/java/com/sun/org/apache/xpath/internal/XPath_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public XObject execute( XPathContext xctxt, int contextNode, PrefixResolver namespaceContext) throws javax.xml.transform.TransformerException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(getPatternString(), "execute"); @@ -45,7 +46,7 @@ public XObject execute( PrefixResolver namespaceContext) throws javax.xml.transform.TransformerException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(getPatternString(), "execute"); @@ -101,9 +102,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible("XPATH_OPERATION_LOCK_JAVAXPATH-"); + return GenericHelper.acquireLockIfPossible(xpath, "XPATH_OPERATION_LOCK_JAVAXPATH-"); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/javax-xpath/src/main/java/javax/xml/xpath/XPath_Instrumentation.java b/instrumentation-security/javax-xpath/src/main/java/javax/xml/xpath/XPath_Instrumentation.java index ce65bb97b..714cf3cba 100644 --- a/instrumentation-security/javax-xpath/src/main/java/javax/xml/xpath/XPath_Instrumentation.java +++ b/instrumentation-security/javax-xpath/src/main/java/javax/xml/xpath/XPath_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -19,7 +20,7 @@ public abstract class XPath_Instrumentation { public String evaluate(String expression, InputSource source) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -42,7 +43,7 @@ public Object evaluate( InputSource source, QName returnType) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -62,7 +63,7 @@ public Object evaluate( public String evaluate(String expression, Object item) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -82,7 +83,7 @@ public String evaluate(String expression, Object item) public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -140,9 +141,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible("XPATH_OPERATION_LOCK_JAVAXPATH-"); + return GenericHelper.acquireLockIfPossible(xpath, "XPATH_OPERATION_LOCK_JAVAXPATH-"); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jaxen-xpath-1.1/src/main/java/org/jaxen/BaseXPath_Instrumentation.java b/instrumentation-security/jaxen-xpath-1.1/src/main/java/org/jaxen/BaseXPath_Instrumentation.java index 591b15f90..6b837641e 100644 --- a/instrumentation-security/jaxen-xpath-1.1/src/main/java/org/jaxen/BaseXPath_Instrumentation.java +++ b/instrumentation-security/jaxen-xpath-1.1/src/main/java/org/jaxen/BaseXPath_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -20,7 +21,7 @@ public abstract class BaseXPath_Instrumentation { private String exprText = Weaver.callOriginal(); public List selectNodes(Object node) throws JaxenException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(this.exprText, XPATHUtils.METHOD_SELECT_NODES); @@ -78,9 +79,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jaxen-xpath/src/main/java/org/jaxen/BaseXPath_Instrumentation.java b/instrumentation-security/jaxen-xpath/src/main/java/org/jaxen/BaseXPath_Instrumentation.java index 94e9edf9b..2a0ec1af5 100644 --- a/instrumentation-security/jaxen-xpath/src/main/java/org/jaxen/BaseXPath_Instrumentation.java +++ b/instrumentation-security/jaxen-xpath/src/main/java/org/jaxen/BaseXPath_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -20,7 +21,7 @@ public abstract class BaseXPath_Instrumentation { private final String exprText = Weaver.callOriginal(); public List selectNodes(Object node) throws JaxenException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(this.exprText, XPATHUtils.METHOD_SELECT_NODES); @@ -78,9 +79,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jcache-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jcache_1_0_0/JCacheHelper.java b/instrumentation-security/jcache-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jcache_1_0_0/JCacheHelper.java index b2c2fb6ae..d813bcff0 100644 --- a/instrumentation-security/jcache-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jcache_1_0_0/JCacheHelper.java +++ b/instrumentation-security/jcache-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jcache_1_0_0/JCacheHelper.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.JCacheOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -54,9 +55,9 @@ public static void releaseLock(int hashcode) { } catch (Throwable ignored) {} } - public static boolean acquireLockIfPossible(int hashcode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashcode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jcache-1.0.0/src/main/java/javax/cache/Cache_Instrumentation.java b/instrumentation-security/jcache-1.0.0/src/main/java/javax/cache/Cache_Instrumentation.java index 76f6a94f5..6672ebfed 100644 --- a/instrumentation-security/jcache-1.0.0/src/main/java/javax/cache/Cache_Instrumentation.java +++ b/instrumentation-security/jcache-1.0.0/src/main/java/javax/cache/Cache_Instrumentation.java @@ -2,6 +2,7 @@ import com.newrelic.agent.security.instrumentation.jcache_1_0_0.JCacheHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ @Weave(type = MatchType.Interface, originalName = "javax.cache.Cache") public abstract class Cache_Instrumentation { public V get(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, Collections.singletonList(key), this.getClass().getName(), "get"); @@ -35,7 +36,7 @@ public V get(K key) { } public Map getAll(Set keys) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, new ArrayList() { { addAll(keys); } }, this.getClass().getName(), "getAll"); @@ -53,7 +54,7 @@ public Map getAll(Set keys) { } public boolean containsKey(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, Collections.singletonList(key), this.getClass().getName(), "containsKey"); @@ -71,7 +72,7 @@ public boolean containsKey(K key) { } public void loadAll(Set keys, boolean replaceExistingValues, CompletionListener completionListener) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, new ArrayList() { { addAll(keys); } }, this.getClass().getName(), "loadAll"); @@ -87,7 +88,7 @@ public void loadAll(Set keys, boolean replaceExistingValues, Comple } public void put(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.WRITE, Arrays.asList(key, value), this.getClass().getName(), "put"); @@ -103,7 +104,7 @@ public void put(K key, V value) { } public V getAndPut(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.WRITE, Arrays.asList(key, value), this.getClass().getName(), "getAndPut"); @@ -121,7 +122,7 @@ public V getAndPut(K key, V value) { } public void putAll(Map map) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { List argList = new ArrayList<>(); @@ -143,7 +144,7 @@ public void putAll(Map map) { } public boolean putIfAbsent(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.WRITE, Arrays.asList(key, value), this.getClass().getName(), "putIfAbsent"); @@ -161,7 +162,7 @@ public boolean putIfAbsent(K key, V value) { } public boolean remove(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, Collections.singletonList(key), this.getClass().getName(), "remove"); @@ -179,7 +180,7 @@ public boolean remove(K key) { } public boolean remove(K key, V oldValue) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, Arrays.asList(key, oldValue), this.getClass().getName(), "remove"); @@ -197,7 +198,7 @@ public boolean remove(K key, V oldValue) { } public V getAndRemove(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, Collections.singletonList(key), this.getClass().getName(), "getAndRemove"); @@ -215,7 +216,7 @@ public V getAndRemove(K key) { } public boolean replace(K key, V oldValue) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.UPDATE, Arrays.asList(key, oldValue), this.getClass().getName(), "replace"); @@ -233,7 +234,7 @@ public boolean replace(K key, V oldValue) { } public boolean replace(K key, V oldValue, V newValue) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.UPDATE, Arrays.asList(key, oldValue, newValue), this.getClass().getName(), "replace"); @@ -251,7 +252,7 @@ public boolean replace(K key, V oldValue, V newValue) { } public V getAndReplace(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.UPDATE, Arrays.asList(key, value), this.getClass().getName(), "getAndReplace"); @@ -269,7 +270,7 @@ public V getAndReplace(K key, V value) { } public void removeAll(Set keys) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, new ArrayList() { { addAll(keys); } }, this.getClass().getName(), "removeAll"); diff --git a/instrumentation-security/jdbc-generic/src/main/java/java/sql/PreparedStatement_Instrumentation.java b/instrumentation-security/jdbc-generic/src/main/java/java/sql/PreparedStatement_Instrumentation.java index 083fc98da..3fdb82046 100644 --- a/instrumentation-security/jdbc-generic/src/main/java/java/sql/PreparedStatement_Instrumentation.java +++ b/instrumentation-security/jdbc-generic/src/main/java/java/sql/PreparedStatement_Instrumentation.java @@ -12,6 +12,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.JdbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.BatchSQLOperation; import com.newrelic.api.agent.security.schema.operation.SQLOperation; @@ -96,20 +97,15 @@ private AbstractOperation preprocessSecurityHook (String sql, String methodName) } private void releaseLock() { - try { - JdbcHelper.releaseLock(); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JdbcHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible() { - try { - return JdbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType sqlDbCommand) { + return GenericHelper.acquireLockIfPossible(sqlDbCommand, JdbcHelper.getNrSecCustomAttribName()); } public ResultSet executeQuery() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { if(preparedSql == null){ @@ -130,7 +126,7 @@ public ResultSet executeQuery() throws SQLException { } public int executeUpdate() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { if(preparedSql == null){ @@ -151,7 +147,7 @@ public int executeUpdate() throws SQLException { } public boolean execute() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { if(preparedSql == null){ @@ -395,7 +391,7 @@ private void setObjectParams(int index, Object data) { objectParams.put(String.valueOf(index), data); } public void addBatch() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); SQLOperation sqlOperation = null; if(isLockAcquired) { sqlOperation = new SQLOperation(this.getClass().getName(), JdbcHelper.METHOD_EXECUTE_BATCH); diff --git a/instrumentation-security/jdbc-generic/src/main/java/java/sql/Statement_Instrumentation.java b/instrumentation-security/jdbc-generic/src/main/java/java/sql/Statement_Instrumentation.java index 2afc4310b..188de5713 100644 --- a/instrumentation-security/jdbc-generic/src/main/java/java/sql/Statement_Instrumentation.java +++ b/instrumentation-security/jdbc-generic/src/main/java/java/sql/Statement_Instrumentation.java @@ -12,6 +12,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.JdbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.BatchSQLOperation; import com.newrelic.api.agent.security.schema.operation.SQLOperation; @@ -104,7 +105,7 @@ private AbstractOperation preprocessSecurityHook(BatchSQLOperation operation){ public ResultSet executeQuery(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_QUERY); @@ -122,20 +123,15 @@ public ResultSet executeQuery(String sql) throws SQLException { } private void releaseLock() { - try { - JdbcHelper.releaseLock(); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JdbcHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible() { - try { - return JdbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType sqlDbCommand) { + return GenericHelper.acquireLockIfPossible(sqlDbCommand, JdbcHelper.getNrSecCustomAttribName()); } public int executeUpdate(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -153,7 +149,7 @@ public int executeUpdate(String sql) throws SQLException { } public boolean execute(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -171,7 +167,7 @@ public boolean execute(String sql) throws SQLException { } public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -189,7 +185,7 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException } public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -207,7 +203,7 @@ public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { } public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -225,7 +221,7 @@ public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { } public int executeUpdate(String sql, String[] columnNames) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -243,7 +239,7 @@ public int executeUpdate(String sql, String[] columnNames) throws SQLException { } public boolean execute(String sql, String[] columnNames) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -261,7 +257,7 @@ public boolean execute(String sql, String[] columnNames) throws SQLException { } public boolean execute(String sql, int[] columnIndexes) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -279,7 +275,7 @@ public boolean execute(String sql, int[] columnIndexes) throws SQLException { } public void addBatch(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); SQLOperation sqlOperation = null; if(isLockAcquired) { sqlOperation = new SQLOperation(this.getClass().getName(), JdbcHelper.METHOD_EXECUTE_BATCH); @@ -301,7 +297,7 @@ public void addBatch(String sql) throws SQLException { } public void clearBatch() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); if(isLockAcquired) { if (batchSQLOperation==null){ batchSQLOperation = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(JdbcHelper.NR_SEC_CUSTOM_ATTRIB_BATCH_SQL_NAME+hashCode(), BatchSQLOperation.class); @@ -320,7 +316,7 @@ public void clearBatch() throws SQLException { } public int[] executeBatch() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { if(batchSQLOperation==null|| batchSQLOperation.isEmpty()){ diff --git a/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsPreparedStatement_Instrumentation.java b/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsPreparedStatement_Instrumentation.java index 7c679301f..4c41e222d 100644 --- a/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsPreparedStatement_Instrumentation.java +++ b/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsPreparedStatement_Instrumentation.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.JdbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -78,16 +79,13 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { - try { - return JdbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType sqlDbCommand) { + return GenericHelper.acquireLockIfPossible(sqlDbCommand, JdbcHelper.getNrSecCustomAttribName()); } @Trace(leaf = true) public ResultSet executeQuery() { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, getParameterValues(), JdbcHelper.METHOD_EXECUTE_QUERY); @@ -106,7 +104,7 @@ public ResultSet executeQuery() { @Trace(leaf = true) public int executeUpdate() { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, getParameterValues(), JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -125,7 +123,7 @@ public int executeUpdate() { @Trace(leaf = true) public boolean execute() { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, getParameterValues(), JdbcHelper.METHOD_EXECUTE); diff --git a/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsStatement_Instrumentation.java b/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsStatement_Instrumentation.java index 804f6a98c..95d6ad062 100644 --- a/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsStatement_Instrumentation.java +++ b/instrumentation-security/jdbc-jtds-generic/src/main/java/net/sourceforge/jtds/jdbc/JtdsStatement_Instrumentation.java @@ -12,6 +12,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.JdbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -70,10 +71,7 @@ private void releaseLock() { } private boolean acquireLockIfPossible() { - try { - return JdbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND, JdbcHelper.getNrSecCustomAttribName()); } public ResultSet executeQuery(String sql) throws SQLException { diff --git a/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/jdbc2/AbstractJdbc2Statement_Instrumentation.java b/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/jdbc2/AbstractJdbc2Statement_Instrumentation.java index 49794b9f2..3fb4d314f 100644 --- a/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/jdbc2/AbstractJdbc2Statement_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/jdbc2/AbstractJdbc2Statement_Instrumentation.java @@ -12,6 +12,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.JdbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -73,16 +74,11 @@ private AbstractOperation preprocessSecurityHook (String sql, String methodName) } private void releaseLock() { - try { - JdbcHelper.releaseLock(); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JdbcHelper.getNrSecCustomAttribName()); } private boolean acquireLockIfPossible() { - try { - return JdbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND, JdbcHelper.getNrSecCustomAttribName()); } public AbstractJdbc2Statement_Instrumentation(AbstractJdbc2Connection connection, String sql, boolean isCallable, int rsType, int rsConcurrency) throws SQLException { diff --git a/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/jdbc/PgStatement_Instrumentation.java b/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/jdbc/PgStatement_Instrumentation.java index 588943d68..e032d4204 100644 --- a/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/jdbc/PgStatement_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/jdbc/PgStatement_Instrumentation.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.JdbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.JDBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -84,10 +85,7 @@ private void releaseLock() { } private boolean acquireLockIfPossible() { - try { - return JdbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND, JdbcHelper.getNrSecCustomAttribName()); } public ResultSet executeQuery() throws SQLException { diff --git a/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/com/newrelic/agent/security/instrumentation/jedis_2_7_1/JedisHelper.java b/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/com/newrelic/agent/security/instrumentation/jedis_2_7_1/JedisHelper.java index 54e1d0bf9..d78ef528b 100644 --- a/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/com/newrelic/agent/security/instrumentation/jedis_2_7_1/JedisHelper.java +++ b/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/com/newrelic/agent/security/instrumentation/jedis_2_7_1/JedisHelper.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RedisOperation; @@ -43,9 +44,9 @@ public static void releaseLock(int hashCode) { } catch (Throwable ignored) {} } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_LOCK_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/redis/clients/jedis/Connection_Instrumentation.java b/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/redis/clients/jedis/Connection_Instrumentation.java index 52f2b9f13..f889ad322 100644 --- a/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/redis/clients/jedis/Connection_Instrumentation.java +++ b/instrumentation-security/jedis-2.7.1_2.7.2/src/main/java/redis/clients/jedis/Connection_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -18,7 +19,7 @@ @Weave(type = MatchType.BaseClass, originalName = "redis.clients.jedis.Connection") public abstract class Connection_Instrumentation { protected Connection sendCommand(final ProtocolCommand cmd, final byte[]... args) { - boolean isLockAcquired = JedisHelper.acquireLockIfPossible(cmd.hashCode()); + boolean isLockAcquired = JedisHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, cmd.hashCode()); AbstractOperation operation = null; if(isLockAcquired && cmd!=null && args!=null) { List argList = new ArrayList<>(); diff --git a/instrumentation-security/jedis-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_3_0_0/JedisHelper.java b/instrumentation-security/jedis-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_3_0_0/JedisHelper.java index 0c1582c19..0b1b7983f 100644 --- a/instrumentation-security/jedis-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_3_0_0/JedisHelper.java +++ b/instrumentation-security/jedis-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_3_0_0/JedisHelper.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RedisOperation; @@ -43,9 +44,9 @@ public static void releaseLock(int hashCode) { } catch (Throwable ignored) {} } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_LOCK_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jedis-3.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java b/instrumentation-security/jedis-3.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java index bf5e48f1b..466e71c8b 100644 --- a/instrumentation-security/jedis-3.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java +++ b/instrumentation-security/jedis-3.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -19,7 +20,7 @@ @Weave(type = MatchType.BaseClass, originalName = "redis.clients.jedis.Connection") public abstract class Connection_Instrumentation { public void sendCommand(final ProtocolCommand cmd, final byte[]... args) { - boolean isLockAcquired = JedisHelper.acquireLockIfPossible(cmd.hashCode()); + boolean isLockAcquired = JedisHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, cmd.hashCode()); AbstractOperation operation = null; if(isLockAcquired && args != null && args.length > 0) { // args.length>0 will ensure the event generation for the commands with data List argList = new ArrayList<>(); diff --git a/instrumentation-security/jedis-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_4_0_0/JedisHelper.java b/instrumentation-security/jedis-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_4_0_0/JedisHelper.java index e0c30b3e4..ddc00efb2 100644 --- a/instrumentation-security/jedis-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_4_0_0/JedisHelper.java +++ b/instrumentation-security/jedis-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_4_0_0/JedisHelper.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RedisOperation; @@ -43,9 +44,9 @@ public static void releaseLock(int hashCode) { } catch (Throwable ignored) {} } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_LOCK_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/jedis-4.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java b/instrumentation-security/jedis-4.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java index 1c9b94479..c37936eac 100644 --- a/instrumentation-security/jedis-4.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java +++ b/instrumentation-security/jedis-4.0.0/src/main/java/redis/clients/jedis/Connection_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ @Weave(type = MatchType.BaseClass, originalName = "redis.clients.jedis.Connection") public abstract class Connection_Instrumentation { public void sendCommand(final CommandArguments args) { - boolean isLockAcquired = JedisHelper.acquireLockIfPossible(args.hashCode()); + boolean isLockAcquired = JedisHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, args.hashCode()); AbstractOperation operation = null; if(isLockAcquired && args.size()>1) { // args.size()>1 will ensure the event generation for the commands with data String command = ""; diff --git a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java index bde87f683..0718f51b8 100644 --- a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java +++ b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; @@ -43,7 +44,7 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); + isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); if(isLockAcquired) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } diff --git a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index 13be4a980..247508404 100644 --- a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java +++ b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; +import jdk.nashorn.internal.codegen.CompilerConstants; import org.glassfish.jersey.internal.PropertiesDelegate; import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.server.ContainerRequest; @@ -230,22 +231,23 @@ private static String getNrSecCustomAttribName() { public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { if(StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE)){ try { - Class grizzlyRequestPropertiesDelegateKlass = getClass(GRIZZLY_REQUEST_PROPERTIES_DELEGATE); + Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); Field requestField = grizzlyRequestPropertiesDelegateKlass.getDeclaredField(FIELD_REQUEST); requestField.setAccessible(true); Object requestObject = requestField.get(propertiesDelegate); - Class requestClass = getClass(GRIZZLY_REQUEST); - Method getRemoteAddr = requestClass.getDeclaredMethod(METHOD_GET_REMOTE_ADDR); - Method getRemotePort = requestClass.getDeclaredMethod(METHOD_GET_REMOTE_PORT); - Method getLocalPort = requestClass.getDeclaredMethod(METHOD_GET_LOCAL_PORT); - Method getScheme = requestClass.getDeclaredMethod(METHOD_GET_SCHEME); - Method getContentType = requestClass.getDeclaredMethod(METHOD_GET_CONTENT_TYPE); + Class requestClass = requestObject.getClass(); + Method getRemoteAddr = requestClass.getMethod(METHOD_GET_REMOTE_ADDR); + Method getRemotePort = requestClass.getMethod(METHOD_GET_REMOTE_PORT); + Method getLocalPort = requestClass.getMethod(METHOD_GET_LOCAL_PORT); + Method getScheme = requestClass.getMethod(METHOD_GET_SCHEME); + Method getContentType = requestClass.getMethod(METHOD_GET_CONTENT_TYPE); + getContentType = requestClass.getMethod(METHOD_GET_CONTENT_TYPE); securityRequest.setClientIP(String.valueOf(getRemoteAddr.invoke(requestObject))); securityRequest.setClientPort(String.valueOf(getRemotePort.invoke(requestObject))); securityRequest.setServerPort((int) getLocalPort.invoke(requestObject)); securityRequest.setProtocol((String) getScheme.invoke(requestObject)); securityRequest.setContentType((String) getContentType.invoke(requestObject)); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | + } catch ( NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2_16, e.getMessage()), e, HttpRequestHelper.class.getName()); NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2_16, e.getMessage()), e, HttpRequestHelper.class.getName()); @@ -253,12 +255,12 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } else if (StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE)){ try { - Class tracingAwarePropertiesDelegateKlass = getClass(TRACING_AWARE_PROPERTIES_DELEGATE); + Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); Field propertiesDelegateField = tracingAwarePropertiesDelegateKlass.getDeclaredField(FIELD_PROPERTIES_DELEGATE); propertiesDelegateField.setAccessible(true); Object propertiesDelegateObject = propertiesDelegateField.get(propertiesDelegate); processPropertiesDelegate((PropertiesDelegate) propertiesDelegateObject, securityRequest); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { + } catch (NoSuchFieldException | IllegalAccessException e) { NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2_16, e.getMessage()), e, HttpRequestHelper.class.getName()); NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2_16, e.getMessage()), e, HttpRequestHelper.class.getName()); } @@ -268,28 +270,6 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } } - private static Class getClass(String klassName) throws ClassNotFoundException { - switch (klassName) { - case GRIZZLY_REQUEST_PROPERTIES_DELEGATE: - if (grizzlyRequestPropertiesDelegateKlass == null) { - grizzlyRequestPropertiesDelegateKlass = Class.forName(ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE); - } - return grizzlyRequestPropertiesDelegateKlass; - case GRIZZLY_REQUEST: - if (grizzlyRequest == null) { - grizzlyRequest = Class.forName(ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST); - } - return grizzlyRequest; - case TRACING_AWARE_PROPERTIES_DELEGATE: - if (tracingAwarePropertiesDelegateKlass == null) { - tracingAwarePropertiesDelegateKlass = Class.forName(ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE); - } - return tracingAwarePropertiesDelegateKlass; - default: - throw new ClassNotFoundException(klassName); - } - } - public static void registerInputStreamHashIfNeeded(int inputStreamHash){ try { Set hashSet = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(REQUEST_INPUTSTREAM_HASH, Set.class); diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java index a0593e5e3..f1f898aa3 100644 --- a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java +++ b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; @@ -39,7 +40,7 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); + isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); if(isLockAcquired) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index 29bc4f7e4..72c7e6ed2 100644 --- a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java +++ b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java @@ -232,22 +232,22 @@ private static String getNrSecCustomAttribName() { public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { if(StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE)){ try { - Class grizzlyRequestPropertiesDelegateKlass = getClass(GRIZZLY_REQUEST_PROPERTIES_DELEGATE); + Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); Field requestField = grizzlyRequestPropertiesDelegateKlass.getDeclaredField(FIELD_REQUEST); requestField.setAccessible(true); Object requestObject = requestField.get(propertiesDelegate); - Class requestClass = getClass(GRIZZLY_REQUEST); - Method getRemoteAddr = requestClass.getDeclaredMethod(METHOD_GET_REMOTE_ADDR); - Method getRemotePort = requestClass.getDeclaredMethod(METHOD_GET_REMOTE_PORT); - Method getLocalPort = requestClass.getDeclaredMethod(METHOD_GET_LOCAL_PORT); - Method getScheme = requestClass.getDeclaredMethod(METHOD_GET_SCHEME); - Method getContentType = requestClass.getDeclaredMethod(METHOD_GET_CONTENT_TYPE); + Class requestClass = requestObject.getClass(); + Method getRemoteAddr = requestClass.getMethod(METHOD_GET_REMOTE_ADDR); + Method getRemotePort = requestClass.getMethod(METHOD_GET_REMOTE_PORT); + Method getLocalPort = requestClass.getMethod(METHOD_GET_LOCAL_PORT); + Method getScheme = requestClass.getMethod(METHOD_GET_SCHEME); + Method getContentType = requestClass.getMethod(METHOD_GET_CONTENT_TYPE); securityRequest.setClientIP(String.valueOf(getRemoteAddr.invoke(requestObject))); securityRequest.setClientPort(String.valueOf(getRemotePort.invoke(requestObject))); securityRequest.setServerPort((int) getLocalPort.invoke(requestObject)); securityRequest.setProtocol((String) getScheme.invoke(requestObject)); securityRequest.setContentType((String) getContentType.invoke(requestObject)); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | + } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2, e.getMessage()), e, HttpRequestHelper.class.getName()); NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2, e.getMessage()), e, HttpRequestHelper.class.getName()); @@ -255,12 +255,12 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } else if (StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE)){ try { - Class tracingAwarePropertiesDelegateKlass = getClass(TRACING_AWARE_PROPERTIES_DELEGATE); + Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); Field propertiesDelegateField = tracingAwarePropertiesDelegateKlass.getDeclaredField(FIELD_PROPERTIES_DELEGATE); propertiesDelegateField.setAccessible(true); Object propertiesDelegateObject = propertiesDelegateField.get(propertiesDelegate); processPropertiesDelegate((PropertiesDelegate) propertiesDelegateObject, securityRequest); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { + } catch (NoSuchFieldException | IllegalAccessException e) { NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2, e.getMessage()), e, HttpRequestHelper.class.getName()); NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_2, e.getMessage()), e, HttpRequestHelper.class.getName()); } @@ -270,28 +270,6 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } } - private static Class getClass(String klassName) throws ClassNotFoundException { - switch (klassName) { - case GRIZZLY_REQUEST_PROPERTIES_DELEGATE: - if (grizzlyRequestPropertiesDelegateKlass == null) { - grizzlyRequestPropertiesDelegateKlass = Class.forName(ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE); - } - return grizzlyRequestPropertiesDelegateKlass; - case GRIZZLY_REQUEST: - if (grizzlyRequest == null) { - grizzlyRequest = Class.forName(ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST); - } - return grizzlyRequest; - case TRACING_AWARE_PROPERTIES_DELEGATE: - if (tracingAwarePropertiesDelegateKlass == null) { - tracingAwarePropertiesDelegateKlass = Class.forName(ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE); - } - return tracingAwarePropertiesDelegateKlass; - default: - throw new ClassNotFoundException(klassName); - } - } - public static void registerInputStreamHashIfNeeded(int inputStreamHash){ try { Set hashSet = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(REQUEST_INPUTSTREAM_HASH, Set.class); diff --git a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java index aa015732b..7990a24c4 100644 --- a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java +++ b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; @@ -39,7 +40,7 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); + isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); if(isLockAcquired) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } diff --git a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index da34cf4f8..62bc4f3f6 100644 --- a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java +++ b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java @@ -230,22 +230,22 @@ private static String getNrSecCustomAttribName() { public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { if(StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE)){ try { - Class grizzlyRequestPropertiesDelegateKlass = getClass(GRIZZLY_REQUEST_PROPERTIES_DELEGATE); + Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); Field requestField = grizzlyRequestPropertiesDelegateKlass.getDeclaredField(FIELD_REQUEST); requestField.setAccessible(true); Object requestObject = requestField.get(propertiesDelegate); - Class requestClass = getClass(GRIZZLY_REQUEST); - Method getRemoteAddr = requestClass.getDeclaredMethod(METHOD_GET_REMOTE_ADDR); - Method getRemotePort = requestClass.getDeclaredMethod(METHOD_GET_REMOTE_PORT); - Method getLocalPort = requestClass.getDeclaredMethod(METHOD_GET_LOCAL_PORT); - Method getScheme = requestClass.getDeclaredMethod(METHOD_GET_SCHEME); - Method getContentType = requestClass.getDeclaredMethod(METHOD_GET_CONTENT_TYPE); + Class requestClass = requestObject.getClass(); + Method getRemoteAddr = requestClass.getMethod(METHOD_GET_REMOTE_ADDR); + Method getRemotePort = requestClass.getMethod(METHOD_GET_REMOTE_PORT); + Method getLocalPort = requestClass.getMethod(METHOD_GET_LOCAL_PORT); + Method getScheme = requestClass.getMethod(METHOD_GET_SCHEME); + Method getContentType = requestClass.getMethod(METHOD_GET_CONTENT_TYPE); securityRequest.setClientIP(String.valueOf(getRemoteAddr.invoke(requestObject))); securityRequest.setClientPort(String.valueOf(getRemotePort.invoke(requestObject))); securityRequest.setServerPort((int) getLocalPort.invoke(requestObject)); securityRequest.setProtocol((String) getScheme.invoke(requestObject)); securityRequest.setContentType((String) getContentType.invoke(requestObject)); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | + } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_3, e.getMessage()), e, HttpRequestHelper.class.getName()); NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_3, e.getMessage()), e, HttpRequestHelper.class.getName()); @@ -253,12 +253,12 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } else if (StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE)){ try { - Class tracingAwarePropertiesDelegateKlass = getClass(TRACING_AWARE_PROPERTIES_DELEGATE); + Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); Field propertiesDelegateField = tracingAwarePropertiesDelegateKlass.getDeclaredField(FIELD_PROPERTIES_DELEGATE); propertiesDelegateField.setAccessible(true); Object propertiesDelegateObject = propertiesDelegateField.get(propertiesDelegate); processPropertiesDelegate((PropertiesDelegate) propertiesDelegateObject, securityRequest); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { + } catch (NoSuchFieldException | IllegalAccessException e) { NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_3, e.getMessage()), e, HttpRequestHelper.class.getName()); NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, JERSEY_3, e.getMessage()), e, HttpRequestHelper.class.getName()); } @@ -268,28 +268,6 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } } - private static Class getClass(String klassName) throws ClassNotFoundException { - switch (klassName) { - case GRIZZLY_REQUEST_PROPERTIES_DELEGATE: - if (grizzlyRequestPropertiesDelegateKlass == null) { - grizzlyRequestPropertiesDelegateKlass = Class.forName(ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE); - } - return grizzlyRequestPropertiesDelegateKlass; - case GRIZZLY_REQUEST: - if (grizzlyRequest == null) { - grizzlyRequest = Class.forName(ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST); - } - return grizzlyRequest; - case TRACING_AWARE_PROPERTIES_DELEGATE: - if (tracingAwarePropertiesDelegateKlass == null) { - tracingAwarePropertiesDelegateKlass = Class.forName(ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE); - } - return tracingAwarePropertiesDelegateKlass; - default: - throw new ClassNotFoundException(klassName); - } - } - public static void registerInputStreamHashIfNeeded(int inputStreamHash){ try { Set hashSet = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(REQUEST_INPUTSTREAM_HASH, Set.class); diff --git a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java index e0528d9e7..b6b51e2e1 100644 --- a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java +++ b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.HttpRequest; import com.newrelic.api.agent.security.schema.SecurityMetaData; +import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; @@ -178,8 +179,10 @@ public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) public static void postProcessSecurityHook(HttpServletRequest request, HttpServletResponse response, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + if (!NewRelicSecurity.isHookProcessingActive()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); @@ -222,6 +225,10 @@ private static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if (StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/jetty-12/src/main/java/com/newrelic/agent/security/instrumentation/jetty12/server/HttpServletHelper.java b/instrumentation-security/jetty-12/src/main/java/com/newrelic/agent/security/instrumentation/jetty12/server/HttpServletHelper.java index 15ebf0561..18bbf3726 100644 --- a/instrumentation-security/jetty-12/src/main/java/com/newrelic/agent/security/instrumentation/jetty12/server/HttpServletHelper.java +++ b/instrumentation-security/jetty-12/src/main/java/com/newrelic/agent/security/instrumentation/jetty12/server/HttpServletHelper.java @@ -177,8 +177,10 @@ public static void preprocessSecurityHook(Request request) { public static void postProcessSecurityHook(Request request, Response response, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + if (!NewRelicSecurity.isHookProcessingActive()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); diff --git a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/HttpServletHelper.java b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/HttpServletHelper.java index 07b87e142..0d41aceeb 100644 --- a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/HttpServletHelper.java +++ b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/HttpServletHelper.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.HttpRequest; import com.newrelic.api.agent.security.schema.SecurityMetaData; +import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; @@ -179,8 +180,10 @@ public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) public static void postProcessSecurityHook(HttpServletRequest request, HttpServletResponse response, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + if (!NewRelicSecurity.isHookProcessingActive()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); @@ -224,6 +227,10 @@ private static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if (StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/ldaptive-1.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java b/instrumentation-security/ldaptive-1.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java index 1d48191a7..3d3eda502 100644 --- a/instrumentation-security/ldaptive-1.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java +++ b/instrumentation-security/ldaptive-1.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.LDAPOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,7 +19,7 @@ public abstract class AbstractOperation_Instrumentation protected Response invoke(final Q request) throws LdapException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired && request instanceof SearchRequest) { SearchRequest searchRequest = (SearchRequest) request; @@ -78,10 +79,7 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { - try { - return GenericHelper.acquireLockIfPossible(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { + return GenericHelper.acquireLockIfPossible(ldap, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/instrumentation-security/ldaptive-2.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java b/instrumentation-security/ldaptive-2.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java index 67f1b09c6..76a624163 100644 --- a/instrumentation-security/ldaptive-2.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java +++ b/instrumentation-security/ldaptive-2.0/src/main/java/org/ldaptive/AbstractOperation_Instrumentation.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.LDAPOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -17,7 +18,7 @@ public abstract class AbstractOperation_Instrumentation { @SuppressWarnings("unchecked") @Trace public AsyncCommand dispatch(RedisCommand_Instrumentation cmd) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(cmd, LettuceUtils.METHOD_DISPATCH); @@ -95,9 +96,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore) { try { - return GenericHelper.acquireLockIfPossible(LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(cachingDataStore, LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/lettuce-5.0/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands_Instrumentation.java b/instrumentation-security/lettuce-5.0/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands_Instrumentation.java index 8a3d141fb..dd0c585f3 100644 --- a/instrumentation-security/lettuce-5.0/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands_Instrumentation.java +++ b/instrumentation-security/lettuce-5.0/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands_Instrumentation.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RedisOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -33,7 +34,7 @@ public abstract class AbstractRedisAsyncCommands_Instrumentation { @SuppressWarnings("unchecked") @Trace public AsyncCommand dispatch(RedisCommand_Instrumentation cmd) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(cmd, LettuceUtils.METHOD_DISPATCH); @@ -98,9 +99,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore) { try { - return GenericHelper.acquireLockIfPossible(LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(cachingDataStore, LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/util/Random_Instrumentation.java b/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/util/Random_Instrumentation.java index ee490d7ae..edf826045 100644 --- a/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/util/Random_Instrumentation.java +++ b/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/util/Random_Instrumentation.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RandomOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public class Random_Instrumentation { public int nextInt() { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -44,7 +45,7 @@ public int nextInt() { } public int nextInt(int bound) { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -66,7 +67,7 @@ public int nextInt(int bound) { } public void nextBytes(byte[] bytes) { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -86,7 +87,7 @@ public void nextBytes(byte[] bytes) { } public long nextLong() { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -108,7 +109,7 @@ public long nextLong() { } public float nextFloat() { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -130,7 +131,7 @@ public float nextFloat() { } public double nextDouble() { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -152,7 +153,7 @@ public double nextDouble() { } public double nextGaussian() { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -174,7 +175,7 @@ public double nextGaussian() { } public boolean nextBoolean() { - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ @@ -246,9 +247,9 @@ private void releaseLock(int hashCode) { } } - private boolean acquireLockIfPossible(int hashCode) { + private boolean acquireLockIfPossible(VulnerabilityCaseType random, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(RandomUtils.NR_SEC_RANDOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(random, RandomUtils.NR_SEC_RANDOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java b/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java index dad1e220d..b7621d8ee 100644 --- a/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.ReadBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final ReadBinding binding) { public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java b/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java index 2c89cab27..1755a4fab 100644 --- a/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncWriteBinding; import com.mongodb.binding.WriteBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandWriteOperation_Instrumentation { public T execute(final WriteBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final WriteBinding binding) { public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/OperationExecutor_Instrumentation.java b/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/OperationExecutor_Instrumentation.java index eca14e3dd..9d61a25b1 100644 --- a/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/OperationExecutor_Instrumentation.java +++ b/instrumentation-security/mongodb-3.0/src/main/java/com/mongodb/operation/OperationExecutor_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -33,9 +34,9 @@ private void releaseLock(int hashCode) { } } - private boolean acquireLockIfPossible(int hashCode) { + private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; @@ -44,7 +45,7 @@ private boolean acquireLockIfPossible(int hashCode) { public T execute(ReadOperation operation, ReadPreference readPreference) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -62,7 +63,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference) public T execute(WriteOperation operation) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.0/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java b/instrumentation-security/mongodb-3.0/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java index eb6a3fe42..2c91aba67 100644 --- a/instrumentation-security/mongodb-3.0/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java +++ b/instrumentation-security/mongodb-3.0/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java @@ -15,6 +15,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.NoSQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -110,9 +111,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/OperationExecutor_Instrumentation.java b/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/OperationExecutor_Instrumentation.java index 0f5c11214..a33cbe032 100644 --- a/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/OperationExecutor_Instrumentation.java +++ b/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/OperationExecutor_Instrumentation.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -35,9 +36,9 @@ private void releaseLock(int hashCode) { } } - private boolean acquireLockIfPossible(int hashCode) { + private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; @@ -45,7 +46,7 @@ private boolean acquireLockIfPossible(int hashCode) { public T execute(ReadOperation operation, ReadPreference readPreference, ClientSession session) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -63,7 +64,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference, public T execute(ReadOperation operation, ReadPreference readPreference) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -82,7 +83,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference) public T execute(WriteOperation operation) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -101,7 +102,7 @@ public T execute(WriteOperation operation) { public T execute(WriteOperation operation, ClientSession session) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java b/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java index dad1e220d..b7621d8ee 100644 --- a/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.ReadBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final ReadBinding binding) { public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java b/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java index 5de24d163..be2f081e0 100644 --- a/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.6/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncWriteBinding; import com.mongodb.binding.WriteBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandWriteOperation_Instrumentation { public T execute(final WriteBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final WriteBinding binding) { public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java b/instrumentation-security/mongodb-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java index 24894c897..b2f7c3f69 100644 --- a/instrumentation-security/mongodb-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java +++ b/instrumentation-security/mongodb-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java @@ -15,6 +15,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.NoSQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -122,9 +123,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java b/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java index a97325997..31b2762a0 100644 --- a/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java +++ b/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -37,9 +38,9 @@ private void releaseLock(int hashCode) { } } - private boolean acquireLockIfPossible(int hashCode) { + private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; @@ -47,7 +48,7 @@ private boolean acquireLockIfPossible(int hashCode) { public T execute(ReadOperation operation, ReadPreference readPreference, @Nullable ClientSession session) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -65,7 +66,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference, public T execute(ReadOperation operation, ReadPreference readPreference) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -84,7 +85,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference) public T execute(WriteOperation operation) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -103,7 +104,7 @@ public T execute(WriteOperation operation) { public T execute(WriteOperation operation, @Nullable ClientSession session) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java b/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java index dad1e220d..b7621d8ee 100644 --- a/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.ReadBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final ReadBinding binding) { public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java b/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java index 2c89cab27..1755a4fab 100644 --- a/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.7/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncWriteBinding; import com.mongodb.binding.WriteBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandWriteOperation_Instrumentation { public T execute(final WriteBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final WriteBinding binding) { public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java b/instrumentation-security/mongodb-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java index 672fb2804..4a921da83 100644 --- a/instrumentation-security/mongodb-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java +++ b/instrumentation-security/mongodb-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java @@ -15,6 +15,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.NoSQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -120,9 +121,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java b/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java index e36c58706..4e89a0475 100644 --- a/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java +++ b/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/client/internal/OperationExecutor_Instrumentation.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -38,9 +39,9 @@ private void releaseLock(int hashCode) { } } - private boolean acquireLockIfPossible(int hashCode) { + private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; @@ -48,7 +49,7 @@ private boolean acquireLockIfPossible(int hashCode) { public T execute(ReadOperation operation, ReadPreference readPreference, ReadConcern readConcern, @Nullable com.mongodb.client.ClientSession session) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -66,7 +67,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference, public T execute(ReadOperation operation, ReadPreference readPreference, ReadConcern readConcern) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.getReadAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -85,7 +86,7 @@ public T execute(ReadOperation operation, ReadPreference readPreference, public T execute(WriteOperation operation, ReadConcern readConcern) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); try { if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); @@ -109,7 +110,7 @@ public T execute(WriteOperation operation, ReadConcern readConcern) { public T execute(WriteOperation operation, ReadConcern readConcern, @Nullable ClientSession session) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = acquireLockIfPossible(operation.hashCode()); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, operation.hashCode()); try { if (isLockAcquired) { noSQLOperation = MongoUtil.getWriteAbstractOperation(operation, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); diff --git a/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java b/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java index dad1e220d..b7621d8ee 100644 --- a/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandReadOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.ReadBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final ReadBinding binding) { public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java b/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java index 2c89cab27..1755a4fab 100644 --- a/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java +++ b/instrumentation-security/mongodb-3.8/src/main/java/com/mongodb/operation/CommandWriteOperation_Instrumentation.java @@ -4,6 +4,7 @@ import com.mongodb.binding.AsyncWriteBinding; import com.mongodb.binding.WriteBinding; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -17,7 +18,7 @@ public class CommandWriteOperation_Instrumentation { public T execute(final WriteBinding binding) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } @@ -35,7 +36,7 @@ public T execute(final WriteBinding binding) { public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; - boolean isLockAcquired = MongoUtil.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); if (isLockAcquired) { noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } diff --git a/instrumentation-security/mongodb-3.8/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java b/instrumentation-security/mongodb-3.8/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java index 255c9612f..f55664b8b 100644 --- a/instrumentation-security/mongodb-3.8/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java +++ b/instrumentation-security/mongodb-3.8/src/main/java/com/newrelic/agent/security/instrumentation/mongo/MongoUtil.java @@ -15,6 +15,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.NoSQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -108,9 +109,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/mule-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mule36/MuleHelper.java b/instrumentation-security/mule-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mule36/MuleHelper.java index 3a79f35d7..dd226db05 100644 --- a/instrumentation-security/mule-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mule36/MuleHelper.java +++ b/instrumentation-security/mule-3.6/src/main/java/com/newrelic/agent/security/instrumentation/mule36/MuleHelper.java @@ -7,7 +7,9 @@ import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper; import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; +import com.newrelic.api.agent.security.schema.Framework; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import org.mule.api.processor.MessageProcessor; import org.mule.module.http.api.HttpHeaders; import org.mule.module.http.api.listener.HttpListener; @@ -29,6 +31,7 @@ public class MuleHelper { private static final String EMPTY = ""; public static final String LIBRARY_NAME = "MULE-SERVER"; private static final Map handlerMap = new HashMap<>(); + public static final String MULE_3_6 = "MULE-3.6"; public static void processHttpRequestHeader(HttpRequest httpRequest, com.newrelic.api.agent.security.schema.HttpRequest securityRequest @@ -114,10 +117,24 @@ public static void gatherURLMappings(HttpListener messageSource, List getHandlerMap() { return handlerMap; } + + // route detection + public static void setRequestRoute(String listenerPath) { + if (NewRelicSecurity.isHookProcessingActive()) { + try { + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(listenerPath); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.MULE); + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, MULE_3_6, e.getMessage()), e, MuleHelper.class.getName()); + } + } + } } diff --git a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java index ca9faf1b5..c558f3348 100644 --- a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java +++ b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -24,6 +25,7 @@ public static MuleEvent transform(final HttpRequestContext requestContext, final { boolean isLockAcquired = acquireLockIfPossible(requestContext.hashCode()); MuleEvent event; + MuleHelper.setRequestRoute(listenerPath); if (isLockAcquired) { preprocessSecurityHook(requestContext); } @@ -82,13 +84,18 @@ private static void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: need to update UserClassEntity ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); - } catch (Throwable ignored){} + } catch (Throwable ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_6, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); + } } private static void postProcessSecurityHook() { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + + if (!NewRelicSecurity.isHookProcessingActive()) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -107,9 +114,11 @@ private static void postProcessSecurityHook() { ServletHelper.tmpFileCleanUp(NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getTempFiles()); } catch (Throwable e) { if(e instanceof NewRelicSecurityException){ - e.printStackTrace(); + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MuleHelper.MULE_3_6, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); throw e; } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_6, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_6, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); } } diff --git a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java index 3ebd77e15..20217b344 100644 --- a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java +++ b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java @@ -9,11 +9,13 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.mule.module.http.internal.domain.request.HttpRequest; import org.mule.module.http.internal.domain.request.HttpRequestContext; +import org.mule.module.http.internal.listener.HttpRequestToMuleEvent_Instrumentation; @Weave(type = MatchType.Interface, originalName = "org.mule.module.http.internal.listener.async.RequestHandler") public class RequestHandler_Instrumentation { @@ -76,13 +78,17 @@ private void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: need to update UserClassEntity ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); - } catch (Throwable ignored){} + } catch (Throwable ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_6, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); + } } private void postProcessSecurityHook() { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + if (!NewRelicSecurity.isHookProcessingActive()) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -101,9 +107,11 @@ private void postProcessSecurityHook() { ServletHelper.tmpFileCleanUp(NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getTempFiles()); } catch (Throwable e) { if(e instanceof NewRelicSecurityException){ - e.printStackTrace(); + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MuleHelper.MULE_3_6, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); throw e; } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_6, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_6, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); } } diff --git a/instrumentation-security/mule-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mule37/MuleHelper.java b/instrumentation-security/mule-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mule37/MuleHelper.java index afc9c97ba..a1b00a487 100644 --- a/instrumentation-security/mule-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mule37/MuleHelper.java +++ b/instrumentation-security/mule-3.7/src/main/java/com/newrelic/agent/security/instrumentation/mule37/MuleHelper.java @@ -7,11 +7,14 @@ import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper; import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; +import com.newrelic.api.agent.security.schema.Framework; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import org.mule.api.processor.MessageProcessor; import org.mule.module.http.api.HttpHeaders; import org.mule.module.http.api.listener.HttpListener; import org.mule.module.http.internal.domain.request.HttpRequest; +import org.mule.module.http.internal.listener.ListenerPath; import org.mule.processor.InvokerMessageProcessor; import java.util.HashMap; @@ -28,6 +31,7 @@ public class MuleHelper { private static final String EMPTY = ""; public static final String LIBRARY_NAME = "MULE-SERVER"; private static final Map handlerMap = new HashMap<>(); + public static final String MULE_3_7 = "MULE-3.7"; public static void processHttpRequestHeader(HttpRequest httpRequest, com.newrelic.api.agent.security.schema.HttpRequest securityRequest) { for (String headerName : httpRequest.getHeaderNames()) { @@ -108,10 +112,23 @@ public static void gatherURLMappings(HttpListener messageSource, List getHandlerMap() { return handlerMap; } + + public static void setRequestRoute(ListenerPath listenerPath) { + if (NewRelicSecurity.isHookProcessingActive()) { + try { + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(listenerPath.getResolvedPath()); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.MULE); + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, MULE_3_7, e.getMessage()), e, MuleHelper.class.getName()); + } + } + } } diff --git a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java index 521808b1a..8b10829fc 100644 --- a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java +++ b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -24,6 +25,7 @@ public static MuleEvent transform(final HttpRequestContext requestContext, final { boolean isLockAcquired = acquireLockIfPossible(requestContext.hashCode()); MuleEvent event; + MuleHelper.setRequestRoute(listenerPath); if (isLockAcquired) { preprocessSecurityHook(requestContext); } @@ -82,13 +84,17 @@ private static void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: need to update UserClassEntity ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); - } catch (Throwable ignored){} + } catch (Throwable ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_7, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); + } } private static void postProcessSecurityHook() { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + if (!NewRelicSecurity.isHookProcessingActive()) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -107,9 +113,11 @@ private static void postProcessSecurityHook() { ServletHelper.tmpFileCleanUp(NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getTempFiles()); } catch (Throwable e) { if(e instanceof NewRelicSecurityException){ - e.printStackTrace(); + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MuleHelper.MULE_3_7, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); throw e; } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_7, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_7, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); } } diff --git a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java index 0d1c0d15f..556231e27 100644 --- a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java +++ b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java @@ -9,14 +9,17 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.mule.module.http.internal.domain.request.HttpRequest; import org.mule.module.http.internal.domain.request.HttpRequestContext; +import org.mule.module.http.internal.listener.HttpRequestToMuleEvent_Instrumentation; @Weave(type = MatchType.Interface, originalName = "org.mule.module.http.internal.listener.async.RequestHandler") public class RequestHandler_Instrumentation { + public void handleRequest(HttpRequestContext requestContext, HttpResponseReadyCallback responseCallback) { boolean isLockAcquired = acquireLockIfPossible(requestContext.hashCode()); if (isLockAcquired) { @@ -76,13 +79,17 @@ private void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: need to update UserClassEntity ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); - } catch (Throwable ignored){} + } catch (Throwable ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_7, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); + } } private void postProcessSecurityHook() { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + if (!NewRelicSecurity.isHookProcessingActive()) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -101,9 +108,11 @@ private void postProcessSecurityHook() { ServletHelper.tmpFileCleanUp(NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getTempFiles()); } catch (Throwable e) { if(e instanceof NewRelicSecurityException){ - e.printStackTrace(); + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MuleHelper.MULE_3_7, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); throw e; } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_7, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, MuleHelper.MULE_3_7, e.getMessage()), e, HttpRequestToMuleEvent_Instrumentation.class.getName()); } } diff --git a/instrumentation-security/nashorn-jsinjection/src/main/java/jdk/nashorn/api/scripting/NashornScriptEngine_Instrumentation.java b/instrumentation-security/nashorn-jsinjection/src/main/java/jdk/nashorn/api/scripting/NashornScriptEngine_Instrumentation.java index 1236a647f..25b8007db 100644 --- a/instrumentation-security/nashorn-jsinjection/src/main/java/jdk/nashorn/api/scripting/NashornScriptEngine_Instrumentation.java +++ b/instrumentation-security/nashorn-jsinjection/src/main/java/jdk/nashorn/api/scripting/NashornScriptEngine_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.JSInjectionOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public class NashornScriptEngine_Instrumentation { private Object evalImpl(ScriptFunction_Instrumentation script, ScriptContext ctxt, Global ctxtGlobal) throws ScriptException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(script, JSEngineUtils.METHOD_EVAL_IMPL); @@ -41,7 +42,7 @@ private Object evalImpl(ScriptFunction_Instrumentation script, ScriptContext ctx } private Object evalImpl(final Source src, final ScriptContext ctxt) throws ScriptException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(String.valueOf(src.getContent()), JSEngineUtils.METHOD_EVAL_IMPL); @@ -127,9 +128,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection) { try { - return GenericHelper.acquireLockIfPossible(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java index 10c000dc3..8ef69f185 100644 --- a/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java +++ b/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -23,7 +24,7 @@ public abstract class ChannelInboundHandler_Instrumentation { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean isLockAcquired = false; if (msg instanceof HttpRequest || msg instanceof HttpContent){ - isLockAcquired = NettyUtils.acquireNettyLockIfPossible(NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK); + isLockAcquired = NettyUtils.acquireNettyLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK); } if (isLockAcquired) { NettyUtils.processSecurityRequest(ctx, msg, getClass().getName()); diff --git a/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java b/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java index 6a93460f1..3a6bfd8d4 100644 --- a/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java +++ b/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java @@ -7,6 +7,7 @@ package security.io.netty400.channel; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -23,7 +24,7 @@ public abstract class ChannelOutboundHandler_Instrumentation { public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { boolean isLockAcquired = false; if (msg instanceof FullHttpResponse){ - isLockAcquired = NettyUtils.acquireNettyLockIfPossible(NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK_OUTBOUND); + isLockAcquired = NettyUtils.acquireNettyLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK_OUTBOUND); } if (isLockAcquired) { NettyUtils.processSecurityResponse(ctx, msg); diff --git a/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/utils/NettyUtils.java b/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/utils/NettyUtils.java index ecdcc8fea..81c468ccc 100644 --- a/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/utils/NettyUtils.java +++ b/instrumentation-security/netty-4.0.0/src/main/java/security/io/netty400/utils/NettyUtils.java @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; @@ -229,22 +230,11 @@ public static boolean isNettyLockAcquired(String operationLock) { return false; } - public static boolean acquireNettyLockIfPossible(String operationLock) { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isNettyLockAcquired(operationLock)) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(operationLock + Thread.currentThread().getId(), true); - return true; - } - } catch (Throwable ignored){} - return false; + public static boolean acquireNettyLockIfPossible(VulnerabilityCaseType reflectedXss, String operationLock) { + return GenericHelper.acquireLockIfPossible(reflectedXss, operationLock+ Thread.currentThread().getId()); } public static void releaseNettyLock(String operationLock) { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(operationLock + Thread.currentThread().getId(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(operationLock + Thread.currentThread().getId()); } } diff --git a/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java index 10c000dc3..8ef69f185 100644 --- a/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java +++ b/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelInboundHandler_Instrumentation.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -23,7 +24,7 @@ public abstract class ChannelInboundHandler_Instrumentation { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean isLockAcquired = false; if (msg instanceof HttpRequest || msg instanceof HttpContent){ - isLockAcquired = NettyUtils.acquireNettyLockIfPossible(NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK); + isLockAcquired = NettyUtils.acquireNettyLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK); } if (isLockAcquired) { NettyUtils.processSecurityRequest(ctx, msg, getClass().getName()); diff --git a/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java b/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java index 6a93460f1..3a6bfd8d4 100644 --- a/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java +++ b/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/channel/ChannelOutboundHandler_Instrumentation.java @@ -7,6 +7,7 @@ package security.io.netty400.channel; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -23,7 +24,7 @@ public abstract class ChannelOutboundHandler_Instrumentation { public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { boolean isLockAcquired = false; if (msg instanceof FullHttpResponse){ - isLockAcquired = NettyUtils.acquireNettyLockIfPossible(NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK_OUTBOUND); + isLockAcquired = NettyUtils.acquireNettyLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NettyUtils.NR_SEC_NETTY_OPERATIONAL_LOCK_OUTBOUND); } if (isLockAcquired) { NettyUtils.processSecurityResponse(ctx, msg); diff --git a/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/utils/NettyUtils.java b/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/utils/NettyUtils.java index ecdcc8fea..7901d121d 100644 --- a/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/utils/NettyUtils.java +++ b/instrumentation-security/netty-4.0.8/src/main/java/security/io/netty400/utils/NettyUtils.java @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; @@ -229,22 +230,11 @@ public static boolean isNettyLockAcquired(String operationLock) { return false; } - public static boolean acquireNettyLockIfPossible(String operationLock) { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isNettyLockAcquired(operationLock)) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(operationLock + Thread.currentThread().getId(), true); - return true; - } - } catch (Throwable ignored){} - return false; + public static boolean acquireNettyLockIfPossible(VulnerabilityCaseType reflectedXss, String operationLock) { + return GenericHelper.acquireLockIfPossible(reflectedXss, operationLock + Thread.currentThread().getId()); } public static void releaseNettyLock(String operationLock) { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(operationLock + Thread.currentThread().getId(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(operationLock + Thread.currentThread().getId()); } } diff --git a/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_0/NingHelper.java b/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_0/NingHelper.java index 8711a0146..8234aaa1b 100644 --- a/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_0/NingHelper.java +++ b/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_0/NingHelper.java @@ -6,15 +6,13 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.ning.http.client.Request; -import java.net.URI; -import java.net.URISyntaxException; - public class NingHelper { public static final String METHOD_NAME_EXECUTE = "execute"; public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SSRF_OPERATION_LOCK_NING-"; @@ -81,9 +79,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java b/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java index b8cd37149..7bb94be73 100644 --- a/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java +++ b/instrumentation-security/ning-async-http-client-1.0.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -20,7 +21,7 @@ public class AsyncHttpProvider_Instrumentation { public Future execute(Request request, AsyncHandler handler) throws IOException { - boolean isLockAcquired = NingHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = NingHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, this.hashCode()); AbstractOperation operation = null; URI uri = null; Future returnObj = null; diff --git a/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_1/NingHelper.java b/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_1/NingHelper.java index c2d17e323..16bdab028 100644 --- a/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_1/NingHelper.java +++ b/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_1/NingHelper.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -73,9 +74,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java b/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java index 04511aa11..4e0957511 100644 --- a/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java +++ b/instrumentation-security/ning-async-http-client-1.1.0/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java @@ -2,6 +2,7 @@ import com.newrelic.agent.security.instrumentation.ning.http_1_1.NingHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -15,7 +16,7 @@ public class AsyncHttpProvider_Instrumentation { public Future execute(Request request, AsyncHandler handler) throws IOException { - boolean isLockAcquired = NingHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = NingHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, this.hashCode()); AbstractOperation operation = null; URI uri = null; Future returnObj = null; diff --git a/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_6_1/NingHelper.java b/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_6_1/NingHelper.java index c4ecbb2f2..b6db3e353 100644 --- a/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_6_1/NingHelper.java +++ b/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/newrelic/agent/security/instrumentation/ning/http_1_6_1/NingHelper.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -78,9 +79,9 @@ public static void releaseLock(int hashCode) { } } - public static boolean acquireLockIfPossible(int hashCode) { + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest, int hashCode) { try { - return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; diff --git a/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java b/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java index 97da6d33c..e464b2e96 100644 --- a/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java +++ b/instrumentation-security/ning-async-http-client-1.6.1/src/main/java/com/ning/http/client/AsyncHttpProvider_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -15,7 +16,7 @@ public class AsyncHttpProvider_Instrumentation { public ListenableFuture execute(Request request, AsyncHandler handler) { - boolean isLockAcquired = NingHelper.acquireLockIfPossible(this.hashCode()); + boolean isLockAcquired = NingHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, this.hashCode()); AbstractOperation operation = null; URI uri = null; ListenableFuture returnObj = null; diff --git a/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/OkhttpHelper.java b/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/OkhttpHelper.java index 21c25c193..deb8b30f2 100644 --- a/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/OkhttpHelper.java +++ b/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/OkhttpHelper.java @@ -27,35 +27,7 @@ public static boolean skipExistsEvent() { return false; } - public static boolean isLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; - } - - public static void releaseLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } - } - - private static String getNrSecCustomAttribName() { + public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } diff --git a/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/RealCall_Instrumentation.java b/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/RealCall_Instrumentation.java index 20ce78e00..942e374c7 100644 --- a/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/RealCall_Instrumentation.java +++ b/instrumentation-security/okhttp-3.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp30/RealCall_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -23,16 +24,11 @@ abstract class RealCall_Instrumentation { Request originalRequest = Weaver.callOriginal(); private void releaseLock() { - try { - OkhttpHelper.releaseLock(); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(OkhttpHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible() { - try { - return OkhttpHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, OkhttpHelper.getNrSecCustomAttribName()); } /** @@ -40,7 +36,7 @@ private boolean acquireLockIfPossible() { * problem in the agent accessing constructor parameters in any non-no-arg constructor. */ public Response execute() { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = OkhttpHelper.preprocessSecurityHook(getUrl(originalRequest), this.getClass().getName(), diff --git a/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/OkhttpHelper.java b/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/OkhttpHelper.java index ea4ee3192..954687e05 100644 --- a/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/OkhttpHelper.java +++ b/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/OkhttpHelper.java @@ -27,35 +27,7 @@ public static boolean skipExistsEvent() { return false; } - public static boolean isLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; - } - - public static void releaseLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } - } - - private static String getNrSecCustomAttribName() { + public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } diff --git a/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/http/HttpCodec_Instrumentation.java b/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/http/HttpCodec_Instrumentation.java index 4da46eb6b..73e218b5d 100644 --- a/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/http/HttpCodec_Instrumentation.java +++ b/instrumentation-security/okhttp-3.5.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp35/http/HttpCodec_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -21,7 +22,7 @@ public abstract class HttpCodec_Instrumentation { public void writeRequestHeaders(Request request) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if (isLockAcquired) { operation = OkhttpHelper.preprocessSecurityHook(getUrl(request), this.getClass().getName(), @@ -42,18 +43,11 @@ public void writeRequestHeaders(Request request) { } private void releaseLock() { - try { - OkhttpHelper.releaseLock(); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(OkhttpHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible() { - try { - return OkhttpHelper.acquireLockIfPossible(); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, OkhttpHelper.getNrSecCustomAttribName()); } private String getUrl(Request originalRequest) { diff --git a/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/ExchangeCodec_Instrumentation.java b/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/ExchangeCodec_Instrumentation.java index d63ee8803..4831696db 100644 --- a/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/ExchangeCodec_Instrumentation.java +++ b/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/ExchangeCodec_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -22,16 +23,11 @@ public abstract class ExchangeCodec_Instrumentation { private void releaseLock() { - try { - OkhttpHelper.releaseLock(); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(OkhttpHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible() { - try { - return OkhttpHelper.acquireLockIfPossible(); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, OkhttpHelper.getNrSecCustomAttribName()); } private String getUrl(Request originalRequest) { @@ -46,7 +42,7 @@ private String getUrl(Request originalRequest) { } public void writeRequestHeaders(Request request) throws IOException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = OkhttpHelper.preprocessSecurityHook(getUrl(request), this.getClass().getName(), OkhttpHelper.METHOD_EXECUTE); diff --git a/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/OkhttpHelper.java b/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/OkhttpHelper.java index 7f2d936da..2274e5ef7 100644 --- a/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/OkhttpHelper.java +++ b/instrumentation-security/okhttp-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/okhttp40/OkhttpHelper.java @@ -27,35 +27,7 @@ public static boolean skipExistsEvent() { return false; } - public static boolean isLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; - } - - public static void releaseLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } - } - - private static String getNrSecCustomAttribName() { + public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } diff --git a/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/GeneratedRouter_Instrumentation.scala b/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/GeneratedRouter_Instrumentation.scala index 2bddaae88..4dabe9884 100644 --- a/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/GeneratedRouter_Instrumentation.scala +++ b/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/GeneratedRouter_Instrumentation.scala @@ -1,7 +1,7 @@ package com.newrelic.agent.security.instrumentation.play2_13 import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper -import com.newrelic.api.agent.security.schema.ApplicationURLMapping +import com.newrelic.api.agent.security.schema.{ApplicationURLMapping, StringUtils} import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver} import play.api.routing.HandlerDef import play.core.routing.{HandlerInvoker, HandlerInvokerFactory} @@ -24,7 +24,8 @@ abstract class GeneratedRouter_Instrumentation { val iterator = documentation.iterator while (iterator.hasNext) { val doc = iterator.next - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(doc._1, doc._2, doc._3)) + val handler = StringUtils.substringBeforeLast(doc._3, StringUtils.DOT_DELIMITER) + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(doc._1, doc._2, handler)) } } } diff --git a/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/HandlerInvoker.scala b/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/HandlerInvoker.scala index e87915497..efc73744b 100644 --- a/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/HandlerInvoker.scala +++ b/instrumentation-security/play-2.13_2.7/src/main/scala/com/newrelic/agent/security/instrumentation/play2_13/HandlerInvoker.scala @@ -9,6 +9,7 @@ package com.newrelic.agent.security.instrumentation.play2_13 import com.newrelic.api.agent.security.NewRelicSecurity import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper +import com.newrelic.api.agent.security.schema.Framework import com.newrelic.api.agent.security.utils.logging.LogLevel import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver} import play.api.mvc.Handler @@ -35,6 +36,16 @@ class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef } catch { case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_DETECTING_USER_CLASS, "PLAY-2.13_2.7"), t, this.getClass.getName) } + + // route detection + try { + if (NewRelicSecurity.isHookProcessingActive) { + NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.setRoute(handlerDef.path) + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFramework(Framework.PLAY) + } + } catch { + case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "PLAY-2.13_2.7"), t, this.getClass.getName) + } underlyingInvoker.call(call) } } diff --git a/instrumentation-security/play-2.13_2.7/src/test/java/com/nr/agent/security/instrumentation/play2_7/APIEndpointTest.java b/instrumentation-security/play-2.13_2.7/src/test/java/com/nr/agent/security/instrumentation/play2_7/APIEndpointTest.java index ddf7bd9fd..6cf9dfd65 100644 --- a/instrumentation-security/play-2.13_2.7/src/test/java/com/nr/agent/security/instrumentation/play2_7/APIEndpointTest.java +++ b/instrumentation-security/play-2.13_2.7/src/test/java/com/nr/agent/security/instrumentation/play2_7/APIEndpointTest.java @@ -13,6 +13,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.SecurityMetaData; import com.newrelic.security.test.marker.Java17IncompatibleTest; import org.junit.Assert; @@ -43,16 +44,15 @@ public class APIEndpointTest { public static void setupMappings() { expectedMappings.put("/hello", SimpleJavaController.class.getName() + ".hello"); expectedMappings.put("/scalaHello", SimpleScalaController.class.getName() + ".scalaHello"); - expectedMappings.put("/post", SimpleJavaController.class.getName() + ".post(data:String)"); + expectedMappings.put("/post/$data<[^/]+>", SimpleJavaController.class.getName() + ".post(data:String)"); + expectedMappings.put("/post1/$data<[a-zA-Z]+>", SimpleJavaController.class.getName() + ".post(data:String)"); expectedMappings.put("/index", SimpleJavaController.class.getName() + ".index"); expectedMappings.put("/simple", SimpleJavaController.class.getName() + ".simple"); } @Test public void testControllerActions() throws IOException { - HttpURLConnection conn = ((HttpURLConnection) serverRule.getEndpoint("/hello").openConnection()); - conn.connect(); - System.out.println(conn.getResponseCode()); + makeRequest("/hello"); Set actualMappings = URLMappingsHelper.getApplicationURLMappings(); Assert.assertNotNull(actualMappings); @@ -64,15 +64,52 @@ public void testControllerActions() throws IOException { // verification of user-class entity SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); SecurityMetaData metaData = introspector.getSecurityMetaData(); + verifyUserClassDetection(metaData, "hello"); + + // verification of route detection + Assert.assertEquals("/hello", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void testRouteDetection() throws IOException { + makeRequest("/post/data"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + SecurityMetaData metaData = introspector.getSecurityMetaData(); + + verifyUserClassDetection(metaData, "post"); + Assert.assertEquals("/post/$data<[^/]+>", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void testRouteDetection1() throws IOException { + makeRequest("/post1/data"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + SecurityMetaData metaData = introspector.getSecurityMetaData(); + + verifyUserClassDetection(metaData, "post"); + Assert.assertEquals("/post1/$data<[a-zA-Z]+>", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework()); + } + + private void makeRequest(String path) throws IOException { + HttpURLConnection conn = ((HttpURLConnection) serverRule.getEndpoint(path).openConnection()); + conn.connect(); + System.out.println(conn.getResponseCode()); + } + + private void verifyUserClassDetection(SecurityMetaData metaData, String methodName) { Assert.assertNotNull(metaData.getMetaData()); Assert.assertTrue(metaData.getMetaData().isUserLevelServiceMethodEncountered()); StackTraceElement element = metaData.getCustomAttribute(GenericHelper.USER_CLASS_ENTITY, StackTraceElement.class); Assert.assertNotNull(element); Assert.assertEquals(SimpleJavaController.class.getName(), element.getClassName()); - Assert.assertEquals("hello", element.getMethodName()); + Assert.assertEquals(methodName, element.getMethodName()); } - private void assertMappings(ApplicationURLMapping actualMapping){ Assert.assertNotNull(actualMapping.getPath()); Assert.assertNotNull(actualMapping.getHandler()); @@ -80,7 +117,7 @@ private void assertMappings(ApplicationURLMapping actualMapping){ String path = actualMapping.getPath(); String handler = expectedMappings.get(path); - String method = !path.equals("/post") ? "GET" : "POST"; + String method = "GET"; Assert.assertEquals(handler, actualMapping.getHandler()); Assert.assertEquals(method, actualMapping.getMethod()); diff --git a/instrumentation-security/play-2.13_2.7/src/test/resources/conf/routes b/instrumentation-security/play-2.13_2.7/src/test/resources/conf/routes index 530d9c58d..3f2a31c82 100644 --- a/instrumentation-security/play-2.13_2.7/src/test/resources/conf/routes +++ b/instrumentation-security/play-2.13_2.7/src/test/resources/conf/routes @@ -2,4 +2,5 @@ GET /hello com.nr.agent.security.instrumentation.play2_7.SimpleJava GET /index com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.index GET /simple com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.simple GET /scalaHello com.nr.agent.security.instrumentation.play2_7.SimpleScalaController.scalaHello -POST /post com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.post(data: String) \ No newline at end of file +GET /post/:data com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.post(data: String) +GET /post1/$data<[a-zA-Z]+> com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.post(data: String) \ No newline at end of file diff --git a/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/GeneratedRouter_Instrumentation.scala b/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/GeneratedRouter_Instrumentation.scala index b0d071e24..3a69e0ce6 100644 --- a/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/GeneratedRouter_Instrumentation.scala +++ b/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/GeneratedRouter_Instrumentation.scala @@ -1,7 +1,7 @@ package com.newrelic.agent.security.instrumentation.play24 import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper -import com.newrelic.api.agent.security.schema.ApplicationURLMapping +import com.newrelic.api.agent.security.schema.{ApplicationURLMapping, StringUtils} import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver} import play.core.routing.{HandlerDef, HandlerInvoker} @@ -22,7 +22,8 @@ abstract class GeneratedRouter_Instrumentation { val iterator = documentation.iterator while (iterator.hasNext) { val doc = iterator.next - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(doc._1, doc._2, doc._3)) + val handler = StringUtils.substringBeforeLast(doc._3, StringUtils.DOT_DELIMITER) + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(doc._1, doc._2, handler)) } } } diff --git a/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/HandlerInvoker.scala b/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/HandlerInvoker.scala index cb0d75e35..ced6c8e13 100644 --- a/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/HandlerInvoker.scala +++ b/instrumentation-security/play-2.4/src/main/scala/com/newrelic/agent/security/instrumentation/play24/HandlerInvoker.scala @@ -8,7 +8,8 @@ package com.newrelic.agent.security.instrumentation.play24 import com.newrelic.api.agent.security.NewRelicSecurity -import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, URLMappingsHelper} +import com.newrelic.api.agent.security.schema.{Framework, SecurityMetaData} import com.newrelic.api.agent.security.utils.logging.LogLevel import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver} import play.api.mvc.Handler @@ -34,6 +35,16 @@ class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef } catch { case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_DETECTING_USER_CLASS, "PLAY-2.4"), t, this.getClass.getName) } + + // route detection + try { + if (NewRelicSecurity.isHookProcessingActive) { + NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.setRoute(handlerDef.path) + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFramework(Framework.PLAY) + } + } catch { + case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "PLAY-2.4"), t, this.getClass.getName) + } underlyingInvoker.call(call) } } diff --git a/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/GeneratedRouter_Instrumentation.scala b/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/GeneratedRouter_Instrumentation.scala index 079fae659..3d67607aa 100644 --- a/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/GeneratedRouter_Instrumentation.scala +++ b/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/GeneratedRouter_Instrumentation.scala @@ -1,7 +1,7 @@ package com.newrelic.agent.security.instrumentation.play26 import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper -import com.newrelic.api.agent.security.schema.ApplicationURLMapping +import com.newrelic.api.agent.security.schema.{ApplicationURLMapping, StringUtils} import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver} import play.api.routing.HandlerDef import play.core.routing.HandlerInvoker @@ -23,7 +23,8 @@ abstract class GeneratedRouter_Instrumentation { val iterator = documentation.iterator while (iterator.hasNext) { val doc = iterator.next - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(doc._1, doc._2, doc._3)) + val handler = StringUtils.substringBeforeLast(doc._3, StringUtils.DOT_DELIMITER) + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(doc._1, doc._2, handler)) } } } diff --git a/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/HandlerInvoker.scala b/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/HandlerInvoker.scala index 389c30bf9..ca6b4fbf8 100644 --- a/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/HandlerInvoker.scala +++ b/instrumentation-security/play-2.6/src/main/scala/com/newrelic/agent/security/instrumentation/play26/HandlerInvoker.scala @@ -9,6 +9,7 @@ package com.newrelic.agent.security.instrumentation.play26 import com.newrelic.api.agent.security.NewRelicSecurity import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper +import com.newrelic.api.agent.security.schema.Framework import com.newrelic.api.agent.security.utils.logging.LogLevel import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver} import play.api.mvc.Handler @@ -35,6 +36,16 @@ class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef } catch { case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_DETECTING_USER_CLASS, "PLAY-2.6"), t, this.getClass.getName) } + + // route detection + try { + if (NewRelicSecurity.isHookProcessingActive) { + NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.setRoute(handlerDef.path) + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFramework(Framework.PLAY) + } + } catch { + case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "PLAY-2.6"), t, this.getClass.getName) + } underlyingInvoker.call(call) } } diff --git a/instrumentation-security/play-2.6/src/test/java/com/nr/agent/security/instrumentation/play26/APIEndpointTest.java b/instrumentation-security/play-2.6/src/test/java/com/nr/agent/security/instrumentation/play26/APIEndpointTest.java index 04b364d3a..cd02ecc49 100644 --- a/instrumentation-security/play-2.6/src/test/java/com/nr/agent/security/instrumentation/play26/APIEndpointTest.java +++ b/instrumentation-security/play-2.6/src/test/java/com/nr/agent/security/instrumentation/play26/APIEndpointTest.java @@ -14,6 +14,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.SecurityMetaData; import com.newrelic.security.test.marker.Java17IncompatibleTest; import org.junit.Assert; @@ -23,6 +24,7 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; +import java.awt.*; import java.io.IOException; import java.net.HttpURLConnection; import java.util.HashMap; @@ -44,16 +46,15 @@ public class APIEndpointTest { public static void setupMappings() { expectedMappings.put("/hello", SimpleJavaController.class.getName() + ".hello"); expectedMappings.put("/scalaHello", SimpleScalaController.class.getName() + ".scalaHello"); - expectedMappings.put("/post", SimpleJavaController.class.getName() + ".post(data:String)"); + expectedMappings.put("/post/$data<[^/]+>", SimpleJavaController.class.getName() + ".post(data:String)"); + expectedMappings.put("/post1/$data<[a-zA-Z]+>", SimpleJavaController.class.getName() + ".post(data:String)"); expectedMappings.put("/index", SimpleJavaController.class.getName() + ".index"); expectedMappings.put("/simple", SimpleJavaController.class.getName() + ".simple"); } @Test public void testControllerActions() throws IOException { - HttpURLConnection conn = ((HttpURLConnection) serverRule.getEndpoint("/hello").openConnection()); - conn.connect(); - System.out.println(conn.getResponseCode()); + makeRequest("/hello"); Set actualMappings = URLMappingsHelper.getApplicationURLMappings(); Assert.assertNotNull(actualMappings); @@ -65,15 +66,52 @@ public void testControllerActions() throws IOException { // verification of user-class entity SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); SecurityMetaData metaData = introspector.getSecurityMetaData(); + verifyUserClassDetection(metaData, "hello"); + + // verification of route detection + Assert.assertEquals("/hello", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void testRouteDetection() throws IOException { + makeRequest("/post/data"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + SecurityMetaData metaData = introspector.getSecurityMetaData(); + + verifyUserClassDetection(metaData, "post"); + Assert.assertEquals("/post/$data<[^/]+>", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void testRouteDetection1() throws IOException { + makeRequest("/post1/data"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + SecurityMetaData metaData = introspector.getSecurityMetaData(); + + verifyUserClassDetection(metaData, "post"); + Assert.assertEquals("/post1/$data<[a-zA-Z]+>", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework()); + } + + private void makeRequest(String path) throws IOException { + HttpURLConnection conn = ((HttpURLConnection) serverRule.getEndpoint(path).openConnection()); + conn.connect(); + System.out.println(conn.getResponseCode()); + } + + private void verifyUserClassDetection(SecurityMetaData metaData, String methodName) { Assert.assertNotNull(metaData.getMetaData()); Assert.assertTrue(metaData.getMetaData().isUserLevelServiceMethodEncountered()); StackTraceElement element = metaData.getCustomAttribute(GenericHelper.USER_CLASS_ENTITY, StackTraceElement.class); Assert.assertNotNull(element); Assert.assertEquals(SimpleJavaController.class.getName(), element.getClassName()); - Assert.assertEquals("hello", element.getMethodName()); + Assert.assertEquals(methodName, element.getMethodName()); } - private void assertMappings(ApplicationURLMapping actualMapping){ Assert.assertNotNull(actualMapping.getPath()); Assert.assertNotNull(actualMapping.getHandler()); @@ -81,7 +119,7 @@ private void assertMappings(ApplicationURLMapping actualMapping){ String path = actualMapping.getPath(); String handler = expectedMappings.get(path); - String method = !path.equals("/post") ? "GET" : "POST"; + String method = "GET"; Assert.assertEquals(handler, actualMapping.getHandler()); Assert.assertEquals(method, actualMapping.getMethod()); diff --git a/instrumentation-security/play-2.6/src/test/resources/conf/routes b/instrumentation-security/play-2.6/src/test/resources/conf/routes index 7af0d11ef..99a1ece7d 100644 --- a/instrumentation-security/play-2.6/src/test/resources/conf/routes +++ b/instrumentation-security/play-2.6/src/test/resources/conf/routes @@ -2,4 +2,5 @@ GET /hello com.nr.agent.security.instrumentation.play26.SimpleJavaC GET /index com.nr.agent.security.instrumentation.play26.SimpleJavaController.index GET /simple com.nr.agent.security.instrumentation.play26.SimpleJavaController.simple GET /scalaHello com.nr.agent.security.instrumentation.play26.SimpleScalaController.scalaHello -POST /post com.nr.agent.security.instrumentation.play26.SimpleJavaController.post(data: String) \ No newline at end of file +GET /post/:data com.nr.agent.security.instrumentation.play26.SimpleJavaController.post(data: String) +GET /post1/$data<[a-zA-Z]+> com.nr.agent.security.instrumentation.play26.SimpleJavaController.post(data: String) \ No newline at end of file diff --git a/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Batch_Instrumentation.java b/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Batch_Instrumentation.java index f8fccbf2d..859b689f0 100644 --- a/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Batch_Instrumentation.java +++ b/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Batch_Instrumentation.java @@ -2,6 +2,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.R2dbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; import com.newrelic.api.agent.weaver.Weave; @@ -19,7 +20,7 @@ public Batch add(String s){ } public Publisher execute() { - boolean isLockAcquired = R2dbcHelper.acquireLockIfPossible(); + boolean isLockAcquired = R2dbcHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if (isLockAcquired) { operation = R2dbcHelper.preprocessSecurityHook(sql, R2dbcHelper.METHOD_EXECUTE, this.getClass().getName(), null, false); diff --git a/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Statement_Instrumention.java b/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Statement_Instrumention.java index 9ca41985b..34934c952 100644 --- a/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Statement_Instrumention.java +++ b/instrumentation-security/r2dbc-generic/src/main/java/io/r2dbc/spi/Statement_Instrumention.java @@ -2,6 +2,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.R2dbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.NewField; import com.newrelic.api.agent.weaver.Weave; @@ -25,7 +26,7 @@ public class Statement_Instrumention { private boolean lock = false; public Publisher execute() { - boolean isLockAcquired = R2dbcHelper.acquireLockIfPossible(); + boolean isLockAcquired = R2dbcHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if (isLockAcquired) { operation = R2dbcHelper.preprocessSecurityHook(sql, R2dbcHelper.METHOD_EXECUTE, this.getClass().getName(), params, isPrepared); diff --git a/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/Client_Instrumentation.java b/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/Client_Instrumentation.java index ccada5043..99d5ea4db 100644 --- a/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/Client_Instrumentation.java +++ b/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/Client_Instrumentation.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.R2dbcHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.R2DBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,7 +19,7 @@ public class Client_Instrumentation { public void execute(String sql) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = R2dbcHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(sql, R2dbcHelper.METHOD_EXECUTE); @@ -81,12 +82,4 @@ private void releaseLock() { } catch (Throwable ignored) { } } - - private boolean acquireLockIfPossible() { - try { - return R2dbcHelper.acquireLockIfPossible(); - } catch (Throwable ignored) { - } - return false; - } } diff --git a/instrumentation-security/resteasy-2.2/src/main/java/com/newrelic/agent/security/instrumentation/resteasy2/RestEasyHelper.java b/instrumentation-security/resteasy-2.2/src/main/java/com/newrelic/agent/security/instrumentation/resteasy2/RestEasyHelper.java index b7f94a8c6..43efac8a5 100644 --- a/instrumentation-security/resteasy-2.2/src/main/java/com/newrelic/agent/security/instrumentation/resteasy2/RestEasyHelper.java +++ b/instrumentation-security/resteasy-2.2/src/main/java/com/newrelic/agent/security/instrumentation/resteasy2/RestEasyHelper.java @@ -6,19 +6,31 @@ import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.security.schema.SecurityMetaData; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import org.jboss.resteasy.core.ResourceInvoker; import org.jboss.resteasy.core.ResourceLocator; import org.jboss.resteasy.core.ResourceMethod; +import java.util.Collections; +import java.util.List; + public class RestEasyHelper { - private static final String WILDCARD = "*"; public static final String RESTEASY_22 = "RESTEASY-2.2"; + public static final String RESTEASY_SUB_RESOURCE_LIST = "SUB_RESOURCE_LIST"; public static final String ROUTE_DETECTION_COMPLETED = "ROUTE_DETECTION_COMPLETED"; public static void gatherUrlMappings(String path, ResourceInvoker invoker) { try{ + List subResourceList = Collections.emptyList(); + if (NewRelicSecurity.isHookProcessingActive()) { + subResourceList = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(RESTEASY_SUB_RESOURCE_LIST, List.class); + } if(invoker instanceof ResourceMethod) { ResourceMethod methodInvoker = (ResourceMethod) invoker; + if (subResourceList != null && !subResourceList.isEmpty() && subResourceList.contains(methodInvoker.getResourceClass().getName())){ + return; + } String handler = methodInvoker.getResourceClass().getName(); for (String httpMethod: methodInvoker.getHttpMethods()){ @@ -28,13 +40,16 @@ public static void gatherUrlMappings(String path, ResourceInvoker invoker) { // case of SubResources else if(invoker instanceof ResourceLocator) { ResourceLocator locatorInvoker = (ResourceLocator) invoker; + if (subResourceList != null && !subResourceList.isEmpty() && subResourceList.contains(locatorInvoker.getMethod().getDeclaringClass().getName())){ + return; + } String handler = locatorInvoker.getMethod().getDeclaringClass().getName(); - String finalPath = StringUtils.appendIfMissing(path, StringUtils.SEPARATOR) + WILDCARD; + String finalPath = StringUtils.appendIfMissing(path, StringUtils.SEPARATOR) + URLMappingsHelper.WILDCARD; - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, finalPath, handler)); + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, finalPath, handler)); } } catch (Exception ignored){ - NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, RESTEASY_22, ignored.getMessage()), ignored, RestEasyHelper.class.getName()); + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, RESTEASY_22, ignored.getMessage()), ignored, RestEasyHelper.class.getName()); } } } diff --git a/instrumentation-security/resteasy-2.2/src/main/java/org/jboss/resteasy/util/GetRestful_Instrumentation.java b/instrumentation-security/resteasy-2.2/src/main/java/org/jboss/resteasy/util/GetRestful_Instrumentation.java new file mode 100644 index 000000000..53fbadcf7 --- /dev/null +++ b/instrumentation-security/resteasy-2.2/src/main/java/org/jboss/resteasy/util/GetRestful_Instrumentation.java @@ -0,0 +1,29 @@ +package org.jboss.resteasy.util; + +import com.newrelic.agent.security.instrumentation.resteasy2.RestEasyHelper; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.schema.SecurityMetaData; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import java.util.ArrayList; +import java.util.List; + +@Weave(originalName = "org.jboss.resteasy.util.GetRestful") +public class GetRestful_Instrumentation { + + private static boolean hasJAXRSAnnotations(Class c){ + boolean result = Weaver.callOriginal(); + if (NewRelicSecurity.isHookProcessingActive() && Boolean.TRUE.equals(result)){ + SecurityMetaData metaData = NewRelicSecurity.getAgent().getSecurityMetaData(); + List subResourceList = metaData.getCustomAttribute(RestEasyHelper.RESTEASY_SUB_RESOURCE_LIST, List.class); + if (subResourceList == null) { + subResourceList = new ArrayList<>(); + } + subResourceList.add(c.getName()); + metaData.addCustomAttribute(RestEasyHelper.RESTEASY_SUB_RESOURCE_LIST, subResourceList); + } + return result; + } + +} diff --git a/instrumentation-security/rhino-jsinjection/src/main/java/org/mozilla/javascript/ScriptRuntime_Instrumentation.java b/instrumentation-security/rhino-jsinjection/src/main/java/org/mozilla/javascript/ScriptRuntime_Instrumentation.java index eab41aa5d..7a5c2ffbc 100644 --- a/instrumentation-security/rhino-jsinjection/src/main/java/org/mozilla/javascript/ScriptRuntime_Instrumentation.java +++ b/instrumentation-security/rhino-jsinjection/src/main/java/org/mozilla/javascript/ScriptRuntime_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.JSInjectionOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -22,7 +23,7 @@ public static Object doTopCall(Callable callable, Context_Instrumentation cx, Sc AbstractOperation operation = null; if(cx != null) { code = cx.hashCode(); - isLockAcquired = acquireLockIfPossible(code); + isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION, code); if (isLockAcquired) { operation = preprocessSecurityHook(code, JSEngineUtils.METHOD_EXEC, cx); } @@ -81,9 +82,9 @@ private static void releaseLock(int code) { } catch (Throwable ignored) {} } - private static boolean acquireLockIfPossible(int code) { + private static boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection, int code) { try { - return GenericHelper.acquireLockIfPossible(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME+code); + return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME+code); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/saxpath/src/main/java/org/saxpath/XPathReader_Instrumentation.java b/instrumentation-security/saxpath/src/main/java/org/saxpath/XPathReader_Instrumentation.java index 438adef1d..fd01d9a7b 100644 --- a/instrumentation-security/saxpath/src/main/java/org/saxpath/XPathReader_Instrumentation.java +++ b/instrumentation-security/saxpath/src/main/java/org/saxpath/XPathReader_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -17,7 +18,7 @@ public abstract class XPathReader_Instrumentation { public void parse(String xpath) throws SAXPathException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_PARSE); @@ -73,9 +74,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/HttpServletHelper.java b/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/HttpServletHelper.java index aa6ceacd9..272fe95d2 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/HttpServletHelper.java +++ b/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/HttpServletHelper.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -13,7 +14,6 @@ import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Enumeration; -import java.util.Iterator; import java.util.Map; public class HttpServletHelper { @@ -142,6 +142,10 @@ public static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if ( StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/FilterChain_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/FilterChain_Instrumentation.java index bf9930a22..1b5a12ea2 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/FilterChain_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/FilterChain_Instrumentation.java @@ -93,6 +93,9 @@ private void preprocessSecurityHook(ServletRequest request, ServletResponse resp private void postProcessSecurityHook(ServletRequest request, ServletResponse response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Filter_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Filter_Instrumentation.java index c62d5a0a7..e4cdc168d 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Filter_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Filter_Instrumentation.java @@ -94,6 +94,9 @@ private void preprocessSecurityHook(ServletRequest request, ServletResponse resp private void postProcessSecurityHook(ServletRequest request, ServletResponse response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Servlet_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Servlet_Instrumentation.java index e3ab77671..be10a2e4d 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Servlet_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/Servlet_Instrumentation.java @@ -99,6 +99,9 @@ private void preprocessSecurityHook(ServletRequest_Instrumentation request, Serv private void postProcessSecurityHook(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpServletResponse_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpServletResponse_Instrumentation.java index f94ba5081..204c7c31e 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpServletResponse_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpServletResponse_Instrumentation.java @@ -9,7 +9,6 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; -import com.newrelic.api.agent.security.schema.operation.SecureCookieOperation; import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; @@ -56,12 +55,16 @@ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className sameSiteStrict = StringUtils.containsIgnoreCase(cookie.getValue(), "SameSite=Strict"); } - SecureCookieOperation operation = new SecureCookieOperation(Boolean.toString(isSecure ), isSecure, isHttpOnly, sameSiteStrict, cookie.getValue(), className, methodName); - operation.setLowSeverityHook(true); - NewRelicSecurity.getAgent().registerOperation(operation); + SecureCookieOperationSet operations = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("SECURE_COOKIE_OPERATION", SecureCookieOperationSet.class); + if(operations == null){ + operations = new SecureCookieOperationSet(className, methodName);; + operations.setLowSeverityHook(true); + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute("SECURE_COOKIE_OPERATION", operations); + } + operations.addOperation(cookie.getName(), cookie.getValue(), isSecure, isHttpOnly, sameSiteStrict); // NewRelicSecurity.getAgent().registerOperation(operation); - return operation; + return operations; } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_2_4, e.getMessage()), e, HttpServletResponse_Instrumentation.class.getName()); diff --git a/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpSessionTest.java b/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpSessionTest.java index 663714725..1902c87c8 100644 --- a/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpSessionTest.java +++ b/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpSessionTest.java @@ -5,7 +5,7 @@ import com.newrelic.agent.security.introspec.SecurityIntrospector; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; -import com.newrelic.api.agent.security.schema.operation.SecureCookieOperation; +import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.schema.operation.TrustBoundaryOperation; import org.junit.Assert; import org.junit.ClassRule; @@ -18,6 +18,7 @@ import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; +import java.util.Iterator; import java.util.List; @RunWith(SecurityInstrumentationTestRunner.class) @@ -29,9 +30,7 @@ public class HttpSessionTest { @Test public void testSessionSetAttribute() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "set"); + makeRequest("set"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); @@ -61,9 +60,7 @@ else if(i==1){ @Test public void testSessionPutValue() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "put"); + makeRequest("put"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); @@ -84,49 +81,117 @@ public void testSessionPutValue() throws IOException, URISyntaxException { @Test public void testAddCookie() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "cookie"); + makeRequest("securecookie"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); Assert.assertTrue("No operations detected", operations.size() > 0); Assert.assertTrue("Unexpected operation count detected", operations.size() == 1 || operations.size() == 2); - SecureCookieOperation targetOperation = null; - for (AbstractOperation operation : operations) { - if (operation instanceof SecureCookieOperation) - targetOperation = (SecureCookieOperation) operation; - }; - Assert.assertNotNull("No target operation detected", targetOperation); - Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); - Assert.assertEquals("Wrong key detected", "false", targetOperation.getValue()); + SecureCookieOperationSet targetOperation = null; + targetOperation = verifySecureCookieOp(operations); + + Assert.assertEquals(1, targetOperation.getOperations().size()); + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "key", false, true); } @Test public void testAddCookie1() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "securecookie"); + makeRequest("cookie"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); - Assert.assertTrue("No operations detected", operations.size() > 0); - Assert.assertTrue("Unexpected operation count detected", operations.size() == 1 || operations.size() == 2); - SecureCookieOperation targetOperation = null; - for (AbstractOperation operation : operations) { - if (operation instanceof SecureCookieOperation) - targetOperation = (SecureCookieOperation) operation; - }; - Assert.assertNotNull("No target operation detected", targetOperation); - Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); - Assert.assertEquals("Wrong key detected", "true", targetOperation.getValue()); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(1, targetOperation.getOperations().size()); + + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "key", false, false); + } + + @Test + public void testAddSecureCookies() throws IOException, URISyntaxException { + makeRequest("secure_cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("secure-cookie-1")) { + verifySecureCookie(secureCookieOp, "secure-cookie-1", false, true); + } else { + verifySecureCookie(secureCookieOp, "secure-cookie-2", true, true); + } + } + } + + @Test + public void testAddInSecureCookies() throws IOException, URISyntaxException { + makeRequest("insecure_cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("insecure-cookie-1")) { + verifySecureCookie(secureCookieOp, "insecure-cookie-1", false, false); + } else { + verifySecureCookie(secureCookieOp, "insecure-cookie-2", false, false); + } + } } - private void makeRequest( String Method, final String POST_PARAMS, String path) throws URISyntaxException, IOException{ + @Test + public void testAddMultiSecureCookies() throws IOException, URISyntaxException { + makeRequest("cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("insecure-cookie")) { + verifySecureCookie(secureCookieOp, "insecure-cookie", false, false); + } else { + verifySecureCookie(secureCookieOp, "secure-cookie", false, true); + } + } + } + + @Test + public void testSingleCookie() throws IOException, URISyntaxException { + makeRequest("single-cookie"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(1, targetOperation.getOperations().size()); + + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "cookie", true, true); + } + + private void makeRequest(String path) throws URISyntaxException, IOException{ URL u = server.getEndPoint("session/"+path).toURL(); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setRequestMethod(Method); conn.setDoOutput(true); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Cache-Control", "no-cache"); @@ -134,6 +199,28 @@ private void makeRequest( String Method, final String POST_PARAMS, String path) conn.connect(); conn.getResponseCode(); + } + + private SecureCookieOperationSet verifySecureCookieOp(List operations) { + SecureCookieOperationSet targetOperation = null; + for (AbstractOperation operation : operations) { + if (operation instanceof SecureCookieOperationSet) { + targetOperation = (SecureCookieOperationSet) operation; + } + } + + Assert.assertNotNull("No target operation detected", targetOperation); + Assert.assertEquals("Wrong method detected", "addCookie", targetOperation.getMethodName()); + Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); + Assert.assertTrue("isLowSeverityHook should be true", targetOperation.isLowSeverityHook()); + return targetOperation; + } + private void verifySecureCookie(SecureCookieOperationSet.SecureCookieOperation secureCookieOp, String key, boolean isHttpOnly, boolean isSecure) { + Assert.assertEquals("Wrong cookie key detected", key, secureCookieOp.getName()); + Assert.assertEquals("Wrong cookie value detected", "value", secureCookieOp.getValue()); + Assert.assertEquals(String.format("isHttpOnly should be %s", isHttpOnly), isHttpOnly, secureCookieOp.isHttpOnly()); + Assert.assertEquals(String.format("isSecure should be %s", isSecure), isSecure, secureCookieOp.isSecure()); + Assert.assertTrue(String.format("isSameSiteStrict should be %s", true), secureCookieOp.isSameSiteStrict()); } } diff --git a/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpTestServlet.java b/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpTestServlet.java index 896b24d07..2e53978e0 100644 --- a/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpTestServlet.java +++ b/instrumentation-security/servlet-2.4/src/test/java/com/nr/agent/security/instrumentation/servlet24/HttpTestServlet.java @@ -102,7 +102,35 @@ else if(path.equals("/session/put")){ cookie.setSecure(true); response.addCookie(cookie); } else if(path.equals("/session/cookie")){ - Cookie cookie = new Cookie("key1", "value1"); + // add insecure cookie to response + response.addCookie(new Cookie("key", "value")); + } else if (path.equals("/session/secure_cookies")) { + // add multiple secure cookies to response + Cookie cookie = new Cookie("secure-cookie-1", "value"); + cookie.setSecure(true); + response.addCookie(cookie); + + Cookie cookie1 = new Cookie("secure-cookie-2", "value"); + cookie1.setSecure(true); + cookie1.setHttpOnly(true); + cookie1.setComment("__SAME_SITE_STRICT__"); + response.addCookie(cookie1); + } else if (path.equals("/session/insecure_cookies")) { + // add multiple insecure cookies to response + response.addCookie(new Cookie("insecure-cookie-1", "value")); + response.addCookie(new Cookie("insecure-cookie-2", "value")); + } else if (path.equals("/session/cookies")){ + // add multiple cookies to response + Cookie cookie = new Cookie("secure-cookie", "value"); + cookie.setSecure(true); + response.addCookie(cookie); + + response.addCookie(new Cookie("insecure-cookie","value")); + } else if (path.equals("/session/single-cookie")){ + Cookie cookie = new Cookie("cookie", "value"); + cookie.setSecure(true); + cookie.setHttpOnly(true); + cookie.setComment("__SAME_SITE_LAX__"); response.addCookie(cookie); } } diff --git a/instrumentation-security/servlet-3.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet30/HttpServletHelper.java b/instrumentation-security/servlet-3.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet30/HttpServletHelper.java index 5084a7634..69fce5348 100644 --- a/instrumentation-security/servlet-3.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet30/HttpServletHelper.java +++ b/instrumentation-security/servlet-3.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet30/HttpServletHelper.java @@ -5,6 +5,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.StringUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import javax.servlet.ServletContext; @@ -36,6 +37,10 @@ public static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if ( StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/HttpServletHelper.java b/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/HttpServletHelper.java index 24c53074c..b87171180 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/HttpServletHelper.java +++ b/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/HttpServletHelper.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; import jakarta.servlet.ServletContext; @@ -142,6 +143,10 @@ public static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if ( StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java index 4ffa56d11..1362bbe9c 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java @@ -92,6 +92,9 @@ private void preprocessSecurityHook(ServletRequest request, ServletResponse resp private void postProcessSecurityHook(ServletRequest request, ServletResponse response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java index fa7051cb3..e82bf14d1 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java @@ -94,6 +94,9 @@ private void preprocessSecurityHook(ServletRequest request, ServletResponse resp private void postProcessSecurityHook(ServletRequest request, ServletResponse response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java index a8b32bfe1..803e80689 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java @@ -98,6 +98,9 @@ private void preprocessSecurityHook(ServletRequest_Instrumentation request, Serv private void postProcessSecurityHook(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java index b81181ba4..186841c43 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java @@ -9,7 +9,6 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; -import com.newrelic.api.agent.security.schema.operation.SecureCookieOperation; import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; @@ -56,12 +55,16 @@ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className sameSiteStrict = StringUtils.containsIgnoreCase(cookie.getValue(), "SameSite=Strict"); } - SecureCookieOperation operation = new SecureCookieOperation(Boolean.toString(isSecure ), isSecure, isHttpOnly, sameSiteStrict, cookie.getValue(), className, methodName); - operation.setLowSeverityHook(true); - NewRelicSecurity.getAgent().registerOperation(operation); + SecureCookieOperationSet operations = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("SECURE_COOKIE_OPERATION", SecureCookieOperationSet.class); + if(operations == null){ + operations = new SecureCookieOperationSet(className, methodName);; + operations.setLowSeverityHook(true); + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute("SECURE_COOKIE_OPERATION", operations); + } + operations.addOperation(cookie.getName(), cookie.getValue(), isSecure, isHttpOnly, sameSiteStrict); // NewRelicSecurity.getAgent().registerOperation(operation); - return operation; + return operations; } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_5_0, e.getMessage()), e, HttpServletResponse_Instrumentation.class.getName()); diff --git a/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpSessionTest.java b/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpSessionTest.java index 95f12ce0f..f39ae8fa0 100644 --- a/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpSessionTest.java +++ b/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpSessionTest.java @@ -5,7 +5,7 @@ import com.newrelic.agent.security.introspec.SecurityIntrospector; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; -import com.newrelic.api.agent.security.schema.operation.SecureCookieOperation; +import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.schema.operation.TrustBoundaryOperation; import org.junit.Assert; import org.junit.ClassRule; @@ -18,6 +18,7 @@ import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; +import java.util.Iterator; import java.util.List; @RunWith(SecurityInstrumentationTestRunner.class) @@ -29,9 +30,7 @@ public class HttpSessionTest { @Test public void testSessionSetAttribute() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "set"); + makeRequest("set"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); @@ -61,9 +60,7 @@ else if(i==1){ @Test public void testSessionPutValue() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "put"); + makeRequest("put"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); @@ -79,53 +76,122 @@ public void testSessionPutValue() throws IOException, URISyntaxException { Assert.assertEquals("Wrong key detected", "key1", targetOperation.getKey()); Assert.assertEquals("Wrong value detected", "value1", targetOperation.getValue()); } + } @Test public void testAddCookie() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "cookie"); + makeRequest("securecookie"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); Assert.assertTrue("No operations detected", operations.size() > 0); Assert.assertTrue("Unexpected operation count detected", operations.size() == 1 || operations.size() == 2); - SecureCookieOperation targetOperation = null; - for (AbstractOperation operation : operations) { - if (operation instanceof SecureCookieOperation) - targetOperation = (SecureCookieOperation) operation; - }; - Assert.assertNotNull("No target operation detected", targetOperation); - Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); - Assert.assertEquals("Wrong key detected", "false", targetOperation.getValue()); + SecureCookieOperationSet targetOperation = null; + targetOperation = verifySecureCookieOp(operations); + + Assert.assertEquals(1, targetOperation.getOperations().size()); + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "key", false, true); } @Test public void testAddCookie1() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "securecookie"); + makeRequest("cookie"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); - Assert.assertTrue("No operations detected", operations.size() > 0); - Assert.assertTrue("Unexpected operation count detected", operations.size() == 1 || operations.size() == 2); - SecureCookieOperation targetOperation = null; - for (AbstractOperation operation : operations) { - if (operation instanceof SecureCookieOperation) - targetOperation = (SecureCookieOperation) operation; - }; - Assert.assertNotNull("No target operation detected", targetOperation); - Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); - Assert.assertEquals("Wrong key detected", "true", targetOperation.getValue()); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(1, targetOperation.getOperations().size()); + + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "key", false, false); + } + + @Test + public void testAddSecureCookies() throws IOException, URISyntaxException { + makeRequest("secure_cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("secure-cookie-1")) { + verifySecureCookie(secureCookieOp, "secure-cookie-1", false, true); + } else { + verifySecureCookie(secureCookieOp, "secure-cookie-2", true, true); + } + } + } + + @Test + public void testAddInSecureCookies() throws IOException, URISyntaxException { + makeRequest("insecure_cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("insecure-cookie-1")) { + verifySecureCookie(secureCookieOp, "insecure-cookie-1", false, false); + } else { + verifySecureCookie(secureCookieOp, "insecure-cookie-2", false, false); + } + } + } + + @Test + public void testAddMultiSecureCookies() throws IOException, URISyntaxException { + makeRequest("cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("insecure-cookie")) { + verifySecureCookie(secureCookieOp, "insecure-cookie", false, false); + } else { + verifySecureCookie(secureCookieOp, "secure-cookie", false, true); + } + } } - private void makeRequest( String Method, final String POST_PARAMS, String path) throws URISyntaxException, IOException{ + @Test + public void testSingleCookie() throws IOException, URISyntaxException { + makeRequest("single-cookie"); + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(1, targetOperation.getOperations().size()); + + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + + Assert.assertTrue(secureCookieOps.hasNext()); + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "cookie", true, true); + } + + private void makeRequest(String path) throws URISyntaxException, IOException{ URL u = server.getEndPoint("session/"+path).toURL(); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setRequestMethod(Method); conn.setDoOutput(true); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Cache-Control", "no-cache"); @@ -133,6 +199,29 @@ private void makeRequest( String Method, final String POST_PARAMS, String path) conn.connect(); conn.getResponseCode(); + } + private SecureCookieOperationSet verifySecureCookieOp(List operations) { + SecureCookieOperationSet targetOperation = null; + for (AbstractOperation operation : operations) { + if (operation instanceof SecureCookieOperationSet) { + targetOperation = (SecureCookieOperationSet) operation; + } + } + + Assert.assertNotNull("No target operation detected", targetOperation); + Assert.assertEquals("Wrong method detected", "addCookie", targetOperation.getMethodName()); + Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); + Assert.assertTrue("isLowSeverityHook should be true", targetOperation.isLowSeverityHook()); + return targetOperation; } + + private void verifySecureCookie(SecureCookieOperationSet.SecureCookieOperation secureCookieOp, String key, boolean isHttpOnly, boolean isSecure) { + Assert.assertEquals("Wrong cookie key detected", key, secureCookieOp.getName()); + Assert.assertEquals("Wrong cookie value detected", "value", secureCookieOp.getValue()); + Assert.assertEquals(String.format("isHttpOnly should be %s", isHttpOnly), isHttpOnly, secureCookieOp.isHttpOnly()); + Assert.assertEquals(String.format("isSecure should be %s", isSecure), isSecure, secureCookieOp.isSecure()); + Assert.assertTrue(String.format("isSameSiteStrict should be %s", true), secureCookieOp.isSameSiteStrict()); + } + } diff --git a/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpTestServlet.java b/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpTestServlet.java index 89df822d9..e0b0611fd 100644 --- a/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpTestServlet.java +++ b/instrumentation-security/servlet-5.0/src/test/java/com/nr/agent/security/instrumentation/servlet5/HttpTestServlet.java @@ -103,8 +103,36 @@ else if(path.equals("/session/securecookie")){ Cookie cookie = new Cookie("key", "value"); cookie.setSecure(true); response.addCookie(cookie); - } else if(path.equals("/session/cookie")){ - Cookie cookie = new Cookie("key1", "value1"); + } else if(path.equals("/session/cookie")){ + // add insecure cookie to response + response.addCookie(new Cookie("key", "value")); + } else if (path.equals("/session/secure_cookies")) { + // add multiple secure cookies to response + Cookie cookie = new Cookie("secure-cookie-1", "value"); + cookie.setSecure(true); + response.addCookie(cookie); + + Cookie cookie1 = new Cookie("secure-cookie-2", "value"); + cookie1.setSecure(true); + cookie1.setHttpOnly(true); + cookie1.setComment("__SAME_SITE_STRICT__"); + response.addCookie(cookie1); + } else if (path.equals("/session/insecure_cookies")) { + // add multiple insecure cookies to response + response.addCookie(new Cookie("insecure-cookie-1", "value")); + response.addCookie(new Cookie("insecure-cookie-2", "value")); + } else if (path.equals("/session/cookies")){ + // add multiple cookies to response + Cookie cookie = new Cookie("secure-cookie", "value"); + cookie.setSecure(true); + response.addCookie(cookie); + + response.addCookie(new Cookie("insecure-cookie","value")); + } else if (path.equals("/session/single-cookie")){ + Cookie cookie = new Cookie("cookie", "value"); + cookie.setSecure(true); + cookie.setHttpOnly(true); + cookie.setComment("__SAME_SITE_LAX__"); response.addCookie(cookie); } } diff --git a/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/HttpServletHelper.java b/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/HttpServletHelper.java index 847d8e440..9f198294e 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/HttpServletHelper.java +++ b/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/HttpServletHelper.java @@ -5,6 +5,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; import jakarta.servlet.ServletContext; @@ -142,6 +143,10 @@ public static void getJSPMappings(ServletContext servletContext, String dir) { if(dir.endsWith(SEPARATOR)){ Collection resourcePaths = servletContext.getResourcePaths(dir); for (String path : resourcePaths) { + String entry = StringUtils.removeStart(StringUtils.removeEnd(path, SEPARATOR), StringUtils.SEPARATOR); + if ( StringUtils.equalsAny(entry, "META-INF", "WEB-INF")) { + continue; + } if(path.endsWith(SEPARATOR)) { getJSPMappings(servletContext, path); } diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java index 3b2ff79a9..d602a19d9 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/FilterChain_Instrumentation.java @@ -93,6 +93,9 @@ private void preprocessSecurityHook(ServletRequest request, ServletResponse resp private void postProcessSecurityHook(ServletRequest request, ServletResponse response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java index c2855bd94..5edd9af5c 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Filter_Instrumentation.java @@ -94,6 +94,9 @@ private void preprocessSecurityHook(ServletRequest request, ServletResponse resp private void postProcessSecurityHook(ServletRequest request, ServletResponse response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java index d7ac8309c..3eb80fe5a 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/Servlet_Instrumentation.java @@ -98,6 +98,9 @@ private void preprocessSecurityHook(ServletRequest_Instrumentation request, Serv private void postProcessSecurityHook(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java index bf70e32d0..c42a612f4 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpServletResponse_Instrumentation.java @@ -9,7 +9,6 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; -import com.newrelic.api.agent.security.schema.operation.SecureCookieOperation; import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; @@ -57,12 +56,16 @@ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className sameSiteStrict = StringUtils.containsIgnoreCase(cookie.getValue(), "SameSite=Strict"); } - SecureCookieOperation operation = new SecureCookieOperation(Boolean.toString(isSecure ), isSecure, isHttpOnly, sameSiteStrict, cookie.getValue(), className, methodName); - operation.setLowSeverityHook(true); - NewRelicSecurity.getAgent().registerOperation(operation); + SecureCookieOperationSet operations = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("SECURE_COOKIE_OPERATION", SecureCookieOperationSet.class); + if(operations == null){ + operations = new SecureCookieOperationSet(className, methodName);; + operations.setLowSeverityHook(true); + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute("SECURE_COOKIE_OPERATION", operations); + } + operations.addOperation(cookie.getName(), cookie.getValue(), isSecure, isHttpOnly, sameSiteStrict); // NewRelicSecurity.getAgent().registerOperation(operation); - return operation; + return operations; } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_6_0, e.getMessage()), e, HttpServletResponse_Instrumentation.class.getName()); diff --git a/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpSessionTest.java b/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpSessionTest.java index 5cfb1b016..5896fbdf2 100644 --- a/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpSessionTest.java +++ b/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpSessionTest.java @@ -5,7 +5,7 @@ import com.newrelic.agent.security.introspec.SecurityIntrospector; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; -import com.newrelic.api.agent.security.schema.operation.SecureCookieOperation; +import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.schema.operation.TrustBoundaryOperation; import org.junit.Assert; import org.junit.ClassRule; @@ -18,6 +18,7 @@ import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; +import java.util.Iterator; import java.util.List; @RunWith(SecurityInstrumentationTestRunner.class) @@ -29,9 +30,7 @@ public class HttpSessionTest { @Test public void testSessionSetAttribute() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "session"); + makeRequest(""); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); @@ -61,49 +60,116 @@ else if(i==1){ @Test public void testAddCookie() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "cookie"); + makeRequest("/cookie"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); Assert.assertTrue("No operations detected", operations.size() > 0); Assert.assertTrue("Unexpected operation count detected", operations.size() == 1 || operations.size() == 2); - SecureCookieOperation targetOperation = null; - for (AbstractOperation operation : operations) { - if (operation instanceof SecureCookieOperation) - targetOperation = (SecureCookieOperation) operation; - }; - Assert.assertNotNull("No target operation detected", targetOperation); - Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); - Assert.assertEquals("Wrong key detected", "false", targetOperation.getValue()); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "key", false, false); } @Test public void testAddCookie1() throws IOException, URISyntaxException { - String method = "GET"; - String POST_PARAMS = "hook=readLine"; - makeRequest(method, POST_PARAMS, "securecookie"); + makeRequest("/securecookie"); SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); Assert.assertTrue("No operations detected", operations.size() > 0); Assert.assertTrue("Unexpected operation count detected", operations.size() == 1 || operations.size() == 2); - SecureCookieOperation targetOperation = null; - for (AbstractOperation operation : operations) { - if (operation instanceof SecureCookieOperation) - targetOperation = (SecureCookieOperation) operation; - }; - Assert.assertNotNull("No target operation detected", targetOperation); - Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); - Assert.assertEquals("Wrong key detected", "true", targetOperation.getValue()); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + Assert.assertTrue(secureCookieOps.hasNext()); + + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "key", false, true); } - private void makeRequest( String Method, final String POST_PARAMS, String path) throws URISyntaxException, IOException{ + @Test + public void testAddSecureCookies() throws IOException, URISyntaxException { + makeRequest("/secure_cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); - URL u = server.getEndPoint(path).toURL(); + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("secure-cookie-1")) { + verifySecureCookie(secureCookieOp, "secure-cookie-1", false, true); + } else { + verifySecureCookie(secureCookieOp, "secure-cookie-2", true, true); + } + } + } + + @Test + public void testAddInSecureCookies() throws IOException, URISyntaxException { + makeRequest("/insecure_cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("insecure-cookie-1")) { + verifySecureCookie(secureCookieOp, "insecure-cookie-1", false, false); + } else { + verifySecureCookie(secureCookieOp, "insecure-cookie-2", false, false); + } + } + } + + @Test + public void testAddMultiSecureCookies() throws IOException, URISyntaxException { + makeRequest("/cookies"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(2, targetOperation.getOperations().size()); + + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { + if (secureCookieOp.getName().equals("insecure-cookie")) { + verifySecureCookie(secureCookieOp, "insecure-cookie", false, false); + } else { + verifySecureCookie(secureCookieOp, "secure-cookie", false, true); + } + } + } + + @Test + public void testSingleCookie() throws IOException, URISyntaxException { + makeRequest("/single-cookie"); + + SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); + List operations = introspector.getOperations(); + + SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); + Assert.assertEquals(1, targetOperation.getOperations().size()); + + Iterator secureCookieOps = targetOperation.getOperations().iterator(); + + Assert.assertTrue(secureCookieOps.hasNext()); + SecureCookieOperationSet.SecureCookieOperation secureCookieOp = secureCookieOps.next(); + verifySecureCookie(secureCookieOp, "cookie", true, true); + } + + private void makeRequest(String path) throws URISyntaxException, IOException{ + URL u = server.getEndPoint("session"+path).toURL(); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setRequestMethod(Method); conn.setDoOutput(true); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Cache-Control", "no-cache"); @@ -111,6 +177,27 @@ private void makeRequest( String Method, final String POST_PARAMS, String path) conn.connect(); conn.getResponseCode(); + } + private SecureCookieOperationSet verifySecureCookieOp(List operations) { + SecureCookieOperationSet targetOperation = null; + for (AbstractOperation operation : operations) { + if (operation instanceof SecureCookieOperationSet) { + targetOperation = (SecureCookieOperationSet) operation; + } + } + + Assert.assertNotNull("No target operation detected", targetOperation); + Assert.assertEquals("Wrong method detected", "addCookie", targetOperation.getMethodName()); + Assert.assertEquals("Wrong case-type detected", VulnerabilityCaseType.SECURE_COOKIE, targetOperation.getCaseType()); + Assert.assertTrue("isLowSeverityHook should be true", targetOperation.isLowSeverityHook()); + return targetOperation; } -} + + private void verifySecureCookie(SecureCookieOperationSet.SecureCookieOperation secureCookieOp, String key, boolean isHttpOnly, boolean isSecure) { + Assert.assertEquals("Wrong cookie key detected", key, secureCookieOp.getName()); + Assert.assertEquals("Wrong cookie value detected", "value", secureCookieOp.getValue()); + Assert.assertEquals(String.format("isHttpOnly should be %s", isHttpOnly), isHttpOnly, secureCookieOp.isHttpOnly()); + Assert.assertEquals(String.format("isSecure should be %s", isSecure), isSecure, secureCookieOp.isSecure()); + Assert.assertTrue(String.format("isSameSiteStrict should be %s", true), secureCookieOp.isSameSiteStrict()); + }} diff --git a/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpTestServlet.java b/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpTestServlet.java index 098ffed0a..688b00001 100644 --- a/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpTestServlet.java +++ b/instrumentation-security/servlet-6.0/src/test/java/com/nr/agent/security/instrumentation/servlet6/HttpTestServlet.java @@ -94,14 +94,40 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro if(path.equals("/session")){ HttpSession session = request.getSession(true); session.setAttribute("key", "value"); - } else if(path.equals("/securecookie")){ + } else if(path.equals("/session/securecookie")){ Cookie cookie = new Cookie("key", "value"); cookie.setSecure(true); response.addCookie(cookie); - } else if(path.equals("/cookie")){ - Cookie cookie = new Cookie("key", "value"); + } else if(path.equals("/session/cookie")){ + // add insecure cookie to response + response.addCookie(new Cookie("key", "value")); + } else if (path.equals("/session/secure_cookies")) { + // add multiple secure cookies to response + Cookie cookie = new Cookie("secure-cookie-1", "value"); + cookie.setSecure(true); response.addCookie(cookie); - } + + Cookie cookie1 = new Cookie("secure-cookie-2", "value"); + cookie1.setSecure(true); + cookie1.setHttpOnly(true); + response.addCookie(cookie1); + } else if (path.equals("/session/insecure_cookies")) { + // add multiple insecure cookies to response + response.addCookie(new Cookie("insecure-cookie-1", "value")); + response.addCookie(new Cookie("insecure-cookie-2", "value")); + } else if (path.equals("/session/cookies")){ + // add multiple cookies to response + Cookie cookie = new Cookie("secure-cookie", "value"); + cookie.setSecure(true); + response.addCookie(cookie); + + response.addCookie(new Cookie("insecure-cookie","value")); + } else if (path.equals("/session/single-cookie")){ + Cookie cookie = new Cookie("cookie", "value"); + cookie.setSecure(true); + cookie.setHttpOnly(true); + response.addCookie(cookie); + } } private void testServletRequestHooks( HttpServletRequest request, HttpServletResponse response) throws IOException { diff --git a/instrumentation-security/solr-4.0.0/build.gradle b/instrumentation-security/solr-4.0.0/build.gradle new file mode 100644 index 000000000..7db53c675 --- /dev/null +++ b/instrumentation-security/solr-4.0.0/build.gradle @@ -0,0 +1,34 @@ +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.lucene:lucene-core:4.0.0") + + implementation("org.apache.solr:solr-core:4.0.0") { + transitive = false + } + implementation("org.apache.solr:solr-solrj:4.0.0") { + transitive = false + } + implementation("org.apache.httpcomponents:httpclient:4.1.3") { + transitive = false + } +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.security.instrumentation.solr-4.0.0' } +} + +verifyInstrumentation { + passesOnly 'org.apache.solr:solr-core:[4.0.0,5.0.0)' + + exclude 'org.apache.solr:solr-core:[0,1.4.0)' + + excludeRegex 'org.apache.solr:solr-core:.*(ALPHA|BETA)+$' +} + +site { + title 'Solr' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation-security/solr-4.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrServer_Instrumentation.java b/instrumentation-security/solr-4.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrServer_Instrumentation.java new file mode 100644 index 000000000..d29563dc9 --- /dev/null +++ b/instrumentation-security/solr-4.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrServer_Instrumentation.java @@ -0,0 +1,111 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.http.client.HttpClient; +import org.apache.solr.client.solrj.ResponseParser; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrServer") +public abstract class HttpSolrServer_Instrumentation { + + public abstract String getBaseURL(); + + public HttpSolrServer_Instrumentation(String baseURL, HttpClient client, ResponseParser parser) { + //TODO report external URL + } + + public NamedList request(final SolrRequest request, ResponseParser processor) { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(request, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", request.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_4.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_4.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + +} diff --git a/instrumentation-security/solr-5.0.0/build.gradle b/instrumentation-security/solr-5.0.0/build.gradle new file mode 100644 index 000000000..e31bd3530 --- /dev/null +++ b/instrumentation-security/solr-5.0.0/build.gradle @@ -0,0 +1,32 @@ +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.lucene:lucene-core:4.0.0") + + implementation("org.apache.solr:solr-core:5.0.0") { + transitive = false + } + implementation("org.apache.solr:solr-solrj:5.0.0") { + transitive = false + } + implementation("org.apache.httpcomponents:httpclient:4.3.1") { + transitive = false + } +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.security.instrumentation.solr-5.0.0' } +} + +verifyInstrumentation { + passesOnly 'org.apache.solr:solr-core:[5.0.0,5.1.0)' + + excludeRegex 'org.apache.solr:solr-core:.*(ALPHA|BETA)+$' +} + +site { + title 'Solr' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation-security/solr-5.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java b/instrumentation-security/solr-5.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java new file mode 100644 index 000000000..8d7596c8d --- /dev/null +++ b/instrumentation-security/solr-5.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java @@ -0,0 +1,111 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.http.client.HttpClient; +import org.apache.solr.client.solrj.ResponseParser; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient") +public abstract class HttpSolrClient_Instrumentation { + + public abstract String getBaseURL(); + + public HttpSolrClient_Instrumentation(String baseURL, HttpClient client, ResponseParser parser) { + //TODO report external URL + } + + public NamedList request(final SolrRequest request, final ResponseParser processor) { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(request, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", request.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_5.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_5.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_5.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_5.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_5.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + +} diff --git a/instrumentation-security/solr-5.0.0/src/main/java/org/apache/solr/handler/StreamHandler.java b/instrumentation-security/solr-5.0.0/src/main/java/org/apache/solr/handler/StreamHandler.java new file mode 100644 index 000000000..a8ada0ab6 --- /dev/null +++ b/instrumentation-security/solr-5.0.0/src/main/java/org/apache/solr/handler/StreamHandler.java @@ -0,0 +1,7 @@ +package org.apache.solr.handler; + +import com.newrelic.api.agent.weaver.SkipIfPresent; + +@SkipIfPresent +public class StreamHandler { +} diff --git a/instrumentation-security/solr-5.1.0/build.gradle b/instrumentation-security/solr-5.1.0/build.gradle new file mode 100644 index 000000000..8988ab011 --- /dev/null +++ b/instrumentation-security/solr-5.1.0/build.gradle @@ -0,0 +1,32 @@ +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.lucene:lucene-core:4.0.0") + + implementation("org.apache.solr:solr-core:5.1.0") { + transitive = false + } + implementation("org.apache.solr:solr-solrj:5.1.0") { + transitive = false + } + implementation("org.apache.httpcomponents:httpclient:4.3.1") { + transitive = false + } +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.security.instrumentation.solr-5.1.0' } +} + +verifyInstrumentation { + passesOnly 'org.apache.solr:solr-core:[5.1.0,7.0.0)' + + excludeRegex 'org.apache.solr:solr-core:.*(ALPHA|BETA)+$' +} + +site { + title 'Solr' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation-security/solr-5.1.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java b/instrumentation-security/solr-5.1.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java new file mode 100644 index 000000000..875a0d378 --- /dev/null +++ b/instrumentation-security/solr-5.1.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java @@ -0,0 +1,111 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.http.client.HttpClient; +import org.apache.solr.client.solrj.ResponseParser; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient") +public abstract class HttpSolrClient_Instrumentation { + + public abstract String getBaseURL(); + + public HttpSolrClient_Instrumentation(String baseURL, HttpClient client, ResponseParser parser) { + //TODO report external URL + } + + public NamedList request(final SolrRequest request, final ResponseParser processor, String collection) { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(request, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", request.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_5.1.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_5.1.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_5.1.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_5.1.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_5.1.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + +} diff --git a/instrumentation-security/solr-7.0.0/build.gradle b/instrumentation-security/solr-7.0.0/build.gradle new file mode 100644 index 000000000..8eb1b68ee --- /dev/null +++ b/instrumentation-security/solr-7.0.0/build.gradle @@ -0,0 +1,29 @@ +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.lucene:lucene-core:4.0.0") + + implementation("org.apache.solr:solr-core:7.0.0") { + transitive = false + } + implementation("org.apache.solr:solr-solrj:7.0.0") { + transitive = false + } +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.security.instrumentation.solr-7.0.0' } +} + +verifyInstrumentation { + passesOnly 'org.apache.solr:solr-core:[7.0.0,8.0.0)' + + excludeRegex 'org.apache.solr:solr-core:.*(ALPHA|BETA)+$' +} + +site { + title 'Solr' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation-security/solr-7.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java b/instrumentation-security/solr-7.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java new file mode 100644 index 000000000..a6471858e --- /dev/null +++ b/instrumentation-security/solr-7.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java @@ -0,0 +1,7 @@ +package org.apache.solr.client.solrj.impl; + +import com.newrelic.api.agent.weaver.SkipIfPresent; + +@SkipIfPresent +public class Http2SolrClient { +} diff --git a/instrumentation-security/solr-7.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java b/instrumentation-security/solr-7.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java new file mode 100644 index 000000000..350b41f12 --- /dev/null +++ b/instrumentation-security/solr-7.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java @@ -0,0 +1,125 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.solr.client.solrj.ResponseParser; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient") +public abstract class HttpSolrClient_Instrumentation { + + + public abstract String getBaseURL(); + + protected HttpSolrClient_Instrumentation(Builder builder) { + //TODO report external URL + } + + public NamedList request(@SuppressWarnings({"rawtypes"})final SolrRequest request, final ResponseParser processor, String collection) + throws SolrServerException, IOException { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(request, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", request.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(@SuppressWarnings({"rawtypes"})SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_7.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_7.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_7.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_7.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_7.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + + @Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient$Builder") + public static class Builder extends SolrClientBuilder { + protected String baseSolrUrl; + + @Override + public Builder getThis() { + return this; + } + } + +} diff --git a/instrumentation-security/solr-8.0.0/build.gradle b/instrumentation-security/solr-8.0.0/build.gradle new file mode 100644 index 000000000..66396945a --- /dev/null +++ b/instrumentation-security/solr-8.0.0/build.gradle @@ -0,0 +1,29 @@ +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.lucene:lucene-core:4.0.0") + + implementation("org.apache.solr:solr-core:8.0.0") { + transitive = false + } + implementation("org.apache.solr:solr-solrj:8.0.0") { + transitive = false + } +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.security.instrumentation.solr-8.0.0' } +} + +verifyInstrumentation { + passesOnly 'org.apache.solr:solr-core:[8.0.0,9.0.0)' + + excludeRegex 'org.apache.solr:solr-core:.*(ALPHA|BETA)+$' +} + +site { + title 'Solr' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation-security/solr-8.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient_Instrumentation.java b/instrumentation-security/solr-8.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient_Instrumentation.java new file mode 100644 index 000000000..662098275 --- /dev/null +++ b/instrumentation-security/solr-8.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient_Instrumentation.java @@ -0,0 +1,114 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.Http2SolrClient") +public abstract class Http2SolrClient_Instrumentation { + + + public abstract String getBaseURL(); + + protected Http2SolrClient_Instrumentation(String serverBaseUrl, Http2SolrClient.Builder builder) { + //TODO report external URL + } + + public NamedList request(SolrRequest solrRequest, + String collection, + Http2SolrClient.OnComplete onComplete) throws IOException, SolrServerException { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", solrRequest.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(solrRequest, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", solrRequest.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_4.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(@SuppressWarnings({"rawtypes"})SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_8.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_8.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + +} diff --git a/instrumentation-security/solr-8.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java b/instrumentation-security/solr-8.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java new file mode 100644 index 000000000..a02577462 --- /dev/null +++ b/instrumentation-security/solr-8.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java @@ -0,0 +1,125 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.solr.client.solrj.ResponseParser; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient") +public abstract class HttpSolrClient_Instrumentation { + + + public abstract String getBaseURL(); + + protected HttpSolrClient_Instrumentation(Builder builder) { + //TODO report external URL + } + + public NamedList request(@SuppressWarnings({"rawtypes"})final SolrRequest request, final ResponseParser processor, String collection) + throws SolrServerException, IOException { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(request, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", request.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(@SuppressWarnings({"rawtypes"})SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_8.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_8.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_8.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + + @Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient$Builder") + public static class Builder extends SolrClientBuilder { + protected String baseSolrUrl; + + @Override + public Builder getThis() { + return this; + } + } + +} diff --git a/instrumentation-security/solr-9.0.0/build.gradle b/instrumentation-security/solr-9.0.0/build.gradle new file mode 100644 index 000000000..4d68d4b8b --- /dev/null +++ b/instrumentation-security/solr-9.0.0/build.gradle @@ -0,0 +1,35 @@ +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.lucene:lucene-core:4.0.0") + + implementation("org.apache.solr:solr-core:9.0.0") { + transitive = false + } + implementation("org.apache.solr:solr-solrj:9.0.0") { + transitive = false + } +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.security.instrumentation.solr-9.0.0' } +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + +verifyInstrumentation { + passesOnly 'org.apache.solr:solr-core:[9.0.0,)' + exclude 'org.apache.solr:solr-core:[8.0.0,9.0.0)' + excludeRegex 'org.apache.solr:solr-core:.*(ALPHA|BETA)+$' +} + +site { + title 'Solr' + type 'Datastore' +} \ No newline at end of file diff --git a/instrumentation-security/solr-9.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient_Instrumentation.java b/instrumentation-security/solr-9.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient_Instrumentation.java new file mode 100644 index 000000000..03e576a68 --- /dev/null +++ b/instrumentation-security/solr-9.0.0/src/main/java/org/apache/solr/client/solrj/impl/Http2SolrClient_Instrumentation.java @@ -0,0 +1,112 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.Http2SolrClient") +public abstract class Http2SolrClient_Instrumentation { + + + public abstract String getBaseURL(); + + protected Http2SolrClient_Instrumentation(String serverBaseUrl, Http2SolrClient.Builder builder) { + //TODO report external URL + } + + public NamedList request(SolrRequest solrRequest, String collection) throws SolrServerException, IOException { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", solrRequest.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(solrRequest, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", solrRequest.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(@SuppressWarnings({"rawtypes"})SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_9.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_9.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + +} diff --git a/instrumentation-security/solr-9.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java b/instrumentation-security/solr-9.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java new file mode 100644 index 000000000..7806af9b2 --- /dev/null +++ b/instrumentation-security/solr-9.0.0/src/main/java/org/apache/solr/client/solrj/impl/HttpSolrClient_Instrumentation.java @@ -0,0 +1,125 @@ +/* + * + * * Copyright 2020 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.apache.solr.client.solrj.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.solr.client.solrj.ResponseParser; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient") +public abstract class HttpSolrClient_Instrumentation { + + + public abstract String getBaseURL(); + + protected HttpSolrClient_Instrumentation(Builder builder) { + //TODO report external URL + } + + public NamedList request(@SuppressWarnings({"rawtypes"})final SolrRequest request, final ResponseParser processor, String collection) + throws SolrServerException, IOException { + boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + AbstractOperation operation = null; + if(isLockAcquired) { + operation = preprocessSolrRequest(request, "REQUEST"); + } + NamedList result; + try { + result = Weaver.callOriginal(); + } finally { + if(isLockAcquired) { + GenericHelper.releaseLock("HTTP_SOLR_REQUEST-", request.hashCode()); + } + } + registerExitOperation(isLockAcquired, operation); + return result; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable e){ + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + } + } + + private AbstractOperation preprocessSolrRequest(@SuppressWarnings({"rawtypes"})SolrRequest request, String methodName) { + try { + String collection = new URL(getBaseURL()).getPath(); + collection = collection.startsWith("/") ? collection.substring(1) : collection; + String method = request.getMethod().toString(); + String path = request.getPath(); + SolrParams solrParams = request.getParams(); + Map params = Collections.emptyMap(); + if(solrParams != null){ + params = SolrParams.toMap(solrParams.toNamedList()); + } + List documents = Collections.emptyList(); + if(request instanceof UpdateRequest) { + documents = ((UpdateRequest) request).getDocuments(); + } + SolrDbOperation solrDbOperation = new SolrDbOperation(this.getClass().getName(), methodName); + solrDbOperation.setCollection(collection); + solrDbOperation.setParams(params); + solrDbOperation.setDocuments(documents); + solrDbOperation.setConnectionURL(getBaseURL()); + solrDbOperation.setMethod(method); + solrDbOperation.setPath(path); + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Solr request %s, %s, %s, %s, %s", collection, method, path, params, documents), this.getClass().getName()); + NewRelicSecurity.getAgent().registerOperation(solrDbOperation); + return solrDbOperation; + } catch (MalformedURLException e){ + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_9.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format("Instrumentation library: %s , error while extracting collection from baseUrl : %s, %s", "HTTP_SOLR_SERVER_9.0.0", getBaseURL(), e.getMessage()), e, this.getClass().getName()); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, "HTTP_SOLR_SERVER_9.0.0", e.getMessage()), e, this.getClass().getName()); + } + return null; + } + + @Weave(type = MatchType.ExactClass, originalName = "org.apache.solr.client.solrj.impl.HttpSolrClient$Builder") + public static class Builder extends SolrClientBuilder { + protected String baseSolrUrl; + + @Override + public Builder getThis() { + return this; + } + } + +} diff --git a/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/rendering/ResponseRendering_Instrumentation.java b/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/rendering/ResponseRendering_Instrumentation.java index ccfccafa1..36717c4e3 100644 --- a/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/rendering/ResponseRendering_Instrumentation.java +++ b/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/rendering/ResponseRendering_Instrumentation.java @@ -3,6 +3,7 @@ import akka.event.LoggingAdapter; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -18,7 +19,7 @@ public class ResponseRendering_Instrumentation { private static boolean renderResponse$1(ResponseRenderingComponent component, HttpResponse response, Rendering rendering, ResponsePartRenderingContext context, LoggingAdapter adapter) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible(SprayHttpUtils.getNrSecCustomAttribNameForResponse()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SprayHttpUtils.getNrSecCustomAttribNameForResponse()); try { if (isLockAcquired && response.entity().nonEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(response.entity().data().asString(StandardCharsets.UTF_8))); diff --git a/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/httpx/marshalling/SprayToResponseMarshallingContext.java b/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/httpx/marshalling/SprayToResponseMarshallingContext.java index 41d03a37e..0c23bf39a 100644 --- a/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/httpx/marshalling/SprayToResponseMarshallingContext.java +++ b/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/httpx/marshalling/SprayToResponseMarshallingContext.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; @@ -25,7 +26,7 @@ public class SprayToResponseMarshallingContext { @Trace(async = true) public void marshalTo(HttpResponse httpResponse) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible(SprayHttpUtils.getNrSecCustomAttribNameForResponse()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SprayHttpUtils.getNrSecCustomAttribNameForResponse()); try { if (isLockAcquired && httpResponse.entity().nonEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(httpResponse.entity().data().asString(StandardCharsets.UTF_8))); diff --git a/instrumentation-security/spring-webclient-5.0/src/main/java/org/springframework/web/reactive/function/client/ExchangeFunction_Instrumentation.java b/instrumentation-security/spring-webclient-5.0/src/main/java/org/springframework/web/reactive/function/client/ExchangeFunction_Instrumentation.java index e773eeb16..92675bf0d 100644 --- a/instrumentation-security/spring-webclient-5.0/src/main/java/org/springframework/web/reactive/function/client/ExchangeFunction_Instrumentation.java +++ b/instrumentation-security/spring-webclient-5.0/src/main/java/org/springframework/web/reactive/function/client/ExchangeFunction_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.agent.security.instrumentation.spring.client5.SpringWebClientHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -19,7 +20,7 @@ public class ExchangeFunction_Instrumentation { public Mono exchange(ClientRequest request) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = SpringWebClientHelper.preprocessSecurityHook(request.url(), request.method(), this.getClass().getName(), SpringWebClientHelper.METHOD_EXECHANGE); @@ -45,8 +46,8 @@ private void releaseLock() { } - private boolean acquireLockIfPossible() { - return GenericHelper.acquireLockIfPossible(SpringWebClientHelper.getNrSecCustomAttribName()); + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, SpringWebClientHelper.getNrSecCustomAttribName()); } } diff --git a/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java b/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java index 8c10e6923..772d0ed51 100644 --- a/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java +++ b/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java @@ -4,12 +4,15 @@ import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner; 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.SecurityMetaData; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Set; @@ -34,7 +37,7 @@ public static void addMappings() { } @Test - public void testAPIEndpointDetection() { + public void testAPIEndpointDetection() throws Exception { methodMapping.addMapping(new TestMappings()); Set mappings = URLMappingsHelper.getApplicationURLMappings(); @@ -42,9 +45,22 @@ public void testAPIEndpointDetection() { for (ApplicationURLMapping mapping: mappings) { Assert.assertNotNull(mapping); + // Assertions for URL Mappings assertMapping(mapping); + + // Assertions for Route Detection + assertRouteDetection(mapping); } + } + + private void assertRouteDetection(ApplicationURLMapping mapping) throws Exception { + methodMapping.handleRequest(new DummyRequest(mapping.getPath(), mapping.getMethod())); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertFalse(metaData.getRequest().getRoute().isEmpty()); + Assert.assertEquals(mapping.getPath(), metaData.getRequest().getRoute()); + + Assert.assertEquals(Framework.SPRING_WEB_MVC.name(), metaData.getMetaData().getFramework()); } private void assertMapping(ApplicationURLMapping actualMapping) { @@ -60,4 +76,7 @@ class TestHandlerMethodMapping extends RequestMappingHandlerMapping { public void addMapping(Object handler) { super.detectHandlerMethods(handler); } + public void handleRequest(HttpServletRequest request) throws Exception { + super.getHandlerInternal(request); + } } diff --git a/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java b/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java new file mode 100644 index 000000000..7c1eb6248 --- /dev/null +++ b/instrumentation-security/spring-webmvc-3.1.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java @@ -0,0 +1,328 @@ +package com.nr.agent.security.instrumentation.spring.webmvc; + +import com.newrelic.api.agent.security.schema.StringUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; + +public class DummyRequest implements HttpServletRequest { + protected String queryString = StringUtils.EMPTY; + protected String pathInfo; + protected String servletPath = StringUtils.SEPARATOR; + private String method; + private static Enumeration dummyEnum = new Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + return null; + } + }; + + public DummyRequest(String pathInfo, String method) { + this.pathInfo = pathInfo; + this.method = method; + } + + public String getContextPath() { + return null; + } + + public ServletRequest getRequest() { + return this; + } + + public String getQueryString() { + return this.queryString; + } + + public String getPathInfo() { + return this.pathInfo; + } + + public String getServletPath() { + return this.servletPath; + } + + public String getMethod() { + return this.method; + } + + public Object getAttribute(String name) { + return pathInfo; + } + + public Enumeration getAttributeNames() { + return null; + } + + public String getCharacterEncoding() { + return null; + } + + public int getContentLength() { + return -1; + } + + public long getContentLengthLong() { + return -1L; + } + + public String getContentType() { + return null; + } + + public ServletInputStream getInputStream() throws IOException { + return null; + } + + public Locale getLocale() { + return null; + } + + public Enumeration getLocales() { + return null; + } + + public String getProtocol() { + return null; + } + + public BufferedReader getReader() throws IOException { + return null; + } + + public String getRealPath(String path) { + return null; + } + + public String getRemoteAddr() { + return null; + } + + public String getRemoteHost() { + return null; + } + + public String getScheme() { + return null; + } + + public String getServerName() { + return null; + } + + public int getServerPort() { + return -1; + } + + public boolean isSecure() { + return false; + } + + public void removeAttribute(String name) { + } + + public void setAttribute(String name, Object value) { + } + + public void setCharacterEncoding(String enc) throws UnsupportedEncodingException { + } + + public String getParameter(String name) { + return null; + } + + public Map getParameterMap() { + return null; + } + + public Enumeration getParameterNames() { + return dummyEnum; + } + + public String[] getParameterValues(String name) { + return null; + } + + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + public String getAuthType() { + return null; + } + + public Cookie[] getCookies() { + return null; + } + + public long getDateHeader(String name) { + return -1L; + } + + public String getHeader(String name) { + return null; + } + + public Enumeration getHeaders(String name) { + return null; + } + + public Enumeration getHeaderNames() { + return null; + } + + public int getIntHeader(String name) { + return -1; + } + + public String getPathTranslated() { + return null; + } + + public String getRemoteUser() { + return null; + } + + public String getRequestedSessionId() { + return null; + } + + public String getRequestURI() { + return null; + } + + public StringBuffer getRequestURL() { + return null; + } + + public HttpSession getSession() { + return null; + } + + public HttpSession getSession(boolean create) { + return null; + } + + public String changeSessionId() { + return null; + } + + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + public boolean isRequestedSessionIdFromURL() { + return false; + } + + public boolean isRequestedSessionIdFromUrl() { + return false; + } + + public boolean isRequestedSessionIdValid() { + return false; + } + + public void setRequestedSessionCookiePath(String cookiePath) { + } + + public boolean isUserInRole(String role) { + return false; + } + + public Principal getUserPrincipal() { + return null; + } + + public String getLocalAddr() { + return null; + } + + public String getLocalName() { + return null; + } + + public int getLocalPort() { + return -1; + } + + public int getRemotePort() { + return -1; + } + + public DispatcherType getDispatcherType() { + return null; + } + + public AsyncContext startAsync() throws IllegalStateException { + return null; + } + + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { + return null; + } + + public boolean isAsyncStarted() { + return false; + } + + public boolean isAsyncSupported() { + return false; + } + + public AsyncContext getAsyncContext() { + return null; + } + + public Collection getParts() { + return null; + } + + public Part getPart(String name) { + return null; + } + + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + return false; + } + + public void login(String username, String password) throws ServletException { + } + + public void logout() throws ServletException { + + } + + public T upgrade(Class handlerClass) { + return null; + } + + public ServletContext getServletContext() { + return null; + } + +} + diff --git a/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java b/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java index d1b94dc24..31b25d089 100644 --- a/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java +++ b/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java @@ -4,12 +4,15 @@ import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner; 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.SecurityMetaData; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Set; @@ -34,7 +37,7 @@ public static void addMappings() { } @Test - public void testAPIEndpointDetection() { + public void testAPIEndpointDetection() throws Exception { methodMapping.addMapping(new TestMappings()); Set mappings = URLMappingsHelper.getApplicationURLMappings(); @@ -42,9 +45,22 @@ public void testAPIEndpointDetection() { for (ApplicationURLMapping mapping: mappings) { Assert.assertNotNull(mapping); + // Assertions for URL Mappings assertMapping(mapping); + + // Assertions for Route Detection + assertRouteDetection(mapping); } + } + + private void assertRouteDetection(ApplicationURLMapping mapping) throws Exception { + methodMapping.handleRequest(new DummyRequest(mapping.getPath(), mapping.getMethod())); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertFalse(metaData.getRequest().getRoute().isEmpty()); + Assert.assertEquals(mapping.getPath(), metaData.getRequest().getRoute()); + + Assert.assertEquals(Framework.SPRING_WEB_MVC.name(), metaData.getMetaData().getFramework()); } private void assertMapping(ApplicationURLMapping actualMapping) { @@ -60,4 +76,8 @@ class TestHandlerMethodMapping extends RequestMappingHandlerMapping { public void addMapping(Object handler) { super.detectHandlerMethods(handler); } + + public void handleRequest(HttpServletRequest request) throws Exception { + super.getHandlerInternal(request); + } } \ No newline at end of file diff --git a/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java b/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java new file mode 100644 index 000000000..69c965f96 --- /dev/null +++ b/instrumentation-security/spring-webmvc-5.3.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java @@ -0,0 +1,328 @@ +package com.nr.agent.security.instrumentation.spring.webmvc; + +import com.newrelic.api.agent.security.schema.StringUtils; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; + +public class DummyRequest implements HttpServletRequest { + protected String queryString = StringUtils.EMPTY; + protected String pathInfo; + protected String servletPath = StringUtils.SEPARATOR; + private String method; + private static Enumeration dummyEnum = new Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + return null; + } + }; + + public DummyRequest(String pathInfo, String method) { + this.pathInfo = pathInfo; + this.method = method; + } + + public String getContextPath() { + return null; + } + + public ServletRequest getRequest() { + return this; + } + + public String getQueryString() { + return this.queryString; + } + + public String getPathInfo() { + return this.pathInfo; + } + + public String getServletPath() { + return this.servletPath; + } + + public String getMethod() { + return this.method; + } + + public Object getAttribute(String name) { + return pathInfo; + } + + public Enumeration getAttributeNames() { + return null; + } + + public String getCharacterEncoding() { + return null; + } + + public int getContentLength() { + return -1; + } + + public long getContentLengthLong() { + return -1L; + } + + public String getContentType() { + return null; + } + + public ServletInputStream getInputStream() throws IOException { + return null; + } + + public Locale getLocale() { + return null; + } + + public Enumeration getLocales() { + return null; + } + + public String getProtocol() { + return null; + } + + public BufferedReader getReader() throws IOException { + return null; + } + + public String getRealPath(String path) { + return null; + } + + public String getRemoteAddr() { + return null; + } + + public String getRemoteHost() { + return null; + } + + public String getScheme() { + return null; + } + + public String getServerName() { + return null; + } + + public int getServerPort() { + return -1; + } + + public boolean isSecure() { + return false; + } + + public void removeAttribute(String name) { + } + + public void setAttribute(String name, Object value) { + } + + public void setCharacterEncoding(String enc) throws UnsupportedEncodingException { + } + + public String getParameter(String name) { + return null; + } + + public Map getParameterMap() { + return null; + } + + public Enumeration getParameterNames() { + return dummyEnum; + } + + public String[] getParameterValues(String name) { + return null; + } + + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + public String getAuthType() { + return null; + } + + public Cookie[] getCookies() { + return null; + } + + public long getDateHeader(String name) { + return -1L; + } + + public String getHeader(String name) { + return null; + } + + public Enumeration getHeaders(String name) { + return null; + } + + public Enumeration getHeaderNames() { + return null; + } + + public int getIntHeader(String name) { + return -1; + } + + public String getPathTranslated() { + return null; + } + + public String getRemoteUser() { + return null; + } + + public String getRequestedSessionId() { + return null; + } + + public String getRequestURI() { + return null; + } + + public StringBuffer getRequestURL() { + return null; + } + + public HttpSession getSession() { + return null; + } + + public HttpSession getSession(boolean create) { + return null; + } + + public String changeSessionId() { + return null; + } + + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + public boolean isRequestedSessionIdFromURL() { + return false; + } + + public boolean isRequestedSessionIdFromUrl() { + return false; + } + + public boolean isRequestedSessionIdValid() { + return false; + } + + public void setRequestedSessionCookiePath(String cookiePath) { + } + + public boolean isUserInRole(String role) { + return false; + } + + public Principal getUserPrincipal() { + return null; + } + + public String getLocalAddr() { + return null; + } + + public String getLocalName() { + return null; + } + + public int getLocalPort() { + return -1; + } + + public int getRemotePort() { + return -1; + } + + public DispatcherType getDispatcherType() { + return null; + } + + public AsyncContext startAsync() throws IllegalStateException { + return null; + } + + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { + return null; + } + + public boolean isAsyncStarted() { + return false; + } + + public boolean isAsyncSupported() { + return false; + } + + public AsyncContext getAsyncContext() { + return null; + } + + public Collection getParts() { + return null; + } + + public Part getPart(String name) { + return null; + } + + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + return false; + } + + public void login(String username, String password) throws ServletException { + } + + public void logout() throws ServletException { + + } + + public T upgrade(Class handlerClass) { + return null; + } + + public ServletContext getServletContext() { + return null; + } + +} + diff --git a/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java b/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java index d1b94dc24..168b08ae3 100644 --- a/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java +++ b/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/APIEndpointTest.java @@ -4,6 +4,9 @@ import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner; 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.SecurityMetaData; +import jakarta.servlet.http.HttpServletRequest; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -34,7 +37,7 @@ public static void addMappings() { } @Test - public void testAPIEndpointDetection() { + public void testAPIEndpointDetection() throws Exception { methodMapping.addMapping(new TestMappings()); Set mappings = URLMappingsHelper.getApplicationURLMappings(); @@ -42,9 +45,22 @@ public void testAPIEndpointDetection() { for (ApplicationURLMapping mapping: mappings) { Assert.assertNotNull(mapping); + // Assertions for URL Mappings assertMapping(mapping); + + // Assertions for Route Detection + assertRouteDetection(mapping); } + } + + private void assertRouteDetection(ApplicationURLMapping mapping) throws Exception { + methodMapping.handleRequest(new DummyRequest(mapping.getPath(), mapping.getMethod())); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertFalse(metaData.getRequest().getRoute().isEmpty()); + Assert.assertEquals(mapping.getPath(), metaData.getRequest().getRoute()); + + Assert.assertEquals(Framework.SPRING_WEB_MVC.name(), metaData.getMetaData().getFramework()); } private void assertMapping(ApplicationURLMapping actualMapping) { @@ -60,4 +76,8 @@ class TestHandlerMethodMapping extends RequestMappingHandlerMapping { public void addMapping(Object handler) { super.detectHandlerMethods(handler); } + + public void handleRequest(HttpServletRequest request) throws Exception { + super.getHandlerInternal(request); + } } \ No newline at end of file diff --git a/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java b/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java new file mode 100644 index 000000000..a68695bbb --- /dev/null +++ b/instrumentation-security/spring-webmvc-6.0.0/src/test/java/com/nr/agent/security/instrumentation/spring/webmvc/DummyRequest.java @@ -0,0 +1,380 @@ +package com.nr.agent.security.instrumentation.spring.webmvc; + +import com.newrelic.api.agent.security.schema.StringUtils; + +import jakarta.servlet.AsyncContext; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import jakarta.servlet.http.HttpUpgradeHandler; +import jakarta.servlet.http.Part; +import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; +import org.springframework.web.util.ServletRequestPathUtils; +import org.springframework.web.util.UrlPathHelper; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class DummyRequest implements HttpServletRequest { + protected String queryString = StringUtils.EMPTY; + protected String pathInfo; + protected String servletPath = StringUtils.SEPARATOR; + private String method; + private static Enumeration dummyEnum = new Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + return null; + } + }; + + public DummyRequest(String pathInfo, String method) { + this.pathInfo = pathInfo; + this.method = method; + } + + public String getContextPath() { + return null; + } + + public String getQueryString() { + return this.queryString; + } + + public String getPathInfo() { + return this.pathInfo; + } + + public String getServletPath() { + return this.servletPath; + } + + public String getMethod() { + return this.method; + } + + public Object getAttribute(String name) { + if (name.equals(ServletRequestPathUtils.class.getName() + ".PATH")) { + return new RequestPath() { + @Override + public PathContainer contextPath() { + return new PathContainer() { + @Override + public String value() { + return pathInfo; + } + + @Override + public List elements() { + return Collections.emptyList(); + } + }; + } + + @Override + public PathContainer pathWithinApplication() { + return new PathContainer() { + @Override + public String value() { + return pathInfo; + } + + @Override + public List elements() { + return Collections.emptyList(); + } + }; + } + + @Override + public RequestPath modifyContextPath(String contextPath) { + return this; + } + + @Override + public String value() { + return ""; + } + + @Override + public List elements() { + return Collections.emptyList(); + } + }; + } else if (name.equals(UrlPathHelper.class.getName() + ".PATH") || name.equals("jakarta.servlet.include.request_uri")){ + return pathInfo; + } else { + return null; + } + } + + public Enumeration getAttributeNames() { + return null; + } + + public String getCharacterEncoding() { + return null; + } + + public int getContentLength() { + return -1; + } + + public long getContentLengthLong() { + return -1L; + } + + public String getContentType() { + return null; + } + + public ServletInputStream getInputStream() throws IOException { + return null; + } + + public Locale getLocale() { + return null; + } + + public Enumeration getLocales() { + return null; + } + + public String getProtocol() { + return null; + } + + public BufferedReader getReader() throws IOException { + return null; + } + + public String getRealPath(String path) { + return null; + } + + public String getRemoteAddr() { + return null; + } + + public String getRemoteHost() { + return null; + } + + public String getScheme() { + return null; + } + + public String getServerName() { + return null; + } + + public int getServerPort() { + return -1; + } + + public boolean isSecure() { + return false; + } + + public void removeAttribute(String name) { + } + + public void setAttribute(String name, Object value) { + } + + public void setCharacterEncoding(String enc) throws UnsupportedEncodingException { + } + + public String getParameter(String name) { + return null; + } + + public Map getParameterMap() { + return null; + } + + public Enumeration getParameterNames() { + return dummyEnum; + } + + public String[] getParameterValues(String name) { + return null; + } + + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + public String getAuthType() { + return null; + } + + public Cookie[] getCookies() { + return null; + } + + public long getDateHeader(String name) { + return -1L; + } + + public String getHeader(String name) { + return null; + } + + public Enumeration getHeaders(String name) { + return null; + } + + public Enumeration getHeaderNames() { + return null; + } + + public int getIntHeader(String name) { + return -1; + } + + public String getPathTranslated() { + return null; + } + + public String getRemoteUser() { + return null; + } + + public String getRequestedSessionId() { + return null; + } + + public String getRequestURI() { + return null; + } + + public StringBuffer getRequestURL() { + return null; + } + + public HttpSession getSession() { + return null; + } + + public HttpSession getSession(boolean create) { + return null; + } + + public String changeSessionId() { + return null; + } + + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + public boolean isRequestedSessionIdFromURL() { + return false; + } + + public boolean isRequestedSessionIdFromUrl() { + return false; + } + + public boolean isRequestedSessionIdValid() { + return false; + } + + public void setRequestedSessionCookiePath(String cookiePath) { + } + + public boolean isUserInRole(String role) { + return false; + } + + public Principal getUserPrincipal() { + return null; + } + + public String getLocalAddr() { + return null; + } + + public String getLocalName() { + return null; + } + + public int getLocalPort() { + return -1; + } + + public int getRemotePort() { + return -1; + } + + public DispatcherType getDispatcherType() { + return null; + } + + public AsyncContext startAsync() throws IllegalStateException { + return null; + } + + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { + return null; + } + + public boolean isAsyncStarted() { + return false; + } + + public boolean isAsyncSupported() { + return false; + } + + public AsyncContext getAsyncContext() { + return null; + } + + public Collection getParts() { + return null; + } + + public Part getPart(String name) { + return null; + } + + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + return false; + } + + public void login(String username, String password) throws ServletException { + } + + public void logout() throws ServletException {} + + public T upgrade(Class handlerClass) { + return null; + } + + public ServletContext getServletContext() { + return null; + } + +} + diff --git a/instrumentation-security/spymemcached-2.12.0/src/main/java/net/spy/memcached/MemcachedClient_Instrumentation.java b/instrumentation-security/spymemcached-2.12.0/src/main/java/net/spy/memcached/MemcachedClient_Instrumentation.java index 66658d078..107c9db98 100644 --- a/instrumentation-security/spymemcached-2.12.0/src/main/java/net/spy/memcached/MemcachedClient_Instrumentation.java +++ b/instrumentation-security/spymemcached-2.12.0/src/main/java/net/spy/memcached/MemcachedClient_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.MemcachedOperation; import com.newrelic.api.agent.weaver.Weave; @@ -19,7 +20,7 @@ public class MemcachedClient_Instrumentation { private OperationFuture asyncStore(StoreType storeType, String key, int exp, T value, Transcoder tc) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible(MemcachedHelper.NR_SEC_CUSTOM_ATTRIB_NAME, value.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, MemcachedHelper.NR_SEC_CUSTOM_ATTRIB_NAME, value.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = MemcachedHelper.preprocessSecurityHook(storeType.name(), MemcachedHelper.WRITE, key, value, this.getClass().getName(), MemcachedHelper.METHOD_ASYNC_STORE); @@ -38,7 +39,7 @@ private OperationFuture asyncStore(StoreType storeType, private OperationFuture asyncCat(ConcatenationType catType, long cas, String key, T value, Transcoder tc) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible(MemcachedHelper.NR_SEC_CUSTOM_ATTRIB_NAME, value.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, MemcachedHelper.NR_SEC_CUSTOM_ATTRIB_NAME, value.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = MemcachedHelper.preprocessSecurityHook(catType.name(), MemcachedHelper.UPDATE, key, value, this.getClass().getName(), MemcachedHelper.METHOD_ASYNC_CAT); @@ -57,7 +58,7 @@ private OperationFuture asyncCat(ConcatenationType catType, public OperationFuture asyncCAS(String key, long casId, int exp, T value, Transcoder tc) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible(MemcachedHelper.NR_SEC_CUSTOM_ATTRIB_NAME, value.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, MemcachedHelper.NR_SEC_CUSTOM_ATTRIB_NAME, value.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = MemcachedHelper.preprocessSecurityHook(StoreType.set.name(), MemcachedHelper.WRITE, key, value, this.getClass().getName(), MemcachedHelper.METHOD_ASYNC_CAS); diff --git a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/Filter_Instrumentation.java b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/Filter_Instrumentation.java index 742298c65..83313fc5a 100644 --- a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/Filter_Instrumentation.java +++ b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/Filter_Instrumentation.java @@ -77,6 +77,9 @@ private void preprocessSecurityHook(HttpExchange exchange) { } private void postProcessSecurityHook(HttpExchange exchange) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive()) { return; } diff --git a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpHandler_Instrumentation.java b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpHandler_Instrumentation.java index 90c4cdb6d..13ffb8068 100644 --- a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpHandler_Instrumentation.java +++ b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpHandler_Instrumentation.java @@ -77,6 +77,9 @@ private void preprocessSecurityHook(HttpExchange exchange) { } private void postProcessSecurityHook(HttpExchange exchange) { try { + if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } if (!NewRelicSecurity.isHookProcessingActive()) { return; } diff --git a/instrumentation-security/unboundid-ldapsdk/src/main/java/com/unboundid/ldap/sdk/LDAPInterface_Instrumentation.java b/instrumentation-security/unboundid-ldapsdk/src/main/java/com/unboundid/ldap/sdk/LDAPInterface_Instrumentation.java index 25132bd44..6ff09631d 100644 --- a/instrumentation-security/unboundid-ldapsdk/src/main/java/com/unboundid/ldap/sdk/LDAPInterface_Instrumentation.java +++ b/instrumentation-security/unboundid-ldapsdk/src/main/java/com/unboundid/ldap/sdk/LDAPInterface_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.LDAPOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -17,7 +18,7 @@ public class LDAPInterface_Instrumentation { public SearchResult search(final SearchRequest searchRequest) throws LDAPSearchException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(searchRequest.getBaseDN(), searchRequest.getFilter().toString(), LDAPUtils.METHOD_SEARCH); @@ -75,9 +76,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { try { - return GenericHelper.acquireLockIfPossible(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(ldap, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/Helper.java b/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/Helper.java index c966d0979..20e1d16ac 100644 --- a/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/Helper.java +++ b/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/Helper.java @@ -9,4 +9,5 @@ public class Helper { public static final String METHOD_NAME_GET_OUTPUT_STREAM = "getOutputStream"; public static final String METHOD_NAME_GET_INPUT_STREAM = "getInputStream"; public static final String URLCONNECTION = "URLCONNECTION"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "URL_CONNECTION-"; } diff --git a/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/URLConnection_Instrumentation.java b/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/URLConnection_Instrumentation.java index aa1eb0fe6..8d8487be8 100644 --- a/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/URLConnection_Instrumentation.java +++ b/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/URLConnection_Instrumentation.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -45,43 +46,49 @@ protected URLConnection_Instrumentation(URL url) { public void connect() throws IOException { String url = null; + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, Helper.NR_SEC_CUSTOM_ATTRIB_NAME); AbstractOperation operation = null; - URL getURL = getURL(); - if(getURL != null) { - url = getURL.toString(); - boolean currentCascadedCall = cascadedCall; - // Preprocess Phase - operation = preprocessSecurityHook(currentCascadedCall, url, getURL.getProtocol(), Helper.METHOD_NAME_CONNECT); + if(isLockAcquired) { + URL getURL = getURL(); + if (getURL != null) { + url = getURL.toString(); + boolean currentCascadedCall = cascadedCall; + // Preprocess Phase + operation = preprocessSecurityHook(currentCascadedCall, url, getURL.getProtocol(), Helper.METHOD_NAME_CONNECT); + } } // Actual Call try { Weaver.callOriginal(); } finally { - /* Not calling `cascadedCall = currentCascadedCall;` is intentional. - * This saves from generating additional getInputStream events while processing a call. - * */ + if(isLockAcquired){ + GenericHelper.releaseLock(Helper.NR_SEC_CUSTOM_ATTRIB_NAME); + } } registerExitOperation(operation); } public synchronized OutputStream getOutputStream() throws IOException { String url = null; + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, Helper.NR_SEC_CUSTOM_ATTRIB_NAME); AbstractOperation operation = null; - URL getURL = getURL(); - if(getURL != null) { - url = getURL.toString(); - boolean currentCascadedCall = cascadedCall; - // Preprocess Phase - operation = preprocessSecurityHook(currentCascadedCall, url, getURL.getProtocol(), Helper.METHOD_NAME_GET_OUTPUT_STREAM); + if(isLockAcquired) { + URL getURL = getURL(); + if (getURL != null) { + url = getURL.toString(); + boolean currentCascadedCall = cascadedCall; + // Preprocess Phase + operation = preprocessSecurityHook(currentCascadedCall, url, getURL.getProtocol(), Helper.METHOD_NAME_GET_OUTPUT_STREAM); + } } // Actual Call OutputStream returnStream = null; try { returnStream = Weaver.callOriginal(); } finally { - /* Not calling `cascadedCall = currentCascadedCall;` is intentional. - * This saves from generating additional getInputStream events while processing a call. - * */ + if(isLockAcquired){ + GenericHelper.releaseLock(Helper.NR_SEC_CUSTOM_ATTRIB_NAME); + } } registerExitOperation(operation); return returnStream; @@ -89,22 +96,25 @@ public synchronized OutputStream getOutputStream() throws IOException { public synchronized InputStream getInputStream() throws IOException { String url = null; + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, Helper.NR_SEC_CUSTOM_ATTRIB_NAME); AbstractOperation operation = null; - URL getURL = getURL(); - if(getURL != null) { - url = getURL.toString(); - boolean currentCascadedCall = cascadedCall; - // Preprocess Phase - operation = preprocessSecurityHook(currentCascadedCall, url, getURL.getProtocol(), Helper.METHOD_NAME_GET_INPUT_STREAM); + if(isLockAcquired) { + URL getURL = getURL(); + if (getURL != null) { + url = getURL.toString(); + boolean currentCascadedCall = cascadedCall; + // Preprocess Phase + operation = preprocessSecurityHook(currentCascadedCall, url, getURL.getProtocol(), Helper.METHOD_NAME_GET_INPUT_STREAM); + } } // Actual Call InputStream returnStream = null; try { returnStream = Weaver.callOriginal(); } finally { - /* Not calling `cascadedCall = currentCascadedCall;` is intentional. - * This saves from generating additional getInputStream events while processing a call on same object. - * */ + if(isLockAcquired){ + GenericHelper.releaseLock(Helper.NR_SEC_CUSTOM_ATTRIB_NAME); + } } registerExitOperation(operation); return returnStream; diff --git a/instrumentation-security/vertx-core-3.3.0/build.gradle b/instrumentation-security/vertx-core-3.3.0/build.gradle index 3f9e79eca..bea94f57b 100644 --- a/instrumentation-security/vertx-core-3.3.0/build.gradle +++ b/instrumentation-security/vertx-core-3.3.0/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("io.vertx:vertx-core:3.3.0") + implementation("io.vertx:vertx-web:3.3.0") } jar { @@ -10,7 +11,9 @@ jar { } verifyInstrumentation { - passesOnly 'io.vertx:vertx-core:[3.3.0,3.4.0)' + passesOnly ('io.vertx:vertx-core:[3.3.0,3.4.0)') { + implementation("io.vertx:vertx-web:3.3.0") + } excludeRegex '.*(milestone|CR|Beta)[0-9]*' } diff --git a/instrumentation-security/vertx-core-3.3.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java b/instrumentation-security/vertx-core-3.3.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java index 53b28229c..4436c41fe 100644 --- a/instrumentation-security/vertx-core-3.3.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java +++ b/instrumentation-security/vertx-core-3.3.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java @@ -1,6 +1,7 @@ package com.newrelic.agent.security.instrumentation.vertx; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; public class VertxClientHelper { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_CORE_OPERATION_LOCK-"; @@ -14,7 +15,7 @@ public static void releaseLock() { GenericHelper.releaseLock(getNrSecCustomAttribName()); } - public static boolean acquireLockIfPossible() { - return GenericHelper.acquireLockIfPossible(getNrSecCustomAttribName()); + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttribName()); } } diff --git a/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java b/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java new file mode 100644 index 000000000..39c730e82 --- /dev/null +++ b/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java @@ -0,0 +1,25 @@ +package io.vertx.core.http; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; + +@Weave(originalName = "io.vertx.core.http.HttpServer", type = MatchType.Interface) +public class HttpServer_Instrumentation { + + public HttpServer_Instrumentation requestHandler(Handler handler){ + HttpServer_Instrumentation server = Weaver.callOriginal(); + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpoints(handler.hashCode()); + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, "VERTX-CORE-3.3.0", e.getMessage()), e, VertxApiEndpointUtils.class.getName()); + } + return server; + } + +} diff --git a/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java b/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java index 2ca52df71..2e3565615 100644 --- a/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java +++ b/instrumentation-security/vertx-core-3.3.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -23,7 +24,7 @@ public abstract class HttpClientRequestImpl_Instrumentation { private String hostHeader() { return Weaver.callOriginal();} public void end(Buffer chunk) { - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { String uri = getAbsoluteUri(ssl, hostHeader(), uri()); @@ -41,7 +42,7 @@ public void end(Buffer chunk) { } public void end() { - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { String uri = getAbsoluteUri(ssl, hostHeader(), uri()); diff --git a/instrumentation-security/vertx-core-3.4.0/build.gradle b/instrumentation-security/vertx-core-3.4.0/build.gradle index 25d8d3d69..a65c8ff23 100644 --- a/instrumentation-security/vertx-core-3.4.0/build.gradle +++ b/instrumentation-security/vertx-core-3.4.0/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("io.vertx:vertx-core:3.4.0") + implementation("io.vertx:vertx-web:3.4.0") testImplementation('io.vertx:vertx-web-client:3.4.0') } @@ -11,7 +12,9 @@ jar { } verifyInstrumentation { - passesOnly 'io.vertx:vertx-core:[3.4.0,3.7.1)' + passesOnly ('io.vertx:vertx-core:[3.4.0,3.7.1)'){ + implementation("io.vertx:vertx-web:3.4.0") + } excludeRegex '.*CR[0-9]*' excludeRegex '.*-milestone[0-9]' excludeRegex '.*Beta[0-9]' diff --git a/instrumentation-security/vertx-core-3.4.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java b/instrumentation-security/vertx-core-3.4.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java index e6efeac10..689089a31 100644 --- a/instrumentation-security/vertx-core-3.4.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java +++ b/instrumentation-security/vertx-core-3.4.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/VertxClientHelper.java @@ -1,6 +1,7 @@ package com.newrelic.agent.security.instrumentation.vertx; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; public class VertxClientHelper { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_CORE_OPERATION_LOCK-"; @@ -15,7 +16,7 @@ public static void releaseLock() { GenericHelper.releaseLock(getNrSecCustomAttribName()); } - public static boolean acquireLockIfPossible() { - return GenericHelper.acquireLockIfPossible(getNrSecCustomAttribName()); + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttribName()); } } diff --git a/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java b/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java new file mode 100644 index 000000000..b7fbb5b67 --- /dev/null +++ b/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java @@ -0,0 +1,26 @@ +package io.vertx.core.http; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; + + +@Weave(originalName = "io.vertx.core.http.HttpServer", type = MatchType.Interface) +public class HttpServer_Instrumentation { + + public HttpServer_Instrumentation requestHandler(Handler handler){ + HttpServer_Instrumentation server = Weaver.callOriginal(); + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpoints(handler.hashCode()); + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, "VERTX-CORE-3.4.0", e.getMessage()), e, VertxApiEndpointUtils.class.getName()); + } + return server; + } + +} diff --git a/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java b/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java index d40dd472c..bc671b229 100644 --- a/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java +++ b/instrumentation-security/vertx-core-3.4.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java @@ -6,6 +6,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -27,7 +28,7 @@ public abstract class HttpClientRequestImpl_Instrumentation { } public void end(Buffer chunk) { - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(absoluteURI(), this.getClass().getName(), VertxClientHelper.METHOD_END); @@ -44,7 +45,7 @@ public void end(Buffer chunk) { } public void end() { - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(absoluteURI(), this.getClass().getName(), VertxClientHelper.METHOD_END); diff --git a/instrumentation-security/vertx-core-3.7.1/build.gradle b/instrumentation-security/vertx-core-3.7.1/build.gradle index d5ee37175..3b1b8db62 100644 --- a/instrumentation-security/vertx-core-3.7.1/build.gradle +++ b/instrumentation-security/vertx-core-3.7.1/build.gradle @@ -9,11 +9,14 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("io.vertx:vertx-core:3.7.1") + implementation("io.vertx:vertx-web:3.7.1") testImplementation('io.vertx:vertx-web-client:3.7.1') } verifyInstrumentation { - passesOnly 'io.vertx:vertx-core:[3.7.1,4.0.0.Beta1)' + passesOnly ('io.vertx:vertx-core:[3.7.1,4.0.0.Beta1)') { + implementation('io.vertx:vertx-web:3.7.1') + } excludeRegex '.*CR[0-9]*' excludeRegex '.*-milestone[0-9]' } diff --git a/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java b/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java new file mode 100644 index 000000000..52435cc6f --- /dev/null +++ b/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java @@ -0,0 +1,25 @@ +package io.vertx.core.http; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; + +@Weave(originalName = "io.vertx.core.http.HttpServer", type = MatchType.Interface) +public class HttpServer_Instrumentation { + + public HttpServer_Instrumentation requestHandler(Handler handler){ + HttpServer_Instrumentation server = Weaver.callOriginal(); + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpoints(handler.hashCode()); + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, "VERTX-CORE-3.7.1", e.getMessage()), e, VertxApiEndpointUtils.class.getName()); + } + return server; + } + +} diff --git a/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java b/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java index afdbc3b3c..2b2b75db3 100644 --- a/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java +++ b/instrumentation-security/vertx-core-3.7.1/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java @@ -10,6 +10,7 @@ import com.newrelic.agent.security.instrumentation.vertx.web.VertxClientHelper; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.vertx.core.AsyncResult; @@ -26,7 +27,7 @@ public abstract class HttpClientRequestImpl_Instrumentation { public abstract String absoluteURI(); public void end(Buffer chunk) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = VertxClientHelper.preprocessSecurityHook(absoluteURI(), this.getClass().getName(), @@ -45,7 +46,7 @@ public void end(Buffer chunk) { public void end(Buffer chunk, Handler> handler) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = VertxClientHelper.preprocessSecurityHook(absoluteURI(), this.getClass().getName(), @@ -64,7 +65,7 @@ public void end(Buffer chunk, Handler> handler) { public void end() { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = VertxClientHelper.preprocessSecurityHook(absoluteURI(), this.getClass().getName(), @@ -83,7 +84,7 @@ public void end() { public void end(Handler> handler) { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = VertxClientHelper.preprocessSecurityHook(absoluteURI(), this.getClass().getName(), @@ -103,7 +104,7 @@ private void releaseLock() { GenericHelper.releaseLock(VertxClientHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible() { - return GenericHelper.acquireLockIfPossible(VertxClientHelper.getNrSecCustomAttribName()); + private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, VertxClientHelper.getNrSecCustomAttribName()); } } diff --git a/instrumentation-security/vertx-core-4.0.0/build.gradle b/instrumentation-security/vertx-core-4.0.0/build.gradle index 50226b02a..8f8012a66 100644 --- a/instrumentation-security/vertx-core-4.0.0/build.gradle +++ b/instrumentation-security/vertx-core-4.0.0/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("io.vertx:vertx-core:4.0.0") + implementation("io.vertx:vertx-web:4.0.0") testImplementation('io.vertx:vertx-web-client:4.0.0') } @@ -13,7 +14,9 @@ jar { } verifyInstrumentation { - passesOnly 'io.vertx:vertx-core:[4.0.0,)' + passesOnly ('io.vertx:vertx-core:[4.0.0,)') { + implementation('io.vertx:vertx-web:4.0.0') + } excludeRegex '.*CR[0-9]*' excludeRegex '.*-milestone[0-9]' excludeRegex '.*Beta[0-9]' diff --git a/instrumentation-security/vertx-core-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java b/instrumentation-security/vertx-core-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java index 69bc6787e..8ead6362e 100644 --- a/instrumentation-security/vertx-core-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java +++ b/instrumentation-security/vertx-core-4.0.0/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java @@ -1,6 +1,7 @@ package com.newrelic.agent.security.instrumentation.vertx.web; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; public class VertxClientHelper { @@ -17,7 +18,7 @@ public static void releaseLock() { GenericHelper.releaseLock(getNrSecCustomAttribName()); } - public static boolean acquireLockIfPossible() { - return GenericHelper.acquireLockIfPossible(getNrSecCustomAttribName()); + public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { + return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttribName()); } } diff --git a/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java b/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java new file mode 100644 index 000000000..d030b540a --- /dev/null +++ b/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/HttpServer_Instrumentation.java @@ -0,0 +1,26 @@ +package io.vertx.core.http; + +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; + + + +@Weave(originalName = "io.vertx.core.http.HttpServer", type = MatchType.Interface) +public class HttpServer_Instrumentation { + + public HttpServer_Instrumentation requestHandler(Handler handler){ + HttpServer_Instrumentation server = Weaver.callOriginal(); + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpoints(handler.hashCode()); + } catch (Exception e){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, "VERTX-CORE-4.0.0", e.getMessage()), e, VertxApiEndpointUtils.class.getName()); + } + return server; + } +} diff --git a/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java b/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java index 21c3f7f25..8c64cf881 100644 --- a/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java +++ b/instrumentation-security/vertx-core-4.0.0/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl_Instrumentation.java @@ -13,6 +13,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SSRFOperation; import com.newrelic.api.agent.security.utils.SSRFUtils; @@ -35,7 +36,7 @@ public abstract class HttpClientRequestImpl_Instrumentation { public Future end(Buffer chunk) { Future result; - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(absoluteURI(), this.getClass().getName(), VertxClientHelper.METHOD_END); @@ -53,7 +54,7 @@ public Future end(Buffer chunk) { } public void end(Buffer chunk, Handler> handler) { - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(absoluteURI(), this.getClass().getName(), VertxClientHelper.METHOD_END); @@ -71,7 +72,7 @@ public void end(Buffer chunk, Handler> handler) { public void end(Handler> handler){ - boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(); + boolean isLockAcquired = VertxClientHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(absoluteURI(), this.getClass().getName(), diff --git a/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/Router_Instrumentation.java b/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/Router_Instrumentation.java new file mode 100644 index 000000000..b89e88acc --- /dev/null +++ b/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/Router_Instrumentation.java @@ -0,0 +1,25 @@ +package io.vertx.ext.web; + +import com.newrelic.api.agent.security.instrumentation.helpers.ThreadLocalLockHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(originalName = "io.vertx.ext.web.Router", type = MatchType.Interface) +public class Router_Instrumentation { + + public Router_Instrumentation mountSubRouter(String mountPoint, Router subRouter) { + Router_Instrumentation result; + boolean isLockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + result = Weaver.callOriginal(); + } finally { + if (isLockAcquired) { + ThreadLocalLockHelper.releaseLock(); + } + } + VertxApiEndpointUtils.getInstance().resolveSubRoutes(this.hashCode(), subRouter.hashCode(), mountPoint); + return result; + } +} diff --git a/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java b/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java index 9217471b8..7135ea14d 100644 --- a/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java +++ b/instrumentation-security/vertx-web-3.2.0/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java @@ -1,15 +1,80 @@ package io.vertx.ext.web.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.web.Route; import io.vertx.ext.web.RoutingContext; +import java.util.regex.Pattern; + @Weave(originalName = "io.vertx.ext.web.impl.RouteImpl") -public class RouteImpl_Instrumentation { +public abstract class RouteImpl_Instrumentation { + + private final RouterImpl router = Weaver.callOriginal(); + + private String path = Weaver.callOriginal(); + + private Pattern pattern = Weaver.callOriginal(); + + RouteImpl_Instrumentation(RouterImpl router, int order){ + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, null, null); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, HttpMethod method, String path) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, method.name()); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, String path) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, null); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, HttpMethod method, String regex, boolean bregex) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, method.name()); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, String regex, boolean bregex) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, null); + } synchronized void handleContext(RoutingContext context) { + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpointsIfNotPresent(this.hashCode()); + VertxApiEndpointUtils.getInstance().routeDetection(path, pattern); + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "VERTX-WEB-3.2.0", e.getMessage()), e, this.getClass().getName()); + } ServletHelper.registerUserLevelCode("vertx-web"); Weaver.callOriginal(); } + + public synchronized Route method(HttpMethod method) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, null, method.name()); + return route; + } + + public synchronized Route path(String path) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, null); + return route; + } + + public synchronized Route pathRegex(String regex) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, null); + return route; + } + + public synchronized Route handler(Handler contextHandler){ + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addHandlerClass(router.hashCode(), this.hashCode(), contextHandler.getClass().getName()); + return route; + } } diff --git a/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/Router_Instrumentation.java b/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/Router_Instrumentation.java new file mode 100644 index 000000000..6d788d82e --- /dev/null +++ b/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/Router_Instrumentation.java @@ -0,0 +1,25 @@ +package io.vertx.ext.web; + +import com.newrelic.api.agent.security.instrumentation.helpers.ThreadLocalLockHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(originalName = "io.vertx.ext.web.Router", type = MatchType.Interface) +public class Router_Instrumentation { + + public Router_Instrumentation mountSubRouter(String mountPoint, Router subRouter) { + Router_Instrumentation result; + boolean isLockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + result = Weaver.callOriginal(); + } finally { + if (isLockAcquired) { + ThreadLocalLockHelper.releaseLock(); + } + } + VertxApiEndpointUtils.getInstance().resolveSubRoutes(this.hashCode(), subRouter.hashCode(), mountPoint); + return result; + } +} \ No newline at end of file diff --git a/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java b/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java index f69d47e2d..683a6cfdb 100644 --- a/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java +++ b/instrumentation-security/vertx-web-3.5.1/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java @@ -1,14 +1,81 @@ package io.vertx.ext.web.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.schema.Framework; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.RoutingContext; + +import java.util.regex.Pattern; @Weave(originalName = "io.vertx.ext.web.impl.RouteImpl") public class RouteImpl_Instrumentation { + private final RouterImpl router = Weaver.callOriginal(); + + private String path = Weaver.callOriginal(); + + private Pattern pattern = Weaver.callOriginal(); + + RouteImpl_Instrumentation(RouterImpl router, int order){ + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, null, null); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, HttpMethod method, String path) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, method.name()); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, String path) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, null); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, HttpMethod method, String regex, boolean bregex) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, method.name()); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, String regex, boolean bregex) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, null); + } + void handleContext(RoutingContextImplBase context) { + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpointsIfNotPresent(this.hashCode()); + VertxApiEndpointUtils.getInstance().routeDetection(path, pattern); + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "VERTX-WEB-3.5.1", e.getMessage()), e, this.getClass().getName()); + } ServletHelper.registerUserLevelCode("vertx-web"); Weaver.callOriginal(); } + + public synchronized Route method(HttpMethod method) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, null, method.name()); + return route; + } + + public synchronized Route path(String path) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, null); + return route; + } + + public synchronized Route pathRegex(String regex) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, null); + return route; + } + + public synchronized Route handler(Handler contextHandler){ + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addHandlerClass(router.hashCode(), this.hashCode(), contextHandler.getClass().getName()); + return route; + } } diff --git a/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java b/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java new file mode 100644 index 000000000..04026fe3c --- /dev/null +++ b/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteImpl_Instrumentation.java @@ -0,0 +1,70 @@ +package io.vertx.ext.web.impl; + +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.vertx.core.Handler; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; + +@Weave(originalName = "io.vertx.ext.web.impl.RouteImpl", type = MatchType.ExactClass) +public class RouteImpl_Instrumentation { + + private final RouterImpl router = Weaver.callOriginal(); + + private volatile RouteState state = Weaver.callOriginal(); + + RouteImpl_Instrumentation(RouterImpl router, int order){ + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, null, null); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, HttpMethod method, String path) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, method.name()); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, String path) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, null); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, HttpMethod method, String regex, boolean bregex) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, method.name()); + } + + RouteImpl_Instrumentation(RouterImpl router, int order, String regex, boolean bregex) { + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, null); + } + + public synchronized Route method(HttpMethod method) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, null, method.name()); + return route; + } + + public synchronized Route path(String path) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), path, null, null); + return route; + } + + public synchronized Route pathRegex(String regex) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addRouteImpl(router.hashCode(), this.hashCode(), null, regex, null); + return route; + } + + public synchronized Route handler(Handler contextHandler){ + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().addHandlerClass(router.hashCode(), this.hashCode(), contextHandler.getClass().getName()); + return route; + } + + public synchronized Route subRouter(Router subRouter) { + Route route = Weaver.callOriginal(); + VertxApiEndpointUtils.getInstance().removeRouteImpl(router.hashCode(), this.hashCode()); + VertxApiEndpointUtils.getInstance().resolveSubRoutes(router.hashCode(), subRouter.hashCode(), VertxApiEndpointUtils.getInstance().getPath(state.getPath(), state.getPattern())); + return route; + } +} diff --git a/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteState_Instrumentation.java b/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteState_Instrumentation.java index acb7d0c98..92a1fae66 100644 --- a/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteState_Instrumentation.java +++ b/instrumentation-security/vertx-web-3.8.3/src/main/java/io/vertx/ext/web/impl/RouteState_Instrumentation.java @@ -1,13 +1,36 @@ package io.vertx.ext.web.impl; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.VertxApiEndpointUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; +import java.util.regex.Pattern; + @Weave(originalName = "io.vertx.ext.web.impl.RouteState") abstract class RouteState_Instrumentation { + + private final RouteImpl route = Weaver.callOriginal(); + void handleContext(RoutingContextImplBase context){ + try { + VertxApiEndpointUtils.getInstance().generateAPIEndpointsIfNotPresent(route.hashCode()); + VertxApiEndpointUtils.getInstance().routeDetection(getPath(), getPattern()); + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "VERTX-WEB-3.8.3", e.getMessage()), e, this.getClass().getName()); + } ServletHelper.registerUserLevelCode("vertx-web"); Weaver.callOriginal(); } + + public String getPath() { + return Weaver.callOriginal(); + } + + public Pattern getPattern() { + return Weaver.callOriginal(); + } } diff --git a/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/build.gradle b/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/build.gradle new file mode 100644 index 000000000..7312021d2 --- /dev/null +++ b/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/build.gradle @@ -0,0 +1,29 @@ +dependencies { + implementation(project(":newrelic-security-api")) + implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") + implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") + implementation(fileTree(include: ["*.jar"], dir: "lib")) +} + +def shouldBuild = fileTree(include: ["*.jar"], dir: "lib").size() > 0 + +compileJava { + enabled(shouldBuild) +} + +compileTestJava { + enabled(shouldBuild) +} + +tasks.getByName("writeCachedWeaveAttributes").enabled(shouldBuild) + +jar { + enabled(shouldBuild) + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.websphere-liberty' } +} + +site { + title 'WebSphere Liberty' + type 'Appserver' + versionOverride '[8.5,)' +} \ No newline at end of file diff --git a/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/lib/.gitignore b/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/lib/.gitignore new file mode 100644 index 000000000..c96a04f00 --- /dev/null +++ b/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/lib/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/src/main/java/com/ibm/ws/tcpchannel/internal/TCPChannelFactory.java b/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/src/main/java/com/ibm/ws/tcpchannel/internal/TCPChannelFactory.java new file mode 100644 index 000000000..848fb3aeb --- /dev/null +++ b/instrumentation-security/websphere-liberty-profile-environment-8.5.5.5/src/main/java/com/ibm/ws/tcpchannel/internal/TCPChannelFactory.java @@ -0,0 +1,37 @@ +package com.ibm.ws.tcpchannel.internal; + +import com.ibm.websphere.channelfw.ChannelData; +import com.ibm.wsspi.channelfw.Channel; +import com.ibm.wsspi.channelfw.exception.ChannelException; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import java.util.Map; + +@Weave +public class TCPChannelFactory { + + protected Channel createChannel(final ChannelData channelData) throws ChannelException { + try { + if (channelData.isInbound() && "defaultHttpEndpoint".equals(channelData.getExternalName())) { + Map propertyBag = channelData.getPropertyBag(); + if (propertyBag.containsKey("port")) { + try { + int port = Integer.parseInt((String) propertyBag.get("port")); + NewRelicSecurity.getAgent().setApplicationConnectionConfig(port, "http"); + } catch (NumberFormatException e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SERVER_CONFIG_ERROR, "WEBSPHERE_LIBERTY", e.getMessage()), e, this.getClass().getName()); + } + } else { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SERVER_CONFIG_ERROR, "WEBSPHERE_LIBERTY", null), null, this.getClass().getName()); + } + } else { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SERVER_CONFIG_ERROR, "WEBSPHERE_LIBERTY", null), null, this.getClass().getName()); + } + } catch (Exception ignored) { + } + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/xalan-xpath/src/main/java/org/apache/xpath/XPath_Instrumentation.java b/instrumentation-security/xalan-xpath/src/main/java/org/apache/xpath/XPath_Instrumentation.java index 17dd55fbc..7250b91c6 100644 --- a/instrumentation-security/xalan-xpath/src/main/java/org/apache/xpath/XPath_Instrumentation.java +++ b/instrumentation-security/xalan-xpath/src/main/java/org/apache/xpath/XPath_Instrumentation.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.XPathOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -23,7 +24,7 @@ public abstract class XPath_Instrumentation { abstract public String getPatternString(); public XObject execute(XPathContext var1, Node var2, PrefixResolver var3) throws TransformerException { - boolean isLockAcquired = acquireLockIfPossible(); + boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(getPatternString(), XPATHUtils.METHOD_EXECUTE); @@ -82,9 +83,9 @@ private void releaseLock() { } catch (Throwable ignored) {} } - private boolean acquireLockIfPossible() { + private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { try { - return GenericHelper.acquireLockIfPossible(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } catch (Throwable ignored) {} return false; } diff --git a/newrelic-security-agent/build.gradle b/newrelic-security-agent/build.gradle index 34c964c35..af21ca6ee 100644 --- a/newrelic-security-agent/build.gradle +++ b/newrelic-security-agent/build.gradle @@ -61,9 +61,10 @@ java { dependencies { shadowIntoJar project(":newrelic-security-api") - shadowIntoJar 'com.googlecode.json-simple:json-simple:1.1.1' - shadowIntoJar 'com.fasterxml.jackson.core:jackson-databind:2.14.2' - shadowIntoJar 'com.fasterxml.jackson.dataformat:jackson-dataformat-properties:2.14.2' + shadowIntoJar ('com.googlecode.json-simple:json-simple:1.1.1'){ + exclude(module:'junit', group:'junit') + } + shadowIntoJar 'com.fasterxml.jackson.core:jackson-databind:2.14.3' shadowIntoJar 'org.java-websocket:Java-WebSocket:1.5.3' shadowIntoJar 'commons-io:commons-io:2.7' shadowIntoJar 'org.apache.commons:commons-text:1.10.0' diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentConfig.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentConfig.java index af043606f..a3fed3d43 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentConfig.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentConfig.java @@ -1,30 +1,44 @@ package com.newrelic.agent.security; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; import com.newrelic.agent.security.instrumentator.os.OSVariables; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.instrumentator.utils.AgentUtils; +import com.newrelic.agent.security.intcodeagent.exceptions.RestrictionModeException; +import com.newrelic.agent.security.intcodeagent.exceptions.SecurityNoticeError; +import com.newrelic.agent.security.intcodeagent.exceptions.RestrictionModeException; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.models.collectorconfig.AgentMode; +import com.newrelic.agent.security.intcodeagent.utils.CronExpression; +import com.newrelic.api.agent.security.Agent; +import com.newrelic.api.agent.security.schema.policy.*; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.filelogging.LogWriter; import com.newrelic.agent.security.intcodeagent.models.collectorconfig.CollectorConfig; import com.newrelic.agent.security.intcodeagent.utils.CommonUtils; import com.newrelic.agent.security.util.IUtilConstants; import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; import org.apache.commons.io.FileUtils; import org.apache.commons.io.comparator.LastModifiedFileComparator; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; +import java.text.ParseException; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.stream.Collectors; -import static com.newrelic.agent.security.util.IUtilConstants.DIRECTORY_PERMISSION; +import static com.newrelic.agent.security.util.IUtilConstants.*; public class AgentConfig { @@ -32,42 +46,238 @@ public class AgentConfig { public static final String AGENT_JAR_LOCATION = "agent_jar_location"; public static final String AGENT_HOME = "agent_home"; + public static final String INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE = "Invalid cron expression provided for IAST Mode"; + public static final String ACCOUNT_ID_IS_REQUIRED_FOR_IAST_RESTRICTED_MODE = "Account ID is required for IAST Restricted Mode"; + public static final String ACCOUNT_ID_LOCATION = "account_id_location"; + public static final String ACCOUNT_ID_KEY = "account_id_key"; + public static final String ROUTE = "route"; + public static final String MAPPING_PARAMETERS_ARE_REQUIRED_FOR_IAST_RESTRICTED_MODE = "Mapping Parameters are required for IAST Restricted Mode"; + public static final String DEFAULT_SCAN_SCHEDULE_EXPRESSION = "0 0 0 * * ?"; + public static final String INVALID_SECURITY_CONFIGURATION_FOR_MODE_IAST_RESTRICTED = "Invalid Security Configuration for mode IAST_RESTRICTED "; + public static final String INVALID_SECURITY_CONFIGURATION = "Invalid Security Configuration "; + private static final Logger log = LoggerFactory.getLogger(AgentConfig.class); private String NR_CSEC_HOME; private String logLevel; private String groupName; + private AgentMode agentMode; + private CollectorConfig config = new CollectorConfig(); private boolean isNRSecurityEnabled; - private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + private static FileLoggerThreadPool logger; private OSVariables osVariables; + private Map noticeErrorCustomParams = new HashMap<>(); + + private String iastTestIdentifier; + private AgentConfig(){ } - public void instantiate(){ + public long instantiate() throws RestrictionModeException { //Set k2 home path - try { - boolean validHomePath = setK2HomePath(); - System.out.println("New Relic Security Agent: Setting csec home path to directory:"+NR_CSEC_HOME); - } catch (IOException e) { - String tmpDir = System.getProperty("java.io.tmpdir"); - System.err.println("[NR-CSEC-JA] "+e.getMessage()+" Please find the error in " + tmpDir + File.separator + "NR-CSEC-Logger.err"); - throw new RuntimeException("CSEC Agent Exiting!!! Unable to create csec home directory", e); + boolean validHomePath = setSecurityHomePath(); + if(validHomePath) { + System.out.println("New Relic Security Agent: Setting Security home path to directory: " + NR_CSEC_HOME); } isNRSecurityEnabled = NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_SECURITY_ENABLED, false); // Set required Group groupName = applyRequiredGroup(); + Agent.getCustomNoticeErrorParameters().put(IUtilConstants.SECURITY_MODE, groupName); // Enable low severity hooks // Set required LogLevel logLevel = applyRequiredLogLevel(); //Instantiation call please do not move or repeat this. osVariables = OsVariablesInstance.instantiate().getOsVariables(); + + logger = FileLoggerThreadPool.getInstance(); + //Do not repeat this task + logger.initialiseLogger(); + + iastTestIdentifier = NewRelic.getAgent().getConfig().getValue(IUtilConstants.IAST_TEST_IDENTIFIER); + + instantiateAgentMode(groupName); + + return triggerIAST(); + } + + public long triggerIAST() throws RestrictionModeException { + try { + if(agentMode.getScanSchedule().getNextScanTime() != null) { + logger.log(LogLevel.FINER, "Security Agent scan time is set to : " + agentMode.getScanSchedule().getNextScanTime(), AgentConfig.class.getName()); + long delay = agentMode.getScanSchedule().getNextScanTime().getTime() - Instant.now().toEpochMilli(); + return (delay > 0)? delay : 0; + } + } catch (Exception e){ + RestrictionModeException restrictionModeException = new RestrictionModeException("Error while calculating next scan time for IAST Restricted Mode", e); + NewRelic.noticeError(restrictionModeException, Agent.getCustomNoticeErrorParameters(), true); + System.err.println("[NR-CSEC-JA] Error while calculating next scan time for IAST Restricted Mode. IAST Restricted Mode will be disabled."); + NewRelic.getAgent().getLogger().log(Level.WARNING, "[NR-CSEC-JA] Error while calculating next scan time for IAST Restricted Mode. IAST Restricted Mode will be disabled."); + throw restrictionModeException; + } + return 0; + } + + private void instantiateAgentMode(String groupName) throws RestrictionModeException { + this.agentMode = new AgentMode(groupName); + switch (groupName){ + case IAST: + readIastConfig(); + break; + case RASP: + readRaspConfig(); + break; + case IAST_RESTRICTED: + try { + readIastRestrictedConfig(); + } catch (RestrictionModeException e) { + System.err.println("[NR-CSEC-JA] Error while reading IAST Restricted Mode Configuration. IAST Restricted Mode will be disabled."); + NewRelic.getAgent().getLogger().log(Level.WARNING, "[NR-CSEC-JA] Error while reading IAST Restricted Mode Configuration. IAST Restricted Mode will be disabled."); + NewRelic.noticeError(e, Agent.getCustomNoticeErrorParameters(), true); + AgentInfo.getInstance().agentStatTrigger(false); + throw e; + } + break; + default: + //this is default case which requires no changes + break; + } + + try { + readScanSchedule(); + readSkipScan(); + updateSkipScanParameters(); + } catch (RestrictionModeException e){ + System.err.println("[NR-CSEC-JA] Error while reading IAST Scan Configuration. Security will be disabled."); + NewRelic.getAgent().getLogger().log(Level.WARNING, "[NR-CSEC-JA] Error while reading IAST Scan Configuration. Security will be disabled. Message : {0}", e.getMessage()); + NewRelic.noticeError(e, Agent.getCustomNoticeErrorParameters(), true); + AgentInfo.getInstance().agentStatTrigger(false); + throw e; + } + logger.log(LogLevel.INFO, String.format("Security Agent Modes and Config : %s", agentMode), AgentConfig.class.getName()); + } + + private void readSkipScan() throws RestrictionModeException { + try { + agentMode.getSkipScan().setApis(NewRelic.getAgent().getConfig().getValue(SKIP_IAST_SCAN_API, Collections.emptyList())); + agentMode.getSkipScan().getParameters().setQuery(NewRelic.getAgent().getConfig().getValue(SKIP_IAST_SCAN_PARAMETERS_QUERY, Collections.emptyList()).stream() + .map(Object::toString) + .collect(Collectors.toList())); + agentMode.getSkipScan().getParameters().setHeader(NewRelic.getAgent().getConfig().getValue(SKIP_IAST_SCAN_PARAMETERS_HEADER, Collections.emptyList()).stream() + .map(Object::toString) + .collect(Collectors.toList())); + agentMode.getSkipScan().getParameters().setBody(NewRelic.getAgent().getConfig().getValue(SKIP_IAST_SCAN_PARAMETERS_BODY, Collections.emptyList()).stream() + .map(Object::toString) + .collect(Collectors.toList())); + agentMode.getSkipScan().getIastDetectionCategory().setInsecureSettingsEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_INSECURE_SETTINGS, false)); + agentMode.getSkipScan().getIastDetectionCategory().setInvalidFileAccessEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_INVALID_FILE_ACCESS, false)); + agentMode.getSkipScan().getIastDetectionCategory().setSqlInjectionEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_SQL_INJECTION, false)); + agentMode.getSkipScan().getIastDetectionCategory().setNoSqlInjectionEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_NOSQL_INJECTION, false)); + agentMode.getSkipScan().getIastDetectionCategory().setLdapInjectionEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_LDAP_INJECTION, false)); + agentMode.getSkipScan().getIastDetectionCategory().setJavascriptInjectionEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_JAVASCRIPT_INJECTION, false)); + agentMode.getSkipScan().getIastDetectionCategory().setCommandInjectionEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_COMMAND_INJECTION, false)); + agentMode.getSkipScan().getIastDetectionCategory().setXpathInjectionEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_XPATH_INJECTION, false)); + agentMode.getSkipScan().getIastDetectionCategory().setSsrfEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_SSRF, false)); + agentMode.getSkipScan().getIastDetectionCategory().setRxssEnabled(NewRelic.getAgent().getConfig().getValue(SKIP_RXSS, false)); + agentMode.getSkipScan().getIastDetectionCategory().generateDisabledCategoriesCSV(); + } catch (ClassCastException | NumberFormatException e){ + throw new RestrictionModeException(INVALID_SECURITY_CONFIGURATION + e.getMessage(), e); + } + } + + private void readScanSchedule() throws RestrictionModeException { + try { + agentMode.getScanSchedule().setDelay(NewRelic.getAgent().getConfig().getValue(SCAN_TIME_DELAY, 0)); + agentMode.getScanSchedule().setDuration(NewRelic.getAgent().getConfig().getValue(SCAN_TIME_DURATION, 0)); + agentMode.getScanSchedule().setSchedule(NewRelic.getAgent().getConfig().getValue(SCAN_TIME_SCHEDULE, StringUtils.EMPTY)); + agentMode.getScanSchedule().setCollectSamples(NewRelic.getAgent().getConfig().getValue(SCAN_TIME_COLLECT_SAMPLES, false)); + if (agentMode.getScanSchedule().getDelay() > 0) { + agentMode.getScanSchedule().setNextScanTime(new Date(Instant.now().toEpochMilli() + TimeUnit.MINUTES.toMillis(agentMode.getScanSchedule().getDelay()))); + } else if (StringUtils.isNotBlank(agentMode.getScanSchedule().getSchedule())) { + agentMode.getScanSchedule().setScheduleOnce(false); + if (CronExpression.isValidExpression(agentMode.getScanSchedule().getSchedule())) { + try { + agentMode.getScanSchedule().setNextScanTime(new CronExpression(agentMode.getScanSchedule().getSchedule()).getTimeAfter(new Date())); + } catch (ParseException e) { + throw new RestrictionModeException(INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE, e); + } + } else { + throw new RestrictionModeException(INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE); + } + } + agentMode.getScanSchedule().setDataCollectionTime(agentMode.getScanSchedule().getNextScanTime()); + if(agentMode.getScanSchedule().isCollectSamples()){ + agentMode.getScanSchedule().setNextScanTime(new Date(Instant.now().toEpochMilli())); + } + } catch (ClassCastException | NumberFormatException e){ + throw new RestrictionModeException(INVALID_SECURITY_CONFIGURATION + e.getMessage(), e); + } + } + + private void updateSkipScanParameters() { + + if(this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getBody().isEnabled()){ + this.agentMode.getSkipScan().getParameters().getBody().addAll(this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getBody().getLocations()); + } + if(this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getQuery().isEnabled()){ + this.agentMode.getSkipScan().getParameters().getQuery().addAll(this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getQuery().getLocations()); + } + if(this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getHeader().isEnabled()){ + this.agentMode.getSkipScan().getParameters().getHeader().addAll(this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getHeader().getLocations()); + } + } + + private void readIastConfig() { + this.agentMode.getIastScan().setEnabled(true); + this.agentMode.getRaspScan().setEnabled(false); + + } + + private void readIastRestrictedConfig() throws RestrictionModeException { + try { + this.agentMode.getIastScan().setRestricted(true); + Agent.getCustomNoticeErrorParameters().put(IAST_RESTRICTED, String.valueOf(true)); + RestrictionCriteria restrictionCriteria = this.agentMode.getIastScan().getRestrictionCriteria(); + restrictionCriteria.setAccountInfo(new AccountInfo(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_ACCOUNT_INFO_ACCOUNT_ID))); + if(restrictionCriteria.getAccountInfo().isEmpty()) { + throw new RestrictionModeException(ACCOUNT_ID_IS_REQUIRED_FOR_IAST_RESTRICTED_MODE); + } + + //Mapping parameters + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getBody().setEnabled(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY_ENABLED, false)); + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getQuery().setEnabled(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY_ENABLED, false)); + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getHeader().setEnabled(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER_ENABLED, false)); + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getPath().setEnabled(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_PATH_ENABLED, false)); + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getBody().setLocations(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY_LOCATION, Collections.emptyList()).stream() + .map(Object::toString) + .collect(Collectors.toList())); + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getQuery().setLocations(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY_LOCATION, Collections.emptyList()).stream() + .map(Object::toString) + .collect(Collectors.toList())); + this.agentMode.getIastScan().getRestrictionCriteria().getMappingParameters().getHeader().setLocations(NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER_LOCATION, Collections.emptyList()).stream() + .map(Object::toString) + .collect(Collectors.toList())); + + //Strict Criteria + List> strictCriteria = NewRelic.getAgent().getConfig().getValue(RESTRICTION_CRITERIA_STRICT, Collections.emptyList()); + for (Map strictCriterion : strictCriteria) { + StrictMappings matchingCriteria = new StrictMappings(strictCriterion.get(ROUTE), HttpParameterLocation.valueOf(strictCriterion.get(ACCOUNT_ID_LOCATION)), strictCriterion.get(ACCOUNT_ID_KEY)); + restrictionCriteria.getStrictMappings().add(matchingCriteria); + } + } catch (ClassCastException | NumberFormatException e){ + throw new RestrictionModeException(INVALID_SECURITY_CONFIGURATION_FOR_MODE_IAST_RESTRICTED + e.getMessage(), e); + } + } + + private void readRaspConfig() { + this.agentMode.getIastScan().setEnabled(false); + this.agentMode.getRaspScan().setEnabled(true); } private static final class InstanceHolder { @@ -88,9 +298,12 @@ private String applyRequiredGroup() { } private String applyRequiredLogLevel() { - String logLevel = IUtilConstants.INFO; - if (StringUtils.isNotBlank(NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_LOG_LEVEL))) { - logLevel = NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_LOG_LEVEL); + String logLevel; + Object value = NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_LOG_LEVEL); + if(value instanceof Boolean) { + logLevel = IUtilConstants.OFF; + } else { + logLevel = NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_LOG_LEVEL, IUtilConstants.INFO); } try { @@ -103,38 +316,48 @@ private String applyRequiredLogLevel() { return logLevel; } - public boolean setK2HomePath() throws IOException { - String agentJarLocation = NewRelic.getAgent().getConfig().getValue(AGENT_JAR_LOCATION); - if (NewRelic.getAgent().getConfig().getValue(AGENT_HOME) != null) { + public boolean setSecurityHomePath(){ + noticeErrorCustomParams.put(IUtilConstants.LOG_FILE_PATH, NewRelic.getAgent().getConfig().getValue(IUtilConstants.LOG_FILE_PATH)); + noticeErrorCustomParams.put(AGENT_JAR_LOCATION, NewRelic.getAgent().getConfig().getValue(AGENT_JAR_LOCATION)); + noticeErrorCustomParams.put(AGENT_HOME, NewRelic.getAgent().getConfig().getValue(AGENT_HOME)); + if(NewRelic.getAgent().getConfig().getValue(IUtilConstants.LOG_FILE_PATH) != null) { + NR_CSEC_HOME = NewRelic.getAgent().getConfig().getValue(IUtilConstants.LOG_FILE_PATH); + } else if (NewRelic.getAgent().getConfig().getValue(AGENT_JAR_LOCATION) != null) { + NR_CSEC_HOME = NewRelic.getAgent().getConfig().getValue(AGENT_JAR_LOCATION); + } else if (NewRelic.getAgent().getConfig().getValue(AGENT_HOME) != null) { + //system property `newrelic.home` or environment variable `NEWRELIC_HOME` NR_CSEC_HOME = NewRelic.getAgent().getConfig().getValue(AGENT_HOME); - } else if (StringUtils.isNotBlank(agentJarLocation)){ - //fallback to agent_jar_location as home - NR_CSEC_HOME = agentJarLocation; } else { - System.err.println("[NR-CSEC-JA] Missing or Incorrect system property `newrelic.home` or environment variable `NEWRELIC_HOME`. Collector exiting."); + NewRelic.noticeError(new SecurityNoticeError("CSEC home directory creation failed, reason directory not found. Please check the agent configs"), noticeErrorCustomParams, true); + System.err.println("[NR-CSEC-JA] CSEC home directory not found. Please check the agent configs or system property `newrelic.home` or environment variable `NEWRELIC_HOME`."); return false; } - Path k2homePath = Paths.get(NR_CSEC_HOME, IUtilConstants.NR_SECURITY_HOME); - if(!CommonUtils.forceMkdirs(k2homePath, DIRECTORY_PERMISSION)){ - System.err.println(String.format("[NR-CSEC-JA] CSEC home directory creation failed at %s", NR_CSEC_HOME)); + Path SecurityhomePath = Paths.get(NR_CSEC_HOME, IUtilConstants.NR_SECURITY_HOME); + NR_CSEC_HOME = SecurityhomePath.toString(); + Agent.getCustomNoticeErrorParameters().put(IUtilConstants.NR_SECURITY_HOME, NR_CSEC_HOME); + try { + noticeErrorCustomParams.put("CSEC_HOME", SecurityhomePath.toString()); + Agent.getCustomNoticeErrorParameters().put(IUtilConstants.NR_SECURITY_HOME, NR_CSEC_HOME); + if(!CommonUtils.forceMkdirs(SecurityhomePath, DIRECTORY_PERMISSION)){ + NewRelic.noticeError(String.format("CSEC home directory creation failed, reason : %s", NR_CSEC_HOME), noticeErrorCustomParams, true); + System.err.printf("[NR-CSEC-JA] CSEC home directory creation failed at %s%n", NR_CSEC_HOME); + return false; + } + } catch (IOException e) { + NewRelic.noticeError(new SecurityNoticeError(String.format("CSEC home directory creation failed, reason %s. Please check the agent configs", e.getMessage()), e), noticeErrorCustomParams, true); return false; } - NR_CSEC_HOME = k2homePath.toString(); AgentUtils.getInstance().getStatusLogValues().put("csec-home", NR_CSEC_HOME); - AgentUtils.getInstance().getStatusLogValues().put("csec-home-permissions", String.valueOf(k2homePath.toFile().canWrite() && k2homePath.toFile().canRead())); - AgentUtils.getInstance().getStatusLogValues().put("agent-location", agentJarLocation); - if (!isValidK2HomePath(NR_CSEC_HOME)) { - System.err.println("[NR-CSEC-JA] Incomplete startup env parameters provided : Missing or Incorrect 'newrelic.home'. Collector exiting."); - return false; - } - return true; + AgentUtils.getInstance().getStatusLogValues().put("csec-home-permissions", String.valueOf(SecurityhomePath.toFile().canWrite() && SecurityhomePath.toFile().canRead())); + AgentUtils.getInstance().getStatusLogValues().put("agent-location", NewRelic.getAgent().getConfig().getValue(AGENT_JAR_LOCATION)); + return isValidSecurityHomePath(NR_CSEC_HOME); } - private static boolean isValidK2HomePath(String k2Home) { - if (StringUtils.isNotBlank(k2Home) && Paths.get(k2Home).toFile().isDirectory()) { + private boolean isValidSecurityHomePath(String securityHome) { + if (StringUtils.isNotBlank(securityHome) && Paths.get(securityHome).toFile().isDirectory()) { long avail = 0; try { - avail = Files.getFileStore(Paths.get(k2Home)).getUsableSpace(); + avail = Files.getFileStore(Paths.get(securityHome)).getUsableSpace(); } catch (Exception e) { return true; } @@ -142,9 +365,12 @@ private static boolean isValidK2HomePath(String k2Home) { if (avail > FileUtils.ONE_GB) { return true; } - System.err.println(String.format("[NR-CSEC-JA] Insufficient disk space available to the location %s is : %s", k2Home, FileUtils.byteCountToDisplaySize(avail))); + noticeErrorCustomParams.put("CSEC_HOME_DISK_AVL_BYTES", String.valueOf(avail)); + NewRelic.noticeError("CSEC home directory creation failed, reason : Insufficient disk space available to the location " + securityHome + " is : " + FileUtils.byteCountToDisplaySize(avail), noticeErrorCustomParams, true); + System.err.println(String.format("[NR-CSEC-JA] Insufficient disk space available to the location %s is : %s", securityHome, FileUtils.byteCountToDisplaySize(avail))); return false; } + NewRelic.noticeError("CSEC home directory creation failed, reason : CSEC home directory not found :"+securityHome, noticeErrorCustomParams, true); return false; } @@ -164,7 +390,14 @@ public void setConfig(CollectorConfig config) { this.config = config; } + public String getLogLevel() { + return logLevel; + } + public void createSnapshotDirectory() throws IOException { + if (osVariables.getSnapshotDir() == null){ + return; + } Path snapshotDir = Paths.get(osVariables.getSnapshotDir()); // Remove any file with this name from target. if (!snapshotDir.toFile().isDirectory()) { @@ -200,11 +433,15 @@ public boolean isNRSecurityEnabled() { return isNRSecurityEnabled; } - public void setNRSecurityEnabled(boolean NRSecurityEnabled) { - isNRSecurityEnabled = NRSecurityEnabled; + public String getSecurityHome() { + return NR_CSEC_HOME; } - public String getK2Home() { - return NR_CSEC_HOME; + public String getIastTestIdentifier() { + return iastTestIdentifier; + } + + public AgentMode getAgentMode() { + return agentMode; } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentInfo.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentInfo.java index b69db9675..596ce452f 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentInfo.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentInfo.java @@ -48,7 +48,7 @@ public class AgentInfo { private BuildInfo buildInfo = new BuildInfo(); - private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + private static FileLoggerThreadPool logger; private boolean processProtected = false; private AgentInfo() { @@ -119,6 +119,10 @@ public void setBuildInfo(BuildInfo buildInfo) { this.buildInfo = buildInfo; } + public static void initialiseLogger() { + logger = FileLoggerThreadPool.getInstance(); + } + public ApplicationInfoBean generateAppInfo(CollectorConfig config) { applicationInfo = ApplicationInfoUtils.createApplicationInfoBean(identifier, getVMPID(), applicationUUID, config); if (applicationInfo == null) { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java index 9aa06df9e..0acc7370e 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java @@ -1,6 +1,7 @@ package com.newrelic.agent.security.instrumentator.dispatcher; import com.google.gson.Gson; +import com.newrelic.agent.security.AgentConfig; import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.helper.DynamoDBRequestConverter; import com.newrelic.agent.security.instrumentator.utils.AgentUtils; @@ -186,7 +187,7 @@ public Object call() throws Exception { eventBean = prepareXPATHEvent(eventBean, xPathOperationalBean); break; case SECURE_COOKIE: - SecureCookieOperation secureCookieOperationalBean = (SecureCookieOperation) operation; + SecureCookieOperationSet secureCookieOperationalBean = (SecureCookieOperationSet) operation; eventBean = prepareSecureCookieEvent(eventBean, secureCookieOperationalBean); break; case TRUSTBOUNDARY: @@ -221,6 +222,10 @@ public Object call() throws Exception { eventBean = prepareMemcachedEvent(eventBean, memcachedOperationalBean); } break; + case SOLR_DB_REQUEST: + SolrDbOperation solrDbOperation = (SolrDbOperation) operation; + eventBean = prepareSolrDbRequestEvent(eventBean, solrDbOperation); + break; default: } @@ -252,6 +257,20 @@ public Object call() throws Exception { return null; } + private JavaAgentEventBean prepareSolrDbRequestEvent(JavaAgentEventBean eventBean, SolrDbOperation solrDbOperation) { + JSONArray params = new JSONArray(); + JSONObject request = new JSONObject(); + request.put("collection", solrDbOperation.getCollection()); + request.put("method", solrDbOperation.getMethod()); + request.put("connectionURL", solrDbOperation.getConnectionURL()); + request.put("path", solrDbOperation.getPath()); + request.put("params", solrDbOperation.getParams()); + request.put("documents", solrDbOperation.getDocuments()); + params.add(request); + eventBean.setParameters(params); + return eventBean; + } + private JavaAgentEventBean prepareCachingDataStoreEvent(JavaAgentEventBean eventBean, RedisOperation redisOperation) { JSONArray params = new JSONArray(); for (Object data : redisOperation.getArguments()) { @@ -312,6 +331,7 @@ private JavaAgentEventBean processFileOperationEvent(JavaAgentEventBean eventBea */ private void processReflectedXSSEvent(JavaAgentEventBean eventBean) { if (!NewRelic.getAgent().getConfig().getValue(INRSettingsKey.SECURITY_DETECTION_RXSS_ENABLED, true)) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementRxssDetectionDeactivated(); return; } Set xssConstructs = CallbackUtils.checkForReflectedXSS(securityMetaData.getRequest(), securityMetaData.getResponse()); @@ -454,16 +474,17 @@ private JavaAgentEventBean prepareRandomEvent(JavaAgentEventBean eventBean, } private JavaAgentEventBean prepareSecureCookieEvent(JavaAgentEventBean eventBean, - SecureCookieOperation secureCookieOperationalBean) { + SecureCookieOperationSet secureCookieOperationalBean) { JSONArray params = new JSONArray(); - params.add(secureCookieOperationalBean.getValue()); - JSONObject cookie = new JSONObject(); - cookie.put(COOKIE_VALUE, secureCookieOperationalBean.getCookie()); - cookie.put(COOKIE_IS_SECURE, secureCookieOperationalBean.isSecure()); - cookie.put(COOKIE_IS_HTTP_ONLY, secureCookieOperationalBean.isHttpOnly()); - cookie.put(COOKIE_IS_SAME_SITE_STRICT, secureCookieOperationalBean.isSameSiteStrict()); - params.add(cookie); - + for (SecureCookieOperationSet.SecureCookieOperation secureCookieOperation : secureCookieOperationalBean.getOperations()) { + JSONObject cookie = new JSONObject(); + cookie.put(COOKIE_NAME, secureCookieOperation.getName()); + cookie.put(COOKIE_VALUE, secureCookieOperation.getValue()); + cookie.put(COOKIE_IS_SECURE, secureCookieOperation.isSecure()); + cookie.put(COOKIE_IS_HTTP_ONLY, secureCookieOperation.isHttpOnly()); + cookie.put(COOKIE_IS_SAME_SITE_STRICT, secureCookieOperation.isSameSiteStrict()); + params.add(cookie); + } eventBean.setParameters(params); return eventBean; } @@ -720,6 +741,7 @@ private JavaAgentEventBean setGenericProperties(AbstractOperation objectBean, Ja private JavaAgentEventBean prepareEvent(HttpRequest httpRequestBean, AgentMetaData metaData, VulnerabilityCaseType vulnerabilityCaseType, K2RequestIdentifier k2RequestIdentifier) { + metaData.setSkipScanParameters(AgentConfig.getInstance().getAgentMode().getSkipScan().getParameters()); JavaAgentEventBean eventBean = new JavaAgentEventBean(); eventBean.setHttpRequest(httpRequestBean); eventBean.setMetaData(metaData); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java index 4be77dfae..0f9db44a7 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java @@ -83,19 +83,18 @@ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { RestRequestThreadPool.getInstance().getRejectedIds().add(fuzzRequestId); } } - + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDispatcher().incrementRejected(); if(dispatcher.getSecurityMetaData() != null) { if(dispatcher.getSecurityMetaData().getFuzzRequestIdentifier().getK2Request()){ - AgentInfo.getInstance().getJaHealthCheck().getIastEventStats().incrementRejectedCount(); - } else { - AgentInfo.getInstance().getJaHealthCheck().getRaspEventStats().incrementRejectedCount(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getIastEvents().incrementRejected(); + } + if(dispatcher.getOperation()!= null && dispatcher.getOperation().isLowSeverityHook()) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getLowSeverityEvents().incrementRejected(); } } else if (dispatcher.getExitEventBean() != null) { - AgentInfo.getInstance().getJaHealthCheck().getExitEventStats().incrementRejectedCount(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getExitEvents().incrementRejected(); } } - AgentInfo.getInstance().getJaHealthCheck().incrementDropCount(); - AgentInfo.getInstance().getJaHealthCheck().incrementEventRejectionCount(); logger.log(LogLevel.FINEST,"Event Dispatch Task " + r.toString() + " rejected from " + e.toString(), DispatcherPool.class.getName()); } } @@ -111,13 +110,35 @@ private DispatcherPool() { @Override protected void afterExecute(Runnable r, Throwable t) { try { - if( t != null) { - AgentInfo.getInstance().getJaHealthCheck().incrementDropCount(); - AgentInfo.getInstance().getJaHealthCheck().incrementEventProcessingErrorCount(); - incrementCount(r, IUtilConstants.ERROR); - } else { - AgentInfo.getInstance().getJaHealthCheck().incrementProcessedCount(); - incrementCount(r, IUtilConstants.PROCESSED); + if (r instanceof CustomFutureTask && ((CustomFutureTask) r).getTask() instanceof Dispatcher) { + Dispatcher dispatcher = (Dispatcher) ((CustomFutureTask) r).getTask(); + AbstractOperation operation = dispatcher.getOperation(); + SecurityMetaData securityMetaData = dispatcher.getSecurityMetaData(); + if(t != null){ + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDispatcher().incrementError(); + if(operation != null) { + if(securityMetaData != null && securityMetaData.getFuzzRequestIdentifier().getK2Request()) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getIastEvents().incrementError(); + } + if (operation.isLowSeverityHook()) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getLowSeverityEvents().incrementError(); + } + } else if (dispatcher.getExitEventBean() != null) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getExitEvents().incrementError(); + } + } else { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDispatcher().incrementCompleted(); + if(operation != null) { + if(securityMetaData != null && securityMetaData.getFuzzRequestIdentifier().getK2Request()) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getIastEvents().incrementCompleted(); + } + if (operation.isLowSeverityHook()) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getLowSeverityEvents().incrementCompleted(); + } + } else if (dispatcher.getExitEventBean() != null) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getExitEvents().incrementCompleted(); + } + } } } catch (Throwable ignored) { logger.log(LogLevel.FINEST, "Error while Dispatcher matric processing", ignored, DispatcherPool.class.getName()); @@ -145,41 +166,6 @@ public Thread newThread(Runnable r) { }); } - private void incrementCount(Runnable r, String type) { - EventStats eventStats = null; - if (r instanceof CustomFutureTask && ((CustomFutureTask) r).getTask() instanceof Dispatcher) { - Dispatcher dispatcher = (Dispatcher) ((CustomFutureTask) r).getTask(); - if(dispatcher.getSecurityMetaData() != null) { - if(dispatcher.getSecurityMetaData().getFuzzRequestIdentifier().getK2Request()){ - eventStats = AgentInfo.getInstance().getJaHealthCheck().getIastEventStats(); - } else { - eventStats = AgentInfo.getInstance().getJaHealthCheck().getRaspEventStats(); - } - } else if (dispatcher.getExitEventBean() != null) { - eventStats = AgentInfo.getInstance().getJaHealthCheck().getExitEventStats(); - } - } - if(eventStats == null){ - return; - } - switch (type){ - case IUtilConstants.ERROR: - eventStats.incrementErrorCount(); - break; - case IUtilConstants.PROCESSED: - eventStats.incrementProcessedCount(); - break; - case IUtilConstants.SENT: - eventStats.incrementSentCount(); - break; - case IUtilConstants.REJECTED: - eventStats.incrementRejectedCount(); - break; - default: - logger.log(LogLevel.FINEST, String.format("Couldn't update event matric for task :%s and type : %s", r, type), DispatcherPool.class.getName()); - } - } - private static final class InstanceHolder { static final DispatcherPool instance = new DispatcherPool(); } @@ -193,15 +179,14 @@ public Set getEid() { public void dispatchEvent(AbstractOperation operation, SecurityMetaData securityMetaData) { - AgentInfo.getInstance().getJaHealthCheck().incrementInvokedHookCount(); if (executor.isShutdown()) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementExecutorUnavailable(); return; } if(!securityMetaData.getFuzzRequestIdentifier().getK2Request() && !AgentUsageMetric.isRASPProcessingActive()){ - AgentInfo.getInstance().getJaHealthCheck().getRaspEventStats().incrementRejectedCount(); - AgentInfo.getInstance().getJaHealthCheck().incrementEventRejectionCount(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementRaspProcessingDeactivated(); return; } @@ -233,6 +218,14 @@ public void dispatchEvent(AbstractOperation operation, SecurityMetaData security securityMetaData.addCustomAttribute(NR_APM_TRACE_ID, traceMetadata.getTraceId()); securityMetaData.addCustomAttribute(NR_APM_SPAN_ID, traceMetadata.getSpanId()); this.executor.submit(new Dispatcher(operation, new SecurityMetaData(securityMetaData))); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDispatcher().incrementSubmitted(); + + if(securityMetaData.getFuzzRequestIdentifier().getK2Request()){ + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getIastEvents().incrementSubmitted(); + } + if(operation.isLowSeverityHook()){ + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getLowSeverityEvents().incrementSubmitted(); + } } public void dispatchExitEvent(ExitEventBean exitEventBean) { @@ -246,6 +239,8 @@ public void dispatchExitEvent(ExitEventBean exitEventBean) { securityMetaData.addCustomAttribute(NR_APM_TRACE_ID, traceMetadata.getTraceId()); securityMetaData.addCustomAttribute(NR_APM_SPAN_ID, traceMetadata.getSpanId()); this.executor.submit(new Dispatcher(exitEventBean)); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDispatcher().incrementSubmitted(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getExitEvents().incrementSubmitted(); } public static void shutDownPool() { @@ -274,5 +269,6 @@ public void shutDownThreadPoolExecutor() { public void reset() { executor.getQueue().clear(); + executor.purge(); } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/EventAbortPolicy.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/EventAbortPolicy.java index 0dd26f8db..7a2595c9f 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/EventAbortPolicy.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/EventAbortPolicy.java @@ -1,5 +1,6 @@ package com.newrelic.agent.security.instrumentator.httpclient; +import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -11,6 +12,7 @@ public class EventAbortPolicy implements RejectedExecutionHandler { public EventAbortPolicy() { + AgentInfo.getInstance().getJaHealthCheck().getIastReplayRequest().incrementReplayRequestRejected(); } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java index 628b2cf99..4832c2412 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java @@ -1,6 +1,10 @@ package com.newrelic.agent.security.instrumentator.httpclient; +import com.newrelic.agent.security.AgentConfig; +import com.newrelic.agent.security.AgentInfo; +import com.newrelic.agent.security.instrumentator.utils.INRSettingsKey; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.util.IUtilConstants; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.models.IASTDataTransferRequest; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; @@ -10,14 +14,13 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.GrpcClientRequestReplayHelper; +import org.apache.commons.lang3.StringUtils; import java.time.Instant; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.HashSet; -import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -26,8 +29,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import static com.newrelic.agent.security.instrumentator.utils.INRSettingsKey.SECURITY_POLICY_VULNERABILITY_SCAN_IAST_SCAN_PROBING_THRESHOLD; - public class IASTDataTransferRequestProcessor { private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); public static final String UNABLE_TO_SEND_IAST_DATA_REQUEST_DUE_TO_ERROR_S_S = "Unable to send IAST data request due to error: %s : %s"; @@ -45,24 +46,34 @@ public class IASTDataTransferRequestProcessor { private final AtomicLong lastFuzzCCTimestamp = new AtomicLong(); + private int currentFetchThresholdPerMin = 3600; + + private long controlCommandRequestedAtEpochMilli = 0; + private void task() { IASTDataTransferRequest request = null; try { if(!AgentUsageMetric.isIASTRequestProcessingActive()){ + logger.log(LogLevel.FINER, "IAST request processing deactivated for the moment.", IASTDataTransferRequestProcessor.class.getName()); return; } - if (WSUtils.getInstance().isReconnecting() || - !WSClient.getInstance().isOpen()) { - synchronized (WSUtils.getInstance()) { - RestRequestThreadPool.getInstance().isWaiting().set(true); - GrpcClientRequestReplayHelper.getInstance().isWaiting().set(true); - WSUtils.getInstance().wait(); - RestRequestThreadPool.getInstance().isWaiting().set(false); - GrpcClientRequestReplayHelper.getInstance().isWaiting().set(false); - } + if (!WSClient.getInstance().isOpen()) { + logger.log(LogLevel.FINER, "IAST request processing deactivated due to websocket connection status.", IASTDataTransferRequestProcessor.class.getName()); + return; } + + if(WSUtils.getInstance().isReconnecting()) { + logger.log(LogLevel.FINER, "IAST request processing deactivated due to SE requested for reconnection..", IASTDataTransferRequestProcessor.class.getName()); + return; + } + long currentTimestamp = Instant.now().toEpochMilli(); + if(controlCommandRequestedAtEpochMilli <= 0){ + AgentInfo.getInstance().getJaHealthCheck().setControlCommandRequestedTime(currentTimestamp); + controlCommandRequestedAtEpochMilli = currentTimestamp; + AgentInfo.getInstance().getJaHealthCheck().setScanActive(true); + } // Sleep if under cooldown long cooldownSleepTime = cooldownTillTimestamp.get() - currentTimestamp; if(cooldownSleepTime > 0) { @@ -73,8 +84,12 @@ private void task() { return; } - int currentFetchThreshold = NewRelic.getAgent().getConfig() - .getValue(SECURITY_POLICY_VULNERABILITY_SCAN_IAST_SCAN_PROBING_THRESHOLD, 300); + int currentFetchThreshold = Math.round((float) currentFetchThresholdPerMin/12); + if (currentFetchThreshold <= 0){ + return; + } + + int fetchRatio = 300/currentFetchThreshold; int remainingRecordCapacityRest = RestRequestThreadPool.getInstance().getQueue().remainingCapacity(); int currentRecordBacklogRest = RestRequestThreadPool.getInstance().getQueue().size(); @@ -89,8 +104,12 @@ private void task() { batchSize /= 2; } - if (batchSize > 100 && remainingRecordCapacity > batchSize) { + if (batchSize > 100/fetchRatio && remainingRecordCapacity > batchSize) { request = new IASTDataTransferRequest(NewRelicSecurity.getAgent().getAgentUUID()); + if (AgentConfig.getInstance().getConfig().getCustomerInfo() != null) { + request.setAppAccountId(AgentConfig.getInstance().getConfig().getCustomerInfo().getAccountId()); + } + request.setAppEntityGuid(AgentInfo.getInstance().getLinkingMetadata().getOrDefault(INRSettingsKey.NR_ENTITY_GUID, StringUtils.EMPTY)); request.setBatchSize(batchSize); request.setCompletedRequests(getEffectiveCompletedRequests()); @@ -150,12 +169,27 @@ public static IASTDataTransferRequestProcessor getInstance() { public void startDataRequestSchedule(long delay, TimeUnit timeUnit){ try { stopDataRequestSchedule(true); - future = executorService.scheduleWithFixedDelay(this::task, 0, delay, timeUnit); + long initialDelay = 0; + if(AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime() != null) { + initialDelay = AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime().toInstant().getEpochSecond() - Instant.now().getEpochSecond(); + } + if(initialDelay < 0){ + initialDelay = 0; + } + // IAST Scan Rate per minute with range [12, 3600]; default 3600 replay requests will be replayed per minute + try { + currentFetchThresholdPerMin = Math.min(Math.max(NewRelic.getAgent().getConfig().getValue(IUtilConstants.SCAN_REQUEST_RATE_LIMIT, 3600), 12), 3600); + } catch (Exception e) { + logger.log(LogLevel.WARNING, String.format("Error while reading Configuration security.scan_request_rate_limit : %s, Using default value %s replay request per min.", e.getMessage(), currentFetchThresholdPerMin), e, this.getClass().getName()); + } + logger.log(LogLevel.INFO, String.format("IAST data pull request is scheduled at %s, after delay of %s seconds", AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime(), initialDelay), IASTDataTransferRequestProcessor.class.getName()); + future = executorService.scheduleWithFixedDelay(this::task, initialDelay, delay, timeUnit); } catch (Throwable ignored){} } public void stopDataRequestSchedule(boolean force){ try { + logger.log(LogLevel.FINER, "deactivating data pull request until reschedule.", IASTDataTransferRequestProcessor.class.getName()); if (this.future != null) { future.cancel(force); future = null; @@ -170,4 +204,8 @@ public void setCooldownTillTimestamp(long timestamp) { public void setLastFuzzCCTimestamp(long timestamp) { lastFuzzCCTimestamp.set(timestamp); } + + public long getControlCommandRequestedAtEpochMilli() { + return controlCommandRequestedAtEpochMilli; + } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/MonitorGrpcFuzzFailRequestQueueThread.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/MonitorGrpcFuzzFailRequestQueueThread.java index baf52fc99..16473fd75 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/MonitorGrpcFuzzFailRequestQueueThread.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/MonitorGrpcFuzzFailRequestQueueThread.java @@ -1,7 +1,5 @@ package com.newrelic.agent.security.instrumentator.httpclient; -import com.newrelic.agent.security.AgentInfo; -import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.models.javaagent.FuzzFailEvent; import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool; import com.newrelic.api.agent.security.instrumentation.helpers.GrpcClientRequestReplayHelper; @@ -23,7 +21,7 @@ public void run() { // TODO: Add to fuzz fail count in HC and remove FuzzFailEvent if not needed. Map fuzzFailMap = GrpcClientRequestReplayHelper.getInstance().getSingleRequestFromFuzzFailRequestQueue(); FuzzRequestBean request = (FuzzRequestBean) fuzzFailMap.keySet().toArray()[0]; - FuzzFailEvent fuzzFailEvent = new FuzzFailEvent(AgentInfo.getInstance().getApplicationUUID()); + FuzzFailEvent fuzzFailEvent = new FuzzFailEvent(); fuzzFailEvent.setFuzzHeader(request.getHeaders().get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)); EventSendPool.getInstance().sendEvent(fuzzFailEvent); } catch (InterruptedException e) { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestClient.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestClient.java index 909775771..726ea5f3e 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestClient.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestClient.java @@ -1,6 +1,5 @@ package com.newrelic.agent.security.instrumentator.httpclient; -import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.models.FuzzRequestBean; @@ -137,7 +136,7 @@ public void fireRequest(FuzzRequestBean httpRequest, List endpoints, int e, RestRequestProcessor.class.getName()); RestRequestThreadPool.getInstance().getProcessedIds().putIfAbsent(fuzzRequestId, new HashSet<>()); // TODO: Add to fuzz fail count in HC and remove FuzzFailEvent if not needed. - FuzzFailEvent fuzzFailEvent = new FuzzFailEvent(AgentInfo.getInstance().getApplicationUUID()); + FuzzFailEvent fuzzFailEvent = new FuzzFailEvent(); fuzzFailEvent.setFuzzHeader(request.header(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)); EventSendPool.getInstance().sendEvent(fuzzFailEvent); } @@ -228,7 +227,7 @@ else if(response.code() >= 400){ e, RestRequestProcessor.class.getName()); RestRequestThreadPool.getInstance().getProcessedIds().putIfAbsent(fuzzRequestId, new HashSet<>()); // TODO: Add to fuzz fail count in HC and remove FuzzFailEvent if not needed. - FuzzFailEvent fuzzFailEvent = new FuzzFailEvent(AgentInfo.getInstance().getApplicationUUID()); + FuzzFailEvent fuzzFailEvent = new FuzzFailEvent(); fuzzFailEvent.setFuzzHeader(request.header(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)); EventSendPool.getInstance().sendEvent(fuzzFailEvent); } catch (Exception e){ diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestProcessor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestProcessor.java index 1baa1d69a..618d33a0f 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestProcessor.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestProcessor.java @@ -41,6 +41,9 @@ public class RestRequestProcessor implements Callable { public static final String JSON_PARSING_ERROR_WHILE_PROCESSING_FUZZING_REQUEST_S = "JSON parsing error while processing fuzzing request : %s"; private static final int MAX_REPETITION = 3; public static final String ENDPOINT_LOCALHOST_S = "%s://localhost:%s"; + private static final String IAST_REQUEST_HAS_NO_ARGUMENTS = "IAST request has no arguments : %s"; + public static final String AGENT_IS_NOT_ACTIVE = "Agent is not active"; + public static final String WS_RECONNECTING = "Websocket reconnecting failing for control command id: %s"; private IntCodeControlCommand controlCommand; private int repeatCount; @@ -61,22 +64,19 @@ public RestRequestProcessor(IntCodeControlCommand controlCommand, int repeatCoun @Override public Boolean call() throws InterruptedException { if (controlCommand.getArguments().size() < 2 ) { + logger.log(LogLevel.FINER, String.format(IAST_REQUEST_HAS_NO_ARGUMENTS, controlCommand.getId()), RestRequestProcessor.class.getSimpleName()); return true; } if( !AgentInfo.getInstance().isAgentActive()) { + logger.log(LogLevel.FINER, AGENT_IS_NOT_ACTIVE, RestRequestProcessor.class.getSimpleName()); return false; } FuzzRequestBean httpRequest = null; try { if (WSUtils.getInstance().isReconnecting()) { - synchronized (WSUtils.getInstance()) { - RestRequestThreadPool.getInstance().isWaiting().set(true); - GrpcClientRequestReplayHelper.getInstance().isWaiting().set(true); - WSUtils.getInstance().wait(); - RestRequestThreadPool.getInstance().isWaiting().set(false); - GrpcClientRequestReplayHelper.getInstance().isWaiting().set(false); - } + logger.log(LogLevel.FINER, String.format(WS_RECONNECTING, controlCommand.getId()), RestRequestProcessor.class.getSimpleName()); + return false; } String req = StringUtils.replace(controlCommand.getArguments().get(0), NR_CSEC_VALIDATOR_HOME_TMP, OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory()); req = StringUtils.replace(req, NR_CSEC_VALIDATOR_HOME_TMP_URL_ENCODED, CallbackUtils.urlEncode(OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory())); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestThreadPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestThreadPool.java index 779217700..e57670be6 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestThreadPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestRequestThreadPool.java @@ -1,5 +1,6 @@ package com.newrelic.agent.security.instrumentator.httpclient; +import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.executor.CustomFutureTask; import com.newrelic.agent.security.intcodeagent.executor.CustomThreadPoolExecutor; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; @@ -28,8 +29,6 @@ public class RestRequestThreadPool { private final TimeUnit timeUnit = TimeUnit.SECONDS; private final boolean allowCoreThreadTimeOut = false; - private static final AtomicBoolean isWaiting = new AtomicBoolean(false); - private final Map> processedIds = new ConcurrentHashMap(); private final Set pendingIds = ConcurrentHashMap.newKeySet(); @@ -127,10 +126,6 @@ public BlockingQueue getQueue() { return this.executor.getQueue(); } - public AtomicBoolean isWaiting() { - return isWaiting; - } - public ThreadPoolExecutor getExecutor() { return executor; } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OsVariablesInstance.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OsVariablesInstance.java index 1ce9277c0..86964a2a6 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OsVariablesInstance.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OsVariablesInstance.java @@ -3,8 +3,7 @@ import com.newrelic.agent.security.AgentConfig; import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; -import com.newrelic.agent.security.util.IUtilConstants; -import com.newrelic.api.agent.NewRelic; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import java.io.File; @@ -18,8 +17,6 @@ public class OsVariablesInstance { public static final String TMP = "tmp"; public static final String SNAPSHOTS = "snapshots"; - public static final String LOG_FILE_PATH = "log_file_path"; - private static OsVariablesInstance instance; private final static Object lock = new Object(); @@ -28,27 +25,12 @@ public class OsVariablesInstance { private OsVariablesInstance() { osVariables = new OSVariables(); - /*Path k2root = Paths.get(AgentInfo.getInstance().getK2Home(), K_2_ROOT); - if (!k2root.toFile().isDirectory()) { - k2root.toFile().mkdir(); - } - - try { - Files.setPosixFilePermissions(k2root, PosixFilePermissions.fromString("rwxrwxrwx")); - } catch (Exception e) { - }*/ - -// osVariables.setK2RootDir(k2root.toString()); -// osVariables.setLogDirectory(Paths.get(k2root.toString(), LOGS, LANGUAGE_AGENT, AgentInfo.getInstance().getApplicationUUID()).toString()); - - if(NewRelic.getAgent().getConfig().getValue(LOG_FILE_PATH) != null) { - osVariables.setLogDirectory(Paths.get(NewRelic.getAgent().getConfig().getValue(LOG_FILE_PATH), IUtilConstants.NR_SECURITY_HOME, LOGS).toString()); - } else { - osVariables.setLogDirectory(Paths.get(AgentConfig.getInstance().getK2Home(), LOGS).toString()); + if(StringUtils.isNotBlank(AgentConfig.getInstance().getSecurityHome())) { + osVariables.setLogDirectory(Paths.get(AgentConfig.getInstance().getSecurityHome(), LOGS).toString()); + osVariables.setTmpDirectory(Paths.get(AgentConfig.getInstance().getSecurityHome(), TMP, LANGUAGE_AGENT, AgentInfo.getInstance().getApplicationUUID()).toString()); + osVariables.setSnapshotDir(Paths.get(osVariables.getLogDirectory(), SNAPSHOTS).toString()); } - osVariables.setTmpDirectory(Paths.get(AgentConfig.getInstance().getK2Home(), TMP, LANGUAGE_AGENT, AgentInfo.getInstance().getApplicationUUID()).toString()); - osVariables.setSnapshotDir(Paths.get(osVariables.getLogDirectory(), SNAPSHOTS).toString()); // osVariables.setPolicyConfigPath(Paths.get(k2root.toString(), CONFIG, LANGUAGE_AGENT).toString()); if (SystemUtils.IS_OS_LINUX) { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java index da5c72381..6b892b330 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java @@ -427,22 +427,6 @@ public static boolean applyPolicy(AgentPolicy newPolicy) { AgentUtils.getInstance().getStatusLogValues().put(POLICY_VERSION, AgentUtils.getInstance().getAgentPolicy().getVersion()); EventSendPool.getInstance().sendEvent(AgentInfo.getInstance().getApplicationInfo()); - // Start IAST data pull if policy allows - if (NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled() - ) { - IASTDataTransferRequestProcessor.getInstance().startDataRequestSchedule( - NewRelicSecurity.getAgent().getCurrentPolicy() - .getVulnerabilityScan().getIastScan().getProbing().getInterval(), TimeUnit.SECONDS); - logger.logInit( - LogLevel.INFO, - String.format(STARTED_MODULE_LOG, AgentServices.IASTDataPullService.name()), - Agent.class.getName() - ); - } else { - IASTDataTransferRequestProcessor.getInstance().stopDataRequestSchedule(true); - } - return true; } catch (Throwable e) { logger.logInit(LogLevel.SEVERE, IAgentConstants.UNABLE_TO_SET_AGENT_POLICY_DUE_TO_ERROR, e, @@ -667,7 +651,6 @@ private void applyNRPolicyOverride() { public static void sendApplicationURLMappings() { - //TODO mappings to be send once new mappings are discovered, after startup. ApplicationURLMappings applicationURLMappings = new ApplicationURLMappings(URLMappingsHelper.getApplicationURLMappings()); applicationURLMappings.setApplicationUUID(AgentInfo.getInstance().getApplicationUUID()); logger.logInit(LogLevel.INFO, String.format("Collected application url mappings %s", applicationURLMappings), Agent.class.getName()); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/ApplicationInfoUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/ApplicationInfoUtils.java index 0c3f2efcc..a5fd967e6 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/ApplicationInfoUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/ApplicationInfoUtils.java @@ -210,7 +210,7 @@ public static ApplicationInfoBean createApplicationInfoBean(Identifier identifie AgentUtils.getInstance().getStatusLogValues().put(PROCESS_BINARY, NOT_AVAILABLE); try { RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); - ApplicationInfoBean applicationInfoBean = new ApplicationInfoBean(vmpid, applicationUUID, STATIC); + ApplicationInfoBean applicationInfoBean = new ApplicationInfoBean(vmpid, STATIC); applicationInfoBean.setStartTime(runtimeMXBean.getStartTime()); identifier.setCollectorIp(getIpAddress()); // TODO: Need to write platform agnostic alternative for this. diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java index 0cf9bb752..e7c8017b3 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java @@ -5,6 +5,7 @@ import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessorThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.schedulers.FileCleaner; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.HealthCheckScheduleThread; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; @@ -13,6 +14,8 @@ import com.newrelic.agent.security.intcodeagent.websocket.WSClient; import com.newrelic.agent.security.intcodeagent.websocket.WSReconnectionST; import org.apache.commons.io.FileUtils; +import org.java_websocket.framing.CloseFrame; +import org.apache.commons.lang3.StringUtils; import java.io.File; import java.util.concurrent.TimeUnit; @@ -47,7 +50,7 @@ public class InstrumentationUtils { private static Boolean IAST = false; - public static void shutdownLogic(boolean doResetInstrumentation) { + public static void shutdownLogic() { // System.out.println("K2 Collector's shutdown hooked called."); // AgentUtils.getInstance().setAgentActive(false); try { @@ -67,14 +70,16 @@ public static void shutdownLogic(boolean doResetInstrumentation) { } catch (Throwable e) { } try { -// ServletEventPool.getInstance().shutDownThreadPoolExecutor(); HealthCheckScheduleThread.getInstance().cancelTask(true); -// EventThreadPool.getInstance().shutDownThreadPoolExecutor(); DispatcherPool.shutDownPool(); ControlCommandProcessorThreadPool.shutDownPool(); EventSendPool.shutDownPool(); WSReconnectionST.shutDownPool(); - FileUtils.deleteQuietly(new File(OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory())); + WSClient.shutDownWSClient(true, CloseFrame.NORMAL, "IAST agent shutting down"); + FileCleaner.cancelTask(); + if(StringUtils.isNotBlank(OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory())) { + FileUtils.deleteQuietly(new File(OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory())); + } } catch (Throwable e) { logger.log(LogLevel.SEVERE, "Error while shutting down executor pools : ", e, diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessor.java index f66a634d4..e18da9551 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessor.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessor.java @@ -1,18 +1,19 @@ package com.newrelic.agent.security.intcodeagent.controlcommand; import com.fasterxml.jackson.core.JsonProcessingException; +import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.httpclient.IASTDataTransferRequestProcessor; import com.newrelic.agent.security.instrumentator.httpclient.RestRequestProcessor; import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool; import com.newrelic.agent.security.instrumentator.utils.AgentUtils; import com.newrelic.agent.security.instrumentator.utils.InstrumentationUtils; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.models.config.AgentPolicyParameters; import com.newrelic.agent.security.intcodeagent.models.javaagent.EventResponse; import com.newrelic.agent.security.intcodeagent.models.javaagent.IntCodeControlCommand; -import com.newrelic.agent.security.intcodeagent.utils.CommonUtils; import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; import com.newrelic.agent.security.intcodeagent.websocket.WSClient; @@ -29,6 +30,7 @@ import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; +import java.util.logging.Level; public class ControlCommandProcessor implements Runnable { @@ -70,6 +72,8 @@ public class ControlCommandProcessor implements Runnable { private long receiveTimestamp; + private static Instant iastReplayRequestMsgReceiveTime = Instant.now(); + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); public ControlCommandProcessor(String controlCommandMessage, long receiveTimestamp) { @@ -107,13 +111,15 @@ public void run() { switch (controlCommand.getControlCommand()) { case IntCodeControlCommand.SHUTDOWN_LANGUAGE_AGENT: - InstrumentationUtils.shutdownLogic(true); + InstrumentationUtils.shutdownLogic(); break; case IntCodeControlCommand.UNSUPPORTED_AGENT: logger.log(LogLevel.SEVERE, controlCommand.getArguments().get(0), ControlCommandProcessor.class.getSimpleName()); + NewRelic.noticeError("Incompatible New Relic Security Agent: " + controlCommand.getArguments().get(0), true); System.err.println(controlCommand.getArguments().get(0)); - InstrumentationUtils.shutdownLogic(true); + NewRelic.getAgent().getLogger().log(Level.SEVERE, controlCommand.getArguments().get(0)); + InstrumentationUtils.shutdownLogic(); break; case IntCodeControlCommand.SEND_POLICY_PARAMETERS: @@ -165,10 +171,16 @@ public void run() { } break; case IntCodeControlCommand.FUZZ_REQUEST: + AgentInfo.getInstance().getJaHealthCheck().getIastReplayRequest().incrementReceivedControlCommands(); logger.log(LogLevel.FINER, FUZZ_REQUEST + controlCommandMessage, ControlCommandProcessor.class.getName()); + iastReplayRequestMsgReceiveTime = Instant.now(); IASTDataTransferRequestProcessor.getInstance().setLastFuzzCCTimestamp(Instant.now().toEpochMilli()); RestRequestProcessor.processControlCommand(controlCommand); + if(ControlCommandProcessorThreadPool.getInstance().getScanStartTime() <= 0) { + ControlCommandProcessorThreadPool.getInstance().setScanStartTime(Instant.now().toEpochMilli()); + AgentInfo.getInstance().getJaHealthCheck().setScanStartTime(ControlCommandProcessorThreadPool.getInstance().getScanStartTime()); + } break; case IntCodeControlCommand.STARTUP_WELCOME_MSG: @@ -213,28 +225,10 @@ public void run() { * Post reconnect: reset 'reconnecting phase' in WSClient. */ try { + AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementReceivedReconnectAtWill(); + WSUtils.getInstance().setReconnecting(true); //TODO no need for draining IAST since last leg has complete ledger. logger.log(LogLevel.INFO, RECEIVED_WS_RECONNECT_COMMAND_FROM_SERVER_INITIATING_SEQUENCE, this.getClass().getName()); - if (NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled() - ) { - WSUtils.getInstance().setReconnecting(true); - while (EventSendPool.getInstance().getExecutor().getActiveCount() > 0 && !EventSendPool.getInstance().isWaiting().get()) { - Thread.sleep(100); - } - logger.log(LogLevel.FINER, WS_RECONNECT_EVENT_SEND_POOL_DRAINED, this.getClass().getName()); - - while (RestRequestThreadPool.getInstance().getExecutor().getActiveCount() > 0 && !RestRequestThreadPool.getInstance().isWaiting().get()) { - Thread.sleep(100); - } - logger.log(LogLevel.FINER, String.format("Request = %s, in process = %s", GrpcClientRequestReplayHelper.getInstance().getRequestQueue().size(), GrpcClientRequestReplayHelper.getInstance().getInProcessRequestQueue().size()), this.getClass().getName()); - while (GrpcClientRequestReplayHelper.getInstance().getRequestQueue().size() > 0 && GrpcClientRequestReplayHelper.getInstance().getInProcessRequestQueue().size() > 0 && !GrpcClientRequestReplayHelper.getInstance().isWaiting().get()) { - Thread.sleep(100); - } - logger.log(LogLevel.FINER, WS_RECONNECT_IAST_REQUEST_REPLAY_POOL_DRAINED, this.getClass().getName()); - } -// RestRequestThreadPool.getInstance().resetIASTProcessing(); -// GrpcClientRequestReplayHelper.getInstance().resetIASTProcessing(); WSClient.getInstance().close(CloseFrame.SERVICE_RESTART, "Reconnecting to service"); } catch (Throwable e) { logger.log(LogLevel.SEVERE, String.format(ERROR_WHILE_PROCESSING_RECONNECTION_CC_S_S, e.getMessage(), e.getCause()), this.getClass().getName()); @@ -272,4 +266,8 @@ public static void processControlCommand(String controlCommandMessage, long rece ControlCommandProcessorThreadPool.getInstance().executor .submit(new ControlCommandProcessor(controlCommandMessage, receiveTimestamp)); } + + public static Instant getIastReplayRequestMsgReceiveTime() { + return iastReplayRequestMsgReceiveTime; + } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessorThreadPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessorThreadPool.java index 7115409d3..0b432f3d9 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessorThreadPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/controlcommand/ControlCommandProcessorThreadPool.java @@ -27,6 +27,12 @@ public class ControlCommandProcessorThreadPool { private final boolean allowCoreThreadTimeOut = false; private static Object mutex = new Object(); + private long scanStartTime = 0; + + public ThreadPoolExecutor getExecutor() { + return executor; + } + /** * A handler for rejected tasks that throws a * {@code RejectedExecutionException}. @@ -115,6 +121,20 @@ public static ControlCommandProcessorThreadPool getInstance() { return instance; } + public static void clearAllTasks() { + if (instance != null) { + instance.clearAllTasks(true); + } + } + + private void clearAllTasks(boolean force) { + executor.getQueue().clear(); + executor.purge(); + if(force) { + + } + } + public static void shutDownPool() { if (instance != null) { instance.shutDownThreadPoolExecutor(); @@ -139,4 +159,11 @@ public void shutDownThreadPoolExecutor() { } } + public long getScanStartTime() { + return scanStartTime; + } + + public void setScanStartTime(long scanStartTime) { + this.scanStartTime = scanStartTime; + } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/exceptions/RestrictionModeException.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/exceptions/RestrictionModeException.java new file mode 100644 index 000000000..488c19da7 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/exceptions/RestrictionModeException.java @@ -0,0 +1,20 @@ +package com.newrelic.agent.security.intcodeagent.exceptions; + +public class RestrictionModeException extends Exception { + + public RestrictionModeException() { + super(); + } + + public RestrictionModeException(String message) { + super(message); + } + + public RestrictionModeException(String message, Throwable cause) { + super(message, cause); + } + + public RestrictionModeException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/exceptions/SecurityNoticeError.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/exceptions/SecurityNoticeError.java new file mode 100644 index 000000000..40c9c5485 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/exceptions/SecurityNoticeError.java @@ -0,0 +1,20 @@ +package com.newrelic.agent.security.intcodeagent.exceptions; + +public class SecurityNoticeError extends Exception { + + public SecurityNoticeError(){ + super(); + } + + public SecurityNoticeError(String message) { + super(message); + } + + public SecurityNoticeError(String message, Throwable cause) { + super(message, cause); + } + + public SecurityNoticeError(Throwable cause) { + super(cause); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java index 521f4cd75..46db8e43d 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java @@ -1,12 +1,15 @@ package com.newrelic.agent.security.intcodeagent.filelogging; import com.newrelic.agent.security.AgentInfo; +import com.newrelic.agent.security.instrumentator.os.OSVariables; +import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.instrumentator.utils.AgentUtils; import com.newrelic.agent.security.intcodeagent.models.javaagent.LogMessage; import com.newrelic.agent.security.intcodeagent.properties.K2JALogProperties; import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.util.concurrent.*; @@ -20,22 +23,43 @@ public class FileLoggerThreadPool { private boolean isInitLoggingActive = true; - protected final int maxfilesize; + protected final long maxfilesize; protected final int maxfiles; protected boolean isLoggingToStdOut = false; + private static OSVariables osVariables = OsVariablesInstance.getInstance().getOsVariables(); + private FileLoggerThreadPool() throws IOException { + maxfiles = LogFileHelper.logFileCount(); + maxfilesize = LogFileHelper.logFileLimit()* 1024L; + } + + /** + * Initialise the logger, call this method only once + */ + public void initialiseLogger() { // load the settings int queueSize = 15000; int maxPoolSize = 1; int corePoolSize = 1; long keepAliveTime = 600; - maxfiles = Math.max(K2JALogProperties.maxfiles, LogFileHelper.logFileCount()); - maxfilesize = LogFileHelper.logFileLimit()*1024; TimeUnit timeUnit = TimeUnit.SECONDS; + try { + if(LogFileHelper.isLoggingToStdOut()){ + this.isLoggingToStdOut = true; + } + } catch (NumberFormatException e){} + + if(!isLoggingToStdOut && StringUtils.isBlank(osVariables.getLogDirectory())) { + isLoggingActive = false; + isInitLoggingActive = false; + return; + } + + boolean allowCoreThreadTimeOut = false; executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, @@ -62,12 +86,6 @@ public Thread newThread(Runnable r) { return t; } }); - try { - if(LogFileHelper.isLoggingToStdOut()){ - this.isLoggingToStdOut = true; - } - } catch (NumberFormatException e){} - } @@ -122,14 +140,14 @@ public static FileLoggerThreadPool getInstance() { } public void log(LogLevel logLevel, String event, String logSourceClassName) { - if (logLevel.getLevel() == 1 || logLevel.getLevel() > LogWriter.defaultLogLevel) { + if (!isLoggingActive || logLevel.getLevel() == 1 || logLevel.getLevel() > LogWriter.defaultLogLevel) { return; } executor.submit(new LogWriter(logLevel, event, logSourceClassName, Thread.currentThread().getName())); } public void log(LogLevel logLevel, String event, Throwable throwableEvent, String logSourceClassName) { - if (logLevel.getLevel() == 1 || logLevel.getLevel() > LogWriter.defaultLogLevel) { + if (!isLoggingActive ||logLevel.getLevel() == 1 || logLevel.getLevel() > LogWriter.defaultLogLevel) { return; } executor.submit(new LogWriter(logLevel, event, throwableEvent, logSourceClassName, Thread.currentThread().getName())); @@ -137,7 +155,7 @@ public void log(LogLevel logLevel, String event, Throwable throwableEvent, Strin public void logInit(LogLevel logLevel, String event, String logSourceClassName) { postLogMessage(logLevel, event, null, logSourceClassName); - if (logLevel.getLevel() == 1 || logLevel.getLevel() > InitLogWriter.defaultLogLevel) { + if (!isInitLoggingActive || logLevel.getLevel() == 1 || logLevel.getLevel() > InitLogWriter.defaultLogLevel) { return; } if(!isLoggingToStdOut) { @@ -148,7 +166,7 @@ public void logInit(LogLevel logLevel, String event, String logSourceClassName) public void logInit(LogLevel logLevel, String event, Throwable throwableEvent, String logSourceClassName) { postLogMessage(logLevel, event, throwableEvent, logSourceClassName); - if (logLevel.getLevel() == 1 || logLevel.getLevel() > InitLogWriter.defaultLogLevel) { + if (!isInitLoggingActive || logLevel.getLevel() == 1 || logLevel.getLevel() > InitLogWriter.defaultLogLevel) { return; } if(!isLoggingToStdOut) { @@ -192,4 +210,8 @@ public void setInitLoggingActive(boolean initLoggingActive) { public boolean isLogLevelEnabled(LogLevel logLevel) { return (logLevel.getLevel() >= LogWriter.defaultLogLevel); } + + public ThreadPoolExecutor getExecutor() { + return executor; + } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/InitLogWriter.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/InitLogWriter.java index ba49ac376..a200b2af9 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/InitLogWriter.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/InitLogWriter.java @@ -79,14 +79,7 @@ public class InitLogWriter implements Runnable { fileName = new File(osVariables.getLogDirectory(), "java-security-collector-init.log").getAbsolutePath(); currentLogFile = new File(fileName); currentLogFileName = fileName; - if(!createLogFile()) { - osVariables.setLogDirectory(Paths.get(AgentConfig.getInstance().getK2Home(), LOGS).toString()); - fileName = new File(osVariables.getLogDirectory(), "java-security-collector-init.log").getAbsolutePath(); - currentLogFile = new File(fileName); - currentLogFileName = fileName; - createLogFile(); - } - + createLogFile(); } } @@ -178,7 +171,9 @@ public void run() { FileLoggerThreadPool.getInstance().setInitLoggingActive(true); // writer.newLine(); - rollover(currentLogFileName); + if(maxFileSize > 0) { + rollover(currentLogFileName); + } } catch (IOException e) { //TODO report to cloud FileLoggerThreadPool.getInstance().setInitLoggingActive(false); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogFileHelper.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogFileHelper.java index 196dba274..1b32f3afb 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogFileHelper.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogFileHelper.java @@ -7,6 +7,7 @@ package com.newrelic.agent.security.intcodeagent.filelogging; +import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.intcodeagent.properties.K2JALogProperties; import com.newrelic.agent.security.util.IUtilConstants; @@ -37,12 +38,13 @@ public class LogFileHelper { public static final String LOG_LIMIT = "log_limit_in_kbytes"; public static final boolean DEFAULT_LOG_DAILY = false; - public static final int DEFAULT_LOG_FILE_COUNT = 1; + public static final Integer DEFAULT_LOG_FILE_COUNT = 1; public static final String DEFAULT_LOG_FILE_NAME = "java-security-collector.log"; public static final String STDOUT = "STDOUT"; private static final String STRING_DOT = "."; + private static final Integer DEFAULT_LOG_FILE_LIMIT = 0; public static boolean isLoggingToStdOut() { String logFileName = NewRelic.getAgent().getConfig().getValue(LogFileHelper.LOG_FILE_NAME, LogFileHelper.DEFAULT_LOG_FILE_NAME); @@ -50,19 +52,26 @@ public static boolean isLoggingToStdOut() { } public static int logFileCount() { - return Math.max(1, NewRelic.getAgent().getConfig().getValue(LogFileHelper.LOG_FILE_COUNT, LogFileHelper.DEFAULT_LOG_FILE_COUNT)); + try { + return NewRelic.getAgent().getConfig().getValue(LogFileHelper.LOG_FILE_COUNT, LogFileHelper.DEFAULT_LOG_FILE_COUNT); + } catch (Exception e) { + return LogFileHelper.DEFAULT_LOG_FILE_COUNT; + } } public static int logFileLimit() { - int size = NewRelic.getAgent().getConfig().getValue(LogFileHelper.LOG_LIMIT, 1); - return size>1?size: K2JALogProperties.maxfilesize; + try { + return NewRelic.getAgent().getConfig().getValue(LogFileHelper.LOG_LIMIT, DEFAULT_LOG_FILE_LIMIT); + } catch (Exception e) { + return DEFAULT_LOG_FILE_LIMIT; + } } public static boolean isDailyRollover() { return NewRelic.getAgent().getConfig().getValue(LogFileHelper.LOG_DAILY, LogFileHelper.DEFAULT_LOG_DAILY); } - public static void deleteRolloverLogFiles(String fileName, int max) { + public static void deleteRolloverLogFiles(String fileName, long max) { Collection rolloverLogFiles = FileUtils.listFiles(new File(OsVariablesInstance.getInstance().getOsVariables().getLogDirectory()), FileFilterUtils.prefixFileFilter(fileName + "."), null); if (rolloverLogFiles.size() > max) { @@ -92,6 +101,7 @@ public static BufferedWriter dailyRollover(String fileName) throws IOException { public static void performDailyRollover(){ try { + AgentInfo.getInstance().getJaHealthCheck().getSchedulerRuns().incrementDailyLogRollover(); InitLogWriter.setWriter(dailyRollover(InitLogWriter.getFileName())); } catch (IOException e) { FileLoggerThreadPool.getInstance().setInitLoggingActive(false); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogWriter.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogWriter.java index 1fac40082..97d51eaa8 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogWriter.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/LogWriter.java @@ -103,14 +103,7 @@ private static boolean createLogFile() { fileName = new File(osVariables.getLogDirectory(), "java-security-collector.log").getAbsolutePath(); currentLogFile = new File(fileName); currentLogFileName = fileName; - if(!createLogFile()) { - osVariables.setLogDirectory(Paths.get(AgentConfig.getInstance().getK2Home(), LOGS).toString()); - fileName = new File(osVariables.getLogDirectory(), "java-security-collector.log").getAbsolutePath(); - currentLogFile = new File(fileName); - currentLogFileName = fileName; - createLogFile(); - } - + createLogFile(); } } @@ -178,7 +171,9 @@ public void run() { FileLoggerThreadPool.getInstance().setLoggingActive(true); // writer.newLine(); - rollover(currentLogFileName); + if(maxFileSize > 0){ + rollover(currentLogFileName); + } } catch (IOException e) { if (FileLoggerThreadPool.getInstance().isLoggingActive()) { //TODO report to cloud diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/HealthCheckScheduleThread.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/HealthCheckScheduleThread.java index 5d71a79d1..308d513da 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/HealthCheckScheduleThread.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/HealthCheckScheduleThread.java @@ -7,7 +7,10 @@ import com.newrelic.agent.security.instrumentator.os.OSVariables; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.instrumentator.utils.AgentUtils; +import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessorThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.models.javaagent.ThreadPoolActiveStat; +import com.newrelic.api.agent.security.instrumentation.helpers.GrpcClientRequestReplayHelper; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.models.javaagent.JAHealthCheck; import com.newrelic.agent.security.intcodeagent.models.javaagent.ThreadPoolStats; @@ -76,7 +79,8 @@ public void run() { } logger.log(LogLevel.INFO, String.format("Pending CCs to be processed : %s", RestRequestThreadPool.getInstance().getQueueSize()), this.getClass().getName()); - AgentInfo.getInstance().getJaHealthCheck().setDsBackLog(RestRequestThreadPool.getInstance().getQueueSize()); + AgentInfo.getInstance().getJaHealthCheck().getIastReplayRequest().incrementPendingControlCommandsBy(RestRequestThreadPool.getInstance().getQueueSize()); + AgentInfo.getInstance().getJaHealthCheck().getIastReplayRequest().incrementPendingControlCommandsBy(GrpcClientRequestReplayHelper.getInstance().getRequestQueue().size()); AgentUtils.getInstance().addStatusLogMostRecentHCs(AgentInfo.getInstance().getJaHealthCheck().toString()); // channel.write(ByteBuffer.wrap(new JAHealthCheck(AgentNew.JA_HEALTH_CHECK).toString().getBytes())); if (WSClient.getInstance().isOpen()) { @@ -101,8 +105,17 @@ public void run() { private ThreadPoolStats populateThreadPoolStats() { ThreadPoolStats threadPoolStats = new ThreadPoolStats(); - threadPoolStats.setDispatcherQueueSize(DispatcherPool.getInstance().getExecutor().getQueue().size()); - threadPoolStats.setEventSendQueueSize(EventSendPool.getInstance().getExecutor().getQueue().size()); + threadPoolStats.setDispatcher(new ThreadPoolActiveStat(DispatcherPool.getInstance().getExecutor().getActiveCount(), + DispatcherPool.getInstance().getExecutor().getQueue().size())); + threadPoolStats.setEventSender(new ThreadPoolActiveStat(EventSendPool.getInstance().getExecutor().getActiveCount(), + EventSendPool.getInstance().getExecutor().getQueue().size())); + threadPoolStats.setControlCommandProcessor(new ThreadPoolActiveStat(ControlCommandProcessorThreadPool.getInstance().getExecutor().getActiveCount(), + ControlCommandProcessorThreadPool.getInstance().getExecutor().getQueue().size())); + threadPoolStats.setIastHttpRequestProcessor(new ThreadPoolActiveStat(RestRequestThreadPool.getInstance().getExecutor().getActiveCount(), + RestRequestThreadPool.getInstance().getExecutor().getQueue().size())); + threadPoolStats.setFileLogger(new ThreadPoolActiveStat(FileLoggerThreadPool.getInstance().getExecutor().getActiveCount(), + FileLoggerThreadPool.getInstance().getExecutor().getQueue().size())); + return threadPoolStats; } @@ -129,6 +142,9 @@ private void writeStatusLogFile(JAHealthCheck sendJaHealthCheck) { if(writerHealthCheck == null){ writerHealthCheck = AgentInfo.getInstance().getJaHealthCheck(); } + if (osVariables.getSnapshotDir() == null){ + return; + } File statusLog = new File(osVariables.getSnapshotDir(), String.format(K_2_AGENT_STATUS_LOG, AgentInfo.getInstance().getApplicationUUID())); try { FileUtils.deleteQuietly(statusLog); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/IAgentConstants.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/IAgentConstants.java index ac86fcf2e..5a11e43d3 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/IAgentConstants.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/logging/IAgentConstants.java @@ -579,4 +579,5 @@ public interface IAgentConstants { String REQUEST_FAILURE_DUE_TO_IOEXCEPTION = "Request failure could be due to cancellation, a connectivity problem or timeout."; String FAILURE_WHILE_GRPC_REQUEST_BODY_CONVERSION = "Failure while processing gRPC Request body, body : %s "; String REQUEST_FAILURE_FOR_S_WITH_RESPONSE_CODE = "Request failure for : %s, with response : %s and response body : %s"; + } \ No newline at end of file diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/IASTDataTransferRequest.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/IASTDataTransferRequest.java index 9a7fe3b02..f7ab3430d 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/IASTDataTransferRequest.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/IASTDataTransferRequest.java @@ -11,6 +11,8 @@ public class IASTDataTransferRequest { private String jsonName = "iast-data-request"; private String applicationUUID; + private String appAccountId; + private String appEntityGuid; private int batchSize; @@ -65,6 +67,22 @@ public void setJsonName(String jsonName) { this.jsonName = jsonName; } + public String getAppAccountId() { + return appAccountId; + } + + public void setAppAccountId(String appAccountId) { + this.appAccountId = appAccountId; + } + + public String getAppEntityGuid() { + return appEntityGuid; + } + + public void setAppEntityGuid(String appEntityGuid) { + this.appEntityGuid = appEntityGuid; + } + @Override public String toString() { try { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/collectorconfig/AgentMode.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/collectorconfig/AgentMode.java new file mode 100644 index 000000000..81183118e --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/collectorconfig/AgentMode.java @@ -0,0 +1,79 @@ +package com.newrelic.agent.security.intcodeagent.models.collectorconfig; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; +import com.newrelic.api.agent.security.schema.policy.IASTScan; +import com.newrelic.api.agent.security.schema.policy.RASPScan; +import com.newrelic.api.agent.security.schema.policy.ScanSchedule; +import com.newrelic.api.agent.security.schema.policy.SkipScan; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder(alphabetic = true) +public class AgentMode { + + private String mode; + + private IASTScan iastScan; + + private RASPScan raspScan; + + private SkipScan skipScan; + + private ScanSchedule scanSchedule; + + public AgentMode() {} + + public AgentMode(String mode) { + this.mode = mode; + iastScan = new IASTScan(); + raspScan = new RASPScan(); + skipScan = new SkipScan(); + scanSchedule = new ScanSchedule(); + } + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + + public IASTScan getIastScan() { + return iastScan; + } + + public void setIastScan(IASTScan iastScan) { + this.iastScan = iastScan; + } + + public RASPScan getRaspScan() { + return raspScan; + } + + public void setRaspScan(RASPScan raspScan) { + this.raspScan = raspScan; + } + + public SkipScan getSkipScan() { + return skipScan; + } + + public void setSkipScan(SkipScan skipScan) { + this.skipScan = skipScan; + } + + public ScanSchedule getScanSchedule() { + return scanSchedule; + } + + public void setScanSchedule(ScanSchedule scanSchedule) { + this.scanSchedule = scanSchedule; + } + + @Override + public String toString() { + return JsonConverter.toJSON(this); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/AgentBasicInfo.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/AgentBasicInfo.java index 5c204b402..cdd23459a 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/AgentBasicInfo.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/AgentBasicInfo.java @@ -60,12 +60,13 @@ public class AgentBasicInfo { private String eventType; private Map linkingMetadata; + private String appAccountId; + private String appEntityGuid; + private String applicationUUID; @JsonInclude private static String policyVersion; - private String accountId; - private boolean isPolicyOverridden = AgentUtils.getInstance().isPolicyOverridden(); /** @@ -79,7 +80,9 @@ public AgentBasicInfo() { setGroupName(AgentConfig.getInstance().getGroupName()); setNodeId(AgentInfo.getInstance().getLinkingMetadata().getOrDefault(INRSettingsKey.NR_ENTITY_GUID, StringUtils.EMPTY)); setLinkingMetadata(new HashMap<>(AgentInfo.getInstance().getLinkingMetadata())); - setAccountId(AgentConfig.getInstance().getConfig().getCustomerInfo().getAccountId()); + setAppEntityGuid(AgentInfo.getInstance().getLinkingMetadata().getOrDefault(INRSettingsKey.NR_ENTITY_GUID, StringUtils.EMPTY)); + setAppAccountId(AgentConfig.getInstance().getConfig().getCustomerInfo().getAccountId()); + setApplicationUUID(AgentInfo.getInstance().getApplicationUUID()); if (this instanceof ApplicationInfoBean) { setJsonName(JSON_NAME_APPLICATION_INFO_BEAN); } else if (this instanceof JavaAgentEventBean) { @@ -240,11 +243,27 @@ public void setLinkingMetadata(Map linkingMetadata) { this.linkingMetadata = linkingMetadata; } - public String getAccountId() { - return accountId; + public String getAppAccountId() { + return appAccountId; + } + + public void setAppAccountId(String appAccountId) { + this.appAccountId = appAccountId; + } + + public String getAppEntityGuid() { + return appEntityGuid; + } + + public void setAppEntityGuid(String appEntityGuid) { + this.appEntityGuid = appEntityGuid; + } + + public String getApplicationUUID() { + return applicationUUID; } - public void setAccountId(String accountId) { - this.accountId = accountId; + public void setApplicationUUID(String applicationUUID) { + this.applicationUUID = applicationUUID; } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationInfoBean.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationInfoBean.java index 3f2620adf..f5732752a 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationInfoBean.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationInfoBean.java @@ -22,11 +22,6 @@ public class ApplicationInfoBean extends AgentBasicInfo { */ private Integer pid; - /** - * UUID per running application. - */ - private String applicationUUID; - /** * name of running application. */ @@ -79,10 +74,9 @@ public void setLibraryPath(List libraryPath) { private Identifier identifier; - public ApplicationInfoBean(Integer pid, String applicationUUID, String agentAttachmentType) { + public ApplicationInfoBean(Integer pid, String agentAttachmentType) { super(); this.pid = pid; - this.applicationUUID = applicationUUID; this.runCommand = System.getProperty("sun.java.command"); this.userDir = System.getProperty("user.dir"); this.libraryPath = new ArrayList(); @@ -121,14 +115,6 @@ public void setPid(Integer pid) { this.pid = pid; } - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - public String getApplicationName() { return applicationName; } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationURLMappings.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationURLMappings.java index a65c8177c..6dec9b791 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationURLMappings.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ApplicationURLMappings.java @@ -7,7 +7,6 @@ public class ApplicationURLMappings extends AgentBasicInfo{ - private String applicationUUID; private Set mappings; public ApplicationURLMappings(Set mappings) { @@ -26,12 +25,4 @@ public void setMappings(Set mappings) { public String toString() { return JsonConverter.toJSON(this); } - - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/DroppedEvents.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/DroppedEvents.java new file mode 100644 index 000000000..647fdea2a --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/DroppedEvents.java @@ -0,0 +1,94 @@ +package com.newrelic.agent.security.intcodeagent.models.javaagent; + +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + +import java.util.concurrent.atomic.AtomicInteger; + +public class DroppedEvents { + + private AtomicInteger unsupportedContentType = new AtomicInteger(); + + private AtomicInteger nrInternalEvent = new AtomicInteger(); + + private AtomicInteger csecInternalEvent = new AtomicInteger(); + + private AtomicInteger executorUnavailable = new AtomicInteger(); + + private AtomicInteger raspProcessingDeactivated = new AtomicInteger(); + + private AtomicInteger rxssDetectionDeactivated = new AtomicInteger(); + + public DroppedEvents() { + } + + public DroppedEvents(DroppedEvents droppedEvents) { + this.unsupportedContentType.set(droppedEvents.unsupportedContentType.get()); + this.nrInternalEvent.set(droppedEvents.nrInternalEvent.get()); + this.csecInternalEvent.set(droppedEvents.csecInternalEvent.get()); + this.executorUnavailable.set(droppedEvents.executorUnavailable.get()); + this.raspProcessingDeactivated.set(droppedEvents.raspProcessingDeactivated.get()); + this.rxssDetectionDeactivated.set(droppedEvents.rxssDetectionDeactivated.get()); + } + + public AtomicInteger getUnsupportedContentType() { + return unsupportedContentType; + } + + public AtomicInteger getNrInternalEvent() { + return nrInternalEvent; + } + + public AtomicInteger getCsecInternalEvent() { + return csecInternalEvent; + } + + public void incrementUnsupportedContentType() { + unsupportedContentType.incrementAndGet(); + } + + public void incrementNrInternalEvent() { + nrInternalEvent.incrementAndGet(); + } + + public void incrementCsecInternalEvent() { + csecInternalEvent.incrementAndGet(); + } + + public AtomicInteger getExecutorUnavailable() { + return executorUnavailable; + } + + public void incrementExecutorUnavailable() { + executorUnavailable.incrementAndGet(); + } + + public AtomicInteger getRaspProcessingDeactivated() { + return raspProcessingDeactivated; + } + + public void incrementRaspProcessingDeactivated() { + raspProcessingDeactivated.incrementAndGet(); + } + + public AtomicInteger getRxssDetectionDeactivated() { + return rxssDetectionDeactivated; + } + + public void incrementRxssDetectionDeactivated() { + rxssDetectionDeactivated.incrementAndGet(); + } + + public void reset(){ + unsupportedContentType.set(0); + nrInternalEvent.set(0); + csecInternalEvent.set(0); + executorUnavailable.set(0); + raspProcessingDeactivated.set(0); + rxssDetectionDeactivated.set(0); + } + + @Override + public String toString() { + return JsonConverter.toJSON(this); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ErrorIncident.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ErrorIncident.java index ed8b21988..0e8669f4b 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ErrorIncident.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ErrorIncident.java @@ -11,8 +11,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class ErrorIncident extends AgentBasicInfo { - private String applicationUUID = AgentInfo.getInstance().getApplicationUUID(); - private LogMessageException exception; private Map linkingMetadata; @@ -23,14 +21,6 @@ public class ErrorIncident extends AgentBasicInfo { private HttpRequest httpRequest; - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - public LogMessageException getException() { return exception; } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventMetric.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventMetric.java new file mode 100644 index 000000000..282876235 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventMetric.java @@ -0,0 +1,70 @@ +package com.newrelic.agent.security.intcodeagent.models.javaagent; + +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + +import java.util.concurrent.atomic.AtomicInteger; + +public class EventMetric { + + private AtomicInteger submitted = new AtomicInteger(0); + + private AtomicInteger completed = new AtomicInteger(0); + + private AtomicInteger rejected = new AtomicInteger(0); + + private AtomicInteger error = new AtomicInteger(0); + + public EventMetric() { + } + + public EventMetric(EventMetric eventMetric) { + this.submitted.set(eventMetric.submitted.get()); + this.completed.set(eventMetric.completed.get()); + this.rejected.set(eventMetric.rejected.get()); + this.error.set(eventMetric.error.get()); + } + + public AtomicInteger getSubmitted() { + return submitted; + } + + public AtomicInteger getCompleted() { + return completed; + } + + public AtomicInteger getRejected() { + return rejected; + } + + public AtomicInteger getError() { + return error; + } + + public int incrementSubmitted() { + return submitted.incrementAndGet(); + } + + public int incrementCompleted() { + return completed.incrementAndGet(); + } + + public int incrementRejected() { + return rejected.incrementAndGet(); + } + + public int incrementError() { + return error.incrementAndGet(); + } + + @Override + public String toString() { + return JsonConverter.toJSON(this); + } + + public void reset(){ + submitted.set(0); + completed.set(0); + rejected.set(0); + error.set(0); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventStats.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventStats.java index 86d3037cf..86465eb61 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventStats.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/EventStats.java @@ -6,86 +6,64 @@ public class EventStats { - private AtomicInteger processed; + private EventMetric eventSender = new EventMetric(); - private AtomicInteger sent; + private EventMetric iastEvents = new EventMetric(); - private AtomicInteger rejected; + private EventMetric dispatcher = new EventMetric(); - private AtomicInteger errorCount; + private DroppedEvents droppedDueTo = new DroppedEvents(); - public EventStats() { - this.processed = new AtomicInteger(0); - this.sent = new AtomicInteger(0); - this.rejected = new AtomicInteger(0); - this.errorCount = new AtomicInteger(0); - } - - public EventStats(EventStats eventStats) { - this.processed = new AtomicInteger(eventStats.processed.intValue()); - this.sent = new AtomicInteger(eventStats.sent.intValue()); - this.rejected = new AtomicInteger(eventStats.rejected.intValue()); - this.errorCount = new AtomicInteger(eventStats.errorCount.intValue()); - } - - public AtomicInteger getProcessed() { - return processed; - } - - public void setProcessed(AtomicInteger processed) { - this.processed = processed; - } - - public AtomicInteger getSent() { - return sent; - } + private EventMetric lowSeverityEvents = new EventMetric(); - public void setSent(AtomicInteger sent) { - this.sent = sent; - } + private EventMetric exitEvents = new EventMetric(); - public AtomicInteger getRejected() { - return rejected; + public EventStats() { } - public void setRejected(AtomicInteger rejected) { - this.rejected = rejected; + public EventStats(EventStats eventStats) { + this.eventSender = new EventMetric(eventStats.eventSender); + this.iastEvents = new EventMetric(eventStats.iastEvents); + this.dispatcher = new EventMetric(eventStats.dispatcher); + this.droppedDueTo = new DroppedEvents(eventStats.droppedDueTo); + this.lowSeverityEvents = new EventMetric(eventStats.lowSeverityEvents); + this.exitEvents = new EventMetric(eventStats.exitEvents); } - public int incrementRejectedCount(){ - return this.rejected.incrementAndGet(); + public void reset(){ + this.lowSeverityEvents.reset(); + this.eventSender.reset(); + this.iastEvents.reset(); + this.dispatcher.reset(); + this.exitEvents.reset(); + this.droppedDueTo.reset(); } - public int incrementSentCount(){ - return this.sent.incrementAndGet(); + public String toString() { + return JsonConverter.toJSON(this); } - public int incrementProcessedCount(){ - return this.processed.incrementAndGet(); + public EventMetric getLowSeverityEvents() { + return lowSeverityEvents; } - public int incrementErrorCount(){ - return this.errorCount.incrementAndGet(); + public EventMetric getEventSender() { + return eventSender; } - public AtomicInteger getErrorCount() { - return errorCount; + public EventMetric getIastEvents() { + return iastEvents; } - public void setErrorCount(AtomicInteger errorCount) { - this.errorCount = errorCount; + public EventMetric getDispatcher() { + return dispatcher; } - public void reset(){ - this.processed.set(0); - this.sent.set(0); - this.errorCount.set(0); - this.rejected.set(0); + public DroppedEvents getDroppedDueTo() { + return droppedDueTo; } - - - public String toString() { - return JsonConverter.toJSON(this); + public EventMetric getExitEvents() { + return exitEvents; } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ExitEventBean.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ExitEventBean.java index c2ae85524..02030da4a 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ExitEventBean.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ExitEventBean.java @@ -7,8 +7,6 @@ public class ExitEventBean extends AgentBasicInfo { private String executionId; private String caseType; private String k2RequestIdentifier; - private String applicationUUID; - public ExitEventBean() { super(); } @@ -17,7 +15,6 @@ public ExitEventBean(String executionId, String caseType) { this(); this.executionId = executionId; this.caseType = caseType; - this.applicationUUID = AgentInfo.getInstance().getApplicationUUID(); } public String getExecutionId() { @@ -44,14 +41,6 @@ public void setK2RequestIdentifier(String k2RequestIdentifier) { this.k2RequestIdentifier = k2RequestIdentifier; } - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - @Override public String toString() { return JsonConverter.toJSON(this); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/FuzzFailEvent.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/FuzzFailEvent.java index 2fcb30a63..88150b81d 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/FuzzFailEvent.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/FuzzFailEvent.java @@ -6,19 +6,8 @@ public class FuzzFailEvent extends AgentBasicInfo { private String fuzzHeader; - private String applicationUUID; - - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - - public FuzzFailEvent(String applicationUUID) { + public FuzzFailEvent() { super(); - this.applicationUUID = applicationUUID; } public String getFuzzHeader() { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/HttpConnectionStat.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/HttpConnectionStat.java index e8a452c1b..7bc6f2d2c 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/HttpConnectionStat.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/HttpConnectionStat.java @@ -8,13 +8,10 @@ public class HttpConnectionStat extends AgentBasicInfo { private Collection httpConnections; - private String applicationUUID; - private Boolean isCached; - public HttpConnectionStat(Collection httpConnections, String applicationUUID, Boolean isCached) { + public HttpConnectionStat(Collection httpConnections, Boolean isCached) { this.httpConnections = httpConnections; - this.applicationUUID = applicationUUID; this.isCached = isCached; } @@ -34,14 +31,6 @@ public void setIsCached(Boolean isCached) { this.isCached = isCached; } - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - public String toString() { return JsonConverter.toJSON(this); } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/IastReplayRequest.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/IastReplayRequest.java new file mode 100644 index 000000000..15b9dba2f --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/IastReplayRequest.java @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.intcodeagent.models.javaagent; + +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + +import java.util.concurrent.atomic.AtomicInteger; + +public class IastReplayRequest { + + private AtomicInteger receivedControlCommands = new AtomicInteger(); + + private AtomicInteger processedControlCommands = new AtomicInteger(); + + private AtomicInteger pendingControlCommands = new AtomicInteger(); + + private AtomicInteger replayRequestGenerated = new AtomicInteger(); + + private AtomicInteger replayRequestExecuted = new AtomicInteger(); + + private AtomicInteger replayRequestSucceeded = new AtomicInteger(); + + private AtomicInteger replayRequestFailed = new AtomicInteger(); + + private AtomicInteger replayRequestRejected = new AtomicInteger(); + + public IastReplayRequest() { + } + + public IastReplayRequest(IastReplayRequest iastReplayRequest) { + this.receivedControlCommands.set(iastReplayRequest.getReceivedControlCommands().get()); + this.processedControlCommands.set(iastReplayRequest.getProcessedControlCommands().get()); + this.pendingControlCommands.set(iastReplayRequest.getPendingControlCommands().get()); + this.replayRequestGenerated.set(iastReplayRequest.getReplayRequestGenerated().get()); + this.replayRequestExecuted.set(iastReplayRequest.getReplayRequestExecuted().get()); + this.replayRequestSucceeded.set(iastReplayRequest.getReplayRequestSucceeded().get()); + this.replayRequestFailed.set(iastReplayRequest.getReplayRequestFailed().get()); + this.replayRequestRejected.set(iastReplayRequest.getReplayRequestRejected().get()); + } + + public AtomicInteger getReceivedControlCommands() { + return receivedControlCommands; + } + + public AtomicInteger getProcessedControlCommands() { + return processedControlCommands; + } + + public AtomicInteger getPendingControlCommands() { + return pendingControlCommands; + } + + public AtomicInteger getReplayRequestGenerated() { + return replayRequestGenerated; + } + + public AtomicInteger getReplayRequestExecuted() { + return replayRequestExecuted; + } + + public AtomicInteger getReplayRequestSucceeded() { + return replayRequestSucceeded; + } + + public AtomicInteger getReplayRequestFailed() { + return replayRequestFailed; + } + + public AtomicInteger getReplayRequestRejected() { + return replayRequestRejected; + } + + public int incrementReceivedControlCommands() { + return receivedControlCommands.incrementAndGet(); + } + + public int incrementProcessedControlCommands() { + return processedControlCommands.incrementAndGet(); + } + + public int incrementPendingControlCommands() { + return pendingControlCommands.incrementAndGet(); + } + + public int incrementReplayRequestGenerated() { + return replayRequestGenerated.incrementAndGet(); + } + + public int incrementReplayRequestExecuted() { + return replayRequestExecuted.incrementAndGet(); + } + + public int incrementReplayRequestSucceeded() { + return replayRequestSucceeded.incrementAndGet(); + } + + public int incrementReplayRequestFailed() { + return replayRequestFailed.incrementAndGet(); + } + + public int incrementReplayRequestRejected() { + return replayRequestRejected.incrementAndGet(); + } + + public void incrementPendingControlCommandsBy(int count) { + pendingControlCommands.addAndGet(count); + } + + public void reset() { + receivedControlCommands.set(0); + processedControlCommands.set(0); + pendingControlCommands.set(0); + replayRequestGenerated.set(0); + replayRequestExecuted.set(0); + replayRequestSucceeded.set(0); + replayRequestFailed.set(0); + replayRequestRejected.set(0); + } + + public String toString() { + return JsonConverter.toJSON(this); + } + + +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JAHealthCheck.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JAHealthCheck.java index da4d409cf..cd926be52 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JAHealthCheck.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JAHealthCheck.java @@ -1,10 +1,13 @@ package com.newrelic.agent.security.intcodeagent.models.javaagent; +import com.newrelic.agent.security.AgentConfig; import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; +import java.lang.management.ManagementFactory; +import java.time.Instant; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -14,39 +17,25 @@ public class JAHealthCheck extends AgentBasicInfo { private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); private static final String HC_CREATED = "Created Health Check: %s"; - private String applicationUUID; + private long procStartTime; -// private String protectedServer; + private long controlCommandRequestedTime; -// private Set protectedDB; + private long scanStartTime; - private AtomicInteger invokedHookCount; - - private AtomicInteger eventDropCount; + private long trafficStartedTime; - private AtomicInteger eventRejectionCount; + private final long csecActivationTime; - private AtomicInteger eventProcessingErrorCount; + private final long iastDataRequestTime; - private AtomicInteger eventSendRejectionCount; + private Boolean scanActive = false; - private AtomicInteger eventSendErrorCount; + private AtomicInteger invokedHookCount; private IdentifierEnvs kind; - private AtomicInteger eventProcessed; - - private AtomicInteger eventSentCount; - - private AtomicInteger exitEventSentCount; - - private AtomicInteger httpRequestCount; - - private EventStats raspEventStats; - - private EventStats iastEventStats; - - private EventStats exitEventStats; + private EventStats eventStats; private ThreadPoolStats threadPoolStats; @@ -54,54 +43,53 @@ public class JAHealthCheck extends AgentBasicInfo { private Map serviceStatus; -// private Set protectedVulnerabilities; + private IastReplayRequest iastReplayRequest = new IastReplayRequest(); + + private WebSocketConnectionStats webSocketConnectionStats = new WebSocketConnectionStats(); + + private SchedulerRuns schedulerRuns = new SchedulerRuns(); - private Integer dsBackLog; public JAHealthCheck(String applicationUUID) { super(); - this.applicationUUID = applicationUUID; this.invokedHookCount = new AtomicInteger(0); - this.eventDropCount = new AtomicInteger(0); - this.eventProcessed = new AtomicInteger(0); - this.eventSentCount = new AtomicInteger(0); - this.httpRequestCount = new AtomicInteger(0); - this.exitEventSentCount = new AtomicInteger(0); - this.eventRejectionCount = new AtomicInteger(0); - this.eventProcessingErrorCount = new AtomicInteger(0); - this.eventSendRejectionCount = new AtomicInteger(0); - this.eventSendErrorCount = new AtomicInteger(0); - this.raspEventStats = new EventStats(); - this.iastEventStats = new EventStats(); - this.exitEventStats = new EventStats(); this.threadPoolStats = new ThreadPoolStats(); this.stats = new HashMap<>(); this.serviceStatus = new HashMap<>(); + this.eventStats = new EventStats(); this.setKind(AgentInfo.getInstance().getApplicationInfo().getIdentifier().getKind()); + this.procStartTime = ManagementFactory.getRuntimeMXBean().getStartTime(); + if(AgentConfig.getInstance().getAgentMode().getScanSchedule().getNextScanTime() != null) { + this.csecActivationTime = AgentConfig.getInstance().getAgentMode().getScanSchedule().getNextScanTime().getTime(); + } else { + this.csecActivationTime = Instant.now().toEpochMilli(); + } + if(AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime() != null) { + this.iastDataRequestTime = AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime().getTime(); + } else { + this.iastDataRequestTime = Instant.now().toEpochMilli(); + } logger.log(LogLevel.INFO, String.format(HC_CREATED, JsonConverter.toJSON(this)), JAHealthCheck.class.getName()); } public JAHealthCheck(JAHealthCheck jaHealthCheck) { super(); - this.applicationUUID = jaHealthCheck.applicationUUID; - this.invokedHookCount = new AtomicInteger(jaHealthCheck.invokedHookCount.intValue()); - this.eventDropCount = new AtomicInteger(jaHealthCheck.eventDropCount.intValue()); - this.eventProcessed = new AtomicInteger(jaHealthCheck.eventProcessed.intValue()); - this.eventSentCount = new AtomicInteger(jaHealthCheck.eventSentCount.intValue()); - this.exitEventSentCount = new AtomicInteger(jaHealthCheck.exitEventSentCount.intValue()); - this.httpRequestCount = new AtomicInteger(jaHealthCheck.httpRequestCount.intValue()); - this.eventRejectionCount = new AtomicInteger(jaHealthCheck.eventRejectionCount.intValue()); - this.eventProcessingErrorCount = new AtomicInteger(jaHealthCheck.eventProcessingErrorCount.intValue()); - this.eventSendRejectionCount = new AtomicInteger(jaHealthCheck.eventSendRejectionCount.intValue()); - this.eventSendErrorCount = new AtomicInteger(jaHealthCheck.eventSendErrorCount.intValue()); - this.raspEventStats = new EventStats(jaHealthCheck.raspEventStats); - this.iastEventStats = new EventStats(jaHealthCheck.iastEventStats); - this.exitEventStats = new EventStats(jaHealthCheck.exitEventStats); this.threadPoolStats = new ThreadPoolStats(jaHealthCheck.threadPoolStats); this.kind = jaHealthCheck.kind; this.stats = new HashMap<>(jaHealthCheck.stats); this.serviceStatus = new HashMap<>(jaHealthCheck.serviceStatus); - this.dsBackLog = jaHealthCheck.dsBackLog; + this.eventStats = new EventStats(jaHealthCheck.eventStats); + this.iastReplayRequest = new IastReplayRequest(jaHealthCheck.iastReplayRequest); + this.schedulerRuns = new SchedulerRuns(jaHealthCheck.schedulerRuns); + this.invokedHookCount = new AtomicInteger(jaHealthCheck.invokedHookCount.get()); + this.webSocketConnectionStats = new WebSocketConnectionStats(jaHealthCheck.webSocketConnectionStats); + this.procStartTime = jaHealthCheck.getProcStartTime(); + this.controlCommandRequestedTime = jaHealthCheck.getControlCommandRequestedTime(); + this.scanStartTime = jaHealthCheck.getScanStartTime(); + this.trafficStartedTime = jaHealthCheck.getTrafficStartedTime(); + this.csecActivationTime = jaHealthCheck.getCsecActivationTime(); + this.iastDataRequestTime = jaHealthCheck.getIastDataRequestTime(); + this.scanActive = jaHealthCheck.getScanActive(); logger.log(LogLevel.INFO, String.format(HC_CREATED, JsonConverter.toJSON(this)), JAHealthCheck.class.getName()); } @@ -113,246 +101,124 @@ public void setKind(IdentifierEnvs kind) { this.kind = kind; } - /** - * @return the applicationUUID - */ - public String getApplicationUUID() { - return applicationUUID; - } - - /** - * @param applicationUUID the applicationUUID to set - */ - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - - /** - * @return the eventDropCount - */ - public Integer getEventDropCount() { - return eventDropCount.get(); - } - - /** - * @param eventDropCount the eventDropCount to set - */ - public void setEventDropCount(Integer eventDropCount) { - this.eventDropCount.set(eventDropCount); - } - - public void incrementDropCount() { - this.eventDropCount.getAndIncrement(); - } - - public AtomicInteger getEventRejectionCount() { - return eventRejectionCount; - } - - public void setEventRejectionCount(int eventRejectionCount) { - this.eventRejectionCount.set(eventRejectionCount); - } - - public int incrementEventRejectionCount(){ - return eventRejectionCount.incrementAndGet(); - } - - public AtomicInteger getEventProcessingErrorCount() { - return eventProcessingErrorCount; - } - - public void setEventProcessingErrorCount(int eventProcessingErrorCount) { - this.eventProcessingErrorCount.set(eventProcessingErrorCount); - } - - public int incrementEventProcessingErrorCount() { - return eventProcessingErrorCount.incrementAndGet(); - } - - public AtomicInteger getEventSendRejectionCount() { - return eventSendRejectionCount; - } - - public void setEventSendRejectionCount(int eventSendRejectionCount) { - this.eventSendRejectionCount.set(eventSendRejectionCount); - } - - public int incrementEventSendRejectionCount() { - return this.eventSendRejectionCount.incrementAndGet(); - } - - public AtomicInteger getEventSendErrorCount() { - return eventSendErrorCount; - } - - public void setEventSendErrorCount(int eventSendErrorCount) { - this.eventSendErrorCount.set(eventSendErrorCount); - } - - public int incrementEventSendErrorCount() { - return this.eventSendErrorCount.incrementAndGet(); - } - - public void incrementProcessedCount() { - this.eventProcessed.getAndIncrement(); - } - - public void incrementEventSentCount() { - this.eventSentCount.getAndIncrement(); - } - - public void decrementEventSentCount() { - this.eventSentCount.getAndDecrement(); - } - - public AtomicInteger getExitEventSentCount() { - return exitEventSentCount; - } - - public AtomicInteger getHttpRequestCount() { - return httpRequestCount; + @Override + public String toString() { + return JsonConverter.toJSON(this); } - public void incrementHttpRequestCount() { - this.httpRequestCount.getAndIncrement(); + public Map getStats() { + return stats; } - public void decrementHttpRequestCount() { - this.httpRequestCount.getAndDecrement(); + public void setStats(Map stats) { + this.stats = stats; } - public void incrementExitEventSentCount() { - this.exitEventSentCount.getAndIncrement(); + public Map getServiceStatus() { + return serviceStatus; } - public void decrementExitEventSentCount() { - this.exitEventSentCount.getAndDecrement(); + public void setServiceStatus(Map serviceStatus) { + this.serviceStatus = serviceStatus; } - public void setExitEventSentCount(Integer exitEventSentCount) { - this.exitEventSentCount.set(exitEventSentCount); - } - @Override - public String toString() { - return JsonConverter.toJSON(this); + public ThreadPoolStats getThreadPoolStats() { + return threadPoolStats; } - /** - * @return the eventProcessed - */ - public Integer getEventProcessed() { - return eventProcessed.get(); + public void setThreadPoolStats(ThreadPoolStats threadPoolStats) { + this.threadPoolStats = threadPoolStats; } - /** - * @param eventProcessed the eventProcessed to set - */ - public void setEventProcessed(Integer eventProcessed) { - this.eventProcessed.set(eventProcessed); - } - /** - * @return the eventSentCount - */ - public AtomicInteger getEventSentCount() { - return eventSentCount; + public int getInvokedHookCount() { + return invokedHookCount.get(); } - /** - * @param eventSentCount the eventSentCount to set - */ - public void setEventSentCount(Integer eventSentCount) { - this.eventSentCount.set(eventSentCount); + public void setInvokedHookCount(int invokedHookCount) { + this.invokedHookCount.set(invokedHookCount); } - public void setHttpRequestCount(Integer httpRequestCount) { - this.httpRequestCount.set(httpRequestCount); + public int incrementInvokedHookCount() { + return invokedHookCount.incrementAndGet(); } - public Integer getDsBackLog() { - return dsBackLog; + public EventStats getEventStats() { + return eventStats; } - public void setDsBackLog(Integer dsBackLog) { - this.dsBackLog = dsBackLog; + public IastReplayRequest getIastReplayRequest() { + return iastReplayRequest; } - public Map getStats() { - return stats; + public WebSocketConnectionStats getWebSocketConnectionStats() { + return webSocketConnectionStats; } - public void setStats(Map stats) { - this.stats = stats; + public SchedulerRuns getSchedulerRuns() { + return schedulerRuns; } - public Map getServiceStatus() { - return serviceStatus; + public void setSchedulerRuns(SchedulerRuns schedulerRuns) { + this.schedulerRuns = schedulerRuns; } - public void setServiceStatus(Map serviceStatus) { - this.serviceStatus = serviceStatus; + public long getProcStartTime() { + return procStartTime; } - public EventStats getRaspEventStats() { - return raspEventStats; + public void setProcStartTime(long procStartTime) { + this.procStartTime = procStartTime; } - public void setRaspEventStats(EventStats raspEventStats) { - this.raspEventStats = raspEventStats; + public long getControlCommandRequestedTime() { + return controlCommandRequestedTime; } - public EventStats getIastEventStats() { - return iastEventStats; + public void setControlCommandRequestedTime(long controlCommandRequestedTime) { + this.controlCommandRequestedTime = controlCommandRequestedTime; } - public void setIastEventStats(EventStats iastEventStats) { - this.iastEventStats = iastEventStats; + public long getScanStartTime() { + return scanStartTime; } - public ThreadPoolStats getThreadPoolStats() { - return threadPoolStats; + public void setScanStartTime(long scanStartTime) { + this.scanStartTime = scanStartTime; } - public void setThreadPoolStats(ThreadPoolStats threadPoolStats) { - this.threadPoolStats = threadPoolStats; + public long getTrafficStartedTime() { + return trafficStartedTime; } - public EventStats getExitEventStats() { - return exitEventStats; + public void setTrafficStartedTime(long trafficStartedTime) { + this.trafficStartedTime = trafficStartedTime; } - public void setExitEventStats(EventStats exitEventStats) { - this.exitEventStats = exitEventStats; + public long getCsecActivationTime() { + return csecActivationTime; } - public int getInvokedHookCount() { - return invokedHookCount.get(); + public Boolean getScanActive() { + return scanActive; } - public void setInvokedHookCount(int invokedHookCount) { - this.invokedHookCount.set(invokedHookCount); + public void setScanActive(Boolean scanActive) { + this.scanActive = scanActive; } - public int incrementInvokedHookCount() { - return invokedHookCount.incrementAndGet(); + public long getIastDataRequestTime() { + return iastDataRequestTime; } public void reset(){ - this.setEventDropCount(0); this.setInvokedHookCount(0); - this.setEventProcessed(0); - this.setEventSentCount(0); - this.setHttpRequestCount(0); - this.setExitEventSentCount(0); - this.setEventRejectionCount(0); - this.setEventProcessingErrorCount(0); - this.setEventSendRejectionCount(0); - this.setEventSendErrorCount(0); - this.raspEventStats.reset(); - this.iastEventStats.reset(); - this.exitEventStats.reset(); this.stats.clear(); this.serviceStatus.clear(); + this.eventStats.reset(); + this.iastReplayRequest.reset(); + this.webSocketConnectionStats.reset(); + this.schedulerRuns.reset(); } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentDynamicPathBean.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentDynamicPathBean.java index f6e207f6c..6f84a2ecf 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentDynamicPathBean.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentDynamicPathBean.java @@ -5,7 +5,6 @@ public class JavaAgentDynamicPathBean extends AgentBasicInfo { - private String applicationUUID; private String workingDirectory; @@ -13,22 +12,13 @@ public class JavaAgentDynamicPathBean extends AgentBasicInfo { private JSONArray dynamicPaths; - public JavaAgentDynamicPathBean(String applicationUUID, String workingDirectory, JSONArray jarPaths, JSONArray dynamicPaths) { + public JavaAgentDynamicPathBean(String workingDirectory, JSONArray jarPaths, JSONArray dynamicPaths) { super(); - this.applicationUUID = applicationUUID; this.workingDirectory = workingDirectory; this.jarPaths = jarPaths; this.dynamicPaths = dynamicPaths; } - public String getApplicationUUID() { - return applicationUUID; - } - - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - public String getWorkingDirectory() { return workingDirectory; } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentEventBean.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentEventBean.java index 76a7deb65..319fdabd0 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentEventBean.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/JavaAgentEventBean.java @@ -9,7 +9,6 @@ public class JavaAgentEventBean extends AgentBasicInfo { private Integer pid; - private String applicationUUID; private Long startTime; private String sourceMethod; private String userFileName; @@ -158,20 +157,6 @@ public void setEventGenerationTime(Long eventGenerationTime) { this.eventGenerationTime = eventGenerationTime; } - /** - * @return the applicationUUID - */ - public String getApplicationUUID() { - return applicationUUID; - } - - /** - * @param applicationUUID the applicationUUID to set - */ - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - /** * @return the servletInfo */ diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/LogMessage.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/LogMessage.java index 4e09c7621..3e7886af7 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/LogMessage.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/LogMessage.java @@ -1,8 +1,11 @@ package com.newrelic.agent.security.intcodeagent.models.javaagent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.newrelic.agent.security.AgentConfig; import com.newrelic.agent.security.AgentInfo; +import com.newrelic.agent.security.instrumentator.utils.INRSettingsKey; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; +import org.apache.commons.lang3.StringUtils; import java.time.Instant; import java.util.Map; @@ -26,6 +29,8 @@ public class LogMessage { private Map linkingMetadata; private String threadName; + private String appAccountId; + private String appEntityGuid; public LogMessage(String level, String message, String caller, Throwable exception, Map linkingMetadata) { this.timestamp = Instant.now().toEpochMilli(); @@ -37,6 +42,10 @@ public LogMessage(String level, String message, String caller, Throwable excepti this.exception = new LogMessageException(exception, 0, 1); } this.threadName = Thread.currentThread().getName(); + this.appEntityGuid = AgentInfo.getInstance().getLinkingMetadata().getOrDefault(INRSettingsKey.NR_ENTITY_GUID, StringUtils.EMPTY); + if (AgentConfig.getInstance().getConfig().getCustomerInfo() != null) { + this.appAccountId = AgentConfig.getInstance().getConfig().getCustomerInfo().getAccountId(); + } } public Long getTimestamp() { @@ -89,6 +98,21 @@ public void setThreadName(String threadName) { this.threadName = threadName; } + public String getAppAccountId() { + return appAccountId; + } + + public void setAppAccountId(String appAccountId) { + this.appAccountId = appAccountId; + } + + public String getAppEntityGuid() { + return appEntityGuid; + } + + public void setAppEntityGuid(String appEntityGuid) { + this.appEntityGuid = appEntityGuid; + } @Override public String toString() { return JsonConverter.toJSON(this); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/SchedulerRuns.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/SchedulerRuns.java new file mode 100644 index 000000000..6fcb650f1 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/SchedulerRuns.java @@ -0,0 +1,70 @@ +package com.newrelic.agent.security.intcodeagent.models.javaagent; + +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + +import java.util.concurrent.atomic.AtomicInteger; + +public class SchedulerRuns { + + private AtomicInteger iastFileCleaner = new AtomicInteger(); + + private AtomicInteger lowPriorityFilterCleaner = new AtomicInteger(); + + private AtomicInteger dailyLogRollover = new AtomicInteger(); + + private AtomicInteger websocketReconnector = new AtomicInteger(); + + public SchedulerRuns() { + } + + public SchedulerRuns(SchedulerRuns schedulerRuns) { + iastFileCleaner.set(schedulerRuns.iastFileCleaner.get()); + lowPriorityFilterCleaner.set(schedulerRuns.lowPriorityFilterCleaner.get()); + dailyLogRollover.set(schedulerRuns.dailyLogRollover.get()); + websocketReconnector.set(schedulerRuns.websocketReconnector.get()); + } + + public AtomicInteger getIastFileCleaner() { + return iastFileCleaner; + } + + public AtomicInteger getLowPriorityFilterCleaner() { + return lowPriorityFilterCleaner; + } + + public AtomicInteger getDailyLogRollover() { + return dailyLogRollover; + } + + public AtomicInteger getWebsocketReconnector() { + return websocketReconnector; + } + + public int incrementIastFileCleaner() { + return iastFileCleaner.incrementAndGet(); + } + + public int incrementLowPriorityFilterCleaner() { + return lowPriorityFilterCleaner.incrementAndGet(); + } + + public int incrementDailyLogRollover() { + return dailyLogRollover.incrementAndGet(); + } + + public int incrementWebsocketReconnector() { + return websocketReconnector.incrementAndGet(); + } + + @Override + public String toString() { + return JsonConverter.toJSON(this); + } + + public void reset() { + iastFileCleaner.set(0); + lowPriorityFilterCleaner.set(0); + dailyLogRollover.set(0); + websocketReconnector.set(0); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ShutDownEvent.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ShutDownEvent.java index 2e81a122d..4a5e63844 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ShutDownEvent.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ShutDownEvent.java @@ -9,8 +9,6 @@ public class ShutDownEvent extends AgentBasicInfo implements Serializable { private static final long serialVersionUID = -2320594688008671870L; - private String applicationUUID; - private String status; private JSONArray resonForTermination; @@ -21,20 +19,6 @@ public ShutDownEvent() { super(); } - /** - * @return the applicationUUID - */ - public String getApplicationUUID() { - return applicationUUID; - } - - /** - * @param applicationUUID the applicationUUID to set - */ - public void setApplicationUUID(String applicationUUID) { - this.applicationUUID = applicationUUID; - } - /** * @return the status */ diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolActiveStat.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolActiveStat.java new file mode 100644 index 000000000..1d5d6989a --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolActiveStat.java @@ -0,0 +1,27 @@ +package com.newrelic.agent.security.intcodeagent.models.javaagent; + +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + +public class ThreadPoolActiveStat { + + private Integer activeThreadCount; + + private Integer currentQueueSize; + + public ThreadPoolActiveStat(Integer activeThreadCount, Integer currentQueueSize) { + this.activeThreadCount = activeThreadCount; + this.currentQueueSize = currentQueueSize; + } + + public Integer getActiveThreadCount() { + return activeThreadCount; + } + + public Integer getCurrentQueueSize() { + return currentQueueSize; + } + + public String toString() { + return JsonConverter.toJSON(this); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolStats.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolStats.java index 880284e87..abc0238af 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolStats.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/ThreadPoolStats.java @@ -4,39 +4,67 @@ public class ThreadPoolStats { - private Integer dispatcherQueueSize; + private ThreadPoolActiveStat dispatcher; - private Integer eventSendQueueSize; + private ThreadPoolActiveStat eventSender; + + private ThreadPoolActiveStat fileLogger; + + private ThreadPoolActiveStat iastHttpRequestProcessor; + + private ThreadPoolActiveStat controlCommandProcessor; public ThreadPoolStats() { } - public ThreadPoolStats(Integer dispatcherQueueSize, Integer eventSendQueueSize) { - this.dispatcherQueueSize = dispatcherQueueSize; - this.eventSendQueueSize = eventSendQueueSize; + public ThreadPoolStats(ThreadPoolStats threadPoolStats) { + this.dispatcher = new ThreadPoolActiveStat(threadPoolStats.dispatcher.getActiveThreadCount(), threadPoolStats.dispatcher.getCurrentQueueSize()); + this.eventSender = new ThreadPoolActiveStat(threadPoolStats.eventSender.getActiveThreadCount(), threadPoolStats.eventSender.getCurrentQueueSize()); + this.fileLogger = new ThreadPoolActiveStat(threadPoolStats.fileLogger.getActiveThreadCount(), threadPoolStats.fileLogger.getCurrentQueueSize()); + this.iastHttpRequestProcessor = new ThreadPoolActiveStat(threadPoolStats.iastHttpRequestProcessor.getActiveThreadCount(), threadPoolStats.iastHttpRequestProcessor.getCurrentQueueSize()); + this.controlCommandProcessor = new ThreadPoolActiveStat(threadPoolStats.controlCommandProcessor.getActiveThreadCount(), threadPoolStats.controlCommandProcessor.getCurrentQueueSize()); + + } + + public ThreadPoolActiveStat getDispatcher() { + return dispatcher; } - public ThreadPoolStats(ThreadPoolStats threadPoolStats) { - this.dispatcherQueueSize = threadPoolStats.dispatcherQueueSize; - this.eventSendQueueSize = threadPoolStats.eventSendQueueSize; + public ThreadPoolActiveStat getEventSender() { + return eventSender; } - public Integer getDispatcherQueueSize() { - return dispatcherQueueSize; + public ThreadPoolActiveStat getFileLogger() { + return fileLogger; } - public void setDispatcherQueueSize(Integer dispatcherQueueSize) { - this.dispatcherQueueSize = dispatcherQueueSize; + public ThreadPoolActiveStat getIastHttpRequestProcessor() { + return iastHttpRequestProcessor; } - public Integer getEventSendQueueSize() { - return eventSendQueueSize; + public ThreadPoolActiveStat getControlCommandProcessor() { + return controlCommandProcessor; } - public void setEventSendQueueSize(Integer eventSendQueueSize) { - this.eventSendQueueSize = eventSendQueueSize; + public void setDispatcher(ThreadPoolActiveStat dispatcher) { + this.dispatcher = dispatcher; } + public void setEventSender(ThreadPoolActiveStat eventSender) { + this.eventSender = eventSender; + } + + public void setFileLogger(ThreadPoolActiveStat fileLogger) { + this.fileLogger = fileLogger; + } + + public void setIastHttpRequestProcessor(ThreadPoolActiveStat iastHttpRequestProcessor) { + this.iastHttpRequestProcessor = iastHttpRequestProcessor; + } + + public void setControlCommandProcessor(ThreadPoolActiveStat controlCommandProcessor) { + this.controlCommandProcessor = controlCommandProcessor; + } public String toString() { return JsonConverter.toJSON(this); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/WebSocketConnectionStats.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/WebSocketConnectionStats.java new file mode 100644 index 000000000..9c3070aa2 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/models/javaagent/WebSocketConnectionStats.java @@ -0,0 +1,92 @@ +package com.newrelic.agent.security.intcodeagent.models.javaagent; + +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + +import java.util.concurrent.atomic.AtomicInteger; + +public class WebSocketConnectionStats { + + private AtomicInteger messagesSent = new AtomicInteger(); + + private AtomicInteger messagesReceived = new AtomicInteger(); + + private AtomicInteger connectionReconnected = new AtomicInteger(); + + private AtomicInteger connectionFailure = new AtomicInteger(); + + private AtomicInteger receivedReconnectAtWill = new AtomicInteger(); + + private AtomicInteger sendFailure = new AtomicInteger(); + + public WebSocketConnectionStats() { + } + + public WebSocketConnectionStats(WebSocketConnectionStats stats) { + messagesSent.set(stats.messagesSent.get()); + messagesReceived.set(stats.messagesReceived.get()); + connectionReconnected.set(stats.connectionReconnected.get()); + connectionFailure.set(stats.connectionFailure.get()); + receivedReconnectAtWill.set(stats.receivedReconnectAtWill.get()); + sendFailure.set(stats.sendFailure.get()); + } + + public AtomicInteger getMessagesSent() { + return messagesSent; + } + + public AtomicInteger getMessagesReceived() { + return messagesReceived; + } + + public AtomicInteger getConnectionReconnected() { + return connectionReconnected; + } + + public AtomicInteger getConnectionFailure() { + return connectionFailure; + } + + public AtomicInteger getReceivedReconnectAtWill() { + return receivedReconnectAtWill; + } + + public AtomicInteger getSendFailure() { + return sendFailure; + } + + public int incrementMessagesSent() { + return messagesSent.incrementAndGet(); + } + + public int incrementMessagesReceived() { + return messagesReceived.incrementAndGet(); + } + + public int incrementConnectionReconnected() { + return connectionReconnected.incrementAndGet(); + } + + public int incrementConnectionFailure() { + return connectionFailure.incrementAndGet(); + } + + public int incrementReceivedReconnectAtWill() { + return receivedReconnectAtWill.incrementAndGet(); + } + + public int incrementSendFailure() { + return sendFailure.incrementAndGet(); + } + + public void reset() { + messagesSent.set(0); + messagesReceived.set(0); + connectionReconnected.set(0); + connectionFailure.set(0); + receivedReconnectAtWill.set(0); + } + + public String toString() { + return JsonConverter.toJSON(this); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/properties/BuildInfo.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/properties/BuildInfo.java index ee01b1d59..8c59238c9 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/properties/BuildInfo.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/properties/BuildInfo.java @@ -1,5 +1,7 @@ package com.newrelic.agent.security.intcodeagent.properties; +import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; + import java.time.Clock; public class BuildInfo { @@ -48,4 +50,9 @@ public String getBuildNumber() { public void setBuildNumber(String buildNumber) { this.buildNumber = buildNumber; } + + @Override + public String toString() { + return JsonConverter.toJSON(this); + } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java index 0bf88915f..f5e46b925 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java @@ -1,5 +1,6 @@ package com.newrelic.agent.security.intcodeagent.schedulers; +import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.os.OSVariables; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; @@ -8,6 +9,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.AgeFileFilter; import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.IOException; @@ -31,8 +33,12 @@ public class FileCleaner { @Override public void run() { + AgentInfo.getInstance().getJaHealthCheck().getSchedulerRuns().incrementIastFileCleaner(); long delay = Instant.now().toEpochMilli() - TimeUnit.MINUTES.toMillis(2); logger.log(LogLevel.INFO, FILE_CLEANER_INVOKED_INITIATING_TEMP_FILE_DIRECTORY_CLEANUP, FileCleaner.class.getName()); + if(StringUtils.isBlank(osVariables.getTmpDirectory())) { + return; + } FileUtils.iterateFiles(new File(osVariables.getTmpDirectory()), new AgeFileFilter(delay), DirectoryFileFilter.INSTANCE).forEachRemaining( file -> { FileUtils.deleteQuietly(file); }); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/SchedulerHelper.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/SchedulerHelper.java index a68025e68..5e1ea25b9 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/SchedulerHelper.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/SchedulerHelper.java @@ -1,6 +1,5 @@ package com.newrelic.agent.security.intcodeagent.schedulers; -import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.LogFileHelper; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.util.IUtilConstants; @@ -11,8 +10,8 @@ import java.util.concurrent.atomic.AtomicInteger; public class SchedulerHelper { - private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + public static final String IAST_TRIGGER = "IastTrigger"; private final ScheduledExecutorService commonExecutor; private SchedulerHelper() { @@ -39,6 +38,16 @@ public static SchedulerHelper getInstance() { private final Map> scheduledFutureMap = new ConcurrentHashMap<>(); + public ScheduledFuture scheduleIastTrigger(Runnable runnable, long initialDelay, TimeUnit unit) { + if(scheduledFutureMap.containsKey(IAST_TRIGGER)){ + ScheduledFuture currentFuture = scheduledFutureMap.get(IAST_TRIGGER); + currentFuture.cancel(false); + } + ScheduledFuture future = commonExecutor.schedule(runnable, initialDelay, unit); + scheduledFutureMap.put(IAST_TRIGGER, future); + return future; + } + public ScheduledFuture scheduleHealthCheck(Runnable command, long initialDelay, long period, @@ -86,4 +95,12 @@ public ScheduledFuture scheduleDailyLogRollover(Runnable command) { return null; } + public void scheduleURLMappingPosting(Runnable runnable) { + if(scheduledFutureMap.containsKey(IAgentConstants.JSON_SEC_APPLICATION_URL_MAPPING)){ + ScheduledFuture future = scheduledFutureMap.get(IAgentConstants.JSON_SEC_APPLICATION_URL_MAPPING); + future.cancel(false); + } + ScheduledFuture future = commonExecutor.schedule(runnable, 60, TimeUnit.SECONDS); + scheduledFutureMap.put(IAgentConstants.JSON_SEC_APPLICATION_URL_MAPPING, future); + } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CommonUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CommonUtils.java index 4bc17ee4b..2def061f0 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CommonUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CommonUtils.java @@ -1,14 +1,9 @@ package com.newrelic.agent.security.intcodeagent.utils; -import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; -import com.newrelic.api.agent.security.utils.logging.LogLevel; -import com.newrelic.api.agent.security.Agent; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -17,10 +12,9 @@ import java.util.Stack; public class CommonUtils { - - private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); - public static final String POLICY_WRITE_FAILED = "policy write failed : "; - public static final String POLICY_WRITTEN_TO_FILE = "policy written to file : "; + /** + * This class can't have a logger + */ public static SecureRandom secureRandom = new SecureRandom(); @@ -49,16 +43,6 @@ public static Boolean forceMkdirs(Path directory, String permissions) throws IOE return true; } - public static InputStream getResourceStreamFromAgentJar(String resourceName) { - try { - return new URL("jar:" + Agent.getAgentJarURL().toExternalForm() + "!/" + resourceName).openStream(); - } catch (Exception e) { - logger.log(LogLevel.SEVERE, String.format("Unable to locate resource from agent jar : %s", e.getMessage()), CommonUtils.class.getName()); - logger.log(LogLevel.FINER, "Unable to locate resource from agent jar : ", e, CommonUtils.class.getName()); - } - return null; - } - /** * Generate random int between range start to end. Both inclusive. diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CronExpression.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CronExpression.java new file mode 100644 index 000000000..07d44d370 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/CronExpression.java @@ -0,0 +1,1428 @@ +package com.newrelic.agent.security.intcodeagent.utils; + +import java.text.ParseException; +import java.util.*; + +public class CronExpression { + + protected static final int SECOND = 0; + protected static final int MINUTE = 1; + protected static final int HOUR = 2; + protected static final int DAY_OF_MONTH = 3; + protected static final int MONTH = 4; + protected static final int DAY_OF_WEEK = 5; + protected static final int YEAR = 6; + protected static final int ALL_SPEC_INT = 99; // '*' + protected static final int NO_SPEC_INT = 98; // '?' + protected static final Integer ALL_SPEC = ALL_SPEC_INT; + protected static final Integer NO_SPEC = NO_SPEC_INT; + + protected static final Map monthMap = new HashMap(20); + protected static final Map dayMap = new HashMap(60); + static { + monthMap.put("JAN", 0); + monthMap.put("FEB", 1); + monthMap.put("MAR", 2); + monthMap.put("APR", 3); + monthMap.put("MAY", 4); + monthMap.put("JUN", 5); + monthMap.put("JUL", 6); + monthMap.put("AUG", 7); + monthMap.put("SEP", 8); + monthMap.put("OCT", 9); + monthMap.put("NOV", 10); + monthMap.put("DEC", 11); + + dayMap.put("SUN", 1); + dayMap.put("MON", 2); + dayMap.put("TUE", 3); + dayMap.put("WED", 4); + dayMap.put("THU", 5); + dayMap.put("FRI", 6); + dayMap.put("SAT", 7); + } + + private final String cronExpression; + private TimeZone timeZone = null; + protected transient TreeSet seconds; + protected transient TreeSet minutes; + protected transient TreeSet hours; + protected transient TreeSet daysOfMonth; + protected transient TreeSet months; + protected transient TreeSet daysOfWeek; + protected transient TreeSet years; + + protected transient boolean lastdayOfWeek = false; + protected transient int nthdayOfWeek = 0; + protected transient boolean lastdayOfMonth = false; + protected transient boolean nearestWeekday = false; + protected transient int lastdayOffset = 0; + protected transient boolean expressionParsed = false; + + public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100; + + public CronExpression(String cronExpression) throws ParseException { + this.cronExpression = cronExpression.toUpperCase(Locale.US); + + buildExpression(this.cronExpression); + } + + /** + * Indicates whether the given date satisfies the cron expression. Note that + * milliseconds are ignored, so two Dates falling on different milliseconds + * of the same second will always have the same result here. + * + * @param date the date to evaluate + * @return a boolean indicating whether the given date satisfies the cron + * expression + */ + public boolean isSatisfiedBy(Date date) { + Calendar testDateCal = Calendar.getInstance(getTimeZone()); + testDateCal.setTime(date); + testDateCal.set(Calendar.MILLISECOND, 0); + Date originalDate = testDateCal.getTime(); + + testDateCal.add(Calendar.SECOND, -1); + + Date timeAfter = getTimeAfter(testDateCal.getTime()); + + return ((timeAfter != null) && (timeAfter.equals(originalDate))); + } + + /** + * Returns the next date/time after the given date/time which + * satisfies the cron expression. + * + * @param date the date/time at which to begin the search for the next valid + * date/time + * @return the next valid date/time + */ + public Date getNextValidTimeAfter(Date date) { + return getTimeAfter(date); + } + + /** + * Returns the next date/time after the given date/time which does + * not satisfy the expression + * + * @param date the date/time at which to begin the search for the next + * invalid date/time + * @return the next valid date/time + */ + public Date getNextInvalidTimeAfter(Date date) { + long difference = 1000; + + //move back to the nearest second so differences will be accurate + Calendar adjustCal = Calendar.getInstance(getTimeZone()); + adjustCal.setTime(date); + adjustCal.set(Calendar.MILLISECOND, 0); + Date lastDate = adjustCal.getTime(); + + Date newDate; + + //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution. + + //keep getting the next included time until it's farther than one second + // apart. At that point, lastDate is the last valid fire time. We return + // the second immediately following it. + while (difference == 1000) { + newDate = getTimeAfter(lastDate); + if(newDate == null) + break; + + difference = newDate.getTime() - lastDate.getTime(); + + if (difference == 1000) { + lastDate = newDate; + } + } + + return new Date(lastDate.getTime() + 1000); + } + + /** + * Returns the time zone for which this CronExpression + * will be resolved. + */ + public TimeZone getTimeZone() { + if (timeZone == null) { + timeZone = TimeZone.getDefault(); + } + + return timeZone; + } + + /** + * Sets the time zone for which this CronExpression + * will be resolved. + */ + public void setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + } + + /** + * Returns the string representation of the CronExpression + * + * @return a string representation of the CronExpression + */ + @Override + public String toString() { + return cronExpression; + } + + /** + * Indicates whether the specified cron expression can be parsed into a + * valid cron expression + * + * @param cronExpression the expression to evaluate + * @return a boolean indicating whether the given expression is a valid cron + * expression + */ + public static boolean isValidExpression(String cronExpression) { + + try { + new CronExpression(cronExpression); + } catch (ParseException pe) { + return false; + } + + return true; + } + + public static void validateExpression(String cronExpression) throws ParseException { + + new CronExpression(cronExpression); + } + + + //////////////////////////////////////////////////////////////////////////// + // + // Expression Parsing Functions + // + //////////////////////////////////////////////////////////////////////////// + + protected void buildExpression(String expression) throws ParseException { + expressionParsed = true; + + try { + + if (seconds == null) { + seconds = new TreeSet(); + } + if (minutes == null) { + minutes = new TreeSet(); + } + if (hours == null) { + hours = new TreeSet(); + } + if (daysOfMonth == null) { + daysOfMonth = new TreeSet(); + } + if (months == null) { + months = new TreeSet(); + } + if (daysOfWeek == null) { + daysOfWeek = new TreeSet(); + } + if (years == null) { + years = new TreeSet(); + } + + int exprOn = SECOND; + + StringTokenizer exprsTok = new StringTokenizer(expression, " \t", + false); + + while (exprsTok.hasMoreTokens() && exprOn <= YEAR) { + String expr = exprsTok.nextToken().trim(); + + // throw an exception if L is used with other days of the month + if(exprOn == DAY_OF_MONTH && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' and 'LW' with other days of the month is not implemented", -1); + } + // throw an exception if L is used with other days of the week + if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1); + } + if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) { + throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1); + } + + StringTokenizer vTok = new StringTokenizer(expr, ","); + while (vTok.hasMoreTokens()) { + String v = vTok.nextToken(); + storeExpressionVals(0, v, exprOn); + } + + exprOn++; + } + + if (exprOn <= DAY_OF_WEEK) { + throw new ParseException("Unexpected end of expression.", + expression.length()); + } + + if (exprOn <= YEAR) { + storeExpressionVals(0, "*", YEAR); + } + + TreeSet dow = getSet(DAY_OF_WEEK); + TreeSet dom = getSet(DAY_OF_MONTH); + + // Copying the logic from the UnsupportedOperationException below + boolean dayOfMSpec = !dom.contains(NO_SPEC); + boolean dayOfWSpec = !dow.contains(NO_SPEC); + + if (!dayOfMSpec || dayOfWSpec) { + if (!dayOfWSpec || dayOfMSpec) { + throw new ParseException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0); + } + } + } catch (ParseException pe) { + throw pe; + } catch (Exception e) { + throw new ParseException("Illegal cron expression format (" + + e.toString() + ")", 0); + } + } + + protected int storeExpressionVals(int pos, String s, int type) + throws ParseException { + + int incr = 0; + int i = skipWhiteSpace(pos, s); + if (i >= s.length()) { + return i; + } + char c = s.charAt(i); + if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) { + String sub = s.substring(i, i + 3); + int sval = -1; + int eval = -1; + if (type == MONTH) { + sval = getMonthNumber(sub) + 1; + if (sval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } + if (s.length() > i + 3) { + c = s.charAt(i + 3); + if (c == '-') { + i += 4; + sub = s.substring(i, i + 3); + eval = getMonthNumber(sub) + 1; + if (eval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } + } + } + } else if (type == DAY_OF_WEEK) { + sval = getDayOfWeekNumber(sub); + if (sval < 0) { + throw new ParseException("Invalid Day-of-Week value: '" + + sub + "'", i); + } + if (s.length() > i + 3) { + c = s.charAt(i + 3); + if (c == '-') { + i += 4; + sub = s.substring(i, i + 3); + eval = getDayOfWeekNumber(sub); + if (eval < 0) { + throw new ParseException( + "Invalid Day-of-Week value: '" + sub + + "'", i); + } + } else if (c == '#') { + try { + i += 4; + nthdayOfWeek = Integer.parseInt(s.substring(i)); + if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { + throw new Exception(); + } + } catch (Exception e) { + throw new ParseException( + "A numeric value between 1 and 5 must follow the '#' option", + i); + } + } else if (c == 'L') { + lastdayOfWeek = true; + i++; + } + } + + } else { + throw new ParseException( + "Illegal characters for this position: '" + sub + "'", + i); + } + if (eval != -1) { + incr = 1; + } + addToSet(sval, eval, incr, type); + return (i + 3); + } + + if (c == '?') { + i++; + if ((i + 1) < s.length() + && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) { + throw new ParseException("Illegal character after '?': " + + s.charAt(i), i); + } + if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) { + throw new ParseException( + "'?' can only be specified for Day-of-Month or Day-of-Week.", + i); + } + if (type == DAY_OF_WEEK && !lastdayOfMonth) { + int val = daysOfMonth.last(); + if (val == NO_SPEC_INT) { + throw new ParseException( + "'?' can only be specified for Day-of-Month -OR- Day-of-Week.", + i); + } + } + + addToSet(NO_SPEC_INT, -1, 0, type); + return i; + } + + if (c == '*' || c == '/') { + if (c == '*' && (i + 1) >= s.length()) { + addToSet(ALL_SPEC_INT, -1, incr, type); + return i + 1; + } else if (c == '/' + && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s + .charAt(i + 1) == '\t')) { + throw new ParseException("'/' must be followed by an integer.", i); + } else if (c == '*') { + i++; + } + c = s.charAt(i); + if (c == '/') { // is an increment specified? + i++; + if (i >= s.length()) { + throw new ParseException("Unexpected end of string.", i); + } + + incr = getNumericValue(s, i); + + i++; + if (incr > 10) { + i++; + } + checkIncrementRange(incr, type, i); + } else { + incr = 1; + } + + addToSet(ALL_SPEC_INT, -1, incr, type); + return i; + } else if (c == 'L') { + i++; + if (type == DAY_OF_MONTH) { + lastdayOfMonth = true; + } + if (type == DAY_OF_WEEK) { + addToSet(7, 7, 0, type); + } + if(type == DAY_OF_MONTH && s.length() > i) { + c = s.charAt(i); + if(c == '-') { + ValueSet vs = getValue(0, s, i+1); + lastdayOffset = vs.value; + if(lastdayOffset > 30) + throw new ParseException("Offset from last day must be <= 30", i+1); + i = vs.pos; + } + if(s.length() > i) { + c = s.charAt(i); + if(c == 'W') { + nearestWeekday = true; + i++; + } + } + } + return i; + } else if (c >= '0' && c <= '9') { + int val = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + addToSet(val, -1, -1, type); + } else { + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(val, s, i); + val = vs.value; + i = vs.pos; + } + i = checkNext(i, s, val, type); + return i; + } + } else { + throw new ParseException("Unexpected character: " + c, i); + } + + return i; + } + + private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException { + if (incr > 59 && (type == SECOND || type == MINUTE)) { + throw new ParseException("Increment > 60 : " + incr, idxPos); + } else if (incr > 23 && (type == HOUR)) { + throw new ParseException("Increment > 24 : " + incr, idxPos); + } else if (incr > 31 && (type == DAY_OF_MONTH)) { + throw new ParseException("Increment > 31 : " + incr, idxPos); + } else if (incr > 7 && (type == DAY_OF_WEEK)) { + throw new ParseException("Increment > 7 : " + incr, idxPos); + } else if (incr > 12 && (type == MONTH)) { + throw new ParseException("Increment > 12 : " + incr, idxPos); + } + } + + protected int checkNext(int pos, String s, int val, int type) + throws ParseException { + + int end = -1; + int i = pos; + + if (i >= s.length()) { + addToSet(val, end, -1, type); + return i; + } + + char c = s.charAt(pos); + + if (c == 'L') { + if (type == DAY_OF_WEEK) { + if(val < 1 || val > 7) + throw new ParseException("Day-of-Week values must be between 1 and 7", -1); + lastdayOfWeek = true; + } else { + throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i); + } + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == 'W') { + if (type == DAY_OF_MONTH) { + nearestWeekday = true; + } else { + throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i); + } + if(val > 31) + throw new ParseException("The 'W' option does not make sense with values larger than 31 (max number of days in a month)", i); + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == '#') { + if (type != DAY_OF_WEEK) { + throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i); + } + i++; + try { + nthdayOfWeek = Integer.parseInt(s.substring(i)); + if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { + throw new Exception(); + } + } catch (Exception e) { + throw new ParseException( + "A numeric value between 1 and 5 must follow the '#' option", + i); + } + + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == '-') { + i++; + c = s.charAt(i); + int v = Integer.parseInt(String.valueOf(c)); + end = v; + i++; + if (i >= s.length()) { + addToSet(val, end, 1, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v, s, i); + end = vs.value; + i = vs.pos; + } + if (i < s.length() && ((c = s.charAt(i)) == '/')) { + i++; + c = s.charAt(i); + int v2 = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + addToSet(val, end, v2, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v2, s, i); + int v3 = vs.value; + addToSet(val, end, v3, type); + i = vs.pos; + return i; + } else { + addToSet(val, end, v2, type); + return i; + } + } else { + addToSet(val, end, 1, type); + return i; + } + } + + if (c == '/') { + if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t') { + throw new ParseException("'/' must be followed by an integer.", i); + } + + i++; + c = s.charAt(i); + int v2 = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + checkIncrementRange(v2, type, i); + addToSet(val, end, v2, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v2, s, i); + int v3 = vs.value; + checkIncrementRange(v3, type, i); + addToSet(val, end, v3, type); + i = vs.pos; + return i; + } else { + throw new ParseException("Unexpected character '" + c + "' after '/'", i); + } + } + + addToSet(val, end, 0, type); + i++; + return i; + } + + public String getCronExpression() { + return cronExpression; + } + + public String getExpressionSummary() { + StringBuilder buf = new StringBuilder(); + + buf.append("seconds: "); + buf.append(getExpressionSetSummary(seconds)); + buf.append("\n"); + buf.append("minutes: "); + buf.append(getExpressionSetSummary(minutes)); + buf.append("\n"); + buf.append("hours: "); + buf.append(getExpressionSetSummary(hours)); + buf.append("\n"); + buf.append("daysOfMonth: "); + buf.append(getExpressionSetSummary(daysOfMonth)); + buf.append("\n"); + buf.append("months: "); + buf.append(getExpressionSetSummary(months)); + buf.append("\n"); + buf.append("daysOfWeek: "); + buf.append(getExpressionSetSummary(daysOfWeek)); + buf.append("\n"); + buf.append("lastdayOfWeek: "); + buf.append(lastdayOfWeek); + buf.append("\n"); + buf.append("nearestWeekday: "); + buf.append(nearestWeekday); + buf.append("\n"); + buf.append("NthDayOfWeek: "); + buf.append(nthdayOfWeek); + buf.append("\n"); + buf.append("lastdayOfMonth: "); + buf.append(lastdayOfMonth); + buf.append("\n"); + buf.append("years: "); + buf.append(getExpressionSetSummary(years)); + buf.append("\n"); + + return buf.toString(); + } + + protected String getExpressionSetSummary(Set set) { + + if (set.contains(NO_SPEC)) { + return "?"; + } + if (set.contains(ALL_SPEC)) { + return "*"; + } + + StringBuilder buf = new StringBuilder(); + + Iterator itr = set.iterator(); + boolean first = true; + while (itr.hasNext()) { + Integer iVal = itr.next(); + String val = iVal.toString(); + if (!first) { + buf.append(","); + } + buf.append(val); + first = false; + } + + return buf.toString(); + } + + protected String getExpressionSetSummary(ArrayList list) { + + if (list.contains(NO_SPEC)) { + return "?"; + } + if (list.contains(ALL_SPEC)) { + return "*"; + } + + StringBuilder buf = new StringBuilder(); + + Iterator itr = list.iterator(); + boolean first = true; + while (itr.hasNext()) { + Integer iVal = itr.next(); + String val = iVal.toString(); + if (!first) { + buf.append(","); + } + buf.append(val); + first = false; + } + + return buf.toString(); + } + + protected int skipWhiteSpace(int i, String s) { + for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) { + ; + } + + return i; + } + + protected int findNextWhiteSpace(int i, String s) { + for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) { + ; + } + + return i; + } + + protected void addToSet(int val, int end, int incr, int type) + throws ParseException { + + TreeSet set = getSet(type); + + if (type == SECOND || type == MINUTE) { + if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Minute and Second values must be between 0 and 59", + -1); + } + } else if (type == HOUR) { + if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Hour values must be between 0 and 23", -1); + } + } else if (type == DAY_OF_MONTH) { + if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day of month values must be between 1 and 31", -1); + } + } else if (type == MONTH) { + if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Month values must be between 1 and 12", -1); + } + } else if (type == DAY_OF_WEEK) { + if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day-of-Week values must be between 1 and 7", -1); + } + } + + if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) { + if (val != -1) { + set.add(val); + } else { + set.add(NO_SPEC); + } + + return; + } + + int startAt = val; + int stopAt = end; + + if (val == ALL_SPEC_INT && incr <= 0) { + incr = 1; + set.add(ALL_SPEC); // put in a marker, but also fill values + } + + if (type == SECOND || type == MINUTE) { + if (stopAt == -1) { + stopAt = 59; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } + } else if (type == HOUR) { + if (stopAt == -1) { + stopAt = 23; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } + } else if (type == DAY_OF_MONTH) { + if (stopAt == -1) { + stopAt = 31; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == MONTH) { + if (stopAt == -1) { + stopAt = 12; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == DAY_OF_WEEK) { + if (stopAt == -1) { + stopAt = 7; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == YEAR) { + if (stopAt == -1) { + stopAt = MAX_YEAR; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1970; + } + } + + // if the end of the range is before the start, then we need to overflow into + // the next day, month etc. This is done by adding the maximum amount for that + // type, and using modulus max to determine the value being added. + int max = -1; + if (stopAt < startAt) { + switch (type) { + case SECOND : max = 60; break; + case MINUTE : max = 60; break; + case HOUR : max = 24; break; + case MONTH : max = 12; break; + case DAY_OF_WEEK : max = 7; break; + case DAY_OF_MONTH : max = 31; break; + case YEAR : throw new IllegalArgumentException("Start year must be less than stop year"); + default : throw new IllegalArgumentException("Unexpected type encountered"); + } + stopAt += max; + } + + for (int i = startAt; i <= stopAt; i += incr) { + if (max == -1) { + // ie: there's no max to overflow over + set.add(i); + } else { + // take the modulus to get the real value + int i2 = i % max; + + // 1-indexed ranges should not include 0, and should include their max + if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) { + i2 = max; + } + + set.add(i2); + } + } + } + + TreeSet getSet(int type) { + switch (type) { + case SECOND: + return seconds; + case MINUTE: + return minutes; + case HOUR: + return hours; + case DAY_OF_MONTH: + return daysOfMonth; + case MONTH: + return months; + case DAY_OF_WEEK: + return daysOfWeek; + case YEAR: + return years; + default: + return null; + } + } + + protected ValueSet getValue(int v, String s, int i) { + char c = s.charAt(i); + StringBuilder s1 = new StringBuilder(String.valueOf(v)); + while (c >= '0' && c <= '9') { + s1.append(c); + i++; + if (i >= s.length()) { + break; + } + c = s.charAt(i); + } + ValueSet val = new ValueSet(); + + val.pos = (i < s.length()) ? i : i + 1; + val.value = Integer.parseInt(s1.toString()); + return val; + } + + protected int getNumericValue(String s, int i) { + int endOfVal = findNextWhiteSpace(i, s); + String val = s.substring(i, endOfVal); + return Integer.parseInt(val); + } + + protected int getMonthNumber(String s) { + Integer integer = monthMap.get(s); + + if (integer == null) { + return -1; + } + + return integer; + } + + protected int getDayOfWeekNumber(String s) { + Integer integer = dayMap.get(s); + + if (integer == null) { + return -1; + } + + return integer; + } + + //////////////////////////////////////////////////////////////////////////// + // + // Computation Functions + // + //////////////////////////////////////////////////////////////////////////// + + public Date getTimeAfter(Date afterTime) { + + // Computation is based on Gregorian year only. + Calendar cl = new GregorianCalendar(getTimeZone()); + + // move ahead one second, since we're computing the time *after* the + // given time + afterTime = new Date(afterTime.getTime() + 1000); + // CronTrigger does not deal with milliseconds + cl.setTime(afterTime); + cl.set(Calendar.MILLISECOND, 0); + + boolean gotOne = false; + // loop until we've computed the next time, or we've past the endTime + while (!gotOne) { + + //if (endTime != null && cl.getTime().after(endTime)) return null; + if(cl.get(Calendar.YEAR) > 2999) { // prevent endless loop... + return null; + } + + SortedSet st = null; + int t = 0; + + int sec = cl.get(Calendar.SECOND); + int min = cl.get(Calendar.MINUTE); + + // get second................................................. + st = seconds.tailSet(sec); + if (st != null && st.size() != 0) { + sec = st.first(); + } else { + sec = seconds.first(); + min++; + cl.set(Calendar.MINUTE, min); + } + cl.set(Calendar.SECOND, sec); + + min = cl.get(Calendar.MINUTE); + int hr = cl.get(Calendar.HOUR_OF_DAY); + t = -1; + + // get minute................................................. + st = minutes.tailSet(min); + if (st != null && st.size() != 0) { + t = min; + min = st.first(); + } else { + min = minutes.first(); + hr++; + } + if (min != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, min); + setCalendarHour(cl, hr); + continue; + } + cl.set(Calendar.MINUTE, min); + + hr = cl.get(Calendar.HOUR_OF_DAY); + int day = cl.get(Calendar.DAY_OF_MONTH); + t = -1; + + // get hour................................................... + st = hours.tailSet(hr); + if (st != null && st.size() != 0) { + t = hr; + hr = st.first(); + } else { + hr = hours.first(); + day++; + } + if (hr != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + setCalendarHour(cl, hr); + continue; + } + cl.set(Calendar.HOUR_OF_DAY, hr); + + day = cl.get(Calendar.DAY_OF_MONTH); + int mon = cl.get(Calendar.MONTH) + 1; + // '+ 1' because calendar is 0-based for this field, and we are + // 1-based + t = -1; + int tmon = mon; + + // get day................................................... + boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC); + boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC); + if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule + st = daysOfMonth.tailSet(day); + if (lastdayOfMonth) { + if(!nearestWeekday) { + t = day; + day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + day -= lastdayOffset; + if(t > day) { + mon++; + if(mon > 12) { + mon = 1; + tmon = 3333; // ensure test of mon != tmon further below fails + cl.add(Calendar.YEAR, 1); + } + day = 1; + } + } else { + t = day; + day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + day -= lastdayOffset; + + Calendar tcal = Calendar.getInstance(getTimeZone()); + tcal.set(Calendar.SECOND, 0); + tcal.set(Calendar.MINUTE, 0); + tcal.set(Calendar.HOUR_OF_DAY, 0); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); + + int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + int dow = tcal.get(Calendar.DAY_OF_WEEK); + + if(dow == Calendar.SATURDAY && day == 1) { + day += 2; + } else if(dow == Calendar.SATURDAY) { + day -= 1; + } else if(dow == Calendar.SUNDAY && day == ldom) { + day -= 2; + } else if(dow == Calendar.SUNDAY) { + day += 1; + } + + tcal.set(Calendar.SECOND, sec); + tcal.set(Calendar.MINUTE, min); + tcal.set(Calendar.HOUR_OF_DAY, hr); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + Date nTime = tcal.getTime(); + if(nTime.before(afterTime)) { + day = 1; + mon++; + } + } + } else if(nearestWeekday) { + t = day; + day = daysOfMonth.first(); + + Calendar tcal = Calendar.getInstance(getTimeZone()); + tcal.set(Calendar.SECOND, 0); + tcal.set(Calendar.MINUTE, 0); + tcal.set(Calendar.HOUR_OF_DAY, 0); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); + + int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + int dow = tcal.get(Calendar.DAY_OF_WEEK); + + if(dow == Calendar.SATURDAY && day == 1) { + day += 2; + } else if(dow == Calendar.SATURDAY) { + day -= 1; + } else if(dow == Calendar.SUNDAY && day == ldom) { + day -= 2; + } else if(dow == Calendar.SUNDAY) { + day += 1; + } + + + tcal.set(Calendar.SECOND, sec); + tcal.set(Calendar.MINUTE, min); + tcal.set(Calendar.HOUR_OF_DAY, hr); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + Date nTime = tcal.getTime(); + if(nTime.before(afterTime)) { + day = daysOfMonth.first(); + mon++; + } + } else if (st != null && st.size() != 0) { + t = day; + day = st.first(); + // make sure we don't over-run a short month, such as february + int lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + if (day > lastDay) { + day = daysOfMonth.first(); + mon++; + } + } else { + day = daysOfMonth.first(); + mon++; + } + + if (day != t || mon != tmon) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we + // are 1-based + continue; + } + } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule + if (lastdayOfWeek) { // are we looking for the last XXX day of + // the month? + int dow = daysOfWeek.first(); // desired + // d-o-w + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + + if (day + daysToAdd > lDay) { // did we already miss the + // last one? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } + + // find date of last occurrence of this day in this month... + while ((day + daysToAdd + 7) <= lDay) { + daysToAdd += 7; + } + + day += daysToAdd; + + if (daysToAdd > 0) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' here because we are not promoting the month + continue; + } + + } else if (nthdayOfWeek != 0) { + // are we looking for the Nth XXX day in the month? + int dow = daysOfWeek.first(); // desired + // d-o-w + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } else if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + boolean dayShifted = false; + if (daysToAdd > 0) { + dayShifted = true; + } + + day += daysToAdd; + int weekOfMonth = day / 7; + if (day % 7 > 0) { + weekOfMonth++; + } + + daysToAdd = (nthdayOfWeek - weekOfMonth) * 7; + day += daysToAdd; + if (daysToAdd < 0 + || day > getLastDayOfMonth(mon, cl + .get(Calendar.YEAR))) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } else if (daysToAdd > 0 || dayShifted) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' here because we are NOT promoting the month + continue; + } + } else { + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int dow = daysOfWeek.first(); // desired + // d-o-w + st = daysOfWeek.tailSet(cDow); + if (st != null && st.size() > 0) { + dow = st.first(); + } + + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + + if (day + daysToAdd > lDay) { // will we pass the end of + // the month? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } else if (daysToAdd > 0) { // are we swithing days? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, + // and we are 1-based + continue; + } + } + } else { // dayOfWSpec && !dayOfMSpec + throw new UnsupportedOperationException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."); + } + cl.set(Calendar.DAY_OF_MONTH, day); + + mon = cl.get(Calendar.MONTH) + 1; + // '+ 1' because calendar is 0-based for this field, and we are + // 1-based + int year = cl.get(Calendar.YEAR); + t = -1; + + // test for expressions that never generate a valid fire date, + // but keep looping... + if (year > MAX_YEAR) { + return null; + } + + // get month................................................... + st = months.tailSet(mon); + if (st != null && st.size() != 0) { + t = mon; + mon = st.first(); + } else { + mon = months.first(); + year++; + } + if (mon != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + cl.set(Calendar.YEAR, year); + continue; + } + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + + year = cl.get(Calendar.YEAR); + t = -1; + + // get year................................................... + st = years.tailSet(year); + if (st != null && st.size() != 0) { + t = year; + year = st.first(); + } else { + return null; // ran out of years... + } + + if (year != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, 0); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + cl.set(Calendar.YEAR, year); + continue; + } + cl.set(Calendar.YEAR, year); + + gotOne = true; + } // while( !done ) + + return cl.getTime(); + } + + /** + * Advance the calendar to the particular hour paying particular attention + * to daylight saving problems. + * + * @param cal the calendar to operate on + * @param hour the hour to set + */ + protected void setCalendarHour(Calendar cal, int hour) { + cal.set(Calendar.HOUR_OF_DAY, hour); + if (cal.get(Calendar.HOUR_OF_DAY) != hour && hour != 24) { + cal.set(Calendar.HOUR_OF_DAY, hour + 1); + } + } + + /** + * NOT YET IMPLEMENTED: Returns the time before the given time + * that the CronExpression matches. + */ + public Date getTimeBefore(Date endTime) { + // FUTURE_TODO: implement QUARTZ-423 + return null; + } + + /** + * NOT YET IMPLEMENTED: Returns the final time that the + * CronExpression will match. + */ + public Date getFinalFireTime() { + // FUTURE_TODO: implement QUARTZ-423 + return null; + } + + protected boolean isLeapYear(int year) { + return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)); + } + + protected int getLastDayOfMonth(int monthNum, int year) { + + switch (monthNum) { + case 1: + return 31; + case 2: + return (isLeapYear(year)) ? 29 : 28; + case 3: + return 31; + case 4: + return 30; + case 5: + return 31; + case 6: + return 30; + case 7: + return 31; + case 8: + return 31; + case 9: + return 30; + case 10: + return 31; + case 11: + return 30; + case 12: + return 31; + default: + throw new IllegalArgumentException("Illegal month number: " + + monthNum); + } + } + + + private void readObject(java.io.ObjectInputStream stream) + throws java.io.IOException, ClassNotFoundException { + + stream.defaultReadObject(); + try { + buildExpression(cronExpression); + } catch (Exception ignore) { + } // never happens + } + +} + +class ValueSet { + public int value; + + public int pos; +} + diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/ResourceUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/ResourceUtils.java new file mode 100644 index 000000000..faa2d3f1c --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/ResourceUtils.java @@ -0,0 +1,23 @@ +package com.newrelic.agent.security.intcodeagent.utils; + +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.Agent; +import com.newrelic.api.agent.security.utils.logging.LogLevel; + +import java.io.InputStream; +import java.net.URL; + +public class ResourceUtils { + + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + public static InputStream getResourceStreamFromAgentJar(String resourceName) { + try { + return new URL("jar:" + Agent.getAgentJarURL().toExternalForm() + "!/" + resourceName).openStream(); + } catch (Exception e) { + logger.log(LogLevel.SEVERE, String.format("Unable to locate resource from agent jar : %s", e.getMessage()), CommonUtils.class.getName()); + logger.log(LogLevel.FINER, "Unable to locate resource from agent jar : ", e, CommonUtils.class.getName()); + } + return null; + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/RestrictionUtility.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/RestrictionUtility.java new file mode 100644 index 000000000..b53d39ced --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/RestrictionUtility.java @@ -0,0 +1,394 @@ +package com.newrelic.agent.security.intcodeagent.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.newrelic.agent.security.intcodeagent.exceptions.RestrictionModeException; +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.policy.RestrictionCriteria; +import com.newrelic.api.agent.security.schema.policy.SkipScan; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.StringReader; +import java.util.*; +import java.util.regex.Pattern; + +public class RestrictionUtility { + + public static final String SEPARATOR_CHARS_QUESTION_MARK = "?"; + public static final String SEPARATOR_CHARS_SEMICOLON = ";"; + public static final String FORWARD_SLASH = "/"; + public static final String AND = "&"; + public static final String SEPARATOR_EQUALS = "="; + public static final String EQUAL = "="; + public static final String CONTENT_TYPE_TEXT_JSON = "text/json"; + public static final String CONTENT_TYPE_TEXT_XML = "text/xml"; + public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json"; + public static final String CONTENT_TYPE_APPLICATION_XML = "application/xml"; + public static final String CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; + + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + public static boolean skippedApiDetected(SkipScan skipScan, HttpRequest httpRequest) { + if (skipScan == null) { + return false; + } + if (httpRequest == null) { + return false; + } + + if(skipScan.getApiRoutes().isEmpty()) { + return false; + } + + for (Pattern pattern : skipScan.getApiRoutes()) { + if (pattern.matcher(httpRequest.getUrl()).matches()) { + return true; + } + } + + return false; + } + + public static boolean hasValidAccountId(RestrictionCriteria restrictionCriteria, HttpRequest request) { + List accountIds = restrictionCriteria.getAccountInfo().getAccountIds(); + if (request == null) { + return false; + } + if(!request.isRequestParametersParsed()){ + parseHttpRequestParameters(request); + } + + if(restrictionCriteria.getMappingParameters().getHeader().isEnabled()) { + List headerValues = getHeaderParameters(restrictionCriteria.getMappingParameters().getHeader().getLocations(), request.getRequestHeaderParameters()); + if(matcher(accountIds, headerValues)){ + return true; + } + } + if(restrictionCriteria.getMappingParameters().getQuery().isEnabled()) { + List queryValues = getQueryString(restrictionCriteria.getMappingParameters().getHeader().getLocations(), request.getQueryParameters()); + if(matcher(accountIds, queryValues)){ + return true; + } + } + if(restrictionCriteria.getMappingParameters().getPath().isEnabled()) { + if(matcher(accountIds, request.getPathParameters())){ + return true; + } + } + if(restrictionCriteria.getMappingParameters().getBody().isEnabled()) { + List bodyValues = getBodyParameters(restrictionCriteria.getMappingParameters().getBody().getLocations(), request.getRequestBodyParameters()); + return matcher(accountIds, bodyValues); + } + + return false; + } + + private static List getBodyParameters(List accountIds, Map> requestBodyParameters) { + if (requestBodyParameters == null || requestBodyParameters.isEmpty()) { + return Collections.emptyList(); + } + + List values = new ArrayList<>(); + for (String accountId : accountIds) { + String lowerCaseAccountId = accountId.toLowerCase(); + if(requestBodyParameters.containsKey(lowerCaseAccountId)) { + values.addAll(requestBodyParameters.get(lowerCaseAccountId)); + } + } + + return values; + } + + private static List getHeaderParameters(List accountIds, Map> requestHeaderParameters) { + if (requestHeaderParameters == null || requestHeaderParameters.isEmpty()) { + return Collections.emptyList(); + } + List values = new ArrayList<>(); + for (String accountId : accountIds) { + String lowerCaseAccountId = accountId.toLowerCase(); + if(requestHeaderParameters.containsKey(lowerCaseAccountId)) { + values.addAll(requestHeaderParameters.get(lowerCaseAccountId)); + } + } + return values; + } + + private static List getQueryString(List accountIds, Map> queryParameters) { + if(queryParameters == null || queryParameters.isEmpty()) { + return Collections.emptyList(); + } + List values = new ArrayList<>(); + for (String accountId : accountIds) { + String lowerCaseAccountId = accountId.toLowerCase(); + if(queryParameters.containsKey(lowerCaseAccountId)) { + values.addAll(queryParameters.get(lowerCaseAccountId)); + } + } + return values; + } + + private static boolean matcher(List accountIds, List values) { + for (String accountId : accountIds) { + if(values == null || values.isEmpty() || StringUtils.isBlank(accountId)) { + continue; + } + String lowerCaseAccountId = accountId.toLowerCase(); + boolean contains = values.contains(lowerCaseAccountId); + if(contains){ + return true; + } + } + return false; + } + + private static void parseHttpRequestParameters(HttpRequest request) { + request.setPathParameters(parsePathParameters(StringUtils.substringBefore(request.getUrl(), + SEPARATOR_CHARS_QUESTION_MARK))); + request.setQueryParameters(parseQueryParameters(request.getUrl())); + request.setRequestHeaderParameters(parseRequestHeaders(request.getHeaders())); + try { + request.setRequestBodyParameters(parseRequestBody(request.getBody(), request.getContentType(), request.getRequestBodyParameters())); + } catch (RestrictionModeException e) { + logger.log(LogLevel.WARNING, String.format("Request Body parsing failed reason %s", e.getMessage()), RestrictionUtility.class.getName()); + } + request.setRequestBodyParameters(parseRequestParameterMap(request.getParameterMap(), request.getRequestBodyParameters())); + request.setRequestParsed(true); + } + + private static Map> parseRequestParameterMap(Map parameterMap, Map> requestBodyParameters) { + if(parameterMap == null) { + return requestBodyParameters; + } + if(requestBodyParameters == null) { + requestBodyParameters = new HashMap<>(); + } + + for (Map.Entry entry : parameterMap.entrySet()) { + String key = entry.getKey(); + String[] values = entry.getValue(); + List valuesList = new ArrayList<>(); + for (String value : values) { + valuesList.add(StringUtils.lowerCase(value)); + } + if(requestBodyParameters.containsKey(key)){ + requestBodyParameters.get(key).addAll(valuesList); + } else { + requestBodyParameters.put(key, valuesList); + } + } + return requestBodyParameters; + } + + private static Map> parseRequestBody(StringBuilder body, String contentType, Map> requestBodyParameters) throws RestrictionModeException { + if(StringUtils.isBlank(body.toString())) { + return requestBodyParameters; + } + + if(requestBodyParameters == null) { + requestBodyParameters = new HashMap<>(); + } + + switch (contentType) { + case CONTENT_TYPE_APPLICATION_JSON: + case CONTENT_TYPE_TEXT_JSON: + requestBodyParameters.putAll(parseJsonRequestBody(body.toString())); + break; + case CONTENT_TYPE_APPLICATION_XML: + case CONTENT_TYPE_TEXT_XML: + requestBodyParameters.putAll(parseXmlRequestBody(body.toString())); + break; + case CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED: + requestBodyParameters.putAll(queryParamKeyValueGenerator(body.toString(),new HashMap<>())); + break; + default: + break; + } + return requestBodyParameters; + + } + + private static Map> parseXmlRequestBody(String body) throws RestrictionModeException { + //write logic to xml parsing + Map> requestBodyParameters = new HashMap<>(); + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(new InputSource(new StringReader(body))); + document.getDocumentElement().normalize(); + Element root = document.getDocumentElement(); + parseXmlNode(root, StringUtils.EMPTY, requestBodyParameters); + } catch (Exception e) { + logger.log(LogLevel.FINER, String.format("JSON Request Body parsing failed for %s : reason %s", body, e.getMessage()), RestrictionUtility.class.getName()); + throw new RestrictionModeException(String.format("XML Request Body parsing failed : reason %s", e.getMessage()), e); + } + return requestBodyParameters; + } + + private static void parseXmlNode(Node node, String baseKey, Map> requestBodyParameters) { + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + NodeList children = element.getChildNodes(); + String key = baseKey.isEmpty() ? element.getTagName() : baseKey + "." + element.getTagName(); + if (children.getLength() == 1 && children.item(0).getNodeType() == Node.TEXT_NODE) { + String value = children.item(0).getTextContent().trim(); + if (!value.isEmpty()) { + requestBodyParameters.computeIfAbsent(key, k -> new ArrayList<>()).add(value); + } + } else { + for (int i = 0; i < children.getLength(); i++) { + parseXmlNode(children.item(i), key, requestBodyParameters); + } + } + } + } + + private static Map> parseJsonRequestBody(String body) throws RestrictionModeException { + JsonNode node; + ObjectMapper mapper = new ObjectMapper(); + try { + node = mapper.readValue(body, JsonNode.class); + Map> requestBodyParameters = new HashMap<>(); + return parseJsonNode(node, StringUtils.EMPTY, requestBodyParameters); + } catch (JsonProcessingException e) { + logger.log(LogLevel.FINER, String.format("JSON Request Body parsing failed for %s : reason %s", body, e.getMessage()), RestrictionUtility.class.getName()); + throw new RestrictionModeException(String.format("JSON Request Body parsing failed : reason %s", e.getMessage())+ e.getMessage(), e); + } + } + + private static Map> parseJsonNode(JsonNode node, String baseKey, Map> requestBodyParameters) { + if (node.isObject()) { + Iterator> iterator = node.fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String key = entry.getKey(); + String base = getBase(baseKey, key); + JsonNode value = entry.getValue(); + if(value.isContainerNode()){ + parseJsonNode(value, base, requestBodyParameters); + } else if (StringUtils.isNotBlank(value.asText())) { + if(!requestBodyParameters.containsKey(base)){ + requestBodyParameters.put(base, new ArrayList<>()); + } + requestBodyParameters.get(base).add(value.asText()); + } + } + } else if (node.isArray()) { + ArrayNode arrayNode = (ArrayNode) node; + for (int i = 0; i < arrayNode.size(); i++) { + JsonNode jsonNode = arrayNode.get(i); + String base = getBase(baseKey, i); + if(jsonNode.isContainerNode()){ + parseJsonNode(jsonNode, base, requestBodyParameters); + } else if (StringUtils.isNotBlank(jsonNode.asText())) { + if(!requestBodyParameters.containsKey(base)){ + requestBodyParameters.put(base, new ArrayList<>()); + } + requestBodyParameters.get(base).add(jsonNode.asText()); + } + } + } + return requestBodyParameters; + } + + private static @NotNull String getBase(String baseKey, String key) { + if(StringUtils.isBlank(baseKey)){ + return key; + } + return baseKey + "." + key; + } + + private static @NotNull String getBase(String baseKey, int index) { + if(StringUtils.isBlank(baseKey)){ + return "[]"; + } + return String.format("%s[]", baseKey); + } + + private static Map> parseRequestHeaders(Map headers) { + Map> requestHeaderParameters = new HashMap<>(); + for (Map.Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + putHeaderParameter(key, value, requestHeaderParameters); + if (StringUtils.containsAny(value, SEPARATOR_CHARS_SEMICOLON, EQUAL)) { + String[] headerKeyValues = value.split(SEPARATOR_CHARS_SEMICOLON); + for (int i = 0; i < headerKeyValues.length; i++) { + if (StringUtils.contains(headerKeyValues[i], EQUAL) + && !StringUtils.endsWith(headerKeyValues[i], EQUAL)) { + String headerKey = StringUtils.substringBefore(headerKeyValues[i], EQUAL).trim(); + String headerValue = StringUtils.substringAfter(headerKeyValues[i], EQUAL).trim(); + putHeaderParameter(headerKey, headerValue, requestHeaderParameters); + } else { + putHeaderParameter(key, headerKeyValues[i], requestHeaderParameters); + } + } + } + } + return requestHeaderParameters; + } + + private static void putHeaderParameter(String key, String value, Map> requestHeaderParameters) { + List headerValues = requestHeaderParameters.get(key); + if (headerValues == null) { + headerValues = new ArrayList<>(); + } + headerValues.add(StringUtils.lowerCase(value)); + headerValues.add(StringUtils.lowerCase(ServletHelper.urlDecode(value))); + requestHeaderParameters.put(StringUtils.lowerCase(key), headerValues); + } + + private static Map> parseQueryParameters(String url) { + Map> queryParameters = new HashMap<>(); + String query = StringUtils.substringAfter(url, SEPARATOR_CHARS_QUESTION_MARK); + if (StringUtils.isNotBlank(query)) { + queryParamKeyValueGenerator(query, queryParameters); + } else { + query = StringUtils.substringAfter(url, SEPARATOR_CHARS_SEMICOLON); + if (StringUtils.isNotBlank(query)) { + queryParamKeyValueGenerator(query, queryParameters); + } + } + return queryParameters; + } + + private static Map> queryParamKeyValueGenerator(String query, Map> queryParameters) { + String[] queryParams = StringUtils.split(query, AND); + for (String queryParam : queryParams) { + String key, value; + key = StringUtils.substringBefore(queryParam, SEPARATOR_EQUALS); + value = StringUtils.substringAfter(queryParam, SEPARATOR_EQUALS); + List values = new ArrayList<>(); + values.add(StringUtils.lowerCase(value)); + values.add(StringUtils.lowerCase(ServletHelper.urlDecode(value))); + queryParameters.put(StringUtils.lowerCase(key), values); + } + return queryParameters; + } + + private static List parsePathParameters(String uri) { + List pathParameters = new ArrayList<>(); + String requestPath = StringUtils.substringBefore(uri, + SEPARATOR_CHARS_SEMICOLON); + if(StringUtils.isNotBlank(requestPath)) { + String[] pathVariables = StringUtils.split(requestPath, FORWARD_SLASH); + for (String pathVariable : pathVariables) { + pathParameters.add(StringUtils.lowerCase(pathVariable)); + pathParameters.add(StringUtils.lowerCase(ServletHelper.urlDecode(pathVariable))); + } + } + return pathParameters; + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSendPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSendPool.java index d940d5844..3da76083b 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSendPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSendPool.java @@ -1,6 +1,7 @@ package com.newrelic.agent.security.intcodeagent.websocket; import com.newrelic.agent.security.AgentInfo; +import com.newrelic.agent.security.instrumentator.dispatcher.Dispatcher; import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool; import com.newrelic.agent.security.intcodeagent.executor.CustomFutureTask; import com.newrelic.agent.security.intcodeagent.executor.CustomThreadPoolExecutor; @@ -26,8 +27,6 @@ public class EventSendPool { private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); - private AtomicBoolean isWaiting = new AtomicBoolean(false); - private EventSendPool() { // load the settings int queueSize = QUEUE_SIZE; @@ -44,13 +43,21 @@ private EventSendPool() { @Override protected void afterExecute(Runnable r, Throwable t) { try { - if (t != null) { - AgentInfo.getInstance().getJaHealthCheck().incrementDropCount(); - AgentInfo.getInstance().getJaHealthCheck().incrementEventSendErrorCount(); - incrementCount(r, IUtilConstants.ERROR); - } else { - incrementCount(r, IUtilConstants.SENT); + if (r instanceof CustomFutureTask && ((CustomFutureTask) r).getTask() instanceof EventSender) { + EventSender task = (EventSender) ((CustomFutureTask) r).getTask(); + if(task.getEvent() instanceof JavaAgentEventBean){ + if (t != null) { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getEventSender().incrementError(); + } else { + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getEventSender().incrementCompleted(); + } + } } +// if (t != null) { +// AgentInfo.getInstance().getJaHealthCheck().getEventStats().getEventSender().incrementError(); +// } else { +// AgentInfo.getInstance().getJaHealthCheck().getEventStats().getEventSender().incrementCompleted(); +// } } catch (Throwable ignored){} super.afterExecute(r, t); } @@ -86,13 +93,13 @@ public void sendEvent(String event) { } public void sendEvent(JavaAgentEventBean event) { + if(!event.getIsIASTRequest() && !AgentUsageMetric.isRASPProcessingActive()){ - AgentInfo.getInstance().getJaHealthCheck().getRaspEventStats().incrementRejectedCount(); - AgentInfo.getInstance().getJaHealthCheck().incrementEventSendRejectionCount(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementRaspProcessingDeactivated(); return; } executor.submit(new EventSender(event)); - AgentInfo.getInstance().getJaHealthCheck().incrementEventSentCount(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getEventSender().incrementSubmitted(); } public void sendEvent(Object event) { @@ -149,67 +156,21 @@ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } else { RestRequestThreadPool.getInstance().getRejectedIds().add(fuzzRequestId); } - AgentInfo.getInstance().getJaHealthCheck().getIastEventStats().incrementRejectedCount(); - } else { - AgentInfo.getInstance().getJaHealthCheck().getRaspEventStats().incrementRejectedCount(); } - } else if (eventSender.getEvent() instanceof ExitEventBean) { - AgentInfo.getInstance().getJaHealthCheck().getExitEventStats().incrementRejectedCount(); } } logger.log(LogLevel.FINER, "Event Send Task " + r.toString() + " rejected from " + e.toString(), EventSendPool.class.getName()); - AgentInfo.getInstance().getJaHealthCheck().incrementDropCount(); - AgentInfo.getInstance().getJaHealthCheck().incrementEventSendRejectionCount(); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getEventSender().incrementRejected(); } } - public AtomicBoolean isWaiting() { - return isWaiting; - } - public ThreadPoolExecutor getExecutor() { return executor; } - private void incrementCount(Runnable r, String type) { - EventStats eventStats = null; - if (r instanceof CustomFutureTask && ((CustomFutureTask) r).getTask() instanceof EventSender) { - EventSender eventSender = (EventSender) ((CustomFutureTask) r).getTask(); - if (eventSender.getEvent() instanceof JavaAgentEventBean) { - JavaAgentEventBean event = (JavaAgentEventBean) eventSender.getEvent(); - if (event.getIsIASTRequest()) { - eventStats = AgentInfo.getInstance().getJaHealthCheck().getIastEventStats(); - } else { - eventStats = AgentInfo.getInstance().getJaHealthCheck().getRaspEventStats(); - } - } else if (eventSender.getEvent() instanceof ExitEventBean) { - eventStats = AgentInfo.getInstance().getJaHealthCheck().getExitEventStats(); - } - } - - if(eventStats == null){ - return; - } - switch (type){ - case IUtilConstants.ERROR: - eventStats.incrementErrorCount(); - break; - case IUtilConstants.PROCESSED: - eventStats.incrementProcessedCount(); - break; - case IUtilConstants.SENT: - eventStats.incrementSentCount(); - break; - case IUtilConstants.REJECTED: - eventStats.incrementRejectedCount(); - break; - default: - logger.log(LogLevel.FINEST, String.format("Couldn't update event matric for task :%s and type : %s", r, type), EventSendPool.class.getName()); - } - } - public void reset() { executor.getQueue().clear(); + executor.purge(); } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSender.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSender.java index 893f5687a..889bd35e0 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSender.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/EventSender.java @@ -35,13 +35,6 @@ public EventSender(Object event) { */ @Override public Boolean call() throws Exception { - if (WSUtils.getInstance().isReconnecting()) { - synchronized (WSUtils.getInstance()) { - EventSendPool.getInstance().isWaiting().set(true); - WSUtils.getInstance().wait(); - EventSendPool.getInstance().isWaiting().set(false); - } - } if (event instanceof JavaAgentEventBean) { ((JavaAgentEventBean) event).setEventGenerationTime(System.currentTimeMillis()); } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSClient.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSClient.java index 64f1ffcfd..b274df306 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSClient.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSClient.java @@ -8,7 +8,9 @@ import com.newrelic.agent.security.instrumentator.utils.INRSettingsKey; import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessor; import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessorThreadPool; +import com.newrelic.agent.security.intcodeagent.exceptions.SecurityNoticeError; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.utils.ResourceUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.utils.CommonUtils; @@ -29,6 +31,7 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.management.ManagementFactory; import java.net.*; import java.nio.file.Files; import java.nio.file.Paths; @@ -37,9 +40,7 @@ import java.security.cert.X509Certificate; import java.time.Instant; import java.time.ZoneId; -import java.util.Collection; -import java.util.LinkedList; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; public class WSClient extends WebSocketClient { @@ -48,7 +49,7 @@ public class WSClient extends WebSocketClient { public static final String SENDING_EVENT = "sending event: "; public static final String UNABLE_TO_SEND_EVENT = "Unable to send event : "; public static final String ERROR_IN_WSOCK_CONNECTION = "Error in WSock connection : "; - public static final String CONNECTION_CLOSED_BY = "Connection closed by "; + public static final String CONNECTION_CLOSED_BY = "WS Connection closed by "; public static final String REMOTE_PEER = "remote peer."; public static final String LOCAL = "local."; public static final String CODE = " Code: "; @@ -70,6 +71,8 @@ public class WSClient extends WebSocketClient { private WebSocketImpl connection = null; + private Map noticeErrorCustomParameters = new HashMap<>(); + private SSLContext createSSLContext() throws Exception { KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -88,6 +91,7 @@ private SSLContext createSSLContext() throws Exception { } catch (Exception e) { logger.log(LogLevel.SEVERE, "Unable to generate ca certificate. Verify the certificate format. Will not process further certs.", e, WSClient.class.getName()); + NewRelic.noticeError(new SecurityNoticeError("New Relic Security Agent is unable to generate CA Certificate. Verify the certificate format. Will not process further certs.", e), noticeErrorCustomParameters, true); break; } } @@ -95,6 +99,7 @@ private SSLContext createSSLContext() throws Exception { logger.log(caCerts.size() > 0 ? LogLevel.INFO : LogLevel.SEVERE, String.format("Found %s certificates.", caCerts.size()), WSClient.class.getName()); + noticeErrorCustomParameters.put("ca_bundle_count", String.valueOf(caCerts.size())); // Initialize the keystore keystore.load(null, null); @@ -122,9 +127,11 @@ private InputStream getCaBundleStream() throws IOException { InputStream inputStream; String caBundlePath = NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_SECURITY_CA_BUNDLE_PATH); if (StringUtils.isNotBlank(caBundlePath)) { + noticeErrorCustomParameters.put("ca_bundle_path", caBundlePath); inputStream = Files.newInputStream(Paths.get(caBundlePath)); } else { - inputStream = CommonUtils.getResourceStreamFromAgentJar("nr-custom-ca.pem"); + noticeErrorCustomParameters.put("ca_bundle_path", "internal-pem"); + inputStream = ResourceUtils.getResourceStreamFromAgentJar("nr-custom-ca.pem"); } return inputStream; } @@ -147,9 +154,15 @@ private WSClient() throws URISyntaxException { this.addHeader("NR-CSEC-JSON-VERSION", AgentInfo.getInstance().getBuildInfo().getJsonVersion()); this.addHeader("NR-ACCOUNT-ID", AgentConfig.getInstance().getConfig().getCustomerInfo().getAccountId()); this.addHeader("NR-CSEC-IAST-DATA-TRANSFER-MODE", "PULL"); + this.addHeader("NR-CSEC-IGNORED-VUL-CATEGORIES", AgentConfig.getInstance().getAgentMode().getSkipScan().getIastDetectionCategory().getDisabledCategoriesCSV()); + this.addHeader("NR-CSEC-PROCESS-START-TIME", String.valueOf(ManagementFactory.getRuntimeMXBean().getStartTime())); + if (AgentConfig.getInstance().getIastTestIdentifier() != null) { + this.addHeader("NR-CSEC-IAST-TEST-IDENTIFIER", AgentConfig.getInstance().getIastTestIdentifier()); + } Proxy proxy = proxyManager(); if(proxy != null) { this.setProxy(proxy); + noticeErrorCustomParameters.put("proxy_host", proxy.address().toString()); } if (StringUtils.startsWithIgnoreCase(AgentConfig.getInstance().getConfig().getK2ServiceInfo().getValidatorServiceEndpointURL(), "wss:")) { try { @@ -159,6 +172,7 @@ private WSClient() throws URISyntaxException { logger.log(LogLevel.FINER, "Error creating socket factory", e, WSClient.class.getName()); } } + noticeErrorCustomParameters.put("csec_ws_url", AgentConfig.getInstance().getConfig().getK2ServiceInfo().getValidatorServiceEndpointURL()); logger.log(LogLevel.INFO, String.format("Connecting to WS client %s", AgentConfig.getInstance().getConfig().getK2ServiceInfo().getValidatorServiceEndpointURL()), WSClient.class.getName()); } @@ -181,16 +195,21 @@ private static Proxy proxyManager() { Proxy proxy = new Proxy(getProxyScheme(proxyScheme), new InetSocketAddress(proxyHost, proxyPort)); if (proxyUser != null && proxyPass != null) { - // This Sets the authenticator that will be used by - // the networking code when a proxy or an HTTP server asks for authentication. - // This can lead to potential leak of authentication info by the application itself. -// Authenticator.setDefault(new Authenticator() { -// @Override -// protected PasswordAuthentication getPasswordAuthentication() { -// return new PasswordAuthentication(proxyUser, proxyPass.toCharArray()); -// } -// }); -// logger.log(LogLevel.FINER, "Authenticated proxy using username and password", WSClient.class.getName()); + /** + * This Sets the authenticator that will be used by + * the networking code when a proxy or an HTTP server asks for authentication. + * This can lead to potential leak of authentication info by the application itself. + */ + // Requires System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); reference https://github.com/TooTallNate/Java-WebSocket/issues/1179#issuecomment-2184917604 + System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); + System.setProperty("jdk.http.auth.proxying.disabledSchemes", ""); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(proxyUser, proxyPass.toCharArray()); + } + }); + logger.log(LogLevel.FINER, "Authenticated proxy using username and password", WSClient.class.getName()); } logger.log(LogLevel.FINER, String.format("Proxy being used to connect with WSS %s", proxy), WSClient.class.getName()); return proxy; @@ -234,6 +253,7 @@ public void openConnection() throws InterruptedException { @Override public void onOpen(ServerHandshake handshakedata) { + AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementConnectionReconnected(); logger.logInit(LogLevel.INFO, String.format(IAgentConstants.INIT_WS_CONNECTION, AgentConfig.getInstance().getConfig().getK2ServiceInfo().getValidatorServiceEndpointURL()), WSClient.class.getName()); logger.logInit(LogLevel.INFO, String.format(IAgentConstants.SENDING_APPLICATION_INFO_ON_WS_CONNECT, AgentInfo.getInstance().getApplicationInfo()), WSClient.class.getName()); @@ -244,7 +264,6 @@ public void onOpen(ServerHandshake handshakedata) { WSUtils.getInstance().notifyAll(); } WSUtils.getInstance().setConnected(true); - AgentUtils.sendApplicationURLMappings(); logger.logInit(LogLevel.INFO, String.format(IAgentConstants.APPLICATION_INFO_SENT_ON_WS_CONNECT, AgentInfo.getInstance().getApplicationInfo()), WSClient.class.getName()); } @@ -261,6 +280,7 @@ private static void cleanIASTState() { public void onMessage(String message) { // Receive communication from IC side. try { + AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementMessagesReceived(); if (logger.isLogLevelEnabled(LogLevel.FINEST)) { logger.log(LogLevel.FINEST, String.format(INCOMING_CONTROL_COMMAND_S, message), this.getClass().getName()); @@ -274,8 +294,10 @@ public void onMessage(String message) { @Override public void onClose(int code, String reason, boolean remote) { - logger.log(LogLevel.WARNING, CONNECTION_CLOSED_BY + (remote ? REMOTE_PEER : LOCAL) + CODE + code - + REASON + reason, WSClient.class.getName()); + String message = CONNECTION_CLOSED_BY + (remote ? REMOTE_PEER : LOCAL) + CODE + code + + REASON + reason; + logger.log(LogLevel.WARNING, message, WSClient.class.getName()); + NewRelic.noticeError(new SecurityNoticeError(message), noticeErrorCustomParameters, true); if (code == CloseFrame.NEVER_CONNECTED) { return; } @@ -289,6 +311,8 @@ public void onClose(int code, String reason, boolean remote) { @Override public void onError(Exception ex) { + AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementConnectionFailure(); + NewRelic.noticeError(new SecurityNoticeError(CONNECTION_CLOSED_BY + ex.getClass().getSimpleName(), ex), noticeErrorCustomParameters, true); logger.logInit(LogLevel.SEVERE, String.format(IAgentConstants.WS_CONNECTION_UNSUCCESSFUL_INFO, AgentConfig .getInstance().getConfig().getK2ServiceInfo().getValidatorServiceEndpointURL(), ex.toString(), ex.getCause()), @@ -306,8 +330,10 @@ public void send(String text) { if (this.isOpen()) { logger.log(LogLevel.FINER, SENDING_EVENT + text, WSClient.class.getName()); super.send(text); + AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementMessagesSent(); } else { logger.log(LogLevel.FINER, UNABLE_TO_SEND_EVENT + text, WSClient.class.getName()); + AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementSendFailure(); } } @@ -347,16 +373,22 @@ public static WSClient reconnectWSClient() throws URISyntaxException, Interrupte return instance; } - public static void shutDownWSClient(boolean clean) { + public static void shutDownWSClientAbnormal(boolean clean) { logger.log(LogLevel.WARNING, "Disconnecting WS client forced by APM", WSClient.class.getName()); + shutDownWSClient(clean, CloseFrame.ABNORMAL_CLOSE, "Client disconnecting forced by APM"); + } + + public static void shutDownWSClient(boolean clean, int frame, String message) { + logger.log(LogLevel.WARNING, String.format("WebSocket Shutdown initiated with %s", frame), + WSClient.class.getName()); WSUtils.getInstance().setConnected(false); if(clean) { RestRequestThreadPool.getInstance().resetIASTProcessing(); GrpcClientRequestReplayHelper.getInstance().resetIASTProcessing(); } if (instance != null) { - instance.close(CloseFrame.ABNORMAL_CLOSE, "Client disconnecting forced by APM"); + instance.close(frame, message); } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSReconnectionST.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSReconnectionST.java index bcbbe8945..ce55ac6e2 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSReconnectionST.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/websocket/WSReconnectionST.java @@ -1,5 +1,6 @@ package com.newrelic.agent.security.intcodeagent.websocket; +import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; @@ -25,6 +26,7 @@ public class WSReconnectionST { @Override public void run() { try { + AgentInfo.getInstance().getJaHealthCheck().getSchedulerRuns().incrementWebsocketReconnector(); if(!WSClient.getInstance().isOpen() || !WSUtils.isConnected()) { logger.log(LogLevel.INFO, "WS is marked disconnected, reconnecting ...", WSReconnectionST.class.getName()); WSClient.reconnectWSClient(); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/util/IUtilConstants.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/util/IUtilConstants.java index 8764c0b62..d40df7dba 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/util/IUtilConstants.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/util/IUtilConstants.java @@ -6,8 +6,58 @@ public interface IUtilConstants { String RASP = "RASP"; String IAST = "IAST"; + String IAST_RESTRICTED = "IAST_RESTRICTED"; + + String SCAN_TIME_DELAY = "security.scan_schedule.delay"; + String SCAN_TIME_SCHEDULE = "security.scan_schedule.schedule"; + String SCAN_TIME_DURATION = "security.scan_schedule.duration"; + String SCAN_TIME_COLLECT_SAMPLES = "security.scan_schedule.always_sample_traces"; + String SCAN_REQUEST_RATE_LIMIT = "security.scan_controllers.iast_scan_request_rate_limit"; + + String SKIP_IAST_SCAN = "security.exclude_from_iast_scan"; + String SKIP_IAST_SCAN_API = SKIP_IAST_SCAN + ".api"; + String SKIP_IAST_SCAN_PARAMETERS = SKIP_IAST_SCAN + ".http_request_parameters"; + String SKIP_IAST_SCAN_PARAMETERS_HEADER = SKIP_IAST_SCAN + ".http_request_parameters.header"; + String SKIP_IAST_SCAN_PARAMETERS_QUERY = SKIP_IAST_SCAN + ".http_request_parameters.query"; + String SKIP_IAST_SCAN_PARAMETERS_BODY = SKIP_IAST_SCAN + ".http_request_parameters.body"; + String SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY = SKIP_IAST_SCAN + ".iast_detection_category"; + String SKIP_INSECURE_SETTINGS = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".insecure_settings"; + String SKIP_INVALID_FILE_ACCESS = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".invalid_file_access"; + String SKIP_SQL_INJECTION = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".sql_injection"; + String SKIP_NOSQL_INJECTION = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".nosql_injection"; + String SKIP_LDAP_INJECTION = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".ldap_injection"; + String SKIP_JAVASCRIPT_INJECTION = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".javascript_injection"; + String SKIP_COMMAND_INJECTION = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".command_injection"; + String SKIP_XPATH_INJECTION = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".xpath_injection"; + String SKIP_SSRF = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".ssrf"; + String SKIP_RXSS = SKIP_IAST_SCAN_PARAMETERS_IAST_DETECTION_CATEGORY + ".rxss"; + + String RESTRICTION_CRITERIA_SCAN_TIME_SCHEDULE = "security.restriction_criteria.scan_time.schedule"; + String RESTRICTION_CRITERIA_SCAN_TIME_DURATION = "security.restriction_criteria.scan_time.duration"; + String RESTRICTION_CRITERIA = "security.restriction_criteria"; + String RESTRICTION_CRITERIA_ACCOUNT_INFO_ACCOUNT_ID = "security.restriction_criteria.account_info.account_id_value"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS = "security.restriction_criteria.mapping_parameters"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER = RESTRICTION_CRITERIA_MAPPING_PARAMETERS + ".header"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY = RESTRICTION_CRITERIA_MAPPING_PARAMETERS + ".query"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY = RESTRICTION_CRITERIA_MAPPING_PARAMETERS + ".body"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_PATH = RESTRICTION_CRITERIA_MAPPING_PARAMETERS + ".path"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER_ENABLED = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER + ".enabled"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY_ENABLED = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY + ".enabled"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY_ENABLED = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY + ".enabled"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_PATH_ENABLED = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_PATH + ".enabled"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER_LOCATION = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_HEADER + ".location"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY_LOCATION = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_QUERY + ".location"; + String RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY_LOCATION = RESTRICTION_CRITERIA_MAPPING_PARAMETERS_BODY + ".location"; + String RESTRICTION_CRITERIA_SKIP_SCAN_PARAMETERS = "security.restriction_criteria.skip_scan_parameters"; + String RESTRICTION_CRITERIA_SKIP_SCAN_PARAMETERS_HEADER = "security.restriction_criteria.skip_scan_parameters.header"; + String RESTRICTION_CRITERIA_SKIP_SCAN_PARAMETERS_QUERY = "security.restriction_criteria.skip_scan_parameters.query"; + String RESTRICTION_CRITERIA_SKIP_SCAN_PARAMETERS_BODY = "security.restriction_criteria.skip_scan_parameters.body"; + String RESTRICTION_CRITERIA_STRICT = "security.restriction_criteria.strict"; + + String GROUP_NAME = "group-name"; String INFO = "INFO"; + String OFF = "OFF"; String K_2_LOG_LEVEL = "K2_LOG_LEVEL"; String NR_LOG_LEVEL = "log_level"; String LOG_LEVEL = "log-level"; @@ -23,10 +73,12 @@ public interface IUtilConstants { String NR_SECURITY_ENABLED = "security.enabled"; String NR_SECURITY_HOME_APP = "security.is_home_app"; + String IAST_TEST_IDENTIFIER = "security.iast_test_identifier"; - String NR_SECURITY_CA_BUNDLE_PATH = "security.ca_bundle_path"; + String NR_SECURITY_CA_BUNDLE_PATH = "ca_bundle_path"; String NR_CSEC_DEBUG_LOGFILE_SIZE = "NR_CSEC_DEBUG_LOGFILE_SIZE"; String NR_CSEC_DEBUG_LOGFILE_MAX_COUNT = "NR_CSEC_DEBUG_LOGFILE_MAX_COUNT"; + String LOG_FILE_PATH = "log_file_path"; String NR_SECURITY_HOME = "nr-security-home"; String PROCESSED = "PROCESSED"; String ERROR = "ERROR"; @@ -40,4 +92,5 @@ public interface IUtilConstants { String APPLICATION_TMP_DIRECTORY = "APPLICATION_TMP_DIRECTORY"; String JAVA_IO_TMPDIR = "java.io.tmpdir"; + } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java index ab468d430..3a99caef4 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java @@ -1,26 +1,31 @@ package com.newrelic.api.agent.security; -import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper; +import com.fasterxml.jackson.databind.ObjectMapper; import com.newrelic.agent.security.AgentConfig; import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.dispatcher.DispatcherPool; +import com.newrelic.agent.security.instrumentator.httpclient.IASTDataTransferRequestProcessor; +import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.instrumentator.utils.*; import com.newrelic.agent.security.intcodeagent.constants.AgentServices; import com.newrelic.agent.security.intcodeagent.constants.HttpStatusCodes; +import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessor; +import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessorThreadPool; +import com.newrelic.agent.security.intcodeagent.exceptions.RestrictionModeException; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.LogFileHelper; import com.newrelic.agent.security.intcodeagent.models.javaagent.*; -import com.newrelic.agent.security.intcodeagent.utils.EncryptorUtils; -import com.newrelic.agent.security.intcodeagent.utils.RuntimeErrorReporter; +import com.newrelic.agent.security.intcodeagent.utils.*; import com.newrelic.api.agent.security.instrumentation.helpers.*; +import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; +import com.newrelic.api.agent.security.schema.policy.IastDetectionCategory; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.HealthCheckScheduleThread; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.properties.BuildInfo; import com.newrelic.agent.security.intcodeagent.schedulers.FileCleaner; import com.newrelic.agent.security.intcodeagent.schedulers.SchedulerHelper; -import com.newrelic.agent.security.intcodeagent.utils.CommonUtils; import com.newrelic.agent.security.intcodeagent.websocket.*; import com.newrelic.agent.security.util.IUtilConstants; import com.newrelic.api.agent.NewRelic; @@ -29,8 +34,7 @@ import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.java_websocket.framing.CloseFrame; import java.io.File; import java.io.IOException; @@ -38,11 +42,11 @@ import java.lang.instrument.UnmodifiableClassException; import java.net.HttpURLConnection; import java.net.URL; +import java.text.ParseException; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -57,7 +61,10 @@ public class Agent implements SecurityAgent { public static final String DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL = "Dropping event as it was generated by agent internal API call : "; private static final AtomicBoolean firstEventProcessed = new AtomicBoolean(false); + private long trafficStartedAt = 0; public static final String ERROR_WHILE_GENERATING_TRACE_ID_FOR_CATEGORY_S = "Error while generating trace id for category : %s"; + public static final String SKIPPING_THE_API_S_AS_IT_IS_PART_OF_THE_SKIP_SCAN_LIST = "Skipping the API %s as it is part of the skip scan list"; + public static final String INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE = "Invalid cron expression provided for IAST Mode"; private AgentInfo info; @@ -70,6 +77,8 @@ public class Agent implements SecurityAgent { private java.net.URL agentJarURL; private Instrumentation instrumentation; + private static final Map customNoticeErrorParameters = new ConcurrentHashMap<>(); + private static final class InstanceHolder { static final Agent instance = new Agent(); } @@ -91,8 +100,23 @@ private Agent(){ System.setProperty("org.slf4j.simpleLogger.logFile", "System.out"); } - private void initialise() { - // TODO: All the bring up tasks are to be performed here. + public static Map getCustomNoticeErrorParameters() { + return customNoticeErrorParameters; + } + + private void initialise() throws RestrictionModeException { + if (!isInitialised()) { + config = AgentConfig.getInstance(); + info = AgentInfo.getInstance(); + } + long delay = config.instantiate(); + AgentInfo.initialiseLogger(); + SchedulerHelper.getInstance().scheduleIastTrigger(this::triggerNrSecurity, delay, TimeUnit.MILLISECONDS); + } + + private void triggerNrSecurity() { + // All the bring up tasks are to be performed here. + /* * * 1. populate policy * 2. create application info @@ -101,50 +125,99 @@ private void initialise() { * */ //NOTE: The bellow call sequence is critical and dependent on each other - if (!isInitialised()) { - config = AgentConfig.getInstance(); - info = AgentInfo.getInstance(); + try { + logger = FileLoggerThreadPool.getInstance(); + logger.logInit( + LogLevel.INFO, + "[STEP-1] => Security agent is starting", + Agent.class.getName()); + logger.logInit( + LogLevel.INFO, + String.format("[STEP-2] => Generating unique identifier: %s", AgentInfo.getInstance().getApplicationUUID()), AgentInfo.class.getName()); + config.setConfig(CollectorConfigurationUtils.populateCollectorConfig()); + + info.setBuildInfo(readCollectorBuildInfo()); + logger.log(LogLevel.INFO, String.format("CSEC Collector build info : %s", info.getBuildInfo()), this.getClass().getName()); + + logger.logInit( + LogLevel.INFO, + "[STEP-3] => Gathering information about the application", + this.getClass().getName()); + logger.logInit(LogLevel.INFO, !config.getAgentMode().getSkipScan().getIastDetectionCategory().getInsecureSettingsEnabled() ? + "Low priority instrumentations are enabled." : "Low priority instrumentations are disabled!", this.getClass().getName()); + if (NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_SECURITY_HOME_APP, false)) { + logger.logInit(LogLevel.INFO, "App being scanned is a Newrelic's Home Grown application", this.getClass().getName()); + } + info.setIdentifier(ApplicationInfoUtils.envDetection()); + ApplicationInfoUtils.continueIdentifierProcessing(info.getIdentifier(), config.getConfig()); + info.generateAppInfo(config.getConfig()); + info.initialiseHC(); + config.populateAgentPolicy(); + config.populateAgentPolicyParameters(); + config.setupSnapshotDir(); + info.initStatusLogValues(); + setInitialised(true); + populateLinkingMetadata(); + populateApplicationTmpDir(); + startSecurityServices(); + info.agentStatTrigger(true); + //Schedule NR csec shutdown if required + scheduleShutdownTrigger(); + } catch (Exception e){ + NewRelic.getAgent().getLogger().log(Level.SEVERE, "[NR-CSEC-JA] Deactivating NewRelic Security Agent due to {0}", e.getMessage()); + NewRelic.noticeError(e, customNoticeErrorParameters, true); } - config.instantiate(); - logger = FileLoggerThreadPool.getInstance(); - logger.logInit( - LogLevel.INFO, - "[STEP-1] => Security agent is starting", - Agent.class.getName()); - logger.logInit( - LogLevel.INFO, - String.format("[STEP-2] => Generating unique identifier: %s", AgentInfo.getInstance().getApplicationUUID()), AgentInfo.class.getName()); - config.setConfig(CollectorConfigurationUtils.populateCollectorConfig()); + } + + private void scheduleShutdownTrigger() { + if(AgentConfig.getInstance().getAgentMode().getScanSchedule().getDuration() > 0) { + int duration = AgentConfig.getInstance().getAgentMode().getScanSchedule().getDuration(); + Instant now = Instant.now(); + if(AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime() != null){ + now = AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime().toInstant(); + } + Instant shutdownInstant = now.plus(duration, ChronoUnit.MINUTES); + long shutdownTime = shutdownInstant.getEpochSecond() - Instant.now().getEpochSecond(); + SchedulerHelper.getInstance().scheduleIastTrigger(this::IastDeactivate, shutdownTime, TimeUnit.SECONDS); + } + } + + private void IastDeactivate() { + if(ControlCommandProcessor.getIastReplayRequestMsgReceiveTime().isAfter(Instant.now().minus(5, ChronoUnit.MINUTES))){ + logger.log(LogLevel.WARNING, "IAST scan is still in progress, may have undetected vulnerabilities. Please increase scan duration and restart application.", Agent.class.getName()); + } + logger.log(LogLevel.INFO, "Scan duration completed, IAST going under hibernate mode.", Agent.class.getName()); + deactivateSecurity(); + if(!config.getAgentMode().getScanSchedule().isScheduleOnce()){ + try { + config.getAgentMode().getScanSchedule().setNextScanTime(new CronExpression(config.getAgentMode().getScanSchedule().getSchedule()).getTimeAfter(new Date())); + config.getAgentMode().getScanSchedule().setDataCollectionTime(config.getAgentMode().getScanSchedule().getNextScanTime()); + if(config.getAgentMode().getScanSchedule().isCollectSamples()){ + config.getAgentMode().getScanSchedule().setNextScanTime(new Date(Instant.now().toEpochMilli())); + } + long delay = config.triggerIAST(); + SchedulerHelper.getInstance().scheduleIastTrigger(this::triggerNrSecurity, delay, TimeUnit.MILLISECONDS); + } catch (RestrictionModeException | SecurityException exception){ + NewRelic.getAgent().getLogger().log(Level.SEVERE, "[NR-CSEC-JA] Deactivating NewRelic Security Agent due to {0}", exception.getMessage()); + NewRelic.noticeError(exception, customNoticeErrorParameters, true); + } catch (ParseException e) { + System.err.println("[NR-CSEC-JA] Error while reading IAST Scan Configuration. Security will be disabled."); + NewRelic.getAgent().getLogger().log(Level.WARNING, "[NR-CSEC-JA] Error while reading IAST Scan Configuration. Security will be disabled. Message :{0}", e.getMessage()); + NewRelic.noticeError(new RestrictionModeException(INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE, e), Agent.getCustomNoticeErrorParameters(), true); + AgentInfo.getInstance().agentStatTrigger(false); + } + } + } + private void IastRestrictedShutdown() { try { - info.setBuildInfo(readCollectorBuildInfo()); - logger.log(LogLevel.INFO, String.format("CSEC Collector build info : %s", new JavaPropsMapper().writeValueAsProperties(info.getBuildInfo())), this.getClass().getName()); - } catch (IOException e) { - // TODO: Need to confirm requirement of this throw. - throw new RuntimeException("Unable to read CSEC Collector build info", e); + InstrumentationUtils.shutdownLogic(); + long delay = config.triggerIAST(); + SchedulerHelper.getInstance().scheduleIastTrigger(this::triggerNrSecurity, delay, TimeUnit.MILLISECONDS); + } catch (RestrictionModeException | SecurityException exception){ + NewRelic.getAgent().getLogger().log(Level.SEVERE, "[NR-CSEC-JA] Deactivating NewRelic Security Agent due to {0}", exception.getMessage()); + NewRelic.noticeError(exception, customNoticeErrorParameters, true); } - logger.logInit( - LogLevel.INFO, - "[STEP-3] => Gathering information about the application", - this.getClass().getName()); - logger.logInit(LogLevel.INFO, NewRelic.getAgent().getConfig().getValue(LowSeverityHelper.LOW_SEVERITY_HOOKS_ENABLED, LowSeverityHelper.DEFAULT)? - "Low priority instrumentations are enabled.":"Low priority instrumentations are disabled!", this.getClass().getName()); - if( NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_SECURITY_HOME_APP, false) ) { - logger.logInit(LogLevel.INFO, "App being scanned is a Newrelic's Home Grown application", this.getClass().getName()); - } - info.setIdentifier(ApplicationInfoUtils.envDetection()); - ApplicationInfoUtils.continueIdentifierProcessing(info.getIdentifier(), config.getConfig()); - info.generateAppInfo(config.getConfig()); - info.initialiseHC(); - config.populateAgentPolicy(); - config.populateAgentPolicyParameters(); - config.setupSnapshotDir(); - info.initStatusLogValues(); - setInitialised(true); - populateLinkingMetadata(); - populateApplicationTmpDir(); - startK2Services(); - info.agentStatTrigger(true); } private void populateApplicationTmpDir() { @@ -155,9 +228,9 @@ private void populateApplicationTmpDir() { private BuildInfo readCollectorBuildInfo() { BuildInfo buildInfo = new BuildInfo(); try { - JavaPropsMapper mapper = new JavaPropsMapper(); - buildInfo = mapper. - readValue(CommonUtils.getResourceStreamFromAgentJar("Agent.properties"), BuildInfo.class); + Properties properties = new Properties(); + properties.load(ResourceUtils.getResourceStreamFromAgentJar("Agent.properties")); + buildInfo = new ObjectMapper().convertValue(properties, BuildInfo.class); } catch (Throwable e) { logger.log(LogLevel.SEVERE, String.format(CRITICAL_ERROR_UNABLE_TO_READ_BUILD_INFO_AND_VERSION_S_S, e.getMessage(), e.getCause()), this.getClass().getName()); logger.postLogMessageIfNecessary(LogLevel.SEVERE, @@ -174,7 +247,7 @@ private void populateLinkingMetadata() { info.setLinkingMetadata(linkingMetaData); } - private void startK2Services() { + private void startSecurityServices() { HealthCheckScheduleThread.getInstance().scheduleNewTask(); FileCleaner.scheduleNewTask(); SchedulerHelper.getInstance().scheduleLowSeverityFilterCleanup(LowSeverityHelper::clearLowSeverityEventFilter, @@ -189,13 +262,32 @@ private void startK2Services() { ); WSReconnectionST.getInstance().submitNewTaskSchedule(0); EventSendPool.getInstance(); + ControlCommandProcessorThreadPool.getInstance(); logger.logInit( LogLevel.INFO, String.format(STARTED_MODULE_LOG, AgentServices.EventWritePool.name()), Agent.class.getName() ); logger.logInit(LogLevel.INFO, AGENT_INIT_LOG_STEP_FIVE_END, Agent.class.getName()); + // Start IAST data pull if policy allows + if (config.getAgentMode().getIastScan().getEnabled()) { + IASTDataTransferRequestProcessor.getInstance().startDataRequestSchedule( + config.getAgentMode().getIastScan().getProbing().getInterval(), TimeUnit.SECONDS); + logger.logInit( + LogLevel.INFO, + String.format(STARTED_MODULE_LOG, AgentServices.IASTDataPullService.name()), + Agent.class.getName() + ); + } else { + IASTDataTransferRequestProcessor.getInstance().stopDataRequestSchedule(true); + } + AgentInfo.getInstance().getJaHealthCheck().setControlCommandRequestedTime(IASTDataTransferRequestProcessor.getInstance().getControlCommandRequestedAtEpochMilli()); + AgentInfo.getInstance().getJaHealthCheck().setScanStartTime(ControlCommandProcessorThreadPool.getInstance().getScanStartTime()); + } + @Override + public IastDetectionCategory getIastDetectionCategory() { + return AgentConfig.getInstance().getAgentMode().getSkipScan().getIastDetectionCategory(); } @Override @@ -203,62 +295,92 @@ public boolean refreshState(java.net.URL agentJarURL, Instrumentation instrument /** * restart k2 services **/ - this.agentJarURL = agentJarURL; - this.instrumentation = instrumentation; - if (isInitialised()) { - config.setNRSecurityEnabled(false); - cancelActiveServiceTasks(); - } - initialise(); - NewRelic.getAgent().getLogger().log(Level.INFO, "Security refresh was invoked, Security Agent initiation is successful."); + try { + this.agentJarURL = agentJarURL; + this.instrumentation = instrumentation; + if (isInitialised()) { + AgentInfo.getInstance().setAgentActive(false); + cancelActiveServiceTasks(); + } + initialise(); + NewRelic.getAgent().getLogger().log(Level.INFO, "Security refresh was invoked, Security Agent initiation is successful."); + } catch (RestrictionModeException | SecurityException exception){ + NewRelic.getAgent().getLogger().log(Level.SEVERE, "[NR-CSEC-JA] Deactivating NewRelic Security Agent due to {0}", exception.getMessage()); + NewRelic.noticeError(exception, customNoticeErrorParameters, true); + } catch (Exception e){ + NewRelic.getAgent().getLogger().log(Level.SEVERE, "Newrelic Security Startup failed!!!", e); + NewRelic.noticeError(e, customNoticeErrorParameters, true); + } return true; } private void cancelActiveServiceTasks() { /** - * Drain the pools (RestClient, EventSend, Dispatcher) before websocket close * Websocket * policy * HealthCheck */ - WSClient.shutDownWSClient(false); + WSClient.shutDownWSClientAbnormal(false); HealthCheckScheduleThread.getInstance().cancelTask(true); + WSReconnectionST.cancelTask(true); FileCleaner.cancelTask(); + ControlCommandProcessorThreadPool.clearAllTasks(); } @Override public boolean deactivateSecurity() { if(isInitialised()) { - config.setNRSecurityEnabled(false); deactivateSecurityServices(); } return true; } private void deactivateSecurityServices(){ - /** - * ShutDown following - * 1. policy + policy parameter - * 2. websocket - * 3. event pool - * 4. HealthCheck - **/ - HealthCheckScheduleThread.getInstance().cancelTask(true); - FileCleaner.cancelTask(); - WSClient.shutDownWSClient(true); - WSReconnectionST.shutDownPool(); - EventSendPool.shutDownPool(); + /* + ShutDown following + 1. policy + policy parameter + 2. websocket + 3. event pool + 4. HealthCheck + */ +// InstrumentationUtils.shutdownLogic(); + IASTDataTransferRequestProcessor.getInstance().stopDataRequestSchedule(true); + info.getJaHealthCheck().setScanActive(false); + if(!config.getAgentMode().getScanSchedule().isCollectSamples()) { + AgentInfo.getInstance().setAgentActive(false); + HealthCheckScheduleThread.getInstance().cancelTask(true); + ControlCommandProcessorThreadPool.clearAllTasks(); + RestRequestThreadPool.getInstance().resetIASTProcessing(); + GrpcClientRequestReplayHelper.getInstance().resetIASTProcessing(); + RestRequestThreadPool.getInstance().getRejectedIds().clear(); + GrpcClientRequestReplayHelper.getInstance().getRejectedIds().clear(); + DispatcherPool.getInstance().reset(); + EventSendPool.getInstance().reset(); + FileCleaner.cancelTask(); + WSReconnectionST.cancelTask(true); + WSClient.shutDownWSClient(true, CloseFrame.NORMAL, "Deactivating Security Agent"); + } + + } @Override public void registerOperation(AbstractOperation operation) { + AgentInfo.getInstance().getJaHealthCheck().incrementInvokedHookCount(); // added to fetch request/response in case of grpc requests boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); try { if(lockAcquired) { + SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); + if(RestrictionUtility.skippedApiDetected(AgentConfig.getInstance().getAgentMode().getSkipScan(), securityMetaData.getRequest())){ + logger.log(LogLevel.FINER, String.format(SKIPPING_THE_API_S_AS_IT_IS_PART_OF_THE_SKIP_SCAN_LIST, securityMetaData.getRequest().getUrl()), Agent.class.getName()); + return; + } + isRequestBodyDataExccedsAllowedLimit(securityMetaData); + if (securityMetaData != null && securityMetaData.getRequest().getIsGrpc()) { securityMetaData.getRequest().setBody( new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_REQUEST_DATA, List.class)))); @@ -283,13 +405,12 @@ public void registerOperation(AbstractOperation operation) { if (operation instanceof RXSSOperation) { operation.setStackTrace(securityMetaData.getMetaData().getServiceTrace()); securityMetaData.addCustomAttribute("RXSS_PROCESSED", true); + } else if (operation instanceof SecureCookieOperationSet) { + operation.setStackTrace(securityMetaData.getMetaData().getServiceTrace()); } else { StackTraceElement[] trace = Thread.currentThread().getStackTrace(); operation.setStackTrace(Arrays.copyOfRange(trace, securityMetaData.getMetaData().getFromJumpRequiredInStackTrace(), trace.length)); } - if(securityMetaData.getMetaData().isFoundAnnotedUserLevelServiceMethod()){ - operation.setUserClassEntity(setUserClassEntityByAnnotation(securityMetaData.getMetaData().getServiceTrace())); - } // added to fetch request/response in case of grpc requests if (securityMetaData.getRequest().getIsGrpc()) { @@ -303,6 +424,7 @@ public void registerOperation(AbstractOperation operation) { logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + JsonConverter.toJSON(operation), Agent.class.getName()); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementCsecInternalEvent(); return; } @@ -310,9 +432,17 @@ public void registerOperation(AbstractOperation operation) { logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + JsonConverter.toJSON(operation), Agent.class.getName()); + AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementNrInternalEvent(); return; } + if(AgentConfig.getInstance().getAgentMode().getIastScan().getEnabled() && AgentConfig.getInstance().getAgentMode().getIastScan().getRestricted()) { + if(!RestrictionUtility.hasValidAccountId(AgentConfig.getInstance().getAgentMode().getIastScan().getRestrictionCriteria(), securityMetaData.getRequest())){ + return; + } + logger.log(LogLevel.FINER, String.format("Valid event for iast restricted environment : %s", operation), Agent.class.getName()); + } + logIfIastScanForFirstTime(securityMetaData.getFuzzRequestIdentifier(), securityMetaData.getRequest()); setRequiredStackTrace(operation, securityMetaData); @@ -323,16 +453,18 @@ public void registerOperation(AbstractOperation operation) { // boolean blockNeeded = checkIfBlockingNeeded(operation.getApiID()); // securityMetaData.getMetaData().setApiBlocked(blockNeeded); HttpRequest request = securityMetaData.getRequest(); -// if (StringUtils.isEmpty(request.getRoute())){ Framework frameWork = Framework.UNKNOWN; if(!securityMetaData.getFuzzRequestIdentifier().getK2Request() && StringUtils.isNotBlank(securityMetaData.getMetaData().getFramework())) { frameWork = Framework.valueOf(securityMetaData.getMetaData().getFramework()); } if (!securityMetaData.getFuzzRequestIdentifier().getK2Request() && StringUtils.isEmpty(request.getRoute())){ - request.setRoute(getEndpointRoute(StringUtils.substringBefore(request.getUrl(), "?"), frameWork), true); - logger.log(LogLevel.FINEST,"Route detection using Application Endpoint", this.getClass().getName()); + String route = getEndpointRoute(StringUtils.substringBefore(request.getUrl(), "?"), frameWork); + if (route != null) { + request.setRoute(route); + logger.log(LogLevel.FINEST,"Route detection using Application Endpoint", this.getClass().getName()); + } } -// } + if (needToGenerateEvent(operation.getApiID())) { DispatcherPool.getInstance().dispatchEvent(operation, securityMetaData); if (!firstEventProcessed.get()) { @@ -340,6 +472,8 @@ public void registerOperation(AbstractOperation operation) { String.format(EVENT_ZERO_PROCESSED, securityMetaData.getRequest()), this.getClass().getName()); firstEventProcessed.set(true); + trafficStartedAt = Instant.now().toEpochMilli(); + AgentInfo.getInstance().getJaHealthCheck().setTrafficStartedTime(trafficStartedAt); } } } @@ -358,7 +492,7 @@ private String getEndpointRoute(String uri, Framework framework){ private String getEndpointRoute(String uri) { List uriSegments = URLMappingsHelper.getSegments(uri); if (uriSegments.isEmpty()){ - return StringUtils.EMPTY; + return null; } for (RouteSegments routeSegments : URLMappingsHelper.getRouteSegments()) { int uriSegIdx = 0; @@ -384,7 +518,7 @@ private String getEndpointRoute(String uri) { } } } - return StringUtils.EMPTY; + return null; } private int jumpRoute(List value, int i1, List uriSegments, int i) { @@ -400,6 +534,29 @@ private int jumpRoute(List value, int i1, List uriSegments return i; } + private static boolean isRequestBodyDataExccedsAllowedLimit(SecurityMetaData securityMetaData) { + if(securityMetaData != null && StringUtils.length(securityMetaData.getRequest().getBody()) > HttpRequest.MAX_ALLOWED_REQUEST_BODY_LENGTH) { + securityMetaData.getRequest().setDataTruncated(true); + securityMetaData.getRequest().setBody(new StringBuilder()); + return true; + //TODO send IASTScanFailure for body truncation and drop event. + } + if(!securityMetaData.getRequest().getParameterMap().isEmpty()) { + boolean parameterTruncated = false; + for (String[] requestParam : securityMetaData.getRequest().getParameterMap().values()) { + if(requestParam.length > HttpRequest.MAX_ALLOWED_REQUEST_BODY_LENGTH) { + securityMetaData.getRequest().setDataTruncated(true); + parameterTruncated = true; + } + } + if(parameterTruncated) { + securityMetaData.getRequest().getParameterMap().clear(); + } + return true; + } + return false; + } + private boolean checkIfCSECGeneratedEvent(AbstractOperation operation) { for (int i = 1, j = 0; i < operation.getStackTrace().length; i++) { // Only remove consecutive top com.newrelic and com.nr. elements from stack. @@ -471,6 +628,7 @@ private UserClassEntity setUserClassEntityByAnnotation(StackTraceElement[] servi } private UserClassEntity setUserClassEntity(AbstractOperation operation, SecurityMetaData securityMetaData) { + boolean frameworkSpecificEntityFound = false; UserClassEntity userClassEntity = new UserClassEntity(); StackTraceElement userStackTraceElement = securityMetaData.getCustomAttribute(GenericHelper.USER_CLASS_ENTITY, StackTraceElement.class); if(userStackTraceElement == null && securityMetaData.getMetaData().getServiceTrace() != null && securityMetaData.getMetaData().getServiceTrace().length > 0){ @@ -494,21 +652,19 @@ private UserClassEntity setUserClassEntity(AbstractOperation operation, Security } switch (framework){ case "vertx-web": - if(i-1 >= 0) { + case "GRPC": + if(!frameworkSpecificEntityFound && i-1 >= 0) { userClassEntity = setUserClassEntityForVertx(operation, userStackTraceElement, userClassEntity, securityMetaData.getMetaData().isUserLevelServiceMethodEncountered(), i); if(userClassEntity.getUserClassElement() != null){ - return userClassEntity; + frameworkSpecificEntityFound = true; } } break; default: - if(userStackTraceElement != null){ - if(StringUtils.equals(stackTraceElement.getClassName(), userStackTraceElement.getClassName()) - && StringUtils.equals(stackTraceElement.getMethodName(), userStackTraceElement.getMethodName())){ - userClassEntity.setUserClassElement(stackTraceElement); - userClassEntity.setCalledByUserCode(securityMetaData.getMetaData().isUserLevelServiceMethodEncountered()); - return userClassEntity; - } + if(userStackTraceElement != null && StringUtils.equals(stackTraceElement.getClassName(), userStackTraceElement.getClassName()) + && StringUtils.equals(stackTraceElement.getMethodName(), userStackTraceElement.getMethodName())){ + userClassEntity.setUserClassElement(stackTraceElement); + userClassEntity.setCalledByUserCode(securityMetaData.getMetaData().isUserLevelServiceMethodEncountered()); } } } @@ -517,6 +673,20 @@ private UserClassEntity setUserClassEntity(AbstractOperation operation, Security userClassEntity.setCalledByUserCode(securityMetaData.getMetaData().isUserLevelServiceMethodEncountered()); return userClassEntity; } + + if (frameworkSpecificEntityFound && userClassEntity.getUserClassElement() != null && !securityMetaData.getMetaData().isFoundAnnotedUserLevelServiceMethod()){ + return userClassEntity; + } + + if (userClassEntity.getUserClassElement() != null){ + return userClassEntity; + } + + // user class identification using annotations + if (securityMetaData.getMetaData().isFoundAnnotedUserLevelServiceMethod()) { + return setUserClassEntityByAnnotation(securityMetaData.getMetaData().getServiceTrace()); + } + if(userClassEntity.getUserClassElement() == null && operation.getStackTrace().length >= 2){ userClassEntity.setUserClassElement(operation.getStackTrace()[1]); userClassEntity.setCalledByUserCode(securityMetaData.getMetaData().isUserLevelServiceMethodEncountered()); @@ -629,7 +799,6 @@ public void registerExitEvent(AbstractOperation operation) { exitEventBean.setK2RequestIdentifier(k2RequestIdentifier.getRaw()); logger.log(LogLevel.FINER, "Exit event : " + exitEventBean, this.getClass().getName()); DispatcherPool.getInstance().dispatchExitEvent(exitEventBean); - AgentInfo.getInstance().getJaHealthCheck().incrementExitEventSentCount(); } } } @@ -713,7 +882,7 @@ public Instrumentation getInstrumentation() { @Override public boolean isLowPriorityInstrumentationEnabled() { - return NewRelicSecurity.isHookProcessingActive() && NewRelic.getAgent().getConfig().getValue(LowSeverityHelper.LOW_SEVERITY_HOOKS_ENABLED, LowSeverityHelper.DEFAULT); + return NewRelicSecurity.isHookProcessingActive() && !config.getAgentMode().getSkipScan().getIastDetectionCategory().getInsecureSettingsEnabled(); } public void setApplicationConnectionConfig(int port, String scheme) { @@ -853,13 +1022,21 @@ public void retransformUninstrumentedClass(Class classToRetransform) { @Override public String decryptAndVerify(String encryptedData, String hashVerifier) { - String decryptedData = EncryptorUtils.decrypt(AgentInfo.getInstance().getLinkingMetadata().get(INRSettingsKey.NR_ENTITY_GUID), encryptedData); - if(EncryptorUtils.verifyHashData(hashVerifier, decryptedData)) { - return decryptedData; - } else { - NewRelic.getAgent().getLogger().log(Level.WARNING, String.format("Agent data decryption verifier fails on data : %s hash : %s", encryptedData, hashVerifier), Agent.class.getName()); - return null; + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if (lockAcquired) { + String decryptedData = EncryptorUtils.decrypt(AgentInfo.getInstance().getLinkingMetadata().get(INRSettingsKey.NR_ENTITY_GUID), encryptedData); + if (EncryptorUtils.verifyHashData(hashVerifier, decryptedData)) { + return decryptedData; + } else { + NewRelic.getAgent().getLogger().log(Level.WARNING, String.format("Agent data decryption verifier fails on data : %s hash : %s", encryptedData, hashVerifier), Agent.class.getName()); + return null; + } + } + } finally { + ThreadLocalLockHelper.releaseLock(); } + return null; } @Override @@ -918,4 +1095,9 @@ public boolean recordExceptions(SecurityMetaData securityMetaData, Throwable exc return RuntimeErrorReporter.getInstance().addApplicationRuntimeError(applicationRuntimeError); } + @Override + public void reportURLMapping() { + SchedulerHelper.getInstance().scheduleURLMappingPosting(AgentUtils::sendApplicationURLMappings); + } + } \ No newline at end of file diff --git a/newrelic-security-api-test-impl/src/main/java/com/newrelic/api/agent/security/Agent.java b/newrelic-security-api-test-impl/src/main/java/com/newrelic/api/agent/security/Agent.java index 3f47b0954..de8c94f3e 100644 --- a/newrelic-security-api-test-impl/src/main/java/com/newrelic/api/agent/security/Agent.java +++ b/newrelic-security-api-test-impl/src/main/java/com/newrelic/api/agent/security/Agent.java @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.schema.ServerConnectionConfiguration; import com.newrelic.api.agent.security.schema.operation.FileIntegrityOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; +import com.newrelic.api.agent.security.schema.policy.IastDetectionCategory; import com.newrelic.api.agent.security.utils.logging.LogLevel; import java.lang.instrument.Instrumentation; @@ -24,6 +25,7 @@ public class Agent implements SecurityAgent { public static final String OPERATIONS = "operations"; public static final String EXIT_OPERATIONS = "exit-operations"; private static Agent instance; + private final IastDetectionCategory defaultIastDetectionCategory = new IastDetectionCategory(); private AgentPolicy policy = new AgentPolicy(); @@ -50,6 +52,11 @@ private Agent() { private void initialise() { } + @Override + public IastDetectionCategory getIastDetectionCategory() { + return defaultIastDetectionCategory; + } + @Override public boolean refreshState(URL agentJarURL, Instrumentation instrumentation) { return true; @@ -211,4 +218,9 @@ public void reportApplicationRuntimeError(SecurityMetaData securityMetaData, Thr public boolean recordExceptions(SecurityMetaData securityMetaData, Throwable exception) { return false; } + + @Override + public void reportURLMapping() { + + } } \ No newline at end of file diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/NoOpAgent.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/NoOpAgent.java index d5e0f6e74..429737aa2 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/NoOpAgent.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/NoOpAgent.java @@ -7,11 +7,11 @@ package com.newrelic.api.agent.security; -import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.ServerConnectionConfiguration; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; +import com.newrelic.api.agent.security.schema.policy.IastDetectionCategory; import com.newrelic.api.agent.security.utils.logging.LogLevel; import java.lang.instrument.Instrumentation; @@ -25,11 +25,17 @@ class NoOpAgent implements SecurityAgent { private static final SecurityAgent INSTANCE = new NoOpAgent(); public static final String EMPTY = ""; + private final IastDetectionCategory defaultIastDetectionCategory = new IastDetectionCategory(); public static SecurityAgent getInstance() { return INSTANCE; } + @Override + public IastDetectionCategory getIastDetectionCategory() { + return defaultIastDetectionCategory; + } + @Override public boolean refreshState(URL agentJarURL, Instrumentation instrumentation) { return true; @@ -142,5 +148,9 @@ public boolean recordExceptions(SecurityMetaData securityMetaData, Throwable exc return false; } + @Override + public void reportURLMapping() { + + } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/SecurityAgent.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/SecurityAgent.java index 82b573974..3d3f9f642 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/SecurityAgent.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/SecurityAgent.java @@ -11,6 +11,7 @@ import com.newrelic.api.agent.security.schema.SecurityMetaData; import com.newrelic.api.agent.security.schema.ServerConnectionConfiguration; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; +import com.newrelic.api.agent.security.schema.policy.IastDetectionCategory; import com.newrelic.api.agent.security.utils.logging.LogLevel; import java.lang.instrument.Instrumentation; @@ -22,6 +23,8 @@ */ public interface SecurityAgent { + IastDetectionCategory getIastDetectionCategory(); + boolean refreshState(URL agentJarURL, Instrumentation instrumentation); boolean deactivateSecurity(); @@ -75,4 +78,6 @@ void reportIASTScanFailure(SecurityMetaData securityMetaData, String apiId, Thro void reportApplicationRuntimeError(SecurityMetaData securityMetaData, Throwable exception); boolean recordExceptions(SecurityMetaData securityMetaData, Throwable exception); + + void reportURLMapping(); } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java index e5fc7954f..ffc269e9a 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java @@ -186,7 +186,7 @@ public static void releaseFileLock() { } catch (Throwable ignored){} } - private static String getNrSecCustomAttribName() { + public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GenericHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GenericHelper.java index 8d4cf3f0f..00d96f453 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GenericHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GenericHelper.java @@ -1,6 +1,7 @@ package com.newrelic.api.agent.security.instrumentation.helpers; import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import java.util.regex.Pattern; @@ -14,6 +15,7 @@ public class GenericHelper { public static final String NR_SEC_CUSTOM_SPRING_REDIS_ATTR = "SPRING-DATA-REDIS"; public static final String REGISTER_OPERATION_EXCEPTION_MESSAGE = "Instrumentation library: %s , error while library instrumented call processing : %s"; + public static final String SERVER_CONFIG_ERROR = "Instrumentation library: %s , error while detecting Server Configuration : %s"; public static final String EXIT_OPERATION_EXCEPTION_MESSAGE = "Instrumentation library: %s , error while generating exit operation: %s"; public static final String SECURITY_EXCEPTION_MESSAGE = "New Relic Security Exception raised for Instrumentation library: %s, reason: %s "; public static final String URI_EXCEPTION_MESSAGE = "Instrumentation library: %s , error while extracting URI : %s"; @@ -49,6 +51,64 @@ public static boolean isLockAcquired(String nrSecCustomAttrName, int hashCode) { return false; } + public static boolean acquireLockIfPossible(VulnerabilityCaseType caseType, String nrSecCustomAttrName, int hashCode) { + boolean enabled = false; + if(!NewRelicSecurity.isHookProcessingActive()) { + return false; + } + switch (caseType) { + case SYSTEM_COMMAND: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getCommandInjectionEnabled(); + break; + case FILE_OPERATION: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getInvalidFileAccessEnabled(); + break; + case SQL_DB_COMMAND: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getSqlInjectionEnabled(); + break; + case NOSQL_DB_COMMAND: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getNoSqlInjectionEnabled(); + break; + case DYNAMO_DB_COMMAND: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getNoSqlInjectionEnabled(); + break; + case HTTP_REQUEST: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getSsrfEnabled(); + break; + case LDAP: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getLdapInjectionEnabled(); + break; + case XPATH: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getXpathInjectionEnabled(); + break; + case REFLECTED_XSS: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled(); + break; + case FILE_INTEGRITY: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getInvalidFileAccessEnabled(); + break; + case JAVASCRIPT_INJECTION: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getJavascriptInjectionEnabled(); + break; + case XQUERY_INJECTION: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getXpathInjectionEnabled(); + break; + case SECURE_COOKIE: + case CRYPTO: + case RANDOM: + case TRUSTBOUNDARY: + case HASH: + enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getInsecureSettingsEnabled(); + break; + default: + break; + } + if(enabled) { + return false; + } + return acquireLockIfPossible(nrSecCustomAttrName, hashCode); + } + public static boolean acquireLockIfPossible(String nrSecCustomAttrName, int hashCode) { try { if (NewRelicSecurity.isHookProcessingActive() && @@ -68,6 +128,10 @@ public static void releaseLock(String nrSecCustomAttrName, int hashCode) { } catch (Throwable ignored){} } + public static boolean acquireLockIfPossible(VulnerabilityCaseType caseType, String nrSecCustomAttrName) { + return acquireLockIfPossible(caseType, nrSecCustomAttrName, 0); + } + public static boolean acquireLockIfPossible(String nrSecCustomAttrName) { return acquireLockIfPossible(nrSecCustomAttrName, 0); } @@ -75,4 +139,8 @@ public static boolean acquireLockIfPossible(String nrSecCustomAttrName) { public static void releaseLock(String nrSecCustomAttrName) { releaseLock(nrSecCustomAttrName, 0); } + + public static void onTransactionFinish() { + + } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GrpcClientRequestReplayHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GrpcClientRequestReplayHelper.java index 46c0e305d..9009d5bef 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GrpcClientRequestReplayHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/GrpcClientRequestReplayHelper.java @@ -20,7 +20,6 @@ public class GrpcClientRequestReplayHelper { private final Map> processedIds = new ConcurrentHashMap(); private final Set pendingIds = ConcurrentHashMap.newKeySet(); private final Set rejectedIds = ConcurrentHashMap.newKeySet(); - private static final AtomicBoolean isWaiting = new AtomicBoolean(false); public static GrpcClientRequestReplayHelper getInstance(){ return InstanceHolder.instance; @@ -69,10 +68,6 @@ public void setGrpcRequestExecutorStarted(boolean grpcRequestExecutorStarted) { isGrpcRequestExecutorStarted = grpcRequestExecutorStarted; } - public AtomicBoolean isWaiting() { - return isWaiting; - } - public void addFuzzFailEventToQueue(FuzzRequestBean requestBean, Throwable e){ fuzzFailRequestQueue.add(Collections.singletonMap(requestBean, e)); } @@ -93,6 +88,9 @@ public Set getPendingIds() { return pendingIds; } + + + public void registerEventForProcessedCC(String controlCommandId, String eventId) { if(StringUtils.isAnyBlank(controlCommandId, eventId)){ return; diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/JdbcHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/JdbcHelper.java index b4081527b..265ce1e79 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/JdbcHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/JdbcHelper.java @@ -85,14 +85,10 @@ public static boolean acquireLockIfPossible() { } public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(JdbcHelper.getNrSecCustomAttribName()); } - private static String getNrSecCustomAttribName() { + public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/R2dbcHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/R2dbcHelper.java index c23e60285..680dec0ec 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/R2dbcHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/R2dbcHelper.java @@ -3,6 +3,7 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.R2DBCVendor; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SQLOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -72,23 +73,12 @@ public static boolean isLockAcquired() { return false; } - public static boolean acquireLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + public static boolean acquireLockIfPossible(VulnerabilityCaseType sqlDbCommand) { + return GenericHelper.acquireLockIfPossible(sqlDbCommand, getNrSecCustomAttribName()); } public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ServletHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ServletHelper.java index 74e03a074..7fd56ec5f 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ServletHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ServletHelper.java @@ -82,19 +82,17 @@ public static K2RequestIdentifier parseFuzzRequestIdentifierHeader(String reques && NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { return k2RequestIdentifierInstance; } - String[] data = StringUtils.splitByWholeSeparatorWorker(requestHeaderVal, SEPARATOR_SEMICOLON, -1, false); + String[] data = StringUtils.splitByWholeSeparatorWorker(requestHeaderVal, SEPARATOR_SEMICOLON, -1, true); - if (data.length >= 5) { + if (data.length >= 8) { k2RequestIdentifierInstance.setApiRecordId(data[0].trim()); k2RequestIdentifierInstance.setRefId(data[1].trim()); k2RequestIdentifierInstance.setRefValue(data[2].trim()); k2RequestIdentifierInstance.setNextStage(APIRecordStatus.valueOf(data[3].trim())); k2RequestIdentifierInstance.setRecordIndex(Integer.parseInt(data[4].trim())); k2RequestIdentifierInstance.setK2Request(true); - if (data.length >= 6 && StringUtils.isNotBlank(data[5])) { - k2RequestIdentifierInstance.setRefKey(data[5].trim()); - } - if (data.length >= 8) { + k2RequestIdentifierInstance.setRefKey(data[5].trim()); + if(!StringUtils.isAnyBlank(data[6], data[7])) { String encryptedData = data[6].trim(); String hashVerifier = data[7].trim(); String filesToCreate = NewRelicSecurity.getAgent().decryptAndVerify(encryptedData, hashVerifier); @@ -103,45 +101,49 @@ public static K2RequestIdentifier parseFuzzRequestIdentifierHeader(String reques return k2RequestIdentifierInstance; } - String[] allFiles = StringUtils.splitByWholeSeparatorWorker(filesToCreate, StringUtils.COMMA_DELIMETER, -1, false); + fileCreationForReplayRequest(filesToCreate, k2RequestIdentifierInstance); + } + } + } + return k2RequestIdentifierInstance; + } - for (int i = 0; i < allFiles.length; i++) { - String tmpFile = allFiles[i].trim(); - if(StringUtils.contains(tmpFile, NR_CSEC_VALIDATOR_HOME_TMP_URL_ENCODED)) { - tmpFile = urlDecode(tmpFile); - } - tmpFile = StringUtils.replace(tmpFile, NR_CSEC_VALIDATOR_HOME_TMP, - NewRelicSecurity.getAgent().getAgentTempDir()); - boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); - try { - if (lockAcquired) { - File fileToCreate = new File(tmpFile); - if (fileToCreate.getParentFile() != null) { - - File parentFile = fileToCreate; - while (parentFile != null && parentFile.getParentFile() != null && !parentFile.getParentFile().exists()) { - parentFile = parentFile.getParentFile(); - } - filesToRemove.add(parentFile.getAbsolutePath()); - fileToCreate.getParentFile().mkdirs(); - } - if (!fileToCreate.exists()) { - Files.createFile(fileToCreate.toPath()); - k2RequestIdentifierInstance.getTempFiles().add(tmpFile); - } - } - } catch (IOException | InvalidPathException ignored) {} - catch (Throwable e) { - String message = "Error while parsing fuzz request : %s"; - NewRelicSecurity.getAgent().log(LogLevel.INFO, String.format(message, e.getMessage()), e, ServletHelper.class.getName()); - } finally { - ThreadLocalLockHelper.releaseLock(); + private static void fileCreationForReplayRequest(String filesToCreate, K2RequestIdentifier k2RequestIdentifierInstance) { + String[] allFiles = StringUtils.splitByWholeSeparatorWorker(filesToCreate, StringUtils.COMMA_DELIMETER, -1, false); + + for (int i = 0; i < allFiles.length; i++) { + String tmpFile = allFiles[i].trim(); + if (StringUtils.contains(tmpFile, NR_CSEC_VALIDATOR_HOME_TMP_URL_ENCODED)) { + tmpFile = urlDecode(tmpFile); + } + tmpFile = StringUtils.replace(tmpFile, NR_CSEC_VALIDATOR_HOME_TMP, + NewRelicSecurity.getAgent().getAgentTempDir()); + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if (lockAcquired) { + File fileToCreate = new File(tmpFile); + if (fileToCreate.getParentFile() != null) { + + File parentFile = fileToCreate; + while (parentFile != null && parentFile.getParentFile() != null && !parentFile.getParentFile().exists()) { + parentFile = parentFile.getParentFile(); } + filesToRemove.add(parentFile.getAbsolutePath()); + fileToCreate.getParentFile().mkdirs(); + } + if (!fileToCreate.exists()) { + Files.createFile(fileToCreate.toPath()); + k2RequestIdentifierInstance.getTempFiles().add(tmpFile); } } + } catch (IOException | InvalidPathException ignored) {} + catch (Throwable e ) { + String message = "Error while parsing fuzz request : %s"; + NewRelicSecurity.getAgent().log(LogLevel.INFO, String.format(message, e.getMessage()), e, ServletHelper.class.getName()); + } finally { + ThreadLocalLockHelper.releaseLock(); } } - return k2RequestIdentifierInstance; } /** 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 a71fce012..ee8aa8315 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 @@ -1,5 +1,6 @@ package com.newrelic.api.agent.security.instrumentation.helpers; +import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.ApplicationURLMapping; import com.newrelic.api.agent.security.schema.RouteSegment; import com.newrelic.api.agent.security.schema.RouteSegments; @@ -31,8 +32,14 @@ public class URLMappingsHelper { add("org.eclipse.jetty.ee8.jsp.JettyJspServlet"); add("org.eclipse.jetty.ee8.servlet.DefaultServlet"); add("org.eclipse.jetty.servlet.NoJspServlet"); - add("javax.faces.webapp.FacesServlet"); add("org.apache.cxf.transport.servlet.CXFServlet"); + add("javax.faces.webapp.FacesServlet"); + add("jakarta.faces.webapp.FacesServlet"); + add("weblogic.servlet.JSPServlet"); + add("weblogic.servlet.FileServlet"); + add("weblogic.management.rest.JerseyServlet"); + add("com.caucho.jsp.XtpServlet"); + add("com.caucho.jsp.JspServlet"); }}; public static Set getApplicationURLMappings() { @@ -57,6 +64,7 @@ public static void addApplicationURLMapping(ApplicationURLMapping mapping) { if (mapping.getHandler() != null){ handlers.add(mapping.getHandler().hashCode()); } + NewRelicSecurity.getAgent().reportURLMapping(); } private synchronized static void generateRouteSegments(String endpoint) { diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/VertxApiEndpointUtils.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/VertxApiEndpointUtils.java new file mode 100644 index 000000000..47de7398a --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/VertxApiEndpointUtils.java @@ -0,0 +1,179 @@ +package com.newrelic.api.agent.security.instrumentation.helpers; + +import com.newrelic.api.agent.security.NewRelicSecurity; +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.schema.helper.VertxRoute; +import com.newrelic.api.agent.security.utils.logging.LogLevel; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +public class VertxApiEndpointUtils { + + private static final class InstanceHolder { + static final VertxApiEndpointUtils instance = new VertxApiEndpointUtils(); + } + private final String VERTX_FRAMEWORK = "VERTX-FRAMEWORK"; + + public static VertxApiEndpointUtils getInstance() { + return InstanceHolder.instance; + } + + private VertxApiEndpointUtils() {} + + private final Map> routes = new ConcurrentHashMap<>(); + + private void clear(){ + routes.clear(); + } + + private void addRouteImpl(int routerHashCode, int routeHashCode) throws Exception { + boolean isLockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if (isLockAcquired) { + VertxRoute route = new VertxRoute(routerHashCode, routeHashCode); + if (!routes.containsKey(routerHashCode)) { + routes.put(routerHashCode, new ConcurrentHashMap<>()); + } + routes.get(routerHashCode).put(routeHashCode, route); + } + } finally { + if (isLockAcquired) { + ThreadLocalLockHelper.releaseLock(); + } + } + } + + public void addRouteImpl(int routerHashCode, int routeHashCode, String path, String pattern, String method){ + try { + addRouteImpl(routerHashCode, routeHashCode); + if (!routes.containsKey(routerHashCode)){ + return; + } + VertxRoute route = routes.get(routerHashCode).get(routeHashCode); + if (route == null){ + return; + } + if (path != null) { + route.setPath(path); + } + if (pattern != null) { + route.setPattern(pattern); + } + if (method != null) { + route.getMethods().add(method); + } + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, VERTX_FRAMEWORK, e.getMessage()), e, VertxApiEndpointUtils.class.getName()); + } + } + + public void addHandlerClass(int routerHashCode, int routeHashCode, String handlerName){ + try { + if (!routes.containsKey(routerHashCode)){ + return; + } + VertxRoute route = routes.get(routerHashCode).get(routeHashCode); + if (route == null || !Objects.isNull(route.getHandlerName())){ + return; + } + route.setHandlerName(handlerName); + } catch (Exception e) {} + } + + public void resolveSubRoutes(int parentRouterHashCode, int childRouterHashCode, String path){ + try { + if (path == null || !routes.containsKey(childRouterHashCode) || !routes.containsKey(parentRouterHashCode)){ + return; + } + + for (Map.Entry vertxRoute : routes.get(childRouterHashCode).entrySet()) { + VertxRoute route = vertxRoute.getValue(); + if (StringUtils.equalsAny(route.getHandlerName(), "io.vertx.ext.web.handler.impl.BodyHandlerImpl", "io.vertx.ext.web.handler.BodyHandler")){ + continue; + } + String subRoutePath = getPath(route.getPath(), route.getPattern()); + route.setPath(StringUtils.removeEnd(path, StringUtils.SEPARATOR) + StringUtils.prependIfMissing(subRoutePath, StringUtils.SEPARATOR)); + route.setRouterHashCode(parentRouterHashCode); + routes.get(parentRouterHashCode).put(route.getRouteHashCode(), route); + } + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, VERTX_FRAMEWORK, e.getMessage()), e, VertxApiEndpointUtils.class.getName()); + } + } + + public void generateAPIEndpoints(int routerHashCode){ + if (!routes.containsKey(routerHashCode)){ + return; + } + for (Map.Entry vertxRoute : routes.get(routerHashCode).entrySet()){ + VertxRoute routeImpl = vertxRoute.getValue(); + String handlerName = routeImpl.getHandlerName(); + if (StringUtils.equalsAny(handlerName, "io.vertx.ext.web.handler.impl.BodyHandlerImpl", "io.vertx.ext.web.handler.BodyHandler")){ + continue; + } + if (handlerName != null){ + handlerName = StringUtils.substringBefore(routeImpl.getHandlerName(), StringUtils.SEPARATOR); + } + if (routeImpl.getMethods().isEmpty()){ + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, getPath(routeImpl.getPath(), routeImpl.getPattern()), handlerName)); + } + for (String method : routeImpl.getMethods()) { + URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(method, getPath(routeImpl.getPath(), routeImpl.getPattern()), handlerName)); + } + } + clear(); + } + + public void removeRouteImpl(int routerHashCode, int routeHashCode){ + try { + if (routes.containsKey(routerHashCode) && routes.get(routerHashCode).containsKey(routeHashCode)){ + VertxRoute route = routes.get(routerHashCode).remove(routeHashCode); + if (route != null && !URLMappingsHelper.getApplicationURLMappings().isEmpty()){ + URLMappingsHelper.getApplicationURLMappings().remove(new ApplicationURLMapping(URLMappingsHelper.WILDCARD, getPath(route.getPath(), route.getPattern()))); + } + } + } catch (Exception e) {} + } + + public String getPath(String path, Object pattern) { + if (path != null){ + return path; + } + if (pattern instanceof Pattern) { + return ((Pattern) pattern).pattern(); + } + if (pattern instanceof String) { + return (String) pattern; + } + return URLMappingsHelper.subResourceSegment; + } + + public void routeDetection(String path, Pattern pattern) { + if (NewRelicSecurity.isHookProcessingActive()){ + String route = StringUtils.EMPTY; + if (path != null){ + route = path; + } else if (pattern != null){ + route = pattern.pattern(); + } + if (URLMappingsHelper.getSegmentCount(NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().getRoute()) == URLMappingsHelper.getSegmentCount(route)) { + return; + } + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().setRoute(route, Objects.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().getFramework(), Framework.SERVLET.name())); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFramework(Framework.VERTX); + } + } + + public void generateAPIEndpointsIfNotPresent(int routeHashCode) { + for (Map.Entry> routesSet : routes.entrySet()) { + if (routesSet.getValue().containsKey(routeHashCode)) { + generateAPIEndpoints(routesSet.getKey()); + } + } + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/AgentMetaData.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/AgentMetaData.java index e7362aa95..dd35b63b0 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/AgentMetaData.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/AgentMetaData.java @@ -1,11 +1,9 @@ package com.newrelic.api.agent.security.schema; import com.newrelic.api.agent.security.schema.annotations.JsonIgnore; +import com.newrelic.api.agent.security.schema.policy.SkipScanParameters; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class AgentMetaData { @@ -26,6 +24,8 @@ public class AgentMetaData { private Map reflectedMetaData; + private SkipScanParameters skipScanParameters; + @JsonIgnore private StackTraceElement[] serviceTrace; @@ -56,6 +56,7 @@ public AgentMetaData() { this.reflectedMetaData = new HashMap<>(); this.appServerInfo = new AppServerInfo(); this.framework = StringUtils.EMPTY; + this.skipScanParameters = new SkipScanParameters(); } public AgentMetaData(AgentMetaData agentMetaData) { @@ -77,6 +78,7 @@ public AgentMetaData(AgentMetaData agentMetaData) { this.foundAnnotedUserLevelServiceMethod = agentMetaData.foundAnnotedUserLevelServiceMethod; this.fromJumpRequiredInStackTrace = agentMetaData.getFromJumpRequiredInStackTrace(); this.framework = agentMetaData.framework; + this.skipScanParameters = agentMetaData.skipScanParameters; } public boolean isTriggerViaRCI() { @@ -219,4 +221,12 @@ public void setFramework(Framework framework) { this.framework = framework.name(); } } + + public SkipScanParameters getSkipScanParameters() { + return skipScanParameters; + } + + public void setSkipScanParameters(SkipScanParameters skipScanParameters) { + this.skipScanParameters = skipScanParameters; + } } 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..1910758bd 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 @@ -1,5 +1,6 @@ package com.newrelic.api.agent.security.schema; +import com.newrelic.api.agent.security.schema.annotations.JsonIgnore; import java.nio.file.Paths; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -7,6 +8,9 @@ public class HttpRequest { public static final String HTTP = "http"; + @JsonIgnore + public static final int MAX_ALLOWED_REQUEST_BODY_LENGTH = 500000; + private StringBuilder body; private boolean dataTruncated; @@ -32,9 +36,28 @@ public class HttpRequest { private Map pathParameterMap; private boolean isRequestParsed; + private boolean isGrpc; + private String route; + private Map customDataType; + + @JsonIgnore + private List pathParameters; + + @JsonIgnore + private Map> queryParameters; + + @JsonIgnore + private Map> requestHeaderParameters; + + @JsonIgnore + private Map> requestBodyParameters; + + @JsonIgnore + private boolean isRequestParametersParsed = false; + public HttpRequest() { this.clientIP = StringUtils.EMPTY; this.body = new StringBuilder(); @@ -50,6 +73,7 @@ public HttpRequest() { this.isRequestParsed = false; this.isGrpc = false; this.route = StringUtils.EMPTY; + this.customDataType = new HashMap<>(); } public HttpRequest(HttpRequest servletInfo) { @@ -67,6 +91,12 @@ public HttpRequest(HttpRequest servletInfo) { this.isRequestParsed = servletInfo.isRequestParsed; this.isGrpc = servletInfo.isGrpc; this.route = servletInfo.route; + this.pathParameterMap = servletInfo.pathParameterMap; + this.queryParameters = servletInfo.queryParameters; + this.requestHeaderParameters = servletInfo.requestHeaderParameters; + this.requestBodyParameters = servletInfo.requestBodyParameters; + this.isRequestParametersParsed = servletInfo.isRequestParametersParsed; + this.customDataType = servletInfo.customDataType; } public String getMethod() { @@ -229,6 +259,51 @@ public void setRoute(String segment, boolean isAlreadyServlet) { this.route = Paths.get(this.route, formatedSegment).normalize().toString(); } } + + public List getPathParameters() { + return pathParameters; + } + + public void setPathParameters(List pathParameters) { + this.pathParameters = pathParameters; + } + + public Map> getQueryParameters() { + return queryParameters; + } + + public void setQueryParameters(Map> queryParameters) { + this.queryParameters = queryParameters; + } + + public Map> getRequestHeaderParameters() { + return requestHeaderParameters; + } + + public void setRequestHeaderParameters(Map> requestHeaderParameters) { + this.requestHeaderParameters = requestHeaderParameters; + } + + public Map> getRequestBodyParameters() { + return requestBodyParameters; + } + + public void setRequestBodyParameters(Map> requestBodyParameters) { + this.requestBodyParameters = requestBodyParameters; + } + + public boolean isRequestParametersParsed() { + return isRequestParametersParsed; + } + + public void setRequestParametersParsed(boolean requestParametersParsed) { + isRequestParametersParsed = requestParametersParsed; + } + + 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/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java index 82808436d..cd35ce8d9 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java @@ -12,8 +12,12 @@ public class StringUtils { public static final String LF = "\n"; public static final int INDEX_NOT_FOUND = -1; public static final String COMMA_DELIMETER = ","; + + public static final String DOT_DELIMITER = "."; + public static final String SEPARATOR = "/"; + /** *

Checks if a CharSequence is not empty (""), not null and not whitespace only.

* @@ -1377,5 +1381,68 @@ public static boolean endsWithAny(final CharSequence sequence, final CharSequenc return false; } + /** + * Removes a char only if it is at the beginning of a source string, + * otherwise returns the source string. + * + *

A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} search char will return the source string.

+ * + *
+     * StringUtils.removeStart(null, *)      = null
+     * StringUtils.removeStart("", *)        = ""
+     * StringUtils.removeStart(*, null)      = *
+     * StringUtils.removeStart("/path", '/') = "path"
+     * StringUtils.removeStart("path", '/')  = "path"
+     * StringUtils.removeStart("path", 0)    = "path"
+     * 
+ * + * @param str the source String to search, may be null. + * @param remove the char to search for and remove. + * @return the substring with the char removed if found, + * {@code null} if null String input. + * @since 3.13.0 + */ + public static String removeStart(final String str, final char remove) { + if (isEmpty(str)) { + return str; + } + return str.charAt(0) == remove ? str.substring(1) : str; + } + + /** + * Removes a substring only if it is at the beginning of a source string, + * otherwise returns the source string. + * + *

A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} search string will return the source string.

+ * + *
+     * StringUtils.removeStart(null, *)      = null
+     * StringUtils.removeStart("", *)        = ""
+     * StringUtils.removeStart(*, null)      = *
+     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
+     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
+     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
+     * StringUtils.removeStart("abc", "")    = "abc"
+     * 
+ * + * @param str the source String to search, may be null + * @param remove the String to search for and remove, may be null + * @return the substring with the string removed if found, + * {@code null} if null String input + * @since 2.1 + */ + public static String removeStart(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + if (str.startsWith(remove)) { + return str.substring(remove.length()); + } + return str; + } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/VulnerabilityCaseType.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/VulnerabilityCaseType.java index 1eb329436..a3d8a31d2 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/VulnerabilityCaseType.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/VulnerabilityCaseType.java @@ -69,7 +69,9 @@ public enum VulnerabilityCaseType { /** JavaScript Injection */ XQUERY_INJECTION("XQUERY_INJECTION"), - CACHING_DATA_STORE("CACHING_DATA_STORE"); + CACHING_DATA_STORE("CACHING_DATA_STORE"), + + SOLR_DB_REQUEST("SOLR_DB_REQUEST"); /** case type. */ diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/annotations/JsonProperty.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/annotations/JsonProperty.java new file mode 100644 index 000000000..19c0e51ed --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/annotations/JsonProperty.java @@ -0,0 +1,14 @@ +package com.newrelic.api.agent.security.schema.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JsonProperty { + + String value() default ""; + +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/helper/VertxRoute.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/helper/VertxRoute.java new file mode 100644 index 000000000..bbd1625c2 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/helper/VertxRoute.java @@ -0,0 +1,83 @@ +package com.newrelic.api.agent.security.schema.helper; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public class VertxRoute { + + private int routerHashCode; + private int routeHashCode; + private String path; + private String pattern; + private Set methods; + private String handlerName; + + public VertxRoute(int routerHashCode, int routeHashCode) { + this.routerHashCode = routerHashCode; + this.routeHashCode = routeHashCode; + this.methods = new HashSet<>(); + } + + public int getRouterHashCode() { + return routerHashCode; + } + + public void setRouterHashCode(int routerHashCode) { + this.routerHashCode = routerHashCode; + } + + public int getRouteHashCode() { + return routeHashCode; + } + + public void setRouteHashCode(int routeHashCode) { + this.routeHashCode = routeHashCode; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getPattern() { + return pattern; + } + + public void setPattern(String pattern) { + this.pattern = pattern; + } + + public Set getMethods() { + return methods; + } + + public void setMethods(Set methods) { + this.methods = methods; + } + + public String getHandlerName() { + return handlerName; + } + + public void setHandlerName(String handlerName) { + this.handlerName = handlerName; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof VertxRoute)) { + return false; + } + return Objects.equals(routerHashCode, ((VertxRoute) obj).routerHashCode) && + Objects.equals(routeHashCode, ((VertxRoute) obj).routeHashCode); + } + + @Override + public int hashCode() { + return Objects.hash(routerHashCode, routeHashCode); + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/SecureCookieOperation.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/SecureCookieOperation.java deleted file mode 100644 index f35208953..000000000 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/SecureCookieOperation.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.newrelic.api.agent.security.schema.operation; - -import com.newrelic.api.agent.security.schema.AbstractOperation; -import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; - -public class SecureCookieOperation extends AbstractOperation { - private String value; - - private boolean isSecure; - private boolean isHttpOnly; - private boolean isSameSiteStrict; - - private String cookie; - - public SecureCookieOperation(String value, String className, String methodName) { - super(className, methodName); - this.setCaseType(VulnerabilityCaseType.SECURE_COOKIE); - this.value = value; - } - - public SecureCookieOperation(String value, boolean isSecure, boolean isHttpOnly, boolean isSameSiteStrict, String cookie, String className, String methodName) { - this(value, className, methodName); - this.isSecure = isSecure; - this.isHttpOnly = isHttpOnly; - this.isSameSiteStrict = isSameSiteStrict; - this.cookie = cookie; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public boolean isSecure() { - return isSecure; - } - - public void setSecure(boolean secure) { - isSecure = secure; - } - - public boolean isHttpOnly() { - return isHttpOnly; - } - - public void setHttpOnly(boolean httpOnly) { - isHttpOnly = httpOnly; - } - - public boolean isSameSiteStrict() { - return isSameSiteStrict; - } - - public void setSameSiteStrict(boolean sameSiteStrict) { - isSameSiteStrict = sameSiteStrict; - } - - public String getCookie() { - return cookie; - } - - public void setCookie(String cookie) { - this.cookie = cookie; - } - - @Override - public boolean isEmpty() { - return (value == null || value.trim().isEmpty()); - } - -} \ No newline at end of file diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/SolrDbOperation.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/SolrDbOperation.java new file mode 100644 index 000000000..ec8ae0353 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/SolrDbOperation.java @@ -0,0 +1,85 @@ +package com.newrelic.api.agent.security.schema.operation; + +import com.newrelic.api.agent.security.schema.AbstractOperation; +import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class SolrDbOperation extends AbstractOperation { + + private String collection; + + private String method; + + private String connectionURL; + + private String path; + + private Map params; + + private List documents; + + public SolrDbOperation(String className, String methodName) { + super(className, methodName); + this.setCaseType(VulnerabilityCaseType.SOLR_DB_REQUEST); + } + + public String getCollection() { + return collection; + } + + public void setCollection(String collection) { + this.collection = collection; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getConnectionURL() { + return connectionURL; + } + + public void setConnectionURL(String connectionURL) { + this.connectionURL = connectionURL; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Map getParams() { + return params; + } + + public void setParams(Map params) { + this.params = params; + } + + public List getDocuments() { + return documents; + } + + public void setDocuments(List documents) { + this.documents = documents; + } + + @Override + public boolean isEmpty() { + return method == null || method.trim().isEmpty() || connectionURL == null || connectionURL.trim().isEmpty() + || path == null || path.trim().isEmpty(); + } +} + diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/AccountInfo.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/AccountInfo.java new file mode 100644 index 000000000..5d79142b1 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/AccountInfo.java @@ -0,0 +1,27 @@ +package com.newrelic.api.agent.security.schema.policy; + +import java.util.List; + +public class AccountInfo { + + private final List accountIds; + + public AccountInfo() { + this.accountIds = null; + } + + public AccountInfo(List accountIds) { + this.accountIds = accountIds; + } + + public List getAccountIds() { + return accountIds; + } + + public boolean isEmpty() { + if(accountIds == null) { + return true; + } + return accountIds.isEmpty(); + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/HttpParameterLocation.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/HttpParameterLocation.java new file mode 100644 index 000000000..97b40ac87 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/HttpParameterLocation.java @@ -0,0 +1,9 @@ +package com.newrelic.api.agent.security.schema.policy; + +public enum HttpParameterLocation { + + QUERY, + PATH, + HEADER, + BODY; +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IASTScan.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IASTScan.java index f010cef9e..c18a9be27 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IASTScan.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IASTScan.java @@ -1,10 +1,14 @@ package com.newrelic.api.agent.security.schema.policy; +import com.newrelic.api.agent.security.schema.annotations.JsonIgnore; + public class IASTScan { - private Boolean enabled = false; + private Boolean enabled = true; private Probing probing = new Probing(); + private Boolean restricted = false; + private RestrictionCriteria restrictionCriteria = new RestrictionCriteria(); /** * No args constructor for use in serialization @@ -36,4 +40,19 @@ public void setProbing(Probing probing) { this.probing = probing; } + public Boolean getRestricted() { + return restricted; + } + + public void setRestricted(Boolean restricted) { + this.restricted = restricted; + } + + public RestrictionCriteria getRestrictionCriteria() { + return restrictionCriteria; + } + + public void setRestrictionCriteria(RestrictionCriteria restrictionCriteria) { + this.restrictionCriteria = restrictionCriteria; + } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IastDetectionCategory.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IastDetectionCategory.java new file mode 100644 index 000000000..25d0439d4 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/IastDetectionCategory.java @@ -0,0 +1,169 @@ +package com.newrelic.api.agent.security.schema.policy; + +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; +import com.newrelic.api.agent.security.schema.annotations.JsonIgnore; + +public class IastDetectionCategory { + + public static final String STR_COMMA = ","; + Boolean sqlInjectionEnabled = false; + Boolean insecureSettingsEnabled = false; + Boolean invalidFileAccessEnabled = false; + Boolean noSqlInjectionEnabled = false; + Boolean rxssEnabled = false; + Boolean commandInjectionEnabled = false; + Boolean ldapInjectionEnabled = false; + Boolean javascriptInjectionEnabled = false; + Boolean xpathInjectionEnabled = false; + Boolean ssrfEnabled = false; + + @JsonIgnore + private String disabledCategoriesCSV; + + public IastDetectionCategory() { + } + + public Boolean getSqlInjectionEnabled() { + return sqlInjectionEnabled; + } + + public void setSqlInjectionEnabled(Boolean sqlInjectionEnabled) { + this.sqlInjectionEnabled = sqlInjectionEnabled; + } + + public Boolean getInsecureSettingsEnabled() { + return insecureSettingsEnabled; + } + + public void setInsecureSettingsEnabled(Boolean insecureSettingsEnabled) { + this.insecureSettingsEnabled = insecureSettingsEnabled; + } + + public Boolean getInvalidFileAccessEnabled() { + return invalidFileAccessEnabled; + } + + public void setInvalidFileAccessEnabled(Boolean invalidFileAccessEnabled) { + this.invalidFileAccessEnabled = invalidFileAccessEnabled; + } + + public Boolean getNoSqlInjectionEnabled() { + return noSqlInjectionEnabled; + } + + public void setNoSqlInjectionEnabled(Boolean noSqlInjectionEnabled) { + this.noSqlInjectionEnabled = noSqlInjectionEnabled; + } + + public Boolean getRxssEnabled() { + return rxssEnabled; + } + + public void setRxssEnabled(Boolean rxssEnabled) { + this.rxssEnabled = rxssEnabled; + } + + public Boolean getCommandInjectionEnabled() { + return commandInjectionEnabled; + } + + public void setCommandInjectionEnabled(Boolean commandInjectionEnabled) { + this.commandInjectionEnabled = commandInjectionEnabled; + } + + public Boolean getLdapInjectionEnabled() { + return ldapInjectionEnabled; + } + + public void setLdapInjectionEnabled(Boolean ldapInjectionEnabled) { + this.ldapInjectionEnabled = ldapInjectionEnabled; + } + + public Boolean getJavascriptInjectionEnabled() { + return javascriptInjectionEnabled; + } + + public void setJavascriptInjectionEnabled(Boolean javascriptInjectionEnabled) { + this.javascriptInjectionEnabled = javascriptInjectionEnabled; + } + + public Boolean getXpathInjectionEnabled() { + return xpathInjectionEnabled; + } + + public void setXpathInjectionEnabled(Boolean xpathInjectionEnabled) { + this.xpathInjectionEnabled = xpathInjectionEnabled; + } + + public Boolean getSsrfEnabled() { + return ssrfEnabled; + } + + public void setSsrfEnabled(Boolean ssrfEnabled) { + this.ssrfEnabled = ssrfEnabled; + } + + public void generateDisabledCategoriesCSV() { + StringBuilder disabledCategoriesCSVBuilder = new StringBuilder(); + if (sqlInjectionEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.SQL_DB_COMMAND); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (insecureSettingsEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.HASH); + disabledCategoriesCSVBuilder.append(STR_COMMA); + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.RANDOM); + disabledCategoriesCSVBuilder.append(STR_COMMA); + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.SECURE_COOKIE); + disabledCategoriesCSVBuilder.append(STR_COMMA); + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.TRUSTBOUNDARY); + disabledCategoriesCSVBuilder.append(STR_COMMA); + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.CRYPTO); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (invalidFileAccessEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.FILE_INTEGRITY); + disabledCategoriesCSVBuilder.append(STR_COMMA); + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.FILE_OPERATION); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (noSqlInjectionEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.NOSQL_DB_COMMAND); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (rxssEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.REFLECTED_XSS); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (commandInjectionEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.SYSTEM_COMMAND); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (ldapInjectionEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.LDAP); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (javascriptInjectionEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.JAVASCRIPT_INJECTION); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (xpathInjectionEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.XPATH); + disabledCategoriesCSVBuilder.append(STR_COMMA); + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.XQUERY_INJECTION); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (ssrfEnabled) { + disabledCategoriesCSVBuilder.append(VulnerabilityCaseType.HTTP_REQUEST); + disabledCategoriesCSVBuilder.append(STR_COMMA); + } + if (disabledCategoriesCSVBuilder.length() > 0) { + disabledCategoriesCSVBuilder.deleteCharAt(disabledCategoriesCSVBuilder.length() - 1); + } + disabledCategoriesCSV = disabledCategoriesCSVBuilder.toString(); + } + + public String getDisabledCategoriesCSV() { + return disabledCategoriesCSV; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/MappingParameter.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/MappingParameter.java new file mode 100644 index 000000000..f4ee7b353 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/MappingParameter.java @@ -0,0 +1,34 @@ +package com.newrelic.api.agent.security.schema.policy; + +import java.util.List; + +public class MappingParameter { + + private boolean enabled; + + private List locations; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public List getLocations() { + return locations; + } + + public void setLocations(List locations) { + this.locations = locations; + } + + public MappingParameter() { + } + + public MappingParameter(boolean enabled, List locations) { + this.enabled = enabled; + this.locations = locations; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/MappingParameters.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/MappingParameters.java new file mode 100644 index 000000000..aa34cbd90 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/MappingParameters.java @@ -0,0 +1,60 @@ +package com.newrelic.api.agent.security.schema.policy; + +import com.newrelic.api.agent.security.schema.annotations.JsonProperty; + +public class MappingParameters { + + private MappingParameter header; + + private MappingParameter body; + + private MappingParameter query; + + private MappingParameter path; + + public MappingParameters() { + this.header = new MappingParameter(); + this.body = new MappingParameter(); + this.query = new MappingParameter(); + this.path = new MappingParameter(); + } + + public MappingParameters(MappingParameter header, MappingParameter body, MappingParameter query, MappingParameter path) { + this.header = header; + this.body = body; + this.query = query; + this.path = path; + } + + public MappingParameter getHeader() { + return header; + } + + public void setHeader(MappingParameter header) { + this.header = header; + } + + public MappingParameter getBody() { + return body; + } + + public void setBody(MappingParameter body) { + this.body = body; + } + + public MappingParameter getQuery() { + return query; + } + + public void setQuery(MappingParameter query) { + this.query = query; + } + + public MappingParameter getPath() { + return path; + } + + public void setPath(MappingParameter path) { + this.path = path; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/RASPScan.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/RASPScan.java new file mode 100644 index 000000000..91c5cc09f --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/RASPScan.java @@ -0,0 +1,17 @@ +package com.newrelic.api.agent.security.schema.policy; + +public class RASPScan { + + private Boolean enabled = false; + + public RASPScan() { + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/RestrictionCriteria.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/RestrictionCriteria.java new file mode 100644 index 000000000..395011a23 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/RestrictionCriteria.java @@ -0,0 +1,40 @@ +package com.newrelic.api.agent.security.schema.policy; + +import java.util.ArrayList; +import java.util.List; + +public class RestrictionCriteria { + + private AccountInfo accountInfo = new AccountInfo(); + + private MappingParameters mappingParameters = new MappingParameters(); + + private List strictMappings = new ArrayList<>(); + + public RestrictionCriteria() { + } + + public AccountInfo getAccountInfo() { + return accountInfo; + } + + public void setAccountInfo(AccountInfo accountInfo) { + this.accountInfo = accountInfo; + } + + public MappingParameters getMappingParameters() { + return mappingParameters; + } + + public void setMappingParameters(MappingParameters mappingParameters) { + this.mappingParameters = mappingParameters; + } + + public List getStrictMappings() { + return strictMappings; + } + + public void setStrictMappings(List strictMappings) { + this.strictMappings = strictMappings; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/ScanSchedule.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/ScanSchedule.java new file mode 100644 index 000000000..22cf5732d --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/ScanSchedule.java @@ -0,0 +1,83 @@ +package com.newrelic.api.agent.security.schema.policy; + +import com.newrelic.api.agent.security.schema.annotations.JsonIgnore; + +import java.util.Date; + +public class ScanSchedule { + + private int duration = -1; + + private String schedule; + + private Date nextScanTime; + + private int delay = 0; + + private boolean collectSamples = false; + + @JsonIgnore + private Date dataCollectionTime; + + @JsonIgnore + private boolean scheduleOnce = true; + + public ScanSchedule() { + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public String getSchedule() { + return schedule; + } + + public void setSchedule(String schedule) { + this.schedule = schedule; + } + + public Date getNextScanTime() { + return nextScanTime; + } + + public void setNextScanTime(Date nextScanTime) { + this.nextScanTime = nextScanTime; + } + + public int getDelay() { + return delay; + } + + public void setDelay(int delay) { + this.delay = delay; + } + + public boolean isCollectSamples() { + return collectSamples; + } + + public void setCollectSamples(boolean collectSamples) { + this.collectSamples = collectSamples; + } + + public Date getDataCollectionTime() { + return dataCollectionTime; + } + + public void setDataCollectionTime(Date dataCollectionTime) { + this.dataCollectionTime = dataCollectionTime; + } + + public boolean isScheduleOnce() { + return scheduleOnce; + } + + public void setScheduleOnce(boolean scheduleOnce) { + this.scheduleOnce = scheduleOnce; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/SkipScan.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/SkipScan.java new file mode 100644 index 000000000..b89eed6b4 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/SkipScan.java @@ -0,0 +1,58 @@ +package com.newrelic.api.agent.security.schema.policy; + +import com.newrelic.api.agent.security.schema.annotations.JsonIgnore; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public class SkipScan { + private List apis = new ArrayList<>(); + + @JsonIgnore + private List apiRoutes = new ArrayList<>(); + + private SkipScanParameters parameters = new SkipScanParameters(); + + private IastDetectionCategory iastDetectionCategory = new IastDetectionCategory(); + + public SkipScan() { + } + + public List getApis() { + return apis; + } + + public void setApis(List apis) { + this.apis = apis; + if(apis != null) { + for (String api : apis) { + apiRoutes.add(Pattern.compile(api)); + } + } + } + + public List getApiRoutes() { + return apiRoutes; + } + + public void setApiRoutes(List apiRoutes) { + this.apiRoutes = apiRoutes; + } + + public SkipScanParameters getParameters() { + return parameters; + } + + public void setParameters(SkipScanParameters parameters) { + this.parameters = parameters; + } + + public IastDetectionCategory getIastDetectionCategory() { + return iastDetectionCategory; + } + + public void setIastDetectionCategory(IastDetectionCategory iastDetectionCategory) { + this.iastDetectionCategory = iastDetectionCategory; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/SkipScanParameters.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/SkipScanParameters.java new file mode 100644 index 000000000..3338c9d84 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/SkipScanParameters.java @@ -0,0 +1,52 @@ +package com.newrelic.api.agent.security.schema.policy; + +import java.util.ArrayList; +import java.util.List; + +public class SkipScanParameters { + + private List header = new ArrayList<>(); + + private List query = new ArrayList<>(); + + private List body = new ArrayList<>(); + + public SkipScanParameters() { + } + + public List getHeader() { + return header; + } + + public List getQuery() { + return query; + } + + public List getBody() { + return body; + } + + public void setHeader(List header) { + this.header = header; + } + + public void setQuery(List query) { + this.query = query; + } + + public void setBody(List body) { + this.body = body; + } + + public void addHeader(String header) { + this.header.add(header); + } + + public void addQuery(String query) { + this.query.add(query); + } + + public void addBody(String body) { + this.body.add(body); + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/StrictMappings.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/StrictMappings.java new file mode 100644 index 000000000..0ea0669e7 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/StrictMappings.java @@ -0,0 +1,53 @@ +package com.newrelic.api.agent.security.schema.policy; + +import java.util.regex.Pattern; + +public class StrictMappings { + + private String route; + + private HttpParameterLocation accountIdLocation; + + private String accountIdKey; + + private Pattern routePattern; + + public StrictMappings() { + } + + public StrictMappings(String route, HttpParameterLocation accountIdLocation, String accountIdKey) { + this.route = route; + this.accountIdLocation = accountIdLocation; + this.accountIdKey = accountIdKey; + this.routePattern = Pattern.compile(route); + } + + public String getRoute() { + return route; + } + + public void setRoute(String route) { + this.route = route; + this.routePattern = Pattern.compile(route); + } + + public HttpParameterLocation getAccountIdLocation() { + return accountIdLocation; + } + + public void setAccountIdLocation(HttpParameterLocation accountIdLocation) { + this.accountIdLocation = accountIdLocation; + } + + public String getAccountIdKey() { + return accountIdKey; + } + + public void setAccountIdKey(String accountIdKey) { + this.accountIdKey = accountIdKey; + } + + public Pattern getRoutePattern() { + return routePattern; + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/VulnerabilityScan.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/VulnerabilityScan.java index 2aad4d717..1a36bf327 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/VulnerabilityScan.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/policy/VulnerabilityScan.java @@ -3,7 +3,7 @@ public class VulnerabilityScan { - private Boolean enabled = false; + private Boolean enabled = true; private IASTScan iastScan = new IASTScan(); private Boolean enableHooks = false; diff --git a/settings.gradle b/settings.gradle index 15c187c6e..a53a1beee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -209,5 +209,14 @@ 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' +include 'instrumentation:solr-4.0.0' +include 'instrumentation:solr-5.0.0' +include 'instrumentation:solr-5.1.0' +include 'instrumentation:solr-7.0.0' +include 'instrumentation:solr-8.0.0' +include 'instrumentation:solr-9.0.0' +include 'instrumentation:graphql-java-16.2' +include 'instrumentation:websphere-liberty-profile-environment-8.5.5.5' include 'instrumentation:http4s-ember-server-2.12_0.23' include 'instrumentation:http4s-ember-server-2.13_0.23' \ No newline at end of file