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..926f06d2e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,122 @@ 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.5.0] - 2024-9-25 +### New features +- Json Version bump to 1.2.9. +- [PR-327](https://github.com/newrelic/csec-java-agent/pull/327) Application endpoint detection for gRPC Server [NR-303616](https://new-relic.atlassian.net/browse/NR-303616) +- [PR-326](https://github.com/newrelic/csec-java-agent/pull/326) Add IAST Scan start time and Traffic Start Time in Health Check [NR-308822](https://new-relic.atlassian.net/browse/NR-308822) +- [PR-320](https://github.com/newrelic/csec-java-agent/pull/320) Add feature to allow IAST Scan Scheduling. [NR-301534](https://new-relic.atlassian.net/browse/NR-301534) + Configuration via yaml: + ```yaml + security: + scan_schedule: + # The delay field specifies the delay in minutes before the IAST scan starts. This allows to schedule the scan to start at a later time. + delay: 0 #In minutes, default is 0 min + + # The duration field specifies the duration of the IAST scan in minutes. This determines how long the scan will run. + duration: 0 #In minutes, default is forever + + # The schedule field specifies a cron expression that defines when the IAST scan should start. + #schedule: "" #By default, schedule is inactive + + # Allow continuously sample collection of IAST events + always_sample_traces: false # Default is false + ``` +- [PR-320](https://github.com/newrelic/csec-java-agent/pull/320) Add feature to ignore IAST Scan of certain APIs, categories, or parameters. [NR-301856](https://new-relic.atlassian.net/browse/NR-301856) + Configuration via yaml: + ```yaml + security: + # The exclude_from_iast_scan configuration allows to specify APIs, parameters, and categories that should not be scanned by Security Agents. + exclude_from_iast_scan: + # The api field specifies list of APIs using regular expression (regex) patterns that follow the syntax of Perl 5. The regex pattern should provide a complete match for the URL without the endpoint. + # Example: + # api: + # - .*account.* + # - .*/\api\/v1\/.*?\/login + api: [] + + # The parameters configuration allows users to specify headers, query parameters, and body keys that should be excluded from IAST scans. + # Example: + # http_request_parameters: + # header: + # - X-Forwarded-For + # query: + # - username + # - password + # body: + # - account.email + # - account.contact + http_request_parameters: + # A list of HTTP header keys. If a request includes any headers with these keys, the corresponding IAST scan will be skipped. + header: [] + # A list of query parameter keys. The presence of these parameters in the request's query string will lead to skipping the IAST scan. + query: [] + # A list of keys within the request body. If these keys are found in the body content, the IAST scan will be omitted. + body: [] + + # The iast_detection_category configuration allows to specify which categories of vulnerabilities should not be detected by Security Agents. + # If any of these categories are set to true, Security Agents will not generate events or flag vulnerabilities for that category. + iast_detection_category: + insecure_settings: false + invalid_file_access: false + sql_injection: false + nosql_injection: false + ldap_injection: false + javascript_injection: false + command_injection: false + xpath_injection: false + ssrf: false + rxss: false + ``` +- [PR-321](https://github.com/newrelic/csec-java-agent/pull/321) Add feature to rate limit the IAST replay requests. [NR-304574](https://new-relic.atlassian.net/browse/NR-304574) + ```yaml + security: + scan_controllers: + # The scan_request_rate_limit configuration allows to specify maximum number of replay request played per minute. + iast_scan_request_rate_limit: 3600 # Number of IAST replay request played per minute, Default is 3600 + ``` +- [PR-315](https://github.com/newrelic/csec-java-agent/pull/315) GraphQL Support : The security agent now also supports GraphQL Version 16.0.0 and above, default is disabled. [NR-299885](https://new-relic.atlassian.net/browse/NR-299885) + +### Fixes +- [PR-322](https://github.com/newrelic/csec-java-agent/pull/322) Report Application endpoints immediately upon detecting new endpoints. [NR-287324](https://new-relic.atlassian.net/browse/NR-287324) +- [PR-323](https://github.com/newrelic/csec-java-agent/pull/323) Extract Server Configuration to resolve IAST localhost connection with application for WebSphere Liberty server [NR-303483](https://new-relic.atlassian.net/browse/NR-303483) +- [PR-327](https://github.com/newrelic/csec-java-agent/pull/327) Fix for User Class Detection in gRPC Server [NR-303616](https://new-relic.atlassian.net/browse/NR-303616) +- [PR-328](https://github.com/newrelic/csec-java-agent/pull/328) Fix for multiple Reflected Events observed in Jersey Framework [NR-307644](https://new-relic.atlassian.net/browse/NR-307644) +- [PR-325](https://github.com/newrelic/csec-java-agent/pull/325) Fix for incorrect Application endpoints detected for Servlet Framework [NR-303615](https://new-relic.atlassian.net/browse/NR-303615) +- [PR-320](https://github.com/newrelic/csec-java-agent/pull/320) Report only uncaught exceptions in IAST Error inbox. [NR-313412](https://new-relic.atlassian.net/browse/NR-313412) + +### 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.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 +132,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/README.md b/README.md index 9bafd1a4c..dc2647886 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The agent automatically instruments the following frameworks. - Resin 3.1.9 to 4.0.x - Jetty 9.3.0.M1 to latest - Mule ESB 3.6 to 3.9.x -- gRPC 1.4.0 to latest** +- gRPC 1.4.0 to latest [**](#grpc-instrumentation) - Jersey 2.0 to latest - Akka Server 10.0 to latest (with scala 2.11 and above) - Spray Can 1.3.1 to latest (with scala 2.11 and above) @@ -42,8 +42,18 @@ The agent automatically instruments the following frameworks. - Netty Server 4.0.0.Final to latest - Netty Reactor Server 0.7.0.RELEASE to latest - Vertx web 3.2.0 to latest - -** IAST for **gRPC** requires the dependency [protobuf-java-util](https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util) for IAST request replay. +- GraphQL 16.0.0 to latest [**](#graphql-instrumentation) + +#### gRPC Instrumentation +IAST for **gRPC** requires the dependency [protobuf-java-util](https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util) for IAST request replay. + +#### GraphQL Instrumentation +By default, GraphQL instrumentation is disabled in IAST as it is an experimental feature. To take advantage of this feature enable GraphQL instrumentation, update your configuration by adding the following settings under the class_transformer section: +```yaml +class_transformer: + com.newrelic.instrumentation.security.graphql-java-16.2: + enabled: true +``` ### Java Native Operations diff --git a/buildSrc/src/main/java/com/nr/builder/publish/PublishConfig.java b/buildSrc/src/main/java/com/nr/builder/publish/PublishConfig.java index 49d093863..46b593994 100644 --- a/buildSrc/src/main/java/com/nr/builder/publish/PublishConfig.java +++ b/buildSrc/src/main/java/com/nr/builder/publish/PublishConfig.java @@ -75,7 +75,7 @@ private static void configureRepo(MavenArtifactRepository repo, String projectVe private static void configurePom(MavenPom pom) { pom.getUrl().set("https://github.com/newrelic/csec-java-agent"); pom.licenses(spec -> spec.license(license -> { - license.getName().set("New Relic Pre-Release Software License"); + license.getName().set("New Relic Software License, Version 1.0"); license.getUrl().set("https://github.com/newrelic/csec-java-agent/blob/main/LICENSE.md"); license.getDistribution().set("repo"); })); diff --git a/gradle.properties b/gradle.properties index 8e99a4eca..31b3918f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # The agent version. -agentVersion=1.4.0 -jsonVersion=1.2.3 +agentVersion=1.5.0 +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/build.gradle b/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle index bb0a864d5..fc1b714d1 100644 --- a/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle +++ b/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle @@ -13,6 +13,7 @@ jar { verifyInstrumentation { passesOnly 'org.graalvm.js:js:[22.0.0,)' + exclude('org.graalvm.js:js:24.1.0') // excludeRegex '.*-rc[0-9]+' } 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..ee706f615 --- /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', 'Enabled': 'false' } +} + +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-1.4.0/build.gradle b/instrumentation-security/jedis-1.4.0/build.gradle index 0646a65ca..aed46fd2d 100644 --- a/instrumentation-security/jedis-1.4.0/build.gradle +++ b/instrumentation-security/jedis-1.4.0/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:1.4.0") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { diff --git a/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle b/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle index 285624fd5..613c97e0c 100644 --- a/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle +++ b/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:2.7.1") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { 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/build.gradle b/instrumentation-security/jedis-3.0.0/build.gradle index ebc2c0673..fc133df28 100644 --- a/instrumentation-security/jedis-3.0.0/build.gradle +++ b/instrumentation-security/jedis-3.0.0/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:3.0.0") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { 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/build.gradle b/instrumentation-security/jedis-4.0.0/build.gradle index 3a727d375..27d4f895f 100644 --- a/instrumentation-security/jedis-4.0.0/build.gradle +++ b/instrumentation-security/jedis-4.0.0/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:4.0.0") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { 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/ApplicationHandler_Handler.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java index 09844d08b..cf8c9867d 100644 --- a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java +++ b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java @@ -7,14 +7,12 @@ package com.newrelic.agent.security.instrumentation.jersey2; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.server.ContainerRequest; -import java.io.OutputStream; - @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ApplicationHandler") public abstract class ApplicationHandler_Handler { @@ -24,6 +22,7 @@ public void handle(ContainerRequest requestContext) { if (requestContext != null) { isRequestLockAcquired = HttpRequestHelper.acquireRequestLockIfPossible(); if (isRequestLockAcquired) { + GenericHelper.acquireLockIfPossible(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.preprocessSecurityHook(requestContext); HttpRequestHelper.registerUserLevelCode("JERSEY"); } @@ -32,6 +31,7 @@ public void handle(ContainerRequest requestContext) { } finally { if(isRequestLockAcquired){ HttpRequestHelper.releaseRequestLock(); + GenericHelper.releaseLock(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); } } } 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..6e58136bb 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; @@ -18,9 +19,6 @@ import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.server.ContainerRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import static com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper.SERVLET_GET_IS_OPERATION_LOCK; @@ -32,7 +30,7 @@ public abstract class ContainerResponse_Instrumentation { NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); } - if(response != null && response.getContext() != null && response.getContext().hasEntity()){ + if(GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()) && response != null && response.getContext() != null && response.getContext().hasEntity()){ Object responseObject = response.getContext().getEntity(); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(String.valueOf(responseObject))); } @@ -43,8 +41,8 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); - if(isLockAcquired) { + isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); + if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } Weaver.callOriginal(); 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..377b367dc 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 @@ -27,17 +27,12 @@ public class HttpRequestHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REQUEST_LOCK-"; - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING = "JERSEY_LOCK_POST_PROCESSING-"; public static final String HEADER_SEPARATOR = ";"; - public static final String GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "GRIZZLY_REQUEST_PROPERTIES_DELEGATE"; - public static final String GRIZZLY_REQUEST = "GRIZZLY_REQUEST"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - public static final String ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST = "org.glassfish.grizzly.http.server.Request"; public static final String FIELD_REQUEST = "request"; public static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; public static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; @@ -45,18 +40,11 @@ public class HttpRequestHelper { public static final String METHOD_GET_SCHEME = "getScheme"; public static final String METHOD_GET_CONTENT_TYPE = "getContentType"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; - public static final String TRACING_AWARE_PROPERTIES_DELEGATE = "TRACING_AWARE_PROPERTIES_DELEGATE"; public static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; public static final String JERSEY_2_16 = "JERSEY-2.16"; - public static Class grizzlyRequestPropertiesDelegateKlass = null; - - public static Class grizzlyRequest = null; - - public static Class tracingAwarePropertiesDelegateKlass = null; - public static void preprocessSecurityHook(ContainerRequest requestContext) { try { if (!NewRelicSecurity.isHookProcessingActive()) { @@ -90,7 +78,7 @@ public static void preprocessSecurityHook(ContainerRequest requestContext) { public static void postProcessSecurityHook(String className, OutboundMessageContext wrappedMessageContext) { try { - if (!NewRelicSecurity.isHookProcessingActive() + if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -196,7 +184,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isRequestLockAcquired() { + private static boolean isRequestLockAcquired() { try { return NewRelicSecurity.isHookProcessingActive() && Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); @@ -227,25 +215,30 @@ private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } + public static String getNrSecCustomAttribForPostProcessing() { + return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); + } + 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_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 +246,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 +261,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.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java index d3ccc680e..19fb1f5d3 100644 --- a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java +++ b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java @@ -56,7 +56,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SecurityInstrumentationTestRunner.class) -@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2", "org.glassfish.jersey"}) +@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2"}) @Category({ Java9IncompatibleTest.class, Java11IncompatibleTest.class, Java17IncompatibleTest.class }) public class JerseyTests { @@ -203,6 +203,7 @@ private void assertOperation(List operations, boolean hasHead assertEquals(MediaType.TEXT_HTML, response.getResponseContentType()); assertEquals(2, responseBody.length); assertEquals(responseBody[0], response.getResponseBody().toString()); + assertFalse(hashCode.isEmpty()); assertEquals(Collections.singleton(Integer.parseInt(responseBody[1])), hashCode); } private static void getRandomPort() diff --git a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java index 299b050d7..41b746c17 100644 --- a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java +++ b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java @@ -19,28 +19,13 @@ public class Resource { @GET @Path("/sync") public String syncEndpoint(@DefaultValue("param") @QueryParam("param") final String param) { - return param; + return "sync result"; } @GET @Path("/async") public void resume(@DefaultValue("1") @QueryParam("sleep") final int sleepMillis, @Suspended final AsyncResponse response) { - new Thread(new Runnable() { - @Override - public void run() { - String result = veryExpensiveOperation(sleepMillis); - response.resume(result); - } - - private String veryExpensiveOperation(int sleepMillis) { - long currentTime = System.currentTimeMillis(); - long endTime = currentTime + sleepMillis; - while (currentTime < endTime) { - currentTime = System.currentTimeMillis(); - } - return "async resume at " + System.currentTimeMillis(); - } - }).start(); + response.resume("async result"); } } diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java index 09844d08b..dfa9ac4dd 100644 --- a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java +++ b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java @@ -7,14 +7,12 @@ package com.newrelic.agent.security.instrumentation.jersey2; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.server.ContainerRequest; -import java.io.OutputStream; - @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ApplicationHandler") public abstract class ApplicationHandler_Handler { @@ -24,6 +22,7 @@ public void handle(ContainerRequest requestContext) { if (requestContext != null) { isRequestLockAcquired = HttpRequestHelper.acquireRequestLockIfPossible(); if (isRequestLockAcquired) { + GenericHelper.acquireLockIfPossible(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.preprocessSecurityHook(requestContext); HttpRequestHelper.registerUserLevelCode("JERSEY"); } @@ -31,6 +30,7 @@ public void handle(ContainerRequest requestContext) { Weaver.callOriginal(); } finally { if(isRequestLockAcquired){ + GenericHelper.releaseLock(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.releaseRequestLock(); } } 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..6271a01e4 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; @@ -28,7 +29,7 @@ public abstract class ContainerResponse_Instrumentation { NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); } - if(response != null && response.getContext() != null && response.getContext().hasEntity()){ + if(GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()) && response != null && response.getContext() != null && response.getContext().hasEntity()){ Object responseObject = response.getContext().getEntity(); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(String.valueOf(responseObject))); } @@ -39,8 +40,8 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); - if(isLockAcquired) { + isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); + if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } Weaver.callOriginal(); 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..a060e849f 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 @@ -27,17 +27,12 @@ public class HttpRequestHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REQUEST_LOCK-"; - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING = "JERSEY_LOCK_POST_PROCESSING-"; public static final String HEADER_SEPARATOR = ";"; - public static final String GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "GRIZZLY_REQUEST_PROPERTIES_DELEGATE"; - public static final String GRIZZLY_REQUEST = "GRIZZLY_REQUEST"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - public static final String ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST = "org.glassfish.grizzly.http.server.Request"; public static final String FIELD_REQUEST = "request"; public static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; public static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; @@ -45,7 +40,6 @@ public class HttpRequestHelper { public static final String METHOD_GET_SCHEME = "getScheme"; public static final String METHOD_GET_CONTENT_TYPE = "getContentType"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; - public static final String TRACING_AWARE_PROPERTIES_DELEGATE = "TRACING_AWARE_PROPERTIES_DELEGATE"; public static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; @@ -53,12 +47,6 @@ public class HttpRequestHelper { public static final String HEADER_CONTENT_TYPE = "contenttype"; public static final String JERSEY_2 = "JERSEY-2"; - public static Class grizzlyRequestPropertiesDelegateKlass = null; - - public static Class grizzlyRequest = null; - - public static Class tracingAwarePropertiesDelegateKlass = null; - public static void preprocessSecurityHook(ContainerRequest requestContext) { try { if (!NewRelicSecurity.isHookProcessingActive()) { @@ -92,8 +80,7 @@ public static void preprocessSecurityHook(ContainerRequest requestContext) { public static void postProcessSecurityHook(String className, OutboundMessageContext wrappedMessageContext) { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -229,25 +216,30 @@ private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } + public static String getNrSecCustomAttribForPostProcessing() { + return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); + } + 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 +247,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 +262,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/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java index f418c45e8..fe5b4e607 100644 --- a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java +++ b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java @@ -56,7 +56,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SecurityInstrumentationTestRunner.class) -@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2", "org.glassfish.jersey"}) +@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2"}) @Category({ Java9IncompatibleTest.class, Java11IncompatibleTest.class, Java17IncompatibleTest.class }) public class JerseyTests { @@ -206,6 +206,7 @@ private void assertOperation(List operations, boolean hasHead assertEquals(MediaType.TEXT_HTML, response.getResponseContentType()); assertEquals(2, responseBody.length); assertEquals(responseBody[0], response.getResponseBody().toString()); + assertFalse(hashCode.isEmpty()); assertEquals(Collections.singleton(Integer.parseInt(responseBody[1])), hashCode); } private static void getRandomPort() diff --git a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java index 299b050d7..41b746c17 100644 --- a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java +++ b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java @@ -19,28 +19,13 @@ public class Resource { @GET @Path("/sync") public String syncEndpoint(@DefaultValue("param") @QueryParam("param") final String param) { - return param; + return "sync result"; } @GET @Path("/async") public void resume(@DefaultValue("1") @QueryParam("sleep") final int sleepMillis, @Suspended final AsyncResponse response) { - new Thread(new Runnable() { - @Override - public void run() { - String result = veryExpensiveOperation(sleepMillis); - response.resume(result); - } - - private String veryExpensiveOperation(int sleepMillis) { - long currentTime = System.currentTimeMillis(); - long endTime = currentTime + sleepMillis; - while (currentTime < endTime) { - currentTime = System.currentTimeMillis(); - } - return "async resume at " + System.currentTimeMillis(); - } - }).start(); + response.resume("async result"); } } diff --git a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java index a810e8bb6..97097940f 100644 --- a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java +++ b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java @@ -7,14 +7,12 @@ package com.newrelic.agent.security.instrumentation.jersey2; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.server.ContainerRequest; -import java.io.OutputStream; - @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ApplicationHandler") public final class ApplicationHandler_Handler { @@ -24,6 +22,7 @@ public void handle(final ContainerRequest request) { if (request != null) { isRequestLockAcquired = HttpRequestHelper.acquireRequestLockIfPossible(); if (isRequestLockAcquired) { + GenericHelper.acquireLockIfPossible(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.preprocessSecurityHook(request); HttpRequestHelper.registerUserLevelCode("JERSEY"); } @@ -31,6 +30,7 @@ public void handle(final ContainerRequest request) { Weaver.callOriginal(); } finally { if(isRequestLockAcquired){ + GenericHelper.releaseLock(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.releaseRequestLock(); } } 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..6271a01e4 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; @@ -18,17 +19,17 @@ import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.server.ContainerRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper.SERVLET_GET_IS_OPERATION_LOCK; @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ContainerResponse") public abstract class ContainerResponse_Instrumentation { ContainerResponse_Instrumentation(final ContainerRequest requestContext, final OutboundJaxrsResponse response) { - if(response != null && response.getContext() != null && response.getContext().hasEntity()){ + if(response != null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); + } + + if(GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()) && response != null && response.getContext() != null && response.getContext().hasEntity()){ Object responseObject = response.getContext().getEntity(); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(String.valueOf(responseObject))); } @@ -39,8 +40,8 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); - if(isLockAcquired) { + isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); + if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } Weaver.callOriginal(); 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..14d88c1af 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 @@ -27,17 +27,12 @@ public class HttpRequestHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REQUEST_LOCK-"; - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING = "JERSEY_LOCK_POST_PROCESSING-"; public static final String HEADER_SEPARATOR = ";"; - public static final String GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "GRIZZLY_REQUEST_PROPERTIES_DELEGATE"; - public static final String GRIZZLY_REQUEST = "GRIZZLY_REQUEST"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - public static final String ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST = "org.glassfish.grizzly.http.server.Request"; public static final String FIELD_REQUEST = "request"; public static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; public static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; @@ -45,18 +40,11 @@ public class HttpRequestHelper { public static final String METHOD_GET_SCHEME = "getScheme"; public static final String METHOD_GET_CONTENT_TYPE = "getContentType"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; - public static final String TRACING_AWARE_PROPERTIES_DELEGATE = "TRACING_AWARE_PROPERTIES_DELEGATE"; public static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; public static final String JERSEY_3 = "JERSEY-3"; - public static Class grizzlyRequestPropertiesDelegateKlass = null; - - public static Class grizzlyRequest = null; - - public static Class tracingAwarePropertiesDelegateKlass = null; - public static void preprocessSecurityHook(ContainerRequest requestContext) { try { if (!NewRelicSecurity.isHookProcessingActive()) { @@ -227,25 +215,30 @@ private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } + public static String getNrSecCustomAttribForPostProcessing() { + return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); + } + 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 +246,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 +261,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/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java index 85ec2d538..0ccf39689 100644 --- a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java +++ b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java @@ -55,7 +55,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SecurityInstrumentationTestRunner.class) -@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2", "org.glassfish.jersey"}) +@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2"}) @Category({Java8IncompatibleTest.class, Java11IncompatibleTest.class}) public class JerseyTests { @@ -203,6 +203,7 @@ private void assertOperation(List operations, boolean hasHead assertEquals(MediaType.TEXT_HTML, response.getResponseContentType()); assertEquals(2, responseBody.length); assertEquals(responseBody[0], response.getResponseBody().toString()); + assertFalse(hashCode.isEmpty()); assertEquals(Collections.singleton(Integer.parseInt(responseBody[1])), hashCode); } private static void getRandomPort() diff --git a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java index 921a6350c..a9a8777c9 100644 --- a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java +++ b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java @@ -19,28 +19,13 @@ public class Resource { @GET @Path("/sync") public String syncEndpoint(@DefaultValue("param") @QueryParam("param") final String param) { - return param; + return "sync result"; } @GET @Path("/async") public void resume(@DefaultValue("1") @QueryParam("sleep") final int sleepMillis, @Suspended final AsyncResponse response) { - new Thread(new Runnable() { - @Override - public void run() { - String result = veryExpensiveOperation(sleepMillis); - response.resume(result); - } - - private String veryExpensiveOperation(int sleepMillis) { - long currentTime = System.currentTimeMillis(); - long endTime = currentTime + sleepMillis; - while (currentTime < endTime) { - currentTime = System.currentTimeMillis(); - } - return "async resume at " + System.currentTimeMillis(); - } - }).start(); + response.resume("async result"); } } 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..bd8ca5aed 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; @@ -126,7 +127,7 @@ public static void releaseServletLock() { } private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; + return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) { @@ -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..b015e742f 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 @@ -26,11 +26,9 @@ public class HttpServletHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String SERVICE_METHOD_NAME = "handle"; - public static final String SERVICE_ASYNC_METHOD_NAME = "handleAsync"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "JETTY_SERVLET_LOCK-"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; public static final String JETTY_12 = "JETTY-12"; public static void processHttpRequestHeader(Request request, HttpRequest securityRequest) { @@ -127,7 +125,7 @@ public static void releaseServletLock() { } private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; + return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static void preprocessSecurityHook(Request request) { @@ -177,8 +175,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..685b15fbf 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; @@ -127,7 +128,7 @@ public static void releaseServletLock() { } private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; + return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) { @@ -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/build.gradle b/instrumentation-security/lettuce-5.0/build.gradle index 79018d90d..7feeb4409 100644 --- a/instrumentation-security/lettuce-5.0/build.gradle +++ b/instrumentation-security/lettuce-5.0/build.gradle @@ -3,7 +3,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation group: 'io.lettuce', name: 'lettuce-core', version: '5.0.3.RELEASE' - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } jar { 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..06b0c88ea 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); } @@ -78,17 +80,19 @@ private static void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // 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 +111,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..8ab323966 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 { @@ -72,17 +74,18 @@ private void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // 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 +104,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..cdcec7a2f 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); } @@ -78,17 +80,18 @@ private static void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // 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 +110,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..228220de6 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) { @@ -72,17 +75,18 @@ private void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // 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 +105,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/netty-reactor-0.7.0/src/test/java/com/nr/agent/security/instrumentation/netty_reactor/APIEndpointTest.java b/instrumentation-security/netty-reactor-0.7.0/src/test/java/com/nr/agent/security/instrumentation/netty_reactor/APIEndpointTest.java new file mode 100644 index 000000000..ef7971c26 --- /dev/null +++ b/instrumentation-security/netty-reactor-0.7.0/src/test/java/com/nr/agent/security/instrumentation/netty_reactor/APIEndpointTest.java @@ -0,0 +1,74 @@ +package com.nr.agent.security.instrumentation.netty_reactor; + +import com.newrelic.agent.security.introspec.InstrumentationTestConfig; +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 io.netty.handler.codec.http.HttpMethod; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; +import reactor.ipc.netty.http.server.HttpServer; +import reactor.ipc.netty.tcp.BlockingNettyContext; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@RunWith(SecurityInstrumentationTestRunner.class) +@InstrumentationTestConfig(includePrefixes = "reactor.ipc.netty.http.server") +public class APIEndpointTest { + private static BlockingNettyContext server; + @BeforeClass + public static void beforeClass() throws Exception { + server = HttpServer + .create(SecurityInstrumentationTestRunner.getIntrospector().getRandomPort()) + .startRouter(r -> r + .post("/file/{path}", (req, res) -> res.send()) + .get("/echo/{param}", (req, res) -> res.send()) + .get("/check", (req, res) -> res.sendString(Mono.just("Check Response data sent..."))) + .route( + httpServerRequest -> httpServerRequest.uri().equals("/test") && httpServerRequest.method().equals(HttpMethod.GET), + (req, res) -> res.send(req.receive().retain())) + .ws("/ws", (req, res) -> res.send(req.receive().retain())) + .get("/echo/{param}", (req, res) -> res.send()) + ); + } + + @AfterClass + public static void afterClass() throws Exception { + if (server != null){ + server.shutdown(); + } + } + + @Test + public void apiEndpointTest() { + String handler = "com.nr.agent.security.instrumentation.netty_reactor.APIEndpointTest$$Lambda$"; + String wsHandler = "reactor.ipc.netty.http.server.HttpServerRoutes$$Lambda$"; + Map expectedMappings = new HashMap<>(); + expectedMappings.put("/file/{path}", "POST"); + expectedMappings.put("/echo/{param}", "GET"); + expectedMappings.put("/check", "GET"); + expectedMappings.put("/*", "*"); + expectedMappings.put("/ws", "GET"); + + Set actualMappings = URLMappingsHelper.getApplicationURLMappings(); + for (ApplicationURLMapping actualMapping : actualMappings) { + Assert.assertNotNull(actualMapping.getMethod()); + Assert.assertNotNull(actualMapping.getPath()); + Assert.assertNotNull(actualMapping.getHandler()); + + + Assert.assertEquals(expectedMappings.get(actualMapping.getPath()), actualMapping.getMethod()); + if (!actualMapping.getPath().equals("/ws")) { + Assert.assertTrue(actualMapping.getHandler().startsWith(handler)); + } else { + Assert.assertTrue(actualMapping.getHandler().startsWith(wsHandler)); + } + } + } +} diff --git a/instrumentation-security/netty-reactor-0.8.0/src/test/java/com/nr/agent/security/instrumentation/netty_reactor/APIEndpointTest.java b/instrumentation-security/netty-reactor-0.8.0/src/test/java/com/nr/agent/security/instrumentation/netty_reactor/APIEndpointTest.java new file mode 100644 index 000000000..958e51ceb --- /dev/null +++ b/instrumentation-security/netty-reactor-0.8.0/src/test/java/com/nr/agent/security/instrumentation/netty_reactor/APIEndpointTest.java @@ -0,0 +1,75 @@ +package com.nr.agent.security.instrumentation.netty_reactor; + +import com.newrelic.agent.security.introspec.InstrumentationTestConfig; +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 io.netty.handler.codec.http.HttpMethod; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; +import reactor.netty.DisposableServer; +import reactor.netty.http.server.HttpServer; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@RunWith(SecurityInstrumentationTestRunner.class) +@InstrumentationTestConfig(includePrefixes = "reactor.netty.http.server") +public class APIEndpointTest { + private static DisposableServer server; + @BeforeClass + public static void beforeClass() { + server = HttpServer + .create() + .port(SecurityInstrumentationTestRunner.getIntrospector().getRandomPort()) + .route(r -> r + .post("/file/{path}", (req, res) -> res.send()) + .get("/echo/{param}", (req, res) -> res.send()) + .get("/check", (req, res) -> res.sendString(Mono.just("Check Response data sent..."))) + .route( + httpServerRequest -> httpServerRequest.uri().equals("/test") && httpServerRequest.method().equals(HttpMethod.GET), + (req, res) -> res.send(req.receive().retain())) + .ws("/ws", (req, res) -> res.send(req.receive().retain())) + .get("/echo/{param}", (req, res) -> res.send()) + ).bindNow(); + } + + @AfterClass + public static void afterClass() throws Exception { + if (server != null){ + server.dispose(); + } + } + + @Test + public void apiEndpointTest() { + String handler = "com.nr.agent.security.instrumentation.netty_reactor.APIEndpointTest$$Lambda$"; + String wsHandler = "reactor.netty.http.server.HttpServerRoutes$$Lambda$"; + Map expectedMappings = new HashMap<>(); + expectedMappings.put("/file/{path}", "POST"); + expectedMappings.put("/echo/{param}", "GET"); + expectedMappings.put("/check", "GET"); + expectedMappings.put("/*", "*"); + expectedMappings.put("/ws", "GET"); + + Set actualMappings = URLMappingsHelper.getApplicationURLMappings(); + for (ApplicationURLMapping actualMapping : actualMappings) { + Assert.assertNotNull(actualMapping.getMethod()); + Assert.assertNotNull(actualMapping.getPath()); + Assert.assertNotNull(actualMapping.getHandler()); + + + Assert.assertEquals(expectedMappings.get(actualMapping.getPath()), actualMapping.getMethod()); + if (!actualMapping.getPath().equals("/ws")) { + Assert.assertTrue(actualMapping.getHandler().startsWith(handler)); + } else { + Assert.assertTrue(actualMapping.getHandler().startsWith(wsHandler)); + } + } + } +} 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 9e2c5768e..31a1a2bc5 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 @@ -75,6 +75,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 27adc1296..808f0e9be 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 @@ -74,6 +74,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..39475f565 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,239 @@ 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(); + + // Set required LogLevel + logLevel = applyRequiredLogLevel(); + + 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 +299,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 +317,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 +366,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 +391,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 +434,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..a08ba5e68 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 @@ -4,6 +4,7 @@ import com.newrelic.agent.security.instrumentator.httpclient.IASTDataTransferRequestProcessor; import com.newrelic.agent.security.intcodeagent.constants.AgentServices; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.websocket.WSUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.DeployedApplication; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; @@ -427,22 +428,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 +652,10 @@ private void applyNRPolicyOverride() { public static void sendApplicationURLMappings() { - //TODO mappings to be send once new mappings are discovered, after startup. + if (!WSUtils.isConnected()){ + NewRelicSecurity.getAgent().reportURLMapping(); + return; + } 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..ffaef9139 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,44 @@ 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; + 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 + osVariables = OsVariablesInstance.getInstance().getOsVariables(); 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 +87,6 @@ public Thread newThread(Runnable r) { return t; } }); - try { - if(LogFileHelper.isLoggingToStdOut()){ - this.isLoggingToStdOut = true; - } - } catch (NumberFormatException e){} - } @@ -122,14 +141,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 +156,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 +167,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 +211,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 da910b3dd..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,6 +405,8 @@ 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)); @@ -300,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; } @@ -307,27 +432,39 @@ 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); - operation.setUserClassEntity(setUserClassEntity(operation, securityMetaData)); + if(operation.getUserClassEntity() == null || !operation.getUserClassEntity().isCalledByUserCode()){ + operation.setUserClassEntity(setUserClassEntity(operation, securityMetaData)); + } processStackTrace(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()) { @@ -335,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); } } } @@ -353,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; @@ -379,7 +518,7 @@ private String getEndpointRoute(String uri) { } } } - return StringUtils.EMPTY; + return null; } private int jumpRoute(List value, int i1, List uriSegments, int i) { @@ -395,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. @@ -458,7 +620,15 @@ && getInstance().getCurrentPolicy().getProtectionMode().getApiBlocking().getEnab ); } + private UserClassEntity setUserClassEntityByAnnotation(StackTraceElement[] serviceTrace) { + UserClassEntity userClassEntity = new UserClassEntity(); + userClassEntity.setUserClassElement(serviceTrace[0]); + userClassEntity.setCalledByUserCode(true); + return userClassEntity; + } + 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){ @@ -482,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()); } } } @@ -505,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()); @@ -617,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(); } } } @@ -701,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) { @@ -841,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 @@ -906,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 4f9aeba84..dc45f5e08 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"; @@ -50,6 +52,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() && @@ -69,6 +129,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); } @@ -76,4 +140,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 a2212d051..ec9aefcdc 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; @@ -27,6 +28,18 @@ public class URLMappingsHelper { add("org.apache.catalina.servlets.DefaultServlet"); add("org.eclipse.jetty.servlet.DefaultServlet"); add("grails.plugin.databasemigration.DbdocController"); + add("org.springframework.web.servlet.DispatcherServlet"); + add("org.eclipse.jetty.ee8.jsp.JettyJspServlet"); + add("org.eclipse.jetty.ee8.servlet.DefaultServlet"); + add("org.eclipse.jetty.servlet.NoJspServlet"); + 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() { @@ -51,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 ca13695b0..64dd79da8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -209,3 +209,12 @@ 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' \ No newline at end of file