diff --git a/Changelog.md b/Changelog.md index a680acb6d..4b1b049d6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,25 @@ 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.6.0] - 2024-12-16 +### Adds +- [PR-329](https://github.com/newrelic/csec-java-agent/pull/329) Apache Pekko Server Support: The security agent now supports Apache Pekko Server version 1.0.0 and newer, compatible with Scala 2.13 and above. [NR-308780](https://new-relic.atlassian.net/browse/NR-308780), [NR-308781](https://new-relic.atlassian.net/browse/NR-308781), [NR-308791](https://new-relic.atlassian.net/browse/NR-308791), [NR-308792](https://new-relic.atlassian.net/browse/NR-308792) [NR-308782](https://new-relic.atlassian.net/browse/NR-308782) +- [PR-228](https://github.com/newrelic/csec-java-agent/pull/228) HTTP4s Ember Server Support: Added support for HTTP4s Ember Server version 0.23 and newer, compatible with Scala 2.12 and above. [NR-293957](https://new-relic.atlassian.net/browse/NR-293957), [NR-293847](https://new-relic.atlassian.net/browse/NR-293847), [NR-293844](https://new-relic.atlassian.net/browse/NR-293844) +- [PR-344](https://github.com/newrelic/csec-java-agent/pull/344) HTTP4s Blaze Server Support: The security agent now supports HTTP4s Blaze Server version 0.21 and newer, compatible with Scala 2.12 and above. [NR-325523](https://new-relic.atlassian.net/browse/NR-325523), [NR-325525](https://new-relic.atlassian.net/browse/NR-325525), [NR-293846](https://new-relic.atlassian.net/browse/NR-293846) +- [PR-228](https://github.com/newrelic/csec-java-agent/pull/228) HTTP4s Ember Client Support: Introduced support for HTTP4s Ember Client version 0.23 and above, compatible with Scala 2.12 and above. [NR-307676](https://new-relic.atlassian.net/browse/NR-307676) +- [PR-346](https://github.com/newrelic/csec-java-agent/pull/346) HTTP4s Blaze Client Support: Added support for HTTP4s Blaze Client version 0.21 and newer, compatible with Scala 2.12 and above. [NR-325526](https://new-relic.atlassian.net/browse/NR-325526), [NR-325527](https://new-relic.atlassian.net/browse/NR-325527) +- [PR-363](https://github.com/newrelic/csec-java-agent/pull/363) GraphQL Support: GraphQL support is now enabled by default. + +### Changes +- [PR-331](https://github.com/newrelic/csec-java-agent/pull/331) REST Client Update for IAST Request Replay: Migrated to utilize the Apache HTTP Client for enhanced request replay functionality. [NR-283130](https://new-relic.atlassian.net/browse/NR-283130) +- [PR-311](https://github.com/newrelic/csec-java-agent/pull/311) Status File Removed: The status file used for debugging has been eliminated. All debugging capabilities have been integrated into Init Logging or the Error Inbox. [NR-297214](https://new-relic.atlassian.net/browse/NR-297214) +- [PR-356](https://github.com/newrelic/csec-java-agent/pull/356) Code Optimization: Optimized code to minimize the overhead of the Security Agent in relation to the APM Agent. [NR-338596](https://new-relic.atlassian.net/browse/NR-338596) + +### Fixes +- [PR-352](https://github.com/newrelic/csec-java-agent/pull/352) Corrected the issue regarding inaccurate user class details in the mule-demo-app. [NR-336715](https://new-relic.atlassian.net/browse/NR-336715) +- [PR-355](https://github.com/newrelic/csec-java-agent/pull/355) Improved logging for scenarios where delay is set to a negative value. [NR-338578](https://new-relic.atlassian.net/browse/NR-338578) + + ## [1.5.1] - 2024-11-9 ### New features - [PR-350](https://github.com/newrelic/csec-java-agent/pull/350) IAST support for CI/CD. diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 2c4ac74ea..2a1aeca34 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -20,7 +20,9 @@ dependencies { implementation("org.ow2.asm:asm-commons:9.2") // Shadow is used here because several classes implement the Transformer interface - implementation("com.github.jengelman.gradle.plugins:shadow:6.0.0") + implementation("com.github.jengelman.gradle.plugins:shadow:6.0.0") { + exclude(group: "org.codehaus.plexus", module: "plexus-utils") + } // Reflections and GSON are used for building the manifest of annotated classes. implementation("org.reflections:reflections:0.9.11") diff --git a/gradle.properties b/gradle.properties index e642d6bf5..220b28d15 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # The agent version. -agentVersion=1.5.1 +agentVersion=1.6.0 jsonVersion=1.2.9 # Updated exposed NR APM API version. nrAPIVersion=8.12.0 diff --git a/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/AkkaResponseHelper.scala b/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/AkkaResponseHelper.scala index 3ff8224e3..6e8725dc5 100644 --- a/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/AkkaResponseHelper.scala +++ b/instrumentation-security/akka-http-2.11_10.0.0/src/main/scala/akka/http/scaladsl/AkkaResponseHelper.scala @@ -7,21 +7,15 @@ package akka.http.scaladsl -import akka.Done import akka.http.scaladsl.model.{HttpEntity, HttpResponse} import akka.http.scaladsl.server.AkkaCoreUtils -import akka.stream.Materializer -import akka.stream.javadsl.Source -import akka.stream.scaladsl.Sink -import akka.util.ByteString +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.exceptions.NewRelicSecurityException import com.newrelic.api.agent.security.utils.logging.LogLevel -import com.newrelic.api.agent.{NewRelic, Token} import java.lang -import scala.concurrent.{ExecutionContext, Future} import scala.runtime.AbstractFunction1 class AkkaResponseHelper extends AbstractFunction1[HttpResponse, HttpResponse] { @@ -29,7 +23,7 @@ class AkkaResponseHelper extends AbstractFunction1[HttpResponse, HttpResponse] { override def apply(httpResponse: HttpResponse): HttpResponse = { try { val stringResponse = new lang.StringBuilder() - val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible() + val isLockAquired = GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME); stringResponse.append(httpResponse.entity.asInstanceOf[HttpEntity.Strict].getData().decodeString("utf-8")) AkkaCoreUtils.postProcessHttpRequest(isLockAquired, stringResponse, httpResponse.entity.contentType.toString(), this.getClass.getName, "apply", NewRelic.getAgent.getTransaction.getToken()) } catch { 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 430dedb60..64bc7cd18 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 @@ -11,6 +11,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; @@ -26,37 +27,10 @@ public class AkkaCoreUtils { public static final String AKKA_HTTP_10_0_0 = "AKKA_HTTP_10.0.0"; private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; - - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} - } - - private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; - } + private static final String QUESTION_MARK = "?"; public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NR_SEC_CUSTOM_ATTRIB_NAME); } public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, String className, String methodName, Token token) { @@ -87,7 +61,7 @@ public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringB } } finally { if(isServletLockAcquired){ - releaseServletLock(); + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } @@ -105,16 +79,12 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); com.newrelic.api.agent.security.schema.HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(httpRequest.method().value()); //TODO Client IP and PORT extraction is pending -// securityRequest.setClientIP(); securityRequest.setServerPort(httpRequest.getUri().port()); processHttpRequestHeader(httpRequest, securityRequest); @@ -144,8 +114,8 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, AKKA_HTTP_10_0_0, ignored.getMessage()), ignored, AkkaCoreUtils.class.getName()); } finally { - if(isServletLockAcquired()){ - releaseServletLock(); + if(GenericHelper.isLockAcquired(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME)){ + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } 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 2ebd36c77..f20f984d9 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 @@ -12,21 +12,19 @@ import akka.http.scaladsl.model.HttpEntity import akka.stream.javadsl.Source import akka.stream.scaladsl.Sink import akka.util.ByteString - -import java.util.concurrent.atomic.AtomicBoolean -import java.util.logging.Level -import com.newrelic.api.agent.{NewRelic, Trace} import com.newrelic.api.agent.security.NewRelicSecurity import com.newrelic.api.agent.security.utils.logging.LogLevel +import com.newrelic.api.agent.{NewRelic, Trace} import java.lang -import scala.collection.mutable +import java.util.concurrent.atomic.AtomicBoolean +import java.util.logging.Level import scala.concurrent.Future import scala.runtime.AbstractFunction1 object CsecAkkaHttpContextFunction { - final val retransformed = new AtomicBoolean(false) + private final val retransformed = new AtomicBoolean(false) def contextWrapper(original: Function1[RequestContext, Future[RouteResult]]): Function1[RequestContext, Future[RouteResult]] = { if (retransformed.compareAndSet(false, true)) { 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 cfd6c386c..4fcf2d24a 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 @@ -11,6 +11,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; @@ -28,37 +29,10 @@ public class AkkaCoreUtils { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; - - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} - } - - private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; - } + private static final String QUESTION_MARK = "?"; public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NR_SEC_CUSTOM_ATTRIB_NAME); } public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder response, String contentType, int responseCode, String className, String methodName, Token token) { @@ -94,7 +68,7 @@ public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringB NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, AKKA_HTTP_CORE_10_0, e.getMessage()), e, AkkaCoreUtils.class.getName()); } finally { if(isServletLockAcquired){ - releaseServletLock(); + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } @@ -121,7 +95,6 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq securityRequest.setMethod(httpRequest.method().value()); //TODO Client IP and PORT extraction is pending -// securityRequest.setClientIP(); securityRequest.setServerPort(httpRequest.getUri().port()); processHttpRequestHeader(httpRequest, securityRequest); @@ -150,13 +123,13 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, AKKA_HTTP_CORE_10_0, ignored.getMessage()), ignored, AkkaCoreUtils.class.getName()); } finally { - if(isServletLockAcquired()){ - releaseServletLock(); + if(GenericHelper.isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME)){ + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -167,7 +140,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ + private static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ Iterator headers = request.getHeaders().iterator(); while (headers.hasNext()) { boolean takeNextValue = false; 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 deada6535..77964cae7 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 @@ -126,11 +126,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest httpRequest, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()) { - return null; - } - // Generate required URL URI methodURI = null; String uri = null; diff --git a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java index d226ac2eb..4a5dcbe0f 100644 --- a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java +++ b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java @@ -31,9 +31,6 @@ public InetSocketAddress localAddress() { @WeaveAllConstructors public ServerBinding() { -// AgentBridge.getAgent().getLogger().log(Level.FINE, "Setting akka-http port to: {0,number,#}", localAddress().getPort()); -// AgentBridge.publicApi.setAppServerPort(localAddress().getPort()); -// AgentBridge.publicApi.setServerInfo("Akka HTTP", ManifestUtils.getVersionFromManifest(getClass(), "akka-http-core", "10.2.0")); NewRelicSecurity.getAgent().setApplicationConnectionConfig(localAddress().getPort(), "http"); try { diff --git a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala index 4176160dc..bcff48b24 100644 --- a/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala +++ b/instrumentation-security/akka-http-core-10.0/src/main/scala/akka/http/scaladsl/ResponseFutureHelper.scala @@ -32,7 +32,7 @@ object ResponseFutureHelper { try { val stringResponse: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, _] = response.entity.getDataBytes() - val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); + val isLockAquired = GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME); val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => val chunk = byteString.utf8String stringResponse.append(chunk) @@ -61,7 +61,7 @@ object ResponseFutureHelper { try { val stringResponse: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, _] = httpResponse.entity.getDataBytes() - val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); + val isLockAquired = GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME); val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => val chunk = byteString.utf8String stringResponse.append(chunk) 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 124589903..0329e7dcf 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 @@ -11,6 +11,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; @@ -28,37 +29,10 @@ public class AkkaCoreUtils { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; - - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} - } - - private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; - } + private static final String QUESTION_MARK = "?"; public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NR_SEC_CUSTOM_ATTRIB_NAME); } public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { @@ -94,7 +68,7 @@ public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringB NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, AKKA_HTTP_CORE_10_0_11, e.getMessage()), e, AkkaCoreUtils.class.getName()); } finally { if(isServletLockAcquired){ - releaseServletLock(); + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } @@ -121,7 +95,6 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq securityRequest.setMethod(httpRequest.method().value()); //TODO Client IP and PORT extraction is pending -// securityRequest.setClientIP(); securityRequest.setServerPort(httpRequest.getUri().getPort()); processHttpRequestHeader(httpRequest, securityRequest); @@ -150,13 +123,13 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, AKKA_HTTP_CORE_10_0_11, ignored.getMessage()), ignored, AkkaCoreUtils.class.getName()); } finally { - if(isServletLockAcquired()){ - releaseServletLock(); + if(GenericHelper.isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME)){ + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -167,7 +140,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ + private static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ Iterator headers = request.getHeaders().iterator(); while (headers.hasNext()) { boolean takeNextValue = false; 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 65d5da00b..b0e9a0fc1 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 @@ -129,11 +129,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest httpRequest, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()) { - return null; - } - // Generate required URL URI methodURI = null; String uri = null; 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 fb29ea791..14d611635 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 @@ -11,6 +11,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; @@ -28,37 +29,10 @@ public class AkkaCoreUtils { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; - - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} - } - - private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; - } + private static final String QUESTION_MARK = "?"; public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, NR_SEC_CUSTOM_ATTRIB_NAME); } public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { @@ -91,7 +65,7 @@ public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringB NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, AKKA_HTTP_CORE_10_0_11, e.getMessage()), e, AkkaCoreUtils.class.getName()); } finally { if(isServletLockAcquired){ - releaseServletLock(); + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } @@ -118,7 +92,6 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq securityRequest.setMethod(httpRequest.method().value()); //TODO Client IP and PORT extraction is pending -// securityRequest.setClientIP(); securityRequest.setServerPort(httpRequest.getUri().getPort()); processHttpRequestHeader(httpRequest, securityRequest); @@ -147,13 +120,13 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, AKKA_HTTP_CORE_10_0_11, ignored.getMessage()), ignored, AkkaCoreUtils.class.getName()); } finally { - if(isServletLockAcquired()){ - releaseServletLock(); + if(GenericHelper.isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME)){ + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -164,7 +137,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ + private static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ Iterator headers = request.getHeaders().iterator(); while (headers.hasNext()) { boolean takeNextValue = false; 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 65d5da00b..b0e9a0fc1 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 @@ -129,11 +129,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest httpRequest, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()) { - return null; - } - // Generate required URL URI methodURI = null; String uri = null; diff --git a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java index 5aee71a85..82e293dbe 100644 --- a/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java +++ b/instrumentation-security/akka-http-core-2.13_10.1.8/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java @@ -31,10 +31,6 @@ public InetSocketAddress localAddress() { @WeaveAllConstructors public ServerBinding() { - // AgentBridge.getAgent().getLogger().log(Level.FINE, "Setting akka-http port to: {0,number,#}", localAddress().getPort()); -// AgentBridge.publicApi.setAppServerPort(localAddress().getPort()); -// AgentBridge.publicApi.setServerInfo("Akka HTTP", ManifestUtils.getVersionFromManifest(getClass(), "akka-http-core", "10.2.0")); - NewRelicSecurity.getAgent().setApplicationConnectionConfig(localAddress().getPort(), "http"); try { Class agentBridgeClass = Class.forName("com.newrelic.agent.bridge.AgentBridge"); 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 60a80405f..f294ed015 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 @@ -32,7 +32,7 @@ object ResponseFutureHelper { try { val stringResponse: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, _] = response.entity.getDataBytes() - val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); + val isLockAquired = GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME); val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => val chunk = byteString.utf8String stringResponse.append(chunk) @@ -61,7 +61,7 @@ object ResponseFutureHelper { try { val stringResponse: lang.StringBuilder = new lang.StringBuilder(); val dataBytes: Source[ByteString, _] = httpResponse.entity.getDataBytes() - val isLockAquired = AkkaCoreUtils.acquireServletLockIfPossible(); + val isLockAquired = GenericHelper.acquireLockIfPossible(AkkaCoreUtils.NR_SEC_CUSTOM_ATTRIB_NAME); val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => val chunk = byteString.utf8String stringResponse.append(chunk) 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 0f36ab5e6..b52bce019 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 @@ -1,6 +1,5 @@ package akka.http.scaladsl; -import akka.Done; import akka.http.javadsl.model.HttpHeader; import akka.http.scaladsl.model.HttpRequest; import com.newrelic.api.agent.Token; @@ -28,37 +27,14 @@ public class AkkaCoreUtils { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; public static final String AKKA_HTTP_CORE_2_13_10_2_0 = "AKKA_HTTP_CORE_2.13_10.2.0"; - public static final String QUESTION_MARK = "?"; - - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} - } + private static final String QUESTION_MARK = "?"; private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME; } public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME); } public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { @@ -92,7 +68,7 @@ public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringB NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, AKKA_HTTP_CORE_2_13_10_2_0, e.getMessage()), e, AkkaCoreUtils.class.getName()); } finally { if(isServletLockAcquired){ - releaseServletLock(); + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } @@ -119,7 +95,6 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq securityRequest.setMethod(httpRequest.method().value()); //TODO Client IP and PORT extraction is pending -// securityRequest.setClientIP(); securityRequest.setServerPort(httpRequest.getUri().getPort()); processHttpRequestHeader(httpRequest, securityRequest); @@ -148,8 +123,8 @@ public static void preProcessHttpRequest (Boolean isServletLockAcquired, HttpReq NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, AKKA_HTTP_CORE_2_13_10_2_0, ignored.getMessage()), ignored, AkkaCoreUtils.class.getName()); } finally { - if(isServletLockAcquired()){ - releaseServletLock(); + if(GenericHelper.isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME)){ + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME); } } } @@ -164,7 +139,7 @@ private static String getProtocol(String value) { } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -175,7 +150,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ + private static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ Iterator headers = request.getHeaders().iterator(); while (headers.hasNext()) { boolean takeNextValue = false; 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 d0f99f329..bb1f64a44 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 @@ -16,7 +16,6 @@ import akka.util.ByteString import com.newrelic.api.agent.{NewRelic, Trace} import java.lang -import scala.collection.JavaConverters import scala.concurrent.Future import scala.runtime.AbstractFunction1 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 41c69c12e..3886f2ed9 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 @@ -138,11 +138,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest httpRequest, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()) { - return null; - } - // Generate required URL URI methodURI = null; String uri = null; diff --git a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java index d226ac2eb..4a5dcbe0f 100644 --- a/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java +++ b/instrumentation-security/akka-http-core-2.13_10.2.0/src/main/scala/akka/http/scaladsl/Http_Instrumentation.java @@ -31,9 +31,6 @@ public InetSocketAddress localAddress() { @WeaveAllConstructors public ServerBinding() { -// AgentBridge.getAgent().getLogger().log(Level.FINE, "Setting akka-http port to: {0,number,#}", localAddress().getPort()); -// AgentBridge.publicApi.setAppServerPort(localAddress().getPort()); -// AgentBridge.publicApi.setServerInfo("Akka HTTP", ManifestUtils.getVersionFromManifest(getClass(), "akka-http-core", "10.2.0")); NewRelicSecurity.getAgent().setApplicationConnectionConfig(localAddress().getPort(), "http"); try { 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 6c7a53102..0d4e11954 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 @@ -37,9 +37,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String name, String filter, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(filter)){ + if (StringUtils.isBlank(filter)){ return null; } LDAPOperation ldapOperation = new LDAPOperation(name, filter, this.getClass().getName(), methodName); @@ -57,16 +55,11 @@ private AbstractOperation preprocessSecurityHook (String name, String filter, St } private void releaseLock() { - try { - GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType caseType) { - try { - return GenericHelper.acquireLockIfPossible(caseType, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(caseType, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } public SearchFuture searchAsync(Dn baseDn, String filter, SearchScope scope, String... attributes ) 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 e8283a5fe..c4b0d99ec 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 @@ -37,9 +37,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String name, String filter, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(filter)){ + if (StringUtils.isBlank(filter)){ return null; } LDAPOperation ldapOperation = new LDAPOperation(name, filter, this.getClass().getName(), methodName); @@ -57,16 +55,11 @@ private AbstractOperation preprocessSecurityHook (String name, String filter, St } private void releaseLock() { - try { - GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType caseType) { - try { - return GenericHelper.acquireLockIfPossible(caseType, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(caseType, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } public EntryCursor search(Dn baseDn, String filter, SearchScope scope, String... attributes ) diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/README.md b/instrumentation-security/apache-pekko-http-core-2.13_1/README.md new file mode 100644 index 000000000..938e551af --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/README.md @@ -0,0 +1,33 @@ +# Pekko HTTP core instrumentation + +This instrumentation is a lift of `akka-http-core-2.13_10.2.0`. + +As of `Pekko Http Core 1.0.0`, `bindAndHandleAsync` and `bindAndHandleSync` have both been deprecated and replaced by +`Http().newServerAt().bind()`. However, these methods still exist and are instrumented where used, +so the documentation below (also taken from Akka) is maintained for historical purposes. + + +## HttpExt Instrumentation +Instrumentation for Pekko HTTP Core is carried out in the `pekko.http.scaladsl.HttpExt` class that serves as the +main entry point for a server. 2 convenience methods from `HttpExt` that can be used to start an HTTP server have +been instrumented, they are : + +- ` bindAndHandleAsync`: Convenience method which starts a new HTTP server at the given endpoint and uses handler that is a function receiving an `HttpRequest` and returning a `Future[HttpResponse]` +- ` bindAndHandleSync`: Convenience method which starts a new HTTP server at the given endpoint and uses handler that is a function receiving an `HttpRequest` and returning a `HttpResponse` + + +It has been decided that instrumentation is not extended for `bindAndHandle` which starts a new HTTP server using a +`pekko.stream.scaladsl.Flow` instance. This is due to a clash in the Akka Http Routing DSL instrumentation. + + +Users wishing to start an HTTP Server from an `pekko.stream.scaladsl.Flow` can use the following workaround + +```scala + val flow: Flow[HttpRequest, HttpResponse, NotUsed] = ??? + val asyncHandler: HttpRequest => Future[HttpResponse] = request => Source.single(request).via(flow).runWith(Sink.head) + Http().bindAndHandleAsync(asyncHandler, host, port) +``` + +This workaround is not needed for users using calling `bindAndHandle` using `akka.http.scaladsl.Route` from the +Pekko Http Routing DSL. Instrumentation should work in the same way being called from the other conveniences methods +to start an HTTP Server. \ No newline at end of file diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/build.gradle b/instrumentation-security/apache-pekko-http-core-2.13_1/build.gradle new file mode 100644 index 000000000..7dd7c2667 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +sourceSets.test.scala.srcDir "src/test/java" +sourceSets.test.java.srcDirs = [] + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.apache-pekko-http-core-2.13_1' } +} + +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.newrelic.agent.java:agent-bridge:${nrAPIVersion}") + implementation("org.apache.pekko:pekko-http_2.13:1.0.1") + implementation("org.apache.pekko:pekko-http-core_2.13:1.0.1") + implementation("org.apache.pekko:pekko-stream_2.13:1.0.1") + implementation("org.apache.pekko:pekko-actor_2.13:1.0.1") +} + +verifyInstrumentation { + passesOnly('org.apache.pekko:pekko-http_2.13:[1.0.0,)') { + implementation("org.apache.pekko:pekko-stream_2.13:1.0.0") + } + passesOnly('org.apache.pekko:pekko-http_3:[1.0.0,)') { + implementation("org.apache.pekko:pekko-stream_3:1.0.0") + } + excludeRegex 'org.apache.pekko:pekko-http_2.13:.*(RC|M)[0-9]*$' + excludeRegex 'org.apache.pekko:pekko-http_2.13:.*-[0-9a-f]{8}$' + excludeRegex 'org.apache.pekko:pekko-http_3:.*(RC|M)[0-9]*$' + excludeRegex 'org.apache.pekko:pekko-http_3:.*-[0-9a-f]{8}$' +} + +site { + title 'Pekko Http Core' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/AsyncRequestHandler.scala b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/AsyncRequestHandler.scala new file mode 100644 index 000000000..66bf19b06 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/AsyncRequestHandler.scala @@ -0,0 +1,35 @@ +package org.apache.pekko.http.scaladsl + +import com.newrelic.api.agent.{NewRelic, Trace} +import org.apache.pekko.Done +import org.apache.pekko.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} +import org.apache.pekko.stream.Materializer +import org.apache.pekko.stream.scaladsl.Sink +import org.apache.pekko.stream.javadsl.Source +import org.apache.pekko.util.ByteString + +import java.lang +import scala.concurrent.{ExecutionContext, Future} +import scala.runtime.AbstractFunction1 + +class AsyncRequestHandler(handler: HttpRequest => Future[HttpResponse])(implicit ec: ExecutionContext, materializer: Materializer) extends AbstractFunction1[HttpRequest, Future[HttpResponse]] { + + @Trace(dispatcher = true) + override def apply(param: HttpRequest): Future[HttpResponse] = { + val body: lang.StringBuilder = new lang.StringBuilder(); + val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() + val isLockAcquired = PekkoCoreUtils.acquireServletLockIfPossible(); + + 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) + } + PekkoCoreUtils.preProcessHttpRequest(isLockAcquired, param, body, NewRelic.getAgent.getTransaction.getToken); + val futureResponse: Future[HttpResponse] = handler.apply(param) + futureResponse.flatMap(ResponseFutureHelper.wrapResponseAsync(NewRelic.getAgent.getTransaction.getToken, materializer)) + futureResponse + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/HttpExt_Instrumentation.java b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/HttpExt_Instrumentation.java new file mode 100644 index 000000000..a222be12e --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/HttpExt_Instrumentation.java @@ -0,0 +1,153 @@ +package org.apache.pekko.http.scaladsl; + +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.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 org.apache.pekko.event.LoggingAdapter; +import org.apache.pekko.http.scaladsl.model.HttpRequest; +import org.apache.pekko.http.scaladsl.model.HttpResponse; +import org.apache.pekko.http.scaladsl.model.headers.RawHeader; +import org.apache.pekko.http.scaladsl.settings.ConnectionPoolSettings; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.pekko.http.scaladsl.settings.ServerSettings; +import org.apache.pekko.stream.Materializer; +import scala.Function1; +import scala.concurrent.Future; + +import java.net.URI; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.pekko.http.scaladsl.HttpExt") +public class HttpExt_Instrumentation { + + // These methods are deprecated but still exist in Pekko Http Core 1.0.0. + // They have been replaced by Http().newServerAt().bind(). + + public Future bindAndHandleAsync( + Function1> handler, + String interfaceString, int port, + ConnectionContext connectionContext, + ServerSettings settings, int parallelism, + LoggingAdapter adapter, Materializer mat) { + + AsyncRequestHandler wrapperHandler = new AsyncRequestHandler(handler, mat.executionContext(), mat); + handler = wrapperHandler; + return Weaver.callOriginal(); + } + + public Future bindAndHandleSync( + Function1 handler, + String interfaceString, int port, + ConnectionContext connectionContext, + ServerSettings settings, + LoggingAdapter adapter, Materializer mat) { + + SyncRequestHandler wrapperHandler = new SyncRequestHandler(handler, mat); + handler = wrapperHandler; + return Weaver.callOriginal(); + } + + public Future singleRequest(HttpRequest httpRequest, HttpsConnectionContext connectionContext, ConnectionPoolSettings poolSettings, LoggingAdapter loggingAdapter) { + + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, PekkoCoreUtils.NR_SEC_CUSTOM_ATTRIB_OUTBOUND_REQ); + AbstractOperation operation = null; + + SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); + if (isLockAcquired) { + operation = preprocessSecurityHook(httpRequest, PekkoCoreUtils.METHOD_SINGLE_REQUEST); + } + + if (operation!=null) { + // Add CSEC Fuzz and parent headers + String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); + if (iastHeader != null && !iastHeader.trim().isEmpty()) { + httpRequest = (HttpRequest)httpRequest.addHeader(RawHeader.apply(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader)); + } + + String csecParaentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class); + if(StringUtils.isNotBlank(csecParaentId)){ + httpRequest = (HttpRequest)httpRequest.addHeader(RawHeader.apply(GenericHelper.CSEC_PARENT_ID, csecParaentId)); + } + + try { + NewRelicSecurity.getAgent().registerOperation(operation); + } catch (Exception e) { + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, this.getClass().getName()); + } finally { + if (operation.getApiID() != null && !operation.getApiID().trim().isEmpty() && + operation.getExecutionId() != null && !operation.getExecutionId().trim().isEmpty()) { + // Add CSEC distributed tracing header + httpRequest = (HttpRequest)httpRequest.addHeader(RawHeader.apply(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, + SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue(), operation.getApiID(), operation.getExecutionId(), + NewRelicSecurity.getAgent().getAgentUUID()))); + } + } + } + + Future returnCode; + // Actual Call + try { + returnCode = Weaver.callOriginal(); + } finally { + if (isLockAcquired) { + GenericHelper.releaseLock(PekkoCoreUtils.NR_SEC_CUSTOM_ATTRIB_OUTBOUND_REQ); + } + } + registerExitOperation(isLockAcquired, operation); + return returnCode; + } + + private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() + ) { + return; + } + NewRelicSecurity.getAgent().registerExitEvent(operation); + } catch (Throwable ignored) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, ignored.getMessage()), ignored, HttpExt_Instrumentation.class.getName()); + } + } + + private AbstractOperation preprocessSecurityHook(HttpRequest httpRequest, String methodName) { + try { + SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); + if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()) { + return null; + } + + // Generate required URL + String uri = null; + try { + URI methodURI = new URI(httpRequest.getUri().toString()); + uri = methodURI.toString(); + if (methodURI == null) { + return null; + } + } catch (Exception ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, ignored.getMessage()), ignored, this.getClass().getName()); + return null; + } + + return new SSRFOperation(uri, this.getClass().getName(), methodName); + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, this.getClass().getName()); + } + return null; + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/Http_Instrumentation.java b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/Http_Instrumentation.java new file mode 100644 index 000000000..41649177d --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/Http_Instrumentation.java @@ -0,0 +1,36 @@ +package org.apache.pekko.http.scaladsl; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.api.agent.NewRelic; +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; +import com.newrelic.api.agent.weaver.Weaver; + +import java.net.InetSocketAddress; +import java.util.logging.Level; + +@Weave(type = MatchType.ExactClass, originalName = "org.apache.pekko.http.scaladsl.Http") +public class Http_Instrumentation { + + @Weave(type = MatchType.ExactClass, originalName = "org.apache.pekko.http.scaladsl.Http$ServerBinding") + public static class ServerBinding { + + public InetSocketAddress localAddress() { + return Weaver.callOriginal(); + } + + @WeaveAllConstructors + public ServerBinding() { + NewRelicSecurity.getAgent().setApplicationConnectionConfig(localAddress().getPort(), "http"); + try { + AgentBridge.instrumentation.retransformUninstrumentedClass(SyncRequestHandler.class); + AgentBridge.instrumentation.retransformUninstrumentedClass(AsyncRequestHandler.class); + } catch (Throwable e) { + NewRelic.getAgent().getLogger().log(Level.SEVERE, "Unable to instrument com.newrelic.instrumentation.security.apache-pekko-http-core-2.13_1 due to error", e); + } + } + } + +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/IncomingConnection_Instrumentation.java b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/IncomingConnection_Instrumentation.java new file mode 100644 index 000000000..b4240ed2f --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/IncomingConnection_Instrumentation.java @@ -0,0 +1,25 @@ +package org.apache.pekko.http.scaladsl; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.apache.pekko.http.scaladsl.model.HttpRequest; +import org.apache.pekko.http.scaladsl.model.HttpResponse; +import org.apache.pekko.stream.Materializer; +import scala.Function1; +import scala.concurrent.Future; + +@Weave(originalName = "org.apache.pekko.http.scaladsl.Http$IncomingConnection") +public class IncomingConnection_Instrumentation { + + public void handleWithSyncHandler(Function1 func, Materializer mat) { + SyncRequestHandler wrapperHandler = new SyncRequestHandler(func, mat); + func = wrapperHandler; + Weaver.callOriginal(); + } + + public void handleWithAsyncHandler(Function1> func, int parallel, Materializer mat) { + AsyncRequestHandler wrapperHandler = new AsyncRequestHandler(func, mat.executionContext(), mat); + func = wrapperHandler; + Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/PekkoCoreUtils.java b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/PekkoCoreUtils.java new file mode 100644 index 000000000..73fa86c44 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/PekkoCoreUtils.java @@ -0,0 +1,215 @@ +package org.apache.pekko.http.scaladsl; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.security.NewRelicSecurity; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; +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.exceptions.NewRelicSecurityException; +import com.newrelic.api.agent.security.schema.operation.RXSSOperation; +import com.newrelic.api.agent.security.schema.policy.AgentPolicy; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.pekko.http.javadsl.model.HttpHeader; +import org.apache.pekko.http.javadsl.model.MediaType; +import org.apache.pekko.http.scaladsl.model.HttpRequest; +import com.newrelic.api.agent.security.instrumentation.helpers.ICsecApiConstants; +import org.apache.pekko.http.scaladsl.model.MediaTypes; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; + +public class PekkoCoreUtils { + + public static final String METHOD_SINGLE_REQUEST = "singleRequest"; + + public static final String NR_SEC_CUSTOM_ATTRIB_OUTBOUND_REQ = "OUTBOUND_REQ_OPERATION_LOCK_PEKKO-"; + private static final String NR_SEC_CUSTOM_ATTRIB_HTTP_REQ = "HTTP_REQUEST_OPERATION_LOCK_PEKKO-"; + + public static final String PEKKO_HTTP_CORE_2_13_1 = "APACHE_PEKKO_HTTP_CORE_2.13-1"; + + private static final String X_FORWARDED_FOR = "x-forwarded-for"; + + private static final String QUESTION_MARK = "?"; + + private static final String NO_MEDIA_CONTENT_TYPE = "none/none"; + + private static boolean isServletLockAcquired() { + try { + return GenericHelper.isLockAcquired(getNrSecCustomAttribHttpReq()); + } catch (Throwable ignored) {} + return false; + } + + private static void releaseServletLock() { + try { + GenericHelper.releaseLock(getNrSecCustomAttribHttpReq()); + } catch (Throwable ignored){} + } + + public static boolean acquireServletLockIfPossible() { + try { + return GenericHelper.acquireLockIfPossible(getNrSecCustomAttribHttpReq()); + } catch (Throwable ignored){} + return false; + } + + private static String getNrSecCustomAttribHttpReq() { + return NR_SEC_CUSTOM_ATTRIB_HTTP_REQ + Thread.currentThread().getId(); + } + + public static void postProcessHttpRequest(Boolean isServletLockAcquired, StringBuilder responseBody, String contentType, int responseCode, String className, String methodName, Token token) { + try { + token.linkAndExpire(); + if(!isServletLockAcquired || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ + return; + } + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(contentType); + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(responseBody); + if (!contentType.equals(NO_MEDIA_CONTENT_TYPE)) { + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(responseCode); + } + ServletHelper.executeBeforeExitingTransaction(); + LowSeverityHelper.addRrequestUriToEventFilter(NewRelicSecurity.getAgent().getSecurityMetaData().getRequest()); + + if(!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().getResponseContentType())) { + RXSSOperation rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent().getSecurityMetaData().getRequest(), + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse(), + className, methodName); + NewRelicSecurity.getAgent().registerOperation(rxssOperation); + } + ServletHelper.tmpFileCleanUp(NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getTempFiles()); + } catch (Throwable e) { + if(e instanceof NewRelicSecurityException){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, PekkoCoreUtils.class.getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, PekkoCoreUtils.class.getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, PEKKO_HTTP_CORE_2_13_1, e.getMessage()), e, PekkoCoreUtils.class.getName()); + } finally { + if(isServletLockAcquired){ + releaseServletLock(); + } + } + } + + public static void preProcessHttpRequest(Boolean isServletLockAcquired, HttpRequest request, StringBuilder requestBody, Token token) { + if(!isServletLockAcquired) { + return; + } + + try { + token.linkAndExpire(); + if (!NewRelicSecurity.isHookProcessingActive()) { + return; + } + SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); + + com.newrelic.api.agent.security.schema.HttpRequest securityRequest = securityMetaData.getRequest(); + if (securityRequest.isRequestParsed()) { + return; + } + + securityRequest.setMethod(request.method().value()); + //TODO Client IP and PORT extraction is pending + + securityRequest.setServerPort(request.getUri().getPort()); + + processHttpRequestHeader(request, securityRequest); + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders())); + + securityRequest.setProtocol(getProtocol(request.protocol().value())); + + securityRequest.setUrl(request.getUri().path()); + String queryString = null; + Optional rawQueryString = request.getUri().rawQueryString(); + if(rawQueryString.isPresent()) { + queryString = rawQueryString.get(); + } + if (queryString != null && !queryString.trim().isEmpty()) { + securityRequest.setUrl(securityRequest.getUrl() + QUESTION_MARK + queryString); + } + if (!request.entity().getContentType().toString().equals(NO_MEDIA_CONTENT_TYPE)) { + securityRequest.setContentType(request.entity().getContentType().toString()); + } + + StackTraceElement[] trace = Thread.currentThread().getStackTrace(); + securityMetaData.getMetaData().setServiceTrace(Arrays.copyOfRange(trace, 2, trace.length)); + securityRequest.setBody(requestBody); + securityRequest.setRequestParsed(true); + } catch (Throwable ignored){ + NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, PEKKO_HTTP_CORE_2_13_1, ignored.getMessage()), ignored, PekkoCoreUtils.class.getName()); + } + finally { + if(isServletLockAcquired()){ + releaseServletLock(); + } + } + } + + private static String getProtocol(String value) { + if(StringUtils.containsIgnoreCase(value, "https")){ + return "https"; + } else { + return "http"; + } + } + + private static String getTraceHeader(Map headers) { + String data = StringUtils.EMPTY; + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); + if (data == null || data.trim().isEmpty()) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase()); + } + } + return data; + } + + private static void processHttpRequestHeader(HttpRequest request, com.newrelic.api.agent.security.schema.HttpRequest securityRequest){ + Iterator headers = request.getHeaders().iterator(); + while (headers.hasNext()) { + boolean takeNextValue = false; + HttpHeader nextHeader = headers.next(); + String headerKey = nextHeader.name(); + if(headerKey != null){ + headerKey = headerKey.toLowerCase(); + } + AgentPolicy agentPolicy = NewRelicSecurity.getAgent().getCurrentPolicy(); + AgentMetaData agentMetaData = NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData(); + if (agentPolicy != null + && agentPolicy.getProtectionMode().getEnabled() + && agentPolicy.getProtectionMode().getIpBlocking().getEnabled() + && agentPolicy.getProtectionMode().getIpBlocking().getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true; + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID.equals(headerKey)) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent().getSecurityMetaData() + .setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(nextHeader.value())); + } else if(GenericHelper.CSEC_PARENT_ID.equals(headerKey)) { + NewRelicSecurity.getAgent().getSecurityMetaData() + .addCustomAttribute(GenericHelper.CSEC_PARENT_ID, request.getHeader(headerKey).get().value()); + } else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST.equals(headerKey)) { + NewRelicSecurity.getAgent().getSecurityMetaData() + .addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true); + } + String headerFullValue = nextHeader.value(); + if (headerFullValue != null && !headerFullValue.trim().isEmpty()) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true); + securityRequest.setClientIP(headerFullValue); + agentMetaData.getIps() + .add(securityRequest.getClientIP()); + securityRequest.setClientPort(StringUtils.EMPTY); + takeNextValue = false; + } + } + securityRequest.getHeaders().put(headerKey, headerFullValue); + } + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/ResponseFutureHelper.scala b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/ResponseFutureHelper.scala new file mode 100644 index 000000000..17ef51906 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/ResponseFutureHelper.scala @@ -0,0 +1,68 @@ +package org.apache.pekko.http.scaladsl + +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.utils.logging.LogLevel +import com.newrelic.api.agent.{NewRelic, Token} +import org.apache.pekko.Done +import org.apache.pekko.http.scaladsl.model.HttpResponse +import org.apache.pekko.stream.Materializer +import org.apache.pekko.stream.scaladsl.Sink +import org.apache.pekko.stream.javadsl.Source +import org.apache.pekko.util.ByteString + +import java.lang +import scala.concurrent.{ExecutionContext, Future} + +object ResponseFutureHelper { + + def wrapResponseAsync(token: Token, materializer: Materializer)(implicit ec: ExecutionContext): HttpResponse => Future[HttpResponse] = { response:HttpResponse => { + Future { + val updatedResponse: HttpResponse = response + try { + val stringResponse: lang.StringBuilder = new lang.StringBuilder(); + val dataBytes: Source[ByteString, _] = response.entity.getDataBytes() + val isLockAcquired = PekkoCoreUtils.acquireServletLockIfPossible(); + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + stringResponse.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) + processingResult.onComplete { + _ => { + token.linkAndExpire() + PekkoCoreUtils.postProcessHttpRequest(isLockAcquired, stringResponse, response.entity.contentType.toString(), response.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, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, t.getMessage), t, classOf[PekkoCoreUtils].getName) + throw t + case _: Throwable => + } + updatedResponse + } + } + } + + def wrapResponseSync(httpResponse: HttpResponse, materializer: Materializer): Unit = { + try { + val stringResponse: lang.StringBuilder = new lang.StringBuilder(); + val dataBytes: Source[ByteString, _] = httpResponse.entity.getDataBytes() + val isLockAcquired = PekkoCoreUtils.acquireServletLockIfPossible(); + val sink: Sink[ByteString, Future[Done]] = Sink.foreach[ByteString] { byteString => + val chunk = byteString.utf8String + stringResponse.append(chunk) + } + val processingResult: Future[Done] = dataBytes.runWith(sink, materializer) + + PekkoCoreUtils.postProcessHttpRequest(isLockAcquired, 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, PekkoCoreUtils.PEKKO_HTTP_CORE_2_13_1, t.getMessage), t, classOf[PekkoCoreUtils].getName) + throw t + case _: Throwable => + } + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/SyncRequestHandler.scala b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/SyncRequestHandler.scala new file mode 100644 index 000000000..5cdb8f286 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/main/scala/org.apache.pekko/http/scaladsl/SyncRequestHandler.scala @@ -0,0 +1,35 @@ +package org.apache.pekko.http.scaladsl + +import com.newrelic.api.agent.{NewRelic, Trace} +import org.apache.pekko.Done +import org.apache.pekko.http.scaladsl.model.{HttpEntity, HttpRequest, HttpResponse} +import org.apache.pekko.stream.Materializer +import org.apache.pekko.stream.scaladsl.Sink +import org.apache.pekko.stream.javadsl.Source +import org.apache.pekko.util.ByteString + +import java.lang +import scala.concurrent.Future +import scala.runtime.AbstractFunction1 + +class SyncRequestHandler(handler: HttpRequest => HttpResponse)(implicit materializer: Materializer) extends AbstractFunction1[HttpRequest, HttpResponse] { + + @Trace(dispatcher = true) + override def apply(param: HttpRequest): HttpResponse = { + val body: lang.StringBuilder = new lang.StringBuilder(); + val dataBytes: Source[ByteString, AnyRef] = param.entity.getDataBytes() + val isLockAcquired = PekkoCoreUtils.acquireServletLockIfPossible(); + + 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) + } + PekkoCoreUtils.preProcessHttpRequest(isLockAcquired, param, body, NewRelic.getAgent.getTransaction.getToken); + val response: HttpResponse = handler.apply(param) + ResponseFutureHelper.wrapResponseSync(response, materializer) + response + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PekkoHttpCoreTest.scala b/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PekkoHttpCoreTest.scala new file mode 100644 index 000000000..690f9ea88 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PekkoHttpCoreTest.scala @@ -0,0 +1,238 @@ +package com.agent.instrumentation.org.apache.pekko.http.core + +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.Trace +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.{RXSSOperation, SSRFOperation} +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.http.javadsl.Http +import org.apache.pekko.http.javadsl.model.{ContentTypes, HttpHeader, HttpRequest} +import org.apache.pekko.http.scaladsl.PekkoCoreUtils +import org.apache.pekko.stream.Materializer +import org.apache.pekko.util.ByteString +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Test} + +import java.net.ServerSocket +import java.util.UUID +import scala.concurrent.Await +import scala.concurrent.duration.{Duration, DurationInt} +import scala.jdk.CollectionConverters._ +import scala.jdk.javaapi.FutureConverters + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@InstrumentationTestConfig(includePrefixes = Array("org.apache.pekko", "scala")) +class PekkoHttpCoreTest { + + implicit val system: ActorSystem = ActorSystem() + implicit val materializer: Materializer = Materializer.createMaterializer(system) + + val PekkoServer = new PekkoServer() + val playServer = new PlayServer() + var port: Int = getRandomPort + val baseUrl: String = "http://localhost:" + port + val asyncUrl: String = "/asyncPing" + val syncUrl: String = "/ping" + val contentType: String = "text/plain" + val responseBody: String = "Hoops!" + val requestBody: String = "Hurray!" + + @Test + def syncHandlerPekkoServerTestWithPekkoServer(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + introspector.setK2FuzzRequestId(headerValue) + introspector.setK2TracingData(headerValue) + introspector.setK2ParentId(headerValue) + + val headers: Seq[HttpHeader] = makeHttpRequest(async = false, withPlay = false) + + // assertions + Assert.assertTrue("No operations detected", introspector.getOperations.size() > 0) + assertCSECHeaders(headers, headerValue) + val operations = introspector.getOperations + for ( op <- operations.asScala){ + op match { + case operation: SSRFOperation => assertSSRFOperation(operation, syncUrl) + case operation: RXSSOperation => assertRXSSOperation(operation) + case _ => + } + } + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def asyncHandlerPekkoServerTestWithPekkoServer(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + introspector.setK2FuzzRequestId(headerValue) + introspector.setK2TracingData(headerValue) + introspector.setK2ParentId(headerValue) + + val headers: Seq[HttpHeader] = makeHttpRequest(async = true, withPlay = false) + + // assertions + Assert.assertTrue("No operations detected", introspector.getOperations.size() > 0) + assertCSECHeaders(headers, headerValue) + val operations = introspector.getOperations + for (op <- operations.asScala){ + op match { + case operation: SSRFOperation => assertSSRFOperation(operation, asyncUrl) + case operation: RXSSOperation => assertRXSSOperation(operation) + case _ => + } + } + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def syncHandlerPekkoServerTestWithPlayServer(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + introspector.setK2FuzzRequestId(headerValue) + introspector.setK2TracingData(headerValue) + introspector.setK2ParentId(headerValue) + + val headers: Seq[HttpHeader] = makeHttpRequest(async = false, withPlay = true) + + // assertions + Assert.assertTrue("No operations detected", introspector.getOperations.size() > 0) + assertCSECHeaders(headers, headerValue) + val operations = introspector.getOperations + for (op <- operations.asScala){ + op match { + case operation: SSRFOperation => assertSSRFOperation(operation, syncUrl) + case operation: RXSSOperation => assertRXSSOperation(operation) + case _ => + } + } + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def asyncHandlerPekkoServerTestWithPlayServer(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + introspector.setK2FuzzRequestId(headerValue) + introspector.setK2TracingData(headerValue) + introspector.setK2ParentId(headerValue) + + val headers: Seq[HttpHeader] = makeHttpRequest(async = true, withPlay = true) + + // assertions + Assert.assertTrue("No operations detected", introspector.getOperations.size() > 0) + assertCSECHeaders(headers, headerValue) + val operations = introspector.getOperations + for (op <- operations.asScala){ + op match { + case operation: SSRFOperation => assertSSRFOperation(operation, asyncUrl) + case operation: RXSSOperation => assertRXSSOperation(operation) + case _ => + } + } + assertMetaData(introspector.getSecurityMetaData) + } + + @Trace(dispatcher = true, nameTransaction = true) + private def makeHttpRequest(async: Boolean, withPlay: Boolean): Seq[HttpHeader] = { + if (withPlay) { + // start play-pekko server & make request + playServer.start(port, async) + + Await.result(FutureConverters.asScala(Http(system = system).singleRequest( + HttpRequest + .GET(baseUrl + (if (async) asyncUrl else syncUrl)) + .withEntity(ContentTypes.TEXT_PLAIN_UTF8, ByteString.fromString(requestBody)))), new DurationInt(20).seconds) + + playServer.stop() + playServer.getHeaders + } else { + // start pekko server & make request + PekkoServer.start(port, async) + + Await.result(FutureConverters.asScala(Http(system = system).singleRequest( + HttpRequest + .GET(baseUrl + (if (async) asyncUrl else syncUrl)) + .withEntity(ContentTypes.TEXT_PLAIN_UTF8, ByteString.fromString(requestBody)))), new DurationInt(20).seconds) + + PekkoServer.stop() + PekkoServer.getHeaders + } + } + + def getRandomPort: Int = { + var port: Int = 0 + try { + val socket: ServerSocket = new ServerSocket(0) + port = socket.getLocalPort + socket.close() + } catch { + case _: Exception => throw new RuntimeException("Unable to allocate ephemeral port") + } + port + } + + private def assertSSRFOperation(operation: SSRFOperation, url: String): Unit = { + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", PekkoCoreUtils.METHOD_SINGLE_REQUEST, operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", baseUrl + url, operation.getArg) + } + private def assertCSECHeaders(headers: Seq[HttpHeader], headerVal: String): Unit = { + Assert.assertTrue( + String.format("%s CSEC header should be present", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), + headers.exists(header => header.name().contains(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + ) + Assert.assertTrue( + String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), + headers.exists(header => header.value().contains(headerVal)) + ) + + Assert.assertTrue( + String.format("%s CSEC header should be present", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), + headers.exists(header => header.name().contains(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER)) + ) + Assert.assertTrue( + String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), + headers.exists(header => header.value().contains(String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerVal))) + ) + + Assert.assertTrue( + String.format("%s CSEC header should be present", GenericHelper.CSEC_PARENT_ID), + headers.exists(header => header.name().contains(GenericHelper.CSEC_PARENT_ID)) + ) + Assert.assertTrue( + String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), + headers.exists(header => header.value().contains(headerVal)) + ) + } + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "apply", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid requestBody.", requestBody, operation.getRequest.getBody.toString) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertEquals("Invalid responseBody.", responseBody, operation.getResponse.getResponseBody.toString) + } + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("response should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid responseBody.", requestBody, metaData.getRequest.getBody.toString) + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid responseBody.", responseBody, metaData.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid protocol.", metaData.getRequest.getProtocol, "http") + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PekkoServer.scala b/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PekkoServer.scala new file mode 100644 index 000000000..97abee653 --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PekkoServer.scala @@ -0,0 +1,75 @@ +package com.agent.instrumentation.org.apache.pekko.http.core + +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.http.scaladsl.Http +import org.apache.pekko.http.scaladsl.model.HttpMethods.GET +import org.apache.pekko.http.scaladsl.model.{HttpHeader, HttpRequest, HttpResponse, Uri} +import org.apache.pekko.stream.Materializer +import org.apache.pekko.stream.scaladsl.{Sink, Source} +import org.apache.pekko.util.Timeout + +import scala.concurrent.duration._ +import scala.concurrent.{Await, ExecutionContextExecutor, Future} +import scala.language.postfixOps + +//how the pekko http core docs' example sets up a server +class PekkoServer() { + implicit val system: ActorSystem = ActorSystem() + implicit val executor: ExecutionContextExecutor = system.dispatcher + implicit val materializer: Materializer = Materializer.createMaterializer(system) + implicit val timeout: Timeout = 3 seconds + + var serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] = _ + var bindingFuture: Future[Http.ServerBinding] = _ + var headers: Seq[HttpHeader] = Seq() + + def start(port: Int, async: Boolean): Unit = { + + serverSource = Http().bind(interface = "localhost", port) + + if (async) { + + val asyncRequestHandler: HttpRequest => Future[HttpResponse] = { + case HttpRequest(GET, Uri.Path("/asyncPing"), var1, _, _) => { + headers = var1 + Future[HttpResponse](HttpResponse(entity = "Hoops!")) + } + } + + bindingFuture = serverSource.to(Sink.foreach { + connection => + println("accepted connection from: " + connection.remoteAddress) + connection handleWithAsyncHandler asyncRequestHandler + }).run() + } + else { + + val requestHandler: HttpRequest => HttpResponse = { + case HttpRequest(GET, Uri.Path("/ping"), var1, _, _) => { + headers = var1 + HttpResponse(entity = "Hoops!") + } + } + + bindingFuture = serverSource.to(Sink.foreach { + connection => + println("accepted connection from: " + connection.remoteAddress) + connection handleWithSyncHandler requestHandler + }).run() + } + + Await.ready({ + bindingFuture + }, timeout.duration) + } + + def stop(): Unit = { + if (bindingFuture != null) { + bindingFuture.flatMap(_.unbind()).onComplete(_ => system.terminate()) + } + } + + def getHeaders: Seq[HttpHeader] = { + headers + } +} diff --git a/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PlayServer.scala b/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PlayServer.scala new file mode 100644 index 000000000..585cd292f --- /dev/null +++ b/instrumentation-security/apache-pekko-http-core-2.13_1/src/test/scala/com/agent/instrumentation/org.apache.pekko/http/core/PlayServer.scala @@ -0,0 +1,67 @@ +package com.agent.instrumentation.org.apache.pekko.http.core + +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.http.scaladsl.Http +import org.apache.pekko.http.scaladsl.model.HttpMethods.GET +import org.apache.pekko.http.scaladsl.model.{HttpHeader, HttpRequest, HttpResponse, Uri} +import org.apache.pekko.stream.Materializer +import org.apache.pekko.stream.scaladsl.{Sink, Source} +import org.apache.pekko.util.Timeout + +import scala.concurrent.duration._ +import scala.concurrent.{Await, ExecutionContextExecutor, Future} +import scala.language.postfixOps + +//how play 2.6 sets up a server +class PlayServer { + implicit val system: ActorSystem = ActorSystem() + implicit val executor: ExecutionContextExecutor = system.dispatcher + implicit val materializer: Materializer = Materializer.createMaterializer(system) + implicit val timeout: Timeout = 3 seconds + + var bindingFuture: Future[Http.ServerBinding] = _ + var headers: Seq[HttpHeader] = Seq() + + def start(port: Int, async: Boolean): Unit = { + + if (async) { + + val asyncRequestHandler: HttpRequest => Future[HttpResponse] = { + case HttpRequest(GET, Uri.Path("/asyncPing"), var1, _, _) => { + headers = var1 + Future[HttpResponse](HttpResponse(entity = "Hoops!")) + } + } + + bindingFuture = Http().newServerAt("localhost", port).bind(asyncRequestHandler) + + } + else { + + val requestHandler: HttpRequest => HttpResponse = { + case HttpRequest(GET, Uri.Path("/ping"), var1, _, _) => { + headers = var1 + HttpResponse(entity = "Hoops!") + } + } + + bindingFuture = Http().newServerAt("localhost", port).bindSync(requestHandler) + } + + Await.ready({ + bindingFuture + }, timeout.duration) + } + + def stop(): Unit = { + if (bindingFuture != null) { + bindingFuture.flatMap(_.unbind()).onComplete(_ => { + system.terminate() + }) + } + } + + def getHeaders: Seq[HttpHeader] = { + headers + } +} 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 8088f8749..ca62242b3 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 @@ -1,122 +1,11 @@ package com.newrelic.agent.security.instrumentation.org.asynchttpclient; -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.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; -import com.newrelic.api.agent.security.utils.logging.LogLevel; -import org.asynchttpclient.Request; - public class AsynchttpHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "ASYNCHTTP_OPERATION_LOCK-"; public static final String METHOD_EXECUTE = "executeRequest"; - public static final String ASYNC_HTTP_CLIENT_2_0_0 = "ASYNC_HTTP_CLIENT_2.0.0"; - - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - 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(VulnerabilityCaseType httpRequest) { - return GenericHelper.acquireLockIfPossible(httpRequest, getNrSecCustomAttribName()); - } - - public static void releaseLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } - } - private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); - } - - public static AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { - try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - url == null || url.trim().isEmpty()) { - return null; - } - - SSRFOperation operation = new SSRFOperation(url, - className, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - return operation; - } catch (Throwable e) { - if (e instanceof NewRelicSecurityException) { - NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, ASYNC_HTTP_CLIENT_2_0_0, e.getMessage()), e, AsynchttpHelper.class.getName()); - throw e; - } - NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, ASYNC_HTTP_CLIENT_2_0_0, e.getMessage()), e, AsynchttpHelper.class.getName()); - NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, ASYNC_HTTP_CLIENT_2_0_0, e.getMessage()), e, AsynchttpHelper.class.getName()); - } - return null; - } - - public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { - try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || skipExistsEvent() - ) { - return; - } - NewRelicSecurity.getAgent().registerExitEvent(operation); - } catch (Throwable ignored) { - NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, AsynchttpHelper.ASYNC_HTTP_CLIENT_2_0_0, ignored.getMessage()), ignored, AsynchttpHelper.class.getName()); - } - } - - public static Request addSecurityHeaders(Request request, AbstractOperation operation) { - if (operation == null || request == null) { - return null; - } - - // Add Security IAST header - String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); - if (iastHeader != null && !iastHeader.trim().isEmpty()) { - request.getHeaders().add(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader); - } - - String csecParaentId = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class); - if(StringUtils.isNotBlank(csecParaentId)){ - request.getHeaders().add(GenericHelper.CSEC_PARENT_ID, csecParaentId); - } + public static final String ASYNC_HTTP_CLIENT_2_0_0 = "ASYNC_HTTP_CLIENT_2.0.0"; - if (operation.getApiID() != null && !operation.getApiID().trim().isEmpty() && - operation.getExecutionId() != null && !operation.getExecutionId().trim().isEmpty()) { - // Add Security distributed tracing header - request.getHeaders().remove(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); - request.getHeaders().add(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, - SSRFUtils.generateTracingHeaderValue(NewRelicSecurity.getAgent().getSecurityMetaData() - .getTracingHeaderValue(), - operation.getApiID(), operation.getExecutionId(), - NewRelicSecurity.getAgent().getAgentUUID())); - } - return request; - } } 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 2a538a84b..3fed3edd5 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 @@ -1,45 +1,39 @@ -/* - * - * * Copyright 2020 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - package org.asynchttpclient; + +import com.newrelic.agent.security.instrumentation.org.asynchttpclient.AsynchttpHelper; 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.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; 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 com.newrelic.agent.security.instrumentation.org.asynchttpclient.AsynchttpHelper; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -/** - * Instrumentation for the provider interface. - */ @Weave(type = MatchType.Interface, originalName = "org.asynchttpclient.AsyncHttpClient") public abstract class AsyncHttpClient_Instrumentation { public ListenableFuture executeRequest(Request request, AsyncHandler handler) { - URI uri = null; - boolean isLockAcquired = AsynchttpHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, getNrSecCustomAttribName()); AbstractOperation operation = null; if(isLockAcquired) { try { - uri = new URI(request.getUrl()); + URI uri = new URI(request.getUrl()); String scheme = uri.getScheme().toLowerCase(); // only instrument HTTP or HTTPS calls if (("http".equals(scheme) || "https".equals(scheme))) { - operation = AsynchttpHelper.preprocessSecurityHook(uri.toURL().toString(), this.getClass().getName(), - AsynchttpHelper.METHOD_EXECUTE); - Request updatedRequest = AsynchttpHelper.addSecurityHeaders(request, operation); + operation = preprocessSecurityHook(uri.toURL().toString(), this.getClass().getName(), AsynchttpHelper.METHOD_EXECUTE); + Request updatedRequest = addSecurityHeaders(request, operation); if (updatedRequest != null) { request = updatedRequest; } @@ -56,10 +50,77 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h returnVal = Weaver.callOriginal(); } finally { if(isLockAcquired){ - AsynchttpHelper.releaseLock(); + GenericHelper.releaseLock(getNrSecCustomAttribName()); } } - AsynchttpHelper.registerExitOperation(isLockAcquired, operation); + registerExitOperation(isLockAcquired, operation); return returnVal; } + + private String getNrSecCustomAttribName() { + return "ASYNCHTTP_OPERATION_LOCK-"; + } + + private AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { + try { + if (url == null || url.trim().isEmpty()) { + return null; + } + + SSRFOperation operation = new SSRFOperation(url, + className, methodName); + NewRelicSecurity.getAgent().registerOperation(operation); + return operation; + } catch (Throwable e) { + if (e instanceof NewRelicSecurityException) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, AsynchttpHelper.NR_SEC_CUSTOM_ATTRIB_NAME, e.getMessage()), e, this.getClass().getName()); + throw e; + } + NewRelicSecurity.getAgent().log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, AsynchttpHelper.NR_SEC_CUSTOM_ATTRIB_NAME, e.getMessage()), e, this.getClass().getName()); + NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE , String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, AsynchttpHelper.NR_SEC_CUSTOM_ATTRIB_NAME, e.getMessage()), e, this.getClass().getName()); + } + return null; + } + + private Request addSecurityHeaders(Request request, AbstractOperation operation) { + if (operation == null || request == null) { + return null; + } + + // Add Security IAST header + String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); + if (iastHeader != null && !iastHeader.trim().isEmpty()) { + request.getHeaders().add(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader); + } + + String csecParaentId = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class); + if(StringUtils.isNotBlank(csecParaentId)){ + request.getHeaders().add(GenericHelper.CSEC_PARENT_ID, csecParaentId); + } + + if (operation.getApiID() != null && !operation.getApiID().trim().isEmpty() && + operation.getExecutionId() != null && !operation.getExecutionId().trim().isEmpty()) { + // Add Security distributed tracing header + request.getHeaders().remove(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); + request.getHeaders().add(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, + SSRFUtils.generateTracingHeaderValue(NewRelicSecurity.getAgent().getSecurityMetaData() + .getTracingHeaderValue(), + operation.getApiID(), operation.getExecutionId(), + NewRelicSecurity.getAgent().getAgentUUID())); + } + return request; + } + + 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 ignored) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, AsynchttpHelper.NR_SEC_CUSTOM_ATTRIB_NAME, ignored.getMessage()), ignored, this.getClass().getName()); + } + } } 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 4c4b94439..eb08287c1 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 @@ -32,9 +32,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String expression, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(expression)){ + if (StringUtils.isBlank(expression)){ return null; } XPathOperation xPathOperation = new XPathOperation(expression, this.getClass().getName(), methodName); @@ -51,21 +49,8 @@ private AbstractOperation preprocessSecurityHook (String expression, String meth return null; } - private void releaseLock() { - try { - GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - } - - private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - 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(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.XPATH, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(value, XPATHUtils.METHOD_XPATH); @@ -76,7 +61,7 @@ public ValueBuilder xpath(String value, Class resultType, Namespaces namespac returnVal = Weaver.callOriginal(); } finally { if(isLockAcquired){ - releaseLock(); + GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } registerExitOperation(isLockAcquired, operation); 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 f5f3343c4..618df5771 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 @@ -26,15 +26,11 @@ public class CassandraUtils { public static final String METHOD_EXECUTE_ASYNC = "executeAsync"; public static final String NR_SEC_CUSTOM_ATTRIB_CQL_STMT = "NR-CQL-STMT"; public static final String EVENT_CATEGORY = "CQL"; - public static final String NR_SEC_CASSANDRA_LOCK = "CASSANDRA_OPERATION_LOCK"; + private static final String NR_SEC_CASSANDRA_LOCK = "CASSANDRA_OPERATION_LOCK"; public static final String CASSANDRA_DATASTAX_3 = "CASSANDRA-DATASTAX-3"; public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashcode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CASSANDRA_LOCK + hashcode); - } catch (Exception ignored){ - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CASSANDRA_LOCK, hashcode); } public static AbstractOperation preProcessSecurityHook(Statement statement, Configuration config, String klass) { @@ -114,7 +110,7 @@ private static Map setParams(BuiltStatement statement, ProtocolV return params; } - public static Map setParams(BoundStatement statement) { + private static Map setParams(BoundStatement statement) { Map params = new HashMap<>(); List variables = statement.preparedStatement().getVariables().asList(); try{ @@ -136,9 +132,6 @@ public static Map setParams(BoundStatement statement) { } public static void releaseLock(int hashcode) { - try { - GenericHelper.releaseLock(NR_SEC_CASSANDRA_LOCK + hashcode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(NR_SEC_CASSANDRA_LOCK, hashcode); } } 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 be4ff6d1a..16315a48f 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 @@ -25,18 +25,14 @@ import java.util.Map; public class CassandraUtils { - public static final String METHOD_EXECUTE = "execute"; + private static final String METHOD_EXECUTE = "execute"; public static final String NR_SEC_CUSTOM_ATTRIB_CQL_STMT = "NR-CQL-STMT"; public static final String EVENT_CATEGORY = "CQL"; - public static final String NR_SEC_CASSANDRA_LOCK = "CASSANDRA_OPERATION_LOCK"; + private static final String NR_SEC_CASSANDRA_LOCK = "CASSANDRA_OPERATION_LOCK"; public static final String CASSANDRA_DATASTAX_4 = "CASSANDRA-DATASTAX-4"; public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CASSANDRA_LOCK, hashCode); - } catch (Exception ignored){ - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, NR_SEC_CASSANDRA_LOCK, hashCode); } public static AbstractOperation preProcessSecurityHook(String klass, RequestT request) { @@ -83,7 +79,7 @@ else if (request instanceof BoundStatement) { return null; } - public static Map setParams(BoundStatement statement) { + private static Map setParams(BoundStatement statement) { Map params = new HashMap<>(); ColumnDefinitions variables = statement.getPreparedStatement().getVariableDefinitions(); try{ @@ -128,10 +124,7 @@ public static Map setParams(SimpleStatement statement) { } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_CASSANDRA_LOCK, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(NR_SEC_CASSANDRA_LOCK, hashCode); } public static void registerExitOperation(boolean isLockAcquired, AbstractOperation operation) { 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 b4abba71d..5c3b6653d 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 @@ -19,7 +19,7 @@ public class JXPathContextReferenceImpl_Instrumentation { public Object getValue(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_GETVALUE); @@ -38,7 +38,7 @@ public Object getValue(String xpath, Expression expr) { } public Iterator iterate(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_ITERATE); @@ -57,7 +57,7 @@ public Iterator iterate(String xpath, Expression expr) { } public void removePath(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_REMOVE_PATH); @@ -74,7 +74,7 @@ public void removePath(String xpath, Expression expr) { } public void removeAll(String xpath, Expression expr) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(xpath, XPATHUtils.METHOD_REMOVE_ALL); @@ -105,9 +105,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -125,15 +123,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } - private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.XPATH, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } 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 66a2d18af..ab54e4cbb 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 @@ -52,17 +52,14 @@ public abstract class DynamoDBUtil { public static AbstractOperation processDynamoDBRequest(Request yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - AmazonWebServiceRequest request = yRequest.getOriginalRequest(); + List requests = new ArrayList(); + AmazonWebServiceRequest request = yRequest.getOriginalRequest(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 0478947e0..e578f4e7a 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 @@ -52,17 +52,14 @@ public abstract class DynamoDBUtil { public static AbstractOperation processDynamoDBRequest(Request yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - AmazonWebServiceRequest request = yRequest.getOriginalRequest(); + List requests = new ArrayList(); + AmazonWebServiceRequest request = yRequest.getOriginalRequest(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 d981b6199..2a99f2819 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 @@ -61,17 +61,14 @@ public abstract class DynamoDBUtil { public static AbstractOperation processDynamoDBRequest(Request yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - AmazonWebServiceRequest request = yRequest.getOriginalRequest(); + List requests = new ArrayList(); + AmazonWebServiceRequest request = yRequest.getOriginalRequest(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 44d708f95..47e96e778 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 @@ -52,17 +52,14 @@ public abstract class DynamoDBUtil { public static AbstractOperation processDynamoDBRequest(Request yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - AmazonWebServiceRequest request = yRequest.getOriginalRequest(); + List requests = new ArrayList(); + AmazonWebServiceRequest request = yRequest.getOriginalRequest(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 1e59b670f..0423e0020 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 @@ -56,16 +56,14 @@ public static AbstractO ClientExecutionParams yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - InputT request = yRequest.getInput(); + List requests = new ArrayList(); + InputT request = yRequest.getInput(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 73f8d5691..dd51a382a 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 @@ -65,16 +65,14 @@ public static AbstractO ClientExecutionParams yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - InputT request = yRequest.getInput(); + List requests = new ArrayList(); + InputT request = yRequest.getInput(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 35c9cc87a..4063dd651 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 @@ -70,16 +70,14 @@ public static AbstractO ClientExecutionParams yRequest, String klassName) { DynamoDBOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List requests = new ArrayList(); - InputT request = yRequest.getInput(); + List requests = new ArrayList(); + InputT request = yRequest.getInput(); - operation = checkAndGenerateOperation(request, requests, klassName); + operation = checkAndGenerateOperation(request, requests, klassName); - if (operation!=null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + if (operation!=null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { 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 989790c66..0c566ca12 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 @@ -23,35 +23,29 @@ public abstract class File_Instrumentation { public abstract String getAbsolutePath(); public boolean exists() { - boolean isFileLockAcquired = acquireFileLockIfPossible(VulnerabilityCaseType.FILE_OPERATION); + boolean isFileLockAcquired = false; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); AbstractOperation operation = null; - if (isOwaspHookEnabled && isFileLockAcquired && !FileHelper.skipExistsEvent(this.getName()) && LowSeverityHelper.isOwaspHookProcessingNeeded()) { - operation = preprocessSecurityHook(true, FileHelper.METHOD_NAME_EXISTS, true, this); + if (isOwaspHookEnabled && !FileHelper.skipExistsEvent(this.getName()) && LowSeverityHelper.isOwaspHookProcessingNeeded()) { + isFileLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.FILE_OPERATION, FileHelper.getNrSecCustomAttribName()); + if (isFileLockAcquired) + operation = preprocessSecurityHook(true, FileHelper.METHOD_NAME_EXISTS, true, this); } boolean returnVal = false; try { returnVal = Weaver.callOriginal(); } finally { - if (isOwaspHookEnabled) { - registerExitOperation(isFileLockAcquired, operation); - } if (isFileLockAcquired) { - releaseFileLock(); + GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); } } + if (isOwaspHookEnabled) { + registerExitOperation(isFileLockAcquired, operation); + } return returnVal; } - private static boolean acquireFileLockIfPossible(VulnerabilityCaseType fileOperation) { - return GenericHelper.acquireLockIfPossible(fileOperation, FileHelper.getNrSecCustomAttribName()); - } - - private static void releaseFileLock() { - GenericHelper.releaseLock(FileHelper.getNrSecCustomAttribName()); - } - private static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { @@ -71,10 +65,7 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private static AbstractOperation preprocessSecurityHook(boolean isBooleanAttributesCall, String methodName, boolean isLowSeverityHook, File_Instrumentation... files) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || files == null || files.length == 0 - ) { + if (files == null || files.length == 0) { return null; } List fileNames = new ArrayList<>(files.length); 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 817531e2d..f95faf703 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 @@ -62,9 +62,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(String filename) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || filename == null || filename.trim().isEmpty() + if (filename == null || filename.trim().isEmpty() ) { return null; } 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 ae6e2e885..27071d763 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 @@ -63,9 +63,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(String filename) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || filename == null || filename.trim().isEmpty() + if (filename == null || filename.trim().isEmpty() ) { return null; } 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 6c7372d77..398bcfcfb 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 @@ -372,9 +372,7 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private static AbstractOperation preprocessSecurityHook(boolean isBooleanAttributesCall, String methodName, boolean isLowSeverityHook, File_Instrumentation... files) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || files == null || files.length == 0 + if (files == null || files.length == 0 ) { return null; } 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 85517df32..5403187c8 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 @@ -62,9 +62,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(String filename) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || filename == null || filename.trim().isEmpty() + if (filename == null || filename.trim().isEmpty() ) { return null; } 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 d2a88246b..e3c763aac 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 @@ -70,9 +70,7 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private static AbstractOperation preprocessSecurityHook(boolean isBooleanAttributesCall, String methodName, boolean isLowSeverityHook, File... files) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || files == null || files.length == 0 + if (files == null || files.length == 0 ) { return null; } 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 36b95a300..2dc5330dd 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 @@ -320,9 +320,6 @@ private void registerExitOperation(AbstractOperation operation, boolean isFileLo private AbstractOperation preprocessSecurityHook(String methodName, Path... filename) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - return null; - } List fileNames = new ArrayList<>(); for (Path path : filename) { diff --git a/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm19/JSEngineUtils.java b/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm19/JSEngineUtils.java index c1498c28f..6092934f8 100644 --- a/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm19/JSEngineUtils.java +++ b/instrumentation-security/graalvm-jsinjection-19.0.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm19/JSEngineUtils.java @@ -3,8 +3,6 @@ public class JSEngineUtils { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "JSENGINE_OPERATION_LOCK_NASHORN-"; - - public static final String METHOD_EVAL = "eval"; public static final String LANGUAGE_ID_JS = "js"; public static final String GRAALVM_JS_INJECTION_19_0_0 = "GRAALVM_JS_INJECTION_19.0.0"; 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 7d7d7c6a4..44b785f08 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 @@ -21,7 +21,7 @@ final class PolyglotContextImpl_Instrumentation { public Value eval(String languageId, Object sourceImpl) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(languageId, sourceImpl, JSEngineUtils.METHOD_EVAL); @@ -54,9 +54,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String languageId, Object sourceImpl, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - !StringUtils.equals(languageId, JSEngineUtils.LANGUAGE_ID_JS)){ + if (!StringUtils.equals(languageId, JSEngineUtils.LANGUAGE_ID_JS)){ return null; } com.oracle.truffle.api.source.Source source = (Source) sourceImpl; @@ -75,15 +73,10 @@ private AbstractOperation preprocessSecurityHook (String languageId, Object sour } private void releaseLock() { - try { - GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } - private boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection) { - try { - return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } 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 43a5cc51c..e2815faeb 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 @@ -21,7 +21,7 @@ final class PolyglotContextImpl_Instrumentation { public Value eval(String languageId, org.graalvm.polyglot.Source source) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(languageId, source, JSEngineUtils.METHOD_EVAL); @@ -54,9 +54,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String languageId, Source source, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - !StringUtils.equals(languageId, JSEngineUtils.LANGUAGE_ID_JS)){ + if (!StringUtils.equals(languageId, JSEngineUtils.LANGUAGE_ID_JS)){ return null; } JSInjectionOperation jsInjectionOperation = new JSInjectionOperation(String.valueOf(source.getCharacters()), this.getClass().getName(), methodName); @@ -74,15 +72,10 @@ private AbstractOperation preprocessSecurityHook (String languageId, Source sour } private void releaseLock() { - try { - GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } - private boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection) { - try { - return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/instrumentation-security/graphql-java-16.2/build.gradle b/instrumentation-security/graphql-java-16.2/build.gradle index ee706f615..2ac60f459 100644 --- a/instrumentation-security/graphql-java-16.2/build.gradle +++ b/instrumentation-security/graphql-java-16.2/build.gradle @@ -6,7 +6,7 @@ dependencies { } jar { - manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.graphql-java-16.2', 'Enabled': 'false' } + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.graphql-java-16.2' } } verifyInstrumentation { 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 fb120f290..bedb59a8f 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 @@ -14,13 +14,13 @@ import io.grpc.Metadata; public class GrpcClientUtils { - public static final String METHOD_NAME_START = "start"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_CLIENT_OPERATIONAL_LOCK_"; + private static final String METHOD_NAME_START = "start"; + + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_CLIENT_OPERATIONAL_LOCK_"; public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { return; } NewRelicSecurity.getAgent().registerExitEvent(operation); @@ -32,12 +32,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(String uri, Metadata meta, String klass) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - SSRFOperation operation = new SSRFOperation(uri, klass, METHOD_NAME_START); NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); 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 6a0f04108..c20978838 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 @@ -22,19 +22,15 @@ import java.util.Set; public class GrpcServerUtils { - public static final String LIBRARY_NAME = "gRPC"; private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String METHOD_NAME_START_CALL = "startCall"; public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_SERVER_OPERATIONAL_LOCK_"; + public static final String METHOD_NAME_START_CALL = "startCall"; private static Set typeRegistries = new HashSet<>(); public static void preprocessSecurityHook(ServerStream_Instrumentation call, ServerMethodDefinition methodDef, Metadata meta, String klass) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); HttpRequest securityRequest = securityMetaData.getRequest(); @@ -91,10 +87,7 @@ 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()) { + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(statusCode); @@ -132,12 +125,7 @@ public static void postProcessSecurityHook(Metadata metadata, int statusCode, St public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttrName()); } private static String getNrSecCustomAttrName() { @@ -145,25 +133,10 @@ private static String getNrSecCustomAttrName() { } 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; + return GenericHelper.acquireLockIfPossible(getNrSecCustomAttrName()); } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -174,7 +147,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static void processGRPCRequestMetadata(Metadata metadata, HttpRequest securityRequest) { + private static void processGRPCRequestMetadata(Metadata metadata, HttpRequest securityRequest) { Set headerNames = metadata.keys(); for (String headerKey : headerNames) { boolean takeNextValue = false; diff --git a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcUtils.java b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcUtils.java index ad6fa9670..7a1dc3373 100644 --- a/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcUtils.java +++ b/instrumentation-security/grpc-1.22.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1220/GrpcUtils.java @@ -47,31 +47,10 @@ public static void preProcessSecurityHook(T receivedMessage, Type type, Stri } public static void releaseLock(int hashcode) { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode, null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } public static boolean acquireLockIfPossible(int hashcode) { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode)) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode, 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; + return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } } 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 b20081e13..4c54274fd 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 @@ -18,7 +18,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class GrpcRequestThreadPool { - public static final String CALL_FAILED_REQUEST_S_REASON = "Call failed : request %s reason : "; /** * Thread pool executor. 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 181f8f155..5d56d191c 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 @@ -14,13 +14,12 @@ import io.grpc.Metadata; public class GrpcClientUtils { - public static final String METHOD_NAME_START = "start"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_CLIENT_OPERATIONAL_LOCK_"; + private static final String METHOD_NAME_START = "start"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_CLIENT_OPERATIONAL_LOCK_"; public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { return; } NewRelicSecurity.getAgent().registerExitEvent(operation); @@ -32,12 +31,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(String uri, Metadata meta, String klass) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - SSRFOperation operation = new SSRFOperation(uri, klass, METHOD_NAME_START); NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); 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 e4e9431d4..87cb954c5 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 @@ -32,9 +32,6 @@ public class GrpcServerUtils { public static void preprocessSecurityHook(ServerStream_Instrumentation call, ServerMethodDefinition methodDef, Metadata meta, String klass) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); HttpRequest securityRequest = securityMetaData.getRequest(); @@ -95,10 +92,7 @@ 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()) { + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(statusCode); @@ -136,12 +130,7 @@ public static void postProcessSecurityHook(Metadata metadata, int statusCode, St public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttrName()); } private static String getNrSecCustomAttrName() { @@ -149,22 +138,7 @@ private static String getNrSecCustomAttrName() { } 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; + return GenericHelper.acquireLockIfPossible(getNrSecCustomAttrName()); } public static String getTraceHeader(Map headers) { diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcUtils.java b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcUtils.java index 3d954c63d..c4588fff1 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcUtils.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/GrpcUtils.java @@ -11,7 +11,7 @@ import java.util.Map; public class GrpcUtils { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_OBJECT_LOCK_"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_OBJECT_LOCK_"; public static final String GRPC_1_4_0 = "GRPC-1.4.0"; public enum Type { @@ -48,30 +48,10 @@ public static void preProcessSecurityHook(T receivedMessage, Type type, Stri } public static void releaseLock(int hashcode) { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode, null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } public static boolean acquireLockIfPossible(int hashcode) { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode)) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode, 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; + return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } } diff --git a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/client/GrpcClient.java b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/client/GrpcClient.java index 774550bf5..2058227af 100644 --- a/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/client/GrpcClient.java +++ b/instrumentation-security/grpc-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc140/client/GrpcClient.java @@ -202,7 +202,7 @@ private static Object customServerStream(ManagedChannel channel, FuzzRequestBean return null; } - public static Object customBiDiStream(ManagedChannel channel, FuzzRequestBean requestBean, List payloads) throws InterruptedException { + private static Object customBiDiStream(ManagedChannel channel, FuzzRequestBean requestBean, List payloads) throws InterruptedException { GrpcStubs.CustomStub stub = GrpcStubs.newStub(channel); StringBuilder body = requestBean.getBody(); String[] methodSplitData = requestBean.getMethod().split("/"); 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 32e8eec98..5c209022d 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 @@ -18,7 +18,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class GrpcRequestThreadPool { - public static final String CALL_FAILED_REQUEST_S_REASON = "Call failed : request %s reason : "; /** * Thread pool executor. 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 3145a0cad..eee35668c 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 @@ -14,13 +14,12 @@ import io.grpc.Metadata; public class GrpcClientUtils { - public static final String METHOD_NAME_START = "start"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_CLIENT_OPERATIONAL_LOCK_"; + private static final String METHOD_NAME_START = "start"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_CLIENT_OPERATIONAL_LOCK_"; public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { return; } NewRelicSecurity.getAgent().registerExitEvent(operation); 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 90cb822dd..3b65ebbf0 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 @@ -31,9 +31,6 @@ public class GrpcServerUtils { public static void preprocessSecurityHook(ServerStream_Instrumentation call, ServerMethodDefinition methodDef, Metadata meta, String klass) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); HttpRequest securityRequest = securityMetaData.getRequest(); @@ -90,10 +87,7 @@ 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()) { + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(statusCode); @@ -131,11 +125,7 @@ public static void postProcessSecurityHook(Metadata metadata, int statusCode, St public static void releaseLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttrName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttrName()); } private static String getNrSecCustomAttrName() { @@ -143,25 +133,10 @@ private static String getNrSecCustomAttrName() { } 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; + return GenericHelper.acquireLockIfPossible(getNrSecCustomAttrName()); } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -172,7 +147,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static void processGRPCRequestMetadata(Metadata metadata, HttpRequest securityRequest) { + private static void processGRPCRequestMetadata(Metadata metadata, HttpRequest securityRequest) { Set headerNames = metadata.keys(); for (String headerKey : headerNames) { boolean takeNextValue = false; diff --git a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcUtils.java b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcUtils.java index 3f0de3499..b285d0db2 100644 --- a/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcUtils.java +++ b/instrumentation-security/grpc-1.40.0/src/main/java/com/newrelic/agent/security/instrumentation/grpc1400/GrpcUtils.java @@ -11,7 +11,7 @@ import java.util.Map; public class GrpcUtils { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_OBJECT_LOCK_"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "NR_CSEC_GRPC_OBJECT_LOCK_"; public static final String GRPC_1_40_0 = "GRPC-1.40.0"; public enum Type { @@ -48,29 +48,11 @@ public static void preProcessSecurityHook(T receivedMessage, Type type, Stri } public static void releaseLock(int hashcode) { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode, null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } public static boolean acquireLockIfPossible(int hashcode) { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode)) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(NR_SEC_CUSTOM_ATTRIB_NAME+hashcode, true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } - 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/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 63391d32a..46cd490fd 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 @@ -40,7 +40,7 @@ public class HttpAsyncClient4_Instrumentation { public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsyncResponseConsumer responseConsumer, HttpContext context, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -66,7 +66,7 @@ public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsync } public Future execute(HttpAsyncRequestProducer requestProducer, HttpAsyncResponseConsumer responseConsumer, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -92,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase @@ -120,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase @@ -148,7 +148,7 @@ public Future execute(HttpHost target, HttpRequest request, Future } public Future execute(HttpUriRequest request, HttpContext context, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -168,7 +168,7 @@ public Future execute(HttpUriRequest request, HttpContext context, } public Future execute(HttpUriRequest request, FutureCallback callback) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -210,10 +210,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest request, String uri, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // Add Security IAST header String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); @@ -250,17 +246,10 @@ private AbstractOperation preprocessSecurityHook(HttpRequest request, String uri } private void releaseLock() { - try { - GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } } diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.21/build.gradle b/instrumentation-security/http4s-blaze-client-2.12_0.21/build.gradle new file mode 100644 index 000000000..cc4ee7d23 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.21/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-blaze-client_2.12:0.21.24') + implementation("org.typelevel:cats-effect_2.12:2.5.5") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-client-2.12_0.21', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-client_2.12:[0.21,0.22)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java new file mode 100644 index 000000000..a80d809da --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java @@ -0,0 +1,22 @@ +package org.http4s; + +import cats.effect.ConcurrentEffect; +import cats.effect.Resource; +import com.newrelic.agent.security.instrumentation.http4s.blaze.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.client.blaze.BlazeClientBuilder") +public abstract class BlazeClientBuilder_Instrumentation { + + public ConcurrentEffect F() { + return Weaver.callOriginal(); + } + + public Resource> resource() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, F()); + } +} diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..cf63c2a81 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import cats.effect.{Async, ConcurrentEffect, Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-BLAZE-CLIENT-OUTBOUND" + private final val HTTP4S_BLAZE_CLIENT: String = "HTTP4S-BLAZE-CLIENT-2.12_0.21" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : ConcurrentEffect](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.liftF(construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + request <- Resource.liftF(construct {addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.liftF(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : ConcurrentEffect](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala new file mode 100644 index 000000000..40a92e4f7 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import org.http4s.util.CaseInsensitiveString +import org.http4s.{Header, Request} + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CaseInsensitiveString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala new file mode 100644 index 000000000..8cc8bc228 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala @@ -0,0 +1,93 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.{ConcurrentEffect, ContextShift, IO, Timer} +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.client.blaze.BlazeClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.global +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BlazeClientTest { + + @Rule + def server: HttpServerRule = httpServer + + implicit val ec: ExecutionContext = global + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_] : ContextShift : Timer](url: String)( + implicit ex: ExecutionContext, c: ConcurrentEffect[F]): F[String] = { + BlazeClientBuilder[F](ex).resource.use { client => + client.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.22/build.gradle b/instrumentation-security/http4s-blaze-client-2.12_0.22/build.gradle new file mode 100644 index 000000000..90a536b9c --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.22/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-blaze-client_2.12:0.22.14') + implementation("org.typelevel:cats-effect_2.12:2.5.5") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-client-2.12_0.22', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-client_2.12:[0.22.0,0.23.0)' + excludeRegex '.*(RC|M)[0-9]*' + excludeRegex '.*0.22\\-[0-9].*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java new file mode 100644 index 000000000..8159dc0be --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java @@ -0,0 +1,22 @@ +package org.http4s; + +import cats.effect.ConcurrentEffect; +import cats.effect.Resource; +import com.newrelic.agent.security.instrumentation.http4s.blaze.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.blaze.client.BlazeClientBuilder") +public abstract class BlazeClientBuilder_Instrumentation { + + public ConcurrentEffect F() { + return Weaver.callOriginal(); + } + + public Resource> resource() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, F()); + } +} diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..c26aaa4d3 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import cats.effect.{Async, Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-BLAZE-CLIENT-OUTBOUND" + private final val HTTP4S_BLAZE_CLIENT: String = "HTTP4S-BLAZE-CLIENT-2.12_0.22" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.eval( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + request <- Resource.eval(construct{addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.eval(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala new file mode 100644 index 000000000..8f30ab6d3 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import org.http4s.{Header, Request} +import org.typelevel.ci.CIString + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CIString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala new file mode 100644 index 000000000..8cc8bc228 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala @@ -0,0 +1,93 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.{ConcurrentEffect, ContextShift, IO, Timer} +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.client.blaze.BlazeClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.global +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BlazeClientTest { + + @Rule + def server: HttpServerRule = httpServer + + implicit val ec: ExecutionContext = global + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_] : ContextShift : Timer](url: String)( + implicit ex: ExecutionContext, c: ConcurrentEffect[F]): F[String] = { + BlazeClientBuilder[F](ex).resource.use { client => + client.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.23/build.gradle b/instrumentation-security/http4s-blaze-client-2.12_0.23/build.gradle new file mode 100644 index 000000000..0ad63331a --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.23/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-blaze-client_2.12:0.23.12') + implementation("org.typelevel:cats-effect_2.12:3.3.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-client-2.12_0.23', 'Priority': '-1' + } +} +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-client_2.12:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java new file mode 100644 index 000000000..c5ebc74be --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java @@ -0,0 +1,22 @@ +package org.http4s; + +import cats.effect.kernel.Async; +import cats.effect.kernel.Resource; +import com.newrelic.agent.security.instrumentation.http4s.blaze.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.blaze.client.BlazeClientBuilder") +public abstract class BlazeClientBuilder_Instrumentation { + + public Async F() { + return Weaver.callOriginal(); + } + + public Resource> resource() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, F()); + } +} diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..d111a785f --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import cats.effect.{Async, Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-BLAZE-CLIENT-OUTBOUND" + private final val HTTP4S_BLAZE_CLIENT: String = "HTTP4S-BLAZE-CLIENT-2.12_0.23" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.eval( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + request <- Resource.eval(construct{addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.eval(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala new file mode 100644 index 000000000..8f30ab6d3 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import org.http4s.{Header, Request} +import org.typelevel.ci.CIString + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CIString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-blaze-client-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala new file mode 100644 index 000000000..0f60d5313 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala @@ -0,0 +1,93 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.IO +import cats.effect.kernel.Async +import cats.effect.unsafe.IORuntime +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.blaze.client.BlazeClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.global +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BlazeClientTest { + + @Rule + def server: HttpServerRule = httpServer + + implicit val ec: ExecutionContext = global + implicit val io: IORuntime = IORuntime.global + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_]: Async](url: String)(implicit ex: ExecutionContext): F[String] = { + BlazeClientBuilder[F].resource.use { client => + client.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.21/build.gradle b/instrumentation-security/http4s-blaze-client-2.13_0.21/build.gradle new file mode 100644 index 000000000..cd6ab5f5f --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.21/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation("org.typelevel:cats-effect_2.13:2.5.5") + implementation('org.http4s:http4s-blaze-client_2.13:0.21.24') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-client-2.13_0.21', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-client_2.13:[0.21.0,0.22.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java new file mode 100644 index 000000000..a80d809da --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java @@ -0,0 +1,22 @@ +package org.http4s; + +import cats.effect.ConcurrentEffect; +import cats.effect.Resource; +import com.newrelic.agent.security.instrumentation.http4s.blaze.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.client.blaze.BlazeClientBuilder") +public abstract class BlazeClientBuilder_Instrumentation { + + public ConcurrentEffect F() { + return Weaver.callOriginal(); + } + + public Resource> resource() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, F()); + } +} diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..989bf012e --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import cats.effect.{Async, Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-BLAZE-CLIENT-OUTBOUND" + private final val HTTP4S_BLAZE_CLIENT: String = "HTTP4S-BLAZE-CLIENT-2.13_0.21" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.liftF( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + request <- Resource.liftF(construct {addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.liftF(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala new file mode 100644 index 000000000..40a92e4f7 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import org.http4s.util.CaseInsensitiveString +import org.http4s.{Header, Request} + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CaseInsensitiveString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala new file mode 100644 index 000000000..a73ddb232 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala @@ -0,0 +1,93 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.{ConcurrentEffect, ContextShift, IO, Timer} +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.BlazeClientTest$.makeRequest +import org.http4s.client.blaze.BlazeClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.global +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BlazeClientTest { + + @Rule + def server: HttpServerRule = httpServer + + implicit val ec: ExecutionContext = global + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object BlazeClientTest$ { + def makeRequest[F[_] : ContextShift : Timer](url: String)( + implicit ex: ExecutionContext, c: ConcurrentEffect[F]): F[String] = { + BlazeClientBuilder[F](ex).resource.use { client => + client.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.22/build.gradle b/instrumentation-security/http4s-blaze-client-2.13_0.22/build.gradle new file mode 100644 index 000000000..89d63f453 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.22/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation("org.typelevel:cats-effect_2.13:2.5.5") + implementation('org.http4s:http4s-blaze-client_2.13:0.22.14') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-client-2.13_0.22', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-client_2.13:[0.22.0,0.23.0)' + excludeRegex '.*(RC|M)[0-9]*' + excludeRegex '.*0.22\\-[0-9].*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java new file mode 100644 index 000000000..8159dc0be --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java @@ -0,0 +1,22 @@ +package org.http4s; + +import cats.effect.ConcurrentEffect; +import cats.effect.Resource; +import com.newrelic.agent.security.instrumentation.http4s.blaze.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.blaze.client.BlazeClientBuilder") +public abstract class BlazeClientBuilder_Instrumentation { + + public ConcurrentEffect F() { + return Weaver.callOriginal(); + } + + public Resource> resource() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, F()); + } +} diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..425ee249c --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import cats.effect.{Async, Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-BLAZE-CLIENT-OUTBOUND" + private final val HTTP4S_BLAZE_CLIENT: String = "HTTP4S-BLAZE-CLIENT-2.13_0.22" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.eval( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + request <- Resource.eval(construct{addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.eval(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala new file mode 100644 index 000000000..8f30ab6d3 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import org.http4s.{Header, Request} +import org.typelevel.ci.CIString + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CIString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala new file mode 100644 index 000000000..fe646f10b --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala @@ -0,0 +1,93 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.{ConcurrentEffect, ContextShift, IO, Timer} +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.blaze.client.BlazeClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.global +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BlazeClientTest { + + @Rule + def server: HttpServerRule = httpServer + + implicit val ec: ExecutionContext = global + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest(s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_] : ContextShift : Timer](url: String)( + implicit ex: ExecutionContext, c: ConcurrentEffect[F]): F[String] = { + BlazeClientBuilder[F](ex).resource.use { client => + client.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.23/build.gradle b/instrumentation-security/http4s-blaze-client-2.13_0.23/build.gradle new file mode 100644 index 000000000..4770da3ff --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.23/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation('org.http4s:http4s-blaze-client_2.13:0.23.12') + implementation("org.typelevel:cats-effect_2.13:3.3.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-client-2.13_0.23', 'Priority': '-1' + } +} +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-client_2.13:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java new file mode 100644 index 000000000..c5ebc74be --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/java/org/http4s/BlazeClientBuilder_Instrumentation.java @@ -0,0 +1,22 @@ +package org.http4s; + +import cats.effect.kernel.Async; +import cats.effect.kernel.Resource; +import com.newrelic.agent.security.instrumentation.http4s.blaze.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.blaze.client.BlazeClientBuilder") +public abstract class BlazeClientBuilder_Instrumentation { + + public Async F() { + return Weaver.callOriginal(); + } + + public Resource> resource() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, F()); + } +} diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..788343539 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,123 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import cats.effect.{Async, Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-BLAZE-CLIENT-OUTBOUND" + private final val HTTP4S_BLAZE_CLIENT: String = "HTTP4S-BLAZE-CLIENT-2.13_0.23" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.eval( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + request <- Resource.eval(construct{addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.eval(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_BLAZE_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala new file mode 100644 index 000000000..8f30ab6d3 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/blaze/OutboundRequestWrapper.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.blaze + +import org.http4s.{Header, Request} +import org.typelevel.ci.CIString + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CIString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-blaze-client-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala new file mode 100644 index 000000000..0f60d5313 --- /dev/null +++ b/instrumentation-security/http4s-blaze-client-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/BlazeClientTest.scala @@ -0,0 +1,93 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.IO +import cats.effect.kernel.Async +import cats.effect.unsafe.IORuntime +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.blaze.client.BlazeClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.global +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BlazeClientTest { + + @Rule + def server: HttpServerRule = httpServer + + implicit val ec: ExecutionContext = global + implicit val io: IORuntime = IORuntime.global + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_]: Async](url: String)(implicit ex: ExecutionContext): F[String] = { + BlazeClientBuilder[F].resource.use { client => + client.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.21/build.gradle b/instrumentation-security/http4s-blaze-server-2.12_0.21/build.gradle new file mode 100644 index 000000000..74acd27fd --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.21/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-blaze-server_2.12:0.21.24') + testImplementation("org.http4s:http4s-dsl_2.12:0.21.24") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-server-2.12_0.21', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-server_2.12:[0.21.0,0.22.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.21/src/main/java/org/http4s/server/blaze/BlazeServerBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/main/java/org/http4s/server/blaze/BlazeServerBuilder_Instrumentation.java new file mode 100644 index 000000000..e6fc9daa9 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/main/java/org/http4s/server/blaze/BlazeServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.server.blaze; + +import cats.data.Kleisli; +import cats.effect.ConcurrentEffect; +import com.newrelic.agent.security.http4s.blaze.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.server.blaze.BlazeServerBuilder") +public class BlazeServerBuilder_Instrumentation { + + private final ConcurrentEffect F = Weaver.callOriginal(); + + public BlazeServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.F); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.21/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala new file mode 100644 index 000000000..ceb9aa337 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala @@ -0,0 +1,184 @@ +package com.newrelic.agent.security.http4s.blaze.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-BLAZE-SERVER-2.12_0.21" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-BLAZE-REQUEST_LOCK") + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort(request.serverPort.toInt) + securityRequest.setClientIP(request.remoteAddr.get.toString) + + securityRequest.setProtocol("http") + if (request.isSecure.get) { + securityRequest.setProtocol("https") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 2, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey = StringUtils.EMPTY + if (header.name != null && !header.name.isEmpty) { + headerKey = header.name.toString + } + val headerValue = header.value + + val agentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyAsText(defaultCharset = charset).compile.string + } else { + msg.bodyAsText.compile.string + } + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired:Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(3) + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && !header.name.isEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_]: Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala new file mode 100644 index 000000000..00dc05603 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala @@ -0,0 +1,135 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.util.CaseInsensitiveString +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.blaze.server")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CaseInsensitiveString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + conn.setDoOutput(true) + + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala new file mode 100644 index 000000000..70cd5c070 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala @@ -0,0 +1,36 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import scala.concurrent.ExecutionContext.global +import cats.effect.{ConcurrentEffect, ContextShift, IO, Resource, Timer} +import org.http4s.HttpApp +import org.http4s.server.blaze.BlazeServerBuilder +import org.http4s.server.Server + +import scala.concurrent.ExecutionContext + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server[IO] = _ + var finalizer: IO[Unit] = _ + + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + implicit val concurrentEffect: ConcurrentEffect[IO] = IO.ioConcurrentEffect + + implicit val ec: ExecutionContext = global + + val serverResource: Resource[IO, Server[IO]] = BlazeServerBuilder.apply(global) + .withHttpApp(httpApp) + .bindHttp(port, testServerHost) + .resource + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.22/build.gradle b/instrumentation-security/http4s-blaze-server-2.12_0.22/build.gradle new file mode 100644 index 000000000..0cbffcfaa --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.22/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-blaze-server_2.12:0.22.14') + testImplementation("org.http4s:http4s-dsl_2.12:0.22.14") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-server-2.12_0.22', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-server_2.12:[0.22.0,0.23.0)' + excludeRegex '.*(RC|M)[0-9]*' + excludeRegex '.*0.22\\-[0-9].*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.22/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java new file mode 100644 index 000000000..aa47a334a --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.blaze.server; + +import cats.data.Kleisli; +import cats.effect.ConcurrentEffect; +import com.newrelic.agent.security.http4s.blaze.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.blaze.server.BlazeServerBuilder") +public class BlazeServerBuilder_Instrumentation { + + private final ConcurrentEffect F = Weaver.callOriginal(); + + public BlazeServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.F); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.22/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala new file mode 100644 index 000000000..5006fa96b --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala @@ -0,0 +1,186 @@ +package com.newrelic.agent.security.http4s.blaze.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.comcast.ip4s.Port +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 fs2.RaiseThrowable +import org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-BLAZE-SERVER-2.12_0.22" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-BLAZE-REQUEST_LOCK") + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort((request.serverPort).get.asInstanceOf[Port].value) + securityRequest.setClientIP(request.remoteAddr.get.toString) + + securityRequest.setProtocol("http") + if (request.isSecure.get) { + securityRequest.setProtocol("https") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 2, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey = StringUtils.EMPTY + if (header.name != null && header.name.nonEmpty) { + headerKey = header.name.toString + } + val headerValue = header.value + + val agentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyText(RaiseThrowable.fromApplicativeError, defaultCharset = charset).compile.string + } else { + msg.bodyText.compile.string + } + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired:Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(3) + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && !header.name.isEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_]: Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala new file mode 100644 index 000000000..3fc5dc675 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala @@ -0,0 +1,135 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} +import org.typelevel.ci.CIString + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.blaze.server", "scala")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CIString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + conn.setDoOutput(true) + + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala new file mode 100644 index 000000000..479ba05f4 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala @@ -0,0 +1,36 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import scala.concurrent.ExecutionContext.global +import cats.effect.{ConcurrentEffect, ContextShift, IO, Resource, Timer} +import org.http4s.HttpApp +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.server.Server + +import scala.concurrent.ExecutionContext + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server = _ + var finalizer: IO[Unit] = _ + + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + implicit val concurrentEffect: ConcurrentEffect[IO] = IO.ioConcurrentEffect + + implicit val ec: ExecutionContext = global + + val serverResource: Resource[IO, Server] = BlazeServerBuilder.apply(global) + .withHttpApp(httpApp) + .bindHttp(port, testServerHost) + .resource + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.23/build.gradle b/instrumentation-security/http4s-blaze-server-2.12_0.23/build.gradle new file mode 100644 index 000000000..1c12651fb --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.23/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-blaze-server_2.12:0.23.12') + implementation("org.typelevel:cats-effect_2.12:3.3.12") + testImplementation("org.http4s:http4s-dsl_2.12:0.23.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-server-2.12_0.23', 'Priority': '-1' + } +} +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-server_2.12:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.23/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java new file mode 100644 index 000000000..50298f8b6 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.blaze.server; + +import cats.data.Kleisli; +import cats.effect.kernel.Async; +import com.newrelic.agent.security.http4s.blaze.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.blaze.server.BlazeServerBuilder") +public class BlazeServerBuilder_Instrumentation { + + private final Async F = Weaver.callOriginal(); + + public BlazeServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.F); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.23/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala new file mode 100644 index 000000000..f96537f72 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala @@ -0,0 +1,186 @@ +package com.newrelic.agent.security.http4s.blaze.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.comcast.ip4s.Port +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 fs2.RaiseThrowable +import org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-BLAZE-SERVER-2.12_0.23" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-BLAZE-REQUEST_LOCK") + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort((request.serverPort).get.asInstanceOf[Port].value) + securityRequest.setClientIP(request.remoteAddr.get.toString) + + securityRequest.setProtocol("http") + if (request.isSecure.get) { + securityRequest.setProtocol("https") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 2, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey = StringUtils.EMPTY + if (header.name != null && header.name.nonEmpty) { + headerKey = header.name.toString + } + val headerValue = header.value + + val agentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyText(RaiseThrowable.fromApplicativeError, defaultCharset = charset).compile.string + } else { + msg.bodyText.compile.string + } + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired:Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(3) + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && !header.name.isEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_]: Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala new file mode 100644 index 000000000..3fc5dc675 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala @@ -0,0 +1,135 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} +import org.typelevel.ci.CIString + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.blaze.server", "scala")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CIString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + conn.setDoOutput(true) + + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala new file mode 100644 index 000000000..182bec092 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala @@ -0,0 +1,28 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.unsafe.implicits.global +import cats.effect.{IO, Resource} +import org.http4s.HttpApp +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.server.Server + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server = _ + var finalizer: IO[Unit] = _ + + val serverResource: Resource[IO, Server] = BlazeServerBuilder[IO] + .withHttpApp(httpApp) + .bindHttp(port, testServerHost) + .resource + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.21/build.gradle b/instrumentation-security/http4s-blaze-server-2.13_0.21/build.gradle new file mode 100644 index 000000000..0f291eb00 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.21/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation('org.http4s:http4s-blaze-server_2.13:0.21.24') + testImplementation("org.http4s:http4s-dsl_2.13:0.21.24") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-server-2.13_0.21', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-server_2.13:[0.21.0,0.22.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.21/src/main/java/org/http4s/server/blaze/BlazeServerBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/main/java/org/http4s/server/blaze/BlazeServerBuilder_Instrumentation.java new file mode 100644 index 000000000..e6fc9daa9 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/main/java/org/http4s/server/blaze/BlazeServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.server.blaze; + +import cats.data.Kleisli; +import cats.effect.ConcurrentEffect; +import com.newrelic.agent.security.http4s.blaze.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.server.blaze.BlazeServerBuilder") +public class BlazeServerBuilder_Instrumentation { + + private final ConcurrentEffect F = Weaver.callOriginal(); + + public BlazeServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.F); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.21/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala new file mode 100644 index 000000000..5d249bf6e --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala @@ -0,0 +1,183 @@ +package com.newrelic.agent.security.http4s.blaze.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-BLAZE-SERVER-2.13_0.21" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-BLAZE-REQUEST_LOCK") + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort(request.serverPort.toInt) + securityRequest.setClientIP(request.remoteAddr.get.toString) + + securityRequest.setProtocol("http") + if (request.isSecure.get) { + securityRequest.setProtocol("https") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 2, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey = StringUtils.EMPTY + if (header.name != null && !header.name.isEmpty) { + headerKey = header.name.toString + } + val headerValue = header.value + + val agentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyAsText(defaultCharset = charset).compile.string + } else { + msg.bodyAsText.compile.string + } + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired:Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(3) + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && !header.name.isEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_]: Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala new file mode 100644 index 000000000..00dc05603 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala @@ -0,0 +1,135 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.util.CaseInsensitiveString +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.blaze.server")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CaseInsensitiveString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + conn.setDoOutput(true) + + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala new file mode 100644 index 000000000..70cd5c070 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.21/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala @@ -0,0 +1,36 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import scala.concurrent.ExecutionContext.global +import cats.effect.{ConcurrentEffect, ContextShift, IO, Resource, Timer} +import org.http4s.HttpApp +import org.http4s.server.blaze.BlazeServerBuilder +import org.http4s.server.Server + +import scala.concurrent.ExecutionContext + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server[IO] = _ + var finalizer: IO[Unit] = _ + + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + implicit val concurrentEffect: ConcurrentEffect[IO] = IO.ioConcurrentEffect + + implicit val ec: ExecutionContext = global + + val serverResource: Resource[IO, Server[IO]] = BlazeServerBuilder.apply(global) + .withHttpApp(httpApp) + .bindHttp(port, testServerHost) + .resource + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.22/build.gradle b/instrumentation-security/http4s-blaze-server-2.13_0.22/build.gradle new file mode 100644 index 000000000..eecd9a894 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.22/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation('org.http4s:http4s-blaze-server_2.13:0.22.14') + testImplementation("org.http4s:http4s-dsl_2.13:0.22.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-server-2.13_0.22', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-server_2.13:[0.22.0,0.23.0)' + excludeRegex '.*(RC|M)[0-9]*' + excludeRegex '.*0.22\\-[0-9].*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.22/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java new file mode 100644 index 000000000..aa47a334a --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.blaze.server; + +import cats.data.Kleisli; +import cats.effect.ConcurrentEffect; +import com.newrelic.agent.security.http4s.blaze.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.blaze.server.BlazeServerBuilder") +public class BlazeServerBuilder_Instrumentation { + + private final ConcurrentEffect F = Weaver.callOriginal(); + + public BlazeServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.F); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.22/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala new file mode 100644 index 000000000..9186f4613 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala @@ -0,0 +1,186 @@ +package com.newrelic.agent.security.http4s.blaze.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.comcast.ip4s.Port +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 fs2.RaiseThrowable +import org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-BLAZE-SERVER-2.13_0.22" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-BLAZE-REQUEST_LOCK") + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort((request.serverPort).get.asInstanceOf[Port].value) + securityRequest.setClientIP(request.remoteAddr.get.toString) + + securityRequest.setProtocol("http") + if (request.isSecure.get) { + securityRequest.setProtocol("https") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 2, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey = StringUtils.EMPTY + if (header.name != null && header.name.nonEmpty) { + headerKey = header.name.toString + } + val headerValue = header.value + + val agentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyText(RaiseThrowable.fromApplicativeError, defaultCharset = charset).compile.string + } else { + msg.bodyText.compile.string + } + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired:Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(3) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && !header.name.isEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_]: Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala new file mode 100644 index 000000000..72aa40728 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala @@ -0,0 +1,135 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} +import org.typelevel.ci.CIString + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.blaze.server")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CIString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + conn.setDoOutput(true) + + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala new file mode 100644 index 000000000..479ba05f4 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.22/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala @@ -0,0 +1,36 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import scala.concurrent.ExecutionContext.global +import cats.effect.{ConcurrentEffect, ContextShift, IO, Resource, Timer} +import org.http4s.HttpApp +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.server.Server + +import scala.concurrent.ExecutionContext + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server = _ + var finalizer: IO[Unit] = _ + + implicit val cs: ContextShift[IO] = IO.contextShift(global) + implicit val timer: Timer[IO] = IO.timer(global) + implicit val concurrentEffect: ConcurrentEffect[IO] = IO.ioConcurrentEffect + + implicit val ec: ExecutionContext = global + + val serverResource: Resource[IO, Server] = BlazeServerBuilder.apply(global) + .withHttpApp(httpApp) + .bindHttp(port, testServerHost) + .resource + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.23/build.gradle b/instrumentation-security/http4s-blaze-server-2.13_0.23/build.gradle new file mode 100644 index 000000000..1dadbfc1e --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.23/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation('org.http4s:http4s-blaze-server_2.13:0.23.12') + implementation("org.typelevel:cats-effect_2.13:3.3.12") + testImplementation("org.http4s:http4s-dsl_2.13:0.23.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-blaze-server-2.13_0.23', 'Priority': '-1' + } +} +verifyInstrumentation { + passes 'org.http4s:http4s-blaze-server_2.13:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.23/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java new file mode 100644 index 000000000..50298f8b6 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/main/java/org/http4s/blaze/server/BlazeServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.blaze.server; + +import cats.data.Kleisli; +import cats.effect.kernel.Async; +import com.newrelic.agent.security.http4s.blaze.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.blaze.server.BlazeServerBuilder") +public class BlazeServerBuilder_Instrumentation { + + private final Async F = Weaver.callOriginal(); + + public BlazeServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.F); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.23/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala new file mode 100644 index 000000000..bbcc5281b --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/main/scala/com/newrelic/agent/security/http4s/blaze/server/RequestProcessor.scala @@ -0,0 +1,187 @@ +package com.newrelic.agent.security.http4s.blaze.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.comcast.ip4s.Port +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 fs2.RaiseThrowable +import org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-BLAZE-SERVER-2.13_0.23" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-BLAZE-REQUEST_LOCK") + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort((request.serverPort).get.asInstanceOf[Port].value) + securityRequest.setClientIP(request.remoteAddr.get.toString) + + securityRequest.setProtocol("http") + if (request.isSecure.get) { + securityRequest.setProtocol("https") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 2, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyText(RaiseThrowable.fromApplicativeError, defaultCharset = charset).compile.string + } else { + msg.bodyText.compile.string + } + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey = StringUtils.EMPTY + if (header.name != null && header.name.nonEmpty) { + headerKey = header.name.toString + } + val headerValue = header.value + + val agentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired:Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (NewRelicSecurity.isHookProcessingActive && isLockAcquired && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(3) + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && !header.name.isEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_] : Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala new file mode 100644 index 000000000..3fc5dc675 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/BlazeServerBuilderTest.scala @@ -0,0 +1,135 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} +import org.typelevel.ci.CIString + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.blaze.server", "scala")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CIString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", operation.getRequest.getProtocol) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + conn.setDoOutput(true) + + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-blaze-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala new file mode 100644 index 000000000..182bec092 --- /dev/null +++ b/instrumentation-security/http4s-blaze-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/server/Http4sTestServer.scala @@ -0,0 +1,28 @@ +package com.nr.agent.security.instrumentation.blaze.server + +import cats.effect.unsafe.implicits.global +import cats.effect.{IO, Resource} +import org.http4s.HttpApp +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.server.Server + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server = _ + var finalizer: IO[Unit] = _ + + val serverResource: Resource[IO, Server] = BlazeServerBuilder[IO] + .withHttpApp(httpApp) + .bindHttp(port, testServerHost) + .resource + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-ember-client-2.12_0.23/build.gradle b/instrumentation-security/http4s-ember-client-2.12_0.23/build.gradle new file mode 100644 index 000000000..1bb37776e --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.12_0.23/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +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.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-ember-client_2.12:0.23.12') + implementation("org.typelevel:cats-effect_2.12:3.3.0") + testImplementation("org.http4s:http4s-dsl_2.12:0.23.12") + +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-ember-client-2.12_0.23' + } +} +verifyInstrumentation { + passes 'org.http4s:http4s-ember-client_2.12:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/java/org/http4s/EmberClientBuilder_Instrumentation.java b/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/java/org/http4s/EmberClientBuilder_Instrumentation.java new file mode 100644 index 000000000..5e56dfaa3 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/java/org/http4s/EmberClientBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s; + +import cats.effect.kernel.Async; +import cats.effect.kernel.Resource; +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.http4s.ember.NewrelicSecurityClientMiddleware$; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.ember.client.EmberClientBuilder") +public abstract class EmberClientBuilder_Instrumentation { + + private final Async evidence$1 = Weaver.callOriginal(); + + public Resource> build() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, evidence$1); + } +} diff --git a/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..594241802 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,125 @@ +package com.newrelic.agent.security.instrumentation.http4s.ember + +import cats.effect.kernel.Async +import cats.effect.{Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + private final val nrSecCustomAttrName: String = "HTTP4S-EMBER-CLIENT-OUTBOUND" + private final val HTTP4S_EMBER_CLIENT: String = "HTTP4S-EMBER-CLIENT-2.12_0.23" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.eval( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + // add Security Headers + request <- Resource.eval(construct {addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.eval(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && !iastHeader.trim.isEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && !operation.getApiID.trim.isEmpty && operation.getExecutionId != null && !operation.getExecutionId.trim.isEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/OutboundRequest.scala b/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/OutboundRequest.scala new file mode 100644 index 000000000..ca6b52a95 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.12_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/OutboundRequest.scala @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.instrumentation.http4s.ember + +import org.http4s.{Header, Request} +import org.typelevel.ci.CIString + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CIString.apply(key), value))) + } + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-ember-client-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/EmberClientTest.scala b/instrumentation-security/http4s-ember-client-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/EmberClientTest.scala new file mode 100644 index 000000000..ccb26c514 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/EmberClientTest.scala @@ -0,0 +1,87 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.unsafe.implicits.global +import cats.effect.{Async, IO} +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.ember.client.EmberClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class EmberClientTest { + + @Rule + def server: HttpServerRule = httpServer + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_]: Async](url: String): F[String] = { + val client = EmberClientBuilder.default[F].build + client.use { c => + c.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-ember-client-2.13_0.23/build.gradle b/instrumentation-security/http4s-ember-client-2.13_0.23/build.gradle new file mode 100644 index 000000000..88b683f7b --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.13_0.23/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +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.scala-lang:scala-library:2.13.3") + implementation('org.http4s:http4s-ember-client_2.13:0.23.12') + implementation("org.typelevel:cats-effect_2.13:3.3.0") + testImplementation("org.http4s:http4s-dsl_2.13:0.23.12") + +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-ember-client-2.13_0.23' + } +} +verifyInstrumentation { + passes 'org.http4s:http4s-ember-client_2.13:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/java/org/http4s/EmberClientBuilder_Instrumentation.java b/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/java/org/http4s/EmberClientBuilder_Instrumentation.java new file mode 100644 index 000000000..f702d27f7 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/java/org/http4s/EmberClientBuilder_Instrumentation.java @@ -0,0 +1,19 @@ +package org.http4s; + +import cats.effect.kernel.Async; +import cats.effect.kernel.Resource; +import com.newrelic.agent.security.instrumentation.http4s.ember.NewrelicSecurityClientMiddleware$; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.client.Client; + +@Weave(type = MatchType.ExactClass, originalName = "org.http4s.ember.client.EmberClientBuilder") +public abstract class EmberClientBuilder_Instrumentation { + + private final Async evidence$1 = Weaver.callOriginal(); + public Resource> build() { + Resource> delegateResource = Weaver.callOriginal(); + return NewrelicSecurityClientMiddleware$.MODULE$.resource(delegateResource, evidence$1); + } +} diff --git a/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/NewrelicSecurityClientMiddleware.scala b/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/NewrelicSecurityClientMiddleware.scala new file mode 100644 index 000000000..4abb321f6 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/NewrelicSecurityClientMiddleware.scala @@ -0,0 +1,126 @@ +package com.newrelic.agent.security.instrumentation.http4s.ember + +import cats.effect.kernel.Async +import cats.effect.{Resource, Sync} +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, StringUtils, VulnerabilityCaseType} +import com.newrelic.api.agent.security.utils.SSRFUtils +import com.newrelic.api.agent.security.utils.logging.LogLevel +import org.http4s.Request +import org.http4s.client.Client + +import java.net.URI + +object NewrelicSecurityClientMiddleware { + + private final val nrSecCustomAttrName: String = "HTTP4S-EMBER-CLIENT-OUTBOUND" + private final val HTTP4S_EMBER_CLIENT: String = "HTTP4S-EMBER-CLIENT-2.13_0.23" + + private def construct[F[_] : Sync, T](t: T): F[T] = Sync[F].delay(t) + + private def clientResource[F[_] : Async](client: Client[F]): Client[F] = + Client { req: Request[F] => + for { + // pre-process hook + operation <- Resource.eval( + construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, nrSecCustomAttrName) + var operation: AbstractOperation = null + if (isLockAcquired) { + operation = preprocessSecurityHook(req) + } + operation + }) + + // add Security Headers + request <- Resource.eval(construct {addSecurityHeaders(req, operation)}) + + // original call + response <- client.run(request) + + // post process and register exit event + newRes <- Resource.eval(construct{ + val isLockAcquired = GenericHelper.isLockAcquired(nrSecCustomAttrName); + if (isLockAcquired) { + GenericHelper.releaseLock(nrSecCustomAttrName) + } + registerExitOperation(isLockAcquired, operation) + response + }) + + } yield newRes + } + + private def addSecurityHeaders[F[_] : Async](request: Request[F], operation: AbstractOperation): Request[F] = { + val outboundRequest = new OutboundRequest(request) + if (operation != null) { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val iastHeader = NewRelicSecurity.getAgent.getSecurityMetaData.getFuzzRequestIdentifier.getRaw + if (iastHeader != null && iastHeader.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader) + } + val csecParentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, classOf[String]) + if (StringUtils.isNotBlank(csecParentId)) { + outboundRequest.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId) + } + try { + NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFromJumpRequiredInStackTrace(Integer.valueOf(4)) + NewRelicSecurity.getAgent.registerOperation(operation) + } + finally { + if (operation.getApiID != null && operation.getApiID.trim.nonEmpty && operation.getExecutionId != null && operation.getExecutionId.trim.nonEmpty) { + outboundRequest.setHeader(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue, operation.getApiID, operation.getExecutionId, NewRelicSecurity.getAgent.getAgentUUID)) + } + } + } + outboundRequest.getRequest + } + + def resource[F[_] : Async](delegate: Resource[F, Client[F]]): Resource[F, Client[F]] = { + val res: Resource[F, Client[F]] = delegate.map(c =>clientResource(c)) + res + } + + private def preprocessSecurityHook[F[_] : Async](httpRequest: Request[F]): AbstractOperation = { + try { + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + if (!NewRelicSecurity.isHookProcessingActive || securityMetaData.getRequest.isEmpty) return null + // Generate required URL + var methodURI: URI = null + var uri: String = null + try { + methodURI = new URI(httpRequest.uri.toString) + uri = methodURI.toString + if (methodURI == null) return null + } catch { + case ignored: Exception => + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.URI_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, ignored.getMessage), ignored, this.getClass.getName) + return null + } + return new SSRFOperation(uri, this.getClass.getName, "run") + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + } + null + } + + private def registerExitOperation(isProcessingAllowed: Boolean, operation: AbstractOperation): Unit = { + try { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive || NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isEmpty) return + NewRelicSecurity.getAgent.registerExitEvent(operation) + } catch { + case e: Throwable => + NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HTTP4S_EMBER_CLIENT, e.getMessage), e, this.getClass.getName) + } + } +} + diff --git a/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/OutboundRequest.scala b/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/OutboundRequest.scala new file mode 100644 index 000000000..c19433953 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.13_0.23/src/main/scala/com/newrelic/agent/security/instrumentation/http4s/ember/OutboundRequest.scala @@ -0,0 +1,20 @@ +package com.newrelic.agent.security.instrumentation.http4s.ember + +import org.http4s.{Header, Request} +import org.typelevel.ci.CIString + +/** + * Http4s's HttpRequest is immutable so we have to create a copy with the new headers. + */ + +class OutboundRequest[F[_]](request: Request[F]) { + private var req: Request[F] = request + + def setHeader(key: String, value: String): Unit = { + req = req.withHeaders(req.headers.put(Header.Raw.apply(CIString.apply(key), value))) + } + + def getRequest: Request[F] = { + req + } +} \ No newline at end of file diff --git a/instrumentation-security/http4s-ember-client-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/EmberClientTest.scala b/instrumentation-security/http4s-ember-client-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/EmberClientTest.scala new file mode 100644 index 000000000..ccb26c514 --- /dev/null +++ b/instrumentation-security/http4s-ember-client-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/blaze/client/EmberClientTest.scala @@ -0,0 +1,87 @@ +package com.nr.agent.security.instrumentation.blaze.client + +import cats.effect.unsafe.implicits.global +import cats.effect.{Async, IO} +import com.newrelic.agent.security.introspec.internal.HttpServerRule +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.SSRFOperation +import com.newrelic.api.agent.security.schema.{AbstractOperation, VulnerabilityCaseType} +import com.nr.agent.security.instrumentation.blaze.client.Http4sTestUtils.makeRequest +import org.http4s.ember.client.EmberClientBuilder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.{Assert, FixMethodOrder, Rule, Test} + +import java.util +import java.util.UUID +import scala.concurrent.duration.DurationInt + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.instrumentation.http4s")) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class EmberClientTest { + + @Rule + def server: HttpServerRule = httpServer + + val httpServer = new HttpServerRule() + + @Test + def blazeClientTest(): Unit = { + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + } + + @Test + def blazeClientTestWithHeaders(): Unit = { + val headerValue = String.valueOf(UUID.randomUUID) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + setCSECHeaders(headerValue = headerValue, introspector = introspector) + makeRequest[IO](s"${server.getEndPoint}").unsafeRunTimed(2.seconds) + assertSSRFOperation(introspector.getOperations) + verifyHeaders(headerValue, httpServer.getHeaders) + } + + + private def assertSSRFOperation(operations: util.List[AbstractOperation]): Unit = { + Assert.assertTrue("Incorrect number of operations detected!", operations.size == 1) + Assert.assertTrue("SSRFOperation not found!", operations.get(0).isInstanceOf[SSRFOperation]) + val operation: SSRFOperation = operations.get(0).asInstanceOf[SSRFOperation] + + Assert.assertFalse("operation should not be empty", operation.isEmpty) + Assert.assertFalse("JNDILookup should be false", operation.isJNDILookup) + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.HTTP_REQUEST, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "run", operation.getMethodName) + Assert.assertEquals("Invalid executed parameters.", server.getEndPoint.toString, operation.getArg) + } + + private def verifyHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def setCSECHeaders(headerValue: String, introspector: SecurityIntrospector): Unit = { + introspector.setK2FuzzRequestId(headerValue + "a") + introspector.setK2ParentId(headerValue + "b") + introspector.setK2TracingData(headerValue) + } +} + +object Http4sTestUtils { + def makeRequest[F[_]: Async](url: String): F[String] = { + val client = EmberClientBuilder.default[F].build + client.use { c => + c.expect[String](url) + } + } +} + diff --git a/instrumentation-security/http4s-ember-server-2.12_0.23/build.gradle b/instrumentation-security/http4s-ember-server-2.12_0.23/build.gradle new file mode 100644 index 000000000..e6281a986 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.12_0.23/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.12") + +dependencies { + implementation(project(":newrelic-security-api")) + implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") + implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") + implementation("org.scala-lang:scala-library:2.12.14") + implementation('org.http4s:http4s-ember-server_2.12:0.23.12') + implementation("org.typelevel:cats-effect_2.12:3.3.0") + testImplementation("org.http4s:http4s-dsl_2.12:0.23.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-ember-server-2.12_0.23', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-ember-server_2.12:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-ember-server-2.12_0.23/src/main/java/org/http4s/ember/server/EmberServerBuilder_Instrumentation.java b/instrumentation-security/http4s-ember-server-2.12_0.23/src/main/java/org/http4s/ember/server/EmberServerBuilder_Instrumentation.java new file mode 100644 index 000000000..1a7b7e891 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.12_0.23/src/main/java/org/http4s/ember/server/EmberServerBuilder_Instrumentation.java @@ -0,0 +1,20 @@ +package org.http4s.ember.server; + +import cats.data.Kleisli; +import cats.effect.kernel.Async; +import com.newrelic.agent.security.http4s.ember.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.ember.server.EmberServerBuilder") +public class EmberServerBuilder_Instrumentation { + + public final Async org$http4s$ember$server$EmberServerBuilder$$evidence$1 = Weaver.callOriginal(); + + public EmberServerBuilder_Instrumentation withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.org$http4s$ember$server$EmberServerBuilder$$evidence$1); + return Weaver.callOriginal(); + } +} diff --git a/instrumentation-security/http4s-ember-server-2.12_0.23/src/main/scala/com.newrelic.agent.security.http4s.ember.server/RequestProcessor.scala b/instrumentation-security/http4s-ember-server-2.12_0.23/src/main/scala/com.newrelic.agent.security.http4s.ember.server/RequestProcessor.scala new file mode 100644 index 000000000..c648c61e4 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.12_0.23/src/main/scala/com.newrelic.agent.security.http4s.ember.server/RequestProcessor.scala @@ -0,0 +1,186 @@ +package com.newrelic.agent.security.http4s.ember.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.comcast.ip4s.Port +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 +import com.newrelic.api.agent.security.utils.logging.LogLevel +import fs2.RaiseThrowable +import org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_12_0_23 = "HTTP4S-EMBER-SERVER-2.12_0.23" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-EMBER-REQUEST_LOCK", request.hashCode()) + try { + if (isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort((request.serverPort).get.asInstanceOf[Port].value) + securityRequest.setClientIP(request.remoteAddr.get.toString) + if(request.isSecure.get){ + securityRequest.setProtocol("https") + } else { + securityRequest.setProtocol("http") + } + + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 1, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired: Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (isLockAcquired && NewRelicSecurity.isHookProcessingActive && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_12_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyText(RaiseThrowable.fromApplicativeError, defaultCharset = charset).compile.string + } else { + msg.bodyText.compile.string + } + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey: String = StringUtils.EMPTY + if (header.name != null && header.name.nonEmpty) { + headerKey = header.name.toString + } + val headerValue: String = header.value + + val agentPolicy: AgentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData: AgentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && header.name.nonEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_] : Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-ember-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/EmberServerBuilderTest.scala b/instrumentation-security/http4s-ember-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/EmberServerBuilderTest.scala new file mode 100644 index 000000000..1c289baf7 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/EmberServerBuilderTest.scala @@ -0,0 +1,137 @@ +package com.nr.agent.security.instrumentation.ember.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} +import org.typelevel.ci.CIString + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s.ember", "com.newrelic.agent.security.http4s.ember.server", "scala")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CIString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + + conn.setDoOutput(true) + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} + diff --git a/instrumentation-security/http4s-ember-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/Http4sTestServer.scala b/instrumentation-security/http4s-ember-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/Http4sTestServer.scala new file mode 100644 index 000000000..d1eed636d --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.12_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/Http4sTestServer.scala @@ -0,0 +1,30 @@ +package com.nr.agent.security.instrumentation.ember.server + +import cats.effect.{IO, Resource} +import com.comcast.ip4s._ +import org.http4s.HttpApp +import org.http4s.server.Server +import org.http4s.ember.server.EmberServerBuilder +import cats.effect.unsafe.implicits.global + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server = _ + var finalizer: IO[Unit] = _ + + val serverResource: Resource[IO, Server] = EmberServerBuilder.default[IO] + .withHttpApp(httpApp) + .withHost(Host.fromString(testServerHost).orNull) + .withPort(Port.fromInt(port).get) + .build + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} diff --git a/instrumentation-security/http4s-ember-server-2.13_0.23/build.gradle b/instrumentation-security/http4s-ember-server-2.13_0.23/build.gradle new file mode 100644 index 000000000..6f9c24c92 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.13_0.23/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'scala' + +isScalaProjectEnabled(project, "scala-2.13") + +dependencies { + implementation(project(":newrelic-security-api")) + implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") + implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") + implementation("org.scala-lang:scala-library:2.13.3") + implementation('org.http4s:http4s-ember-server_2.13:0.23.12') + implementation("org.typelevel:cats-effect_2.13:3.3.12"){transitive = false} + testImplementation("org.http4s:http4s-dsl_2.13:0.23.12") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.http4s-ember-server-2.13_0.23', 'Priority': '-1' + } +} + +verifyInstrumentation { + passes 'org.http4s:http4s-ember-server_2.13:[0.23.0,0.24.0)' + excludeRegex '.*(RC|M)[0-9]*' +} + +sourceSets.main.scala.srcDirs = ['src/main/scala', 'src/main/java'] +sourceSets.main.java.srcDirs = [] diff --git a/instrumentation-security/http4s-ember-server-2.13_0.23/src/main/java/org/http4s/ember/server/EmberServerBuilder_Instrumentation.java b/instrumentation-security/http4s-ember-server-2.13_0.23/src/main/java/org/http4s/ember/server/EmberServerBuilder_Instrumentation.java new file mode 100644 index 000000000..d7beb29c2 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.13_0.23/src/main/java/org/http4s/ember/server/EmberServerBuilder_Instrumentation.java @@ -0,0 +1,21 @@ +package org.http4s.ember.server; + +import cats.data.Kleisli; +import cats.effect.kernel.Async; +import com.newrelic.agent.security.http4s.ember.server.RequestProcessor$; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.http4s.Request; +import org.http4s.Response; + +@Weave(originalName = "org.http4s.ember.server.EmberServerBuilder") +public class EmberServerBuilder_Instrumentation { + + public final Async org$http4s$ember$server$EmberServerBuilder$$evidence$1 = Weaver.callOriginal(); + + public EmberServerBuilder withHttpApp(Kleisli, Response> httpApp) { + httpApp = RequestProcessor$.MODULE$.genHttpApp(httpApp, this.org$http4s$ember$server$EmberServerBuilder$$evidence$1); + return Weaver.callOriginal(); + } +} + diff --git a/instrumentation-security/http4s-ember-server-2.13_0.23/src/main/scala/com.newrelic.agent.security.http4s.ember.server/RequestProcessor.scala b/instrumentation-security/http4s-ember-server-2.13_0.23/src/main/scala/com.newrelic.agent.security.http4s.ember.server/RequestProcessor.scala new file mode 100644 index 000000000..536ecfc10 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.13_0.23/src/main/scala/com.newrelic.agent.security.http4s.ember.server/RequestProcessor.scala @@ -0,0 +1,186 @@ +package com.newrelic.agent.security.http4s.ember.server + +import cats.data.Kleisli +import cats.effect.Sync +import cats.implicits._ +import com.comcast.ip4s.Port +import com.newrelic.api.agent.security.NewRelicSecurity +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ICsecApiConstants, ServletHelper} +import com.newrelic.api.agent.security.schema._ +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 +import com.newrelic.api.agent.security.utils.logging.LogLevel +import fs2.RaiseThrowable +import org.http4s.{Headers, Message, Request, Response} + +import java.util + + +object RequestProcessor { + + private val METHOD_WITH_HTTP_APP = "withHttpApp" + private val HTTP_4S_EMBER_SERVER_2_13_0_23 = "HTTP4S-EMBER-SERVER-2.13_0.23" + private val X_FORWARDED_FOR = "x-forwarded-for" + + def genHttpApp[F[_] : Sync](httpApp: Kleisli[F, Request[F], Response[F]]): Kleisli[F, Request[F], Response[F]] = { + Kleisli { req: Request[F] => nrRequestResponse(req, httpApp) } + } + + private def nrRequestResponse[F[_] : Sync](request: Request[F], httpApp: Kleisli[F, Request[F], Response[F]]): F[Response[F]] = { + val result = construct((): Unit) + .redeemWith(_ => httpApp(request), + _ => for { + requestBody <- extractBody(request) + isLockAcquired <- preprocessHttpRequest(request, requestBody) + resp <- httpApp(request) + responseBody <- extractBody(resp) + _ <- postProcessSecurityHook(isLockAcquired, resp, responseBody) + } yield resp + ) + result + } + + private def preprocessHttpRequest[F[_]: Sync](request: Request[F], body: String): F[Boolean] = construct { + val isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP4S-EMBER-REQUEST_LOCK", request.hashCode()) + try { + if (isLockAcquired && !NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.isRequestParsed){ + + val securityMetaData: SecurityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + val securityRequest: HttpRequest = securityMetaData.getRequest + val securityAgentMetaData: AgentMetaData = securityMetaData.getMetaData + + securityRequest.setMethod(request.method.name) + securityRequest.setServerPort((request.serverPort).get.asInstanceOf[Port].value) + securityRequest.setClientIP(request.remoteAddr.get.toString) + if(request.isSecure.get){ + securityRequest.setProtocol("https") + } else { + securityRequest.setProtocol("http") + } + securityRequest.setUrl(request.uri.toString) + + if (securityRequest.getClientIP != null && securityRequest.getClientIP.trim.nonEmpty) { + securityAgentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(String.valueOf(request.remotePort.get)) + } + + processRequestHeaders(request.headers, securityRequest) + securityMetaData.setTracingHeaderValue(getTraceHeader(securityRequest.getHeaders)) + securityRequest.setContentType(getContentType(securityRequest.getHeaders)) + + securityRequest.getBody.append(body) + + val trace: Array[StackTraceElement] = Thread.currentThread.getStackTrace + securityMetaData.getMetaData.setServiceTrace(util.Arrays.copyOfRange(trace, 1, trace.length)) + securityRequest.setRequestParsed(true) + } + + } catch { + case e: Throwable => NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, HTTP_4S_EMBER_SERVER_2_13_0_23, e.getMessage), e, this.getClass.getName) + } + isLockAcquired + } + + private def extractBody[F[_]: Sync](msg: Message[F]): F[String] = { + if (msg.contentType.nonEmpty && msg.contentType.get.charset.nonEmpty) { + val charset = msg.contentType.get.charset.get; + msg.bodyText(RaiseThrowable.fromApplicativeError, defaultCharset = charset).compile.string + } else { + msg.bodyText.compile.string + } + } + + private def postProcessSecurityHook[F[_]: Sync](isLockAcquired: Boolean, response: Response[F], body: String): F[Unit] = construct { + try { + if (isLockAcquired && NewRelicSecurity.isHookProcessingActive && !NewRelicSecurity.getAgent.getIastDetectionCategory.getRxssEnabled) { + val securityResponse = NewRelicSecurity.getAgent.getSecurityMetaData.getResponse + securityResponse.setResponseCode(response.status.code) + processResponseHeaders(response.headers, securityResponse) + securityResponse.setResponseContentType(getContentType(securityResponse.getHeaders)) + + securityResponse.getResponseBody.append(body) + + ServletHelper.executeBeforeExitingTransaction() + if (!ServletHelper.isResponseContentTypeExcluded(NewRelicSecurity.getAgent.getSecurityMetaData.getResponse.getResponseContentType)) { + val rxssOperation = new RXSSOperation(NewRelicSecurity.getAgent.getSecurityMetaData.getRequest, NewRelicSecurity.getAgent.getSecurityMetaData.getResponse, this.getClass.getName, METHOD_WITH_HTTP_APP) + NewRelicSecurity.getAgent.registerOperation(rxssOperation) + } + } + } catch { + case e: Throwable => + if (e.isInstanceOf[NewRelicSecurityException]) { + NewRelicSecurity.getAgent.log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_13_0_23, e.getMessage), e, this.getClass.getName) + throw e + } + NewRelicSecurity.getAgent.log(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_13_0_23, e.getMessage), e, this.getClass.getName) + NewRelicSecurity.getAgent.reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HTTP_4S_EMBER_SERVER_2_13_0_23, e.getMessage), e, this.getClass.getName) + } + } + + private def processRequestHeaders(headers: Headers, securityRequest: HttpRequest): Unit = { + headers.foreach(header => { + var takeNextValue = false + var headerKey: String = StringUtils.EMPTY + if (header.name != null && header.name.nonEmpty) { + headerKey = header.name.toString + } + val headerValue: String = header.value + + val agentPolicy: AgentPolicy = NewRelicSecurity.getAgent.getCurrentPolicy + val agentMetaData: AgentMetaData = NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData + if (agentPolicy != null + && agentPolicy.getProtectionMode.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getEnabled() + && agentPolicy.getProtectionMode.getIpBlocking.getIpDetectViaXFF() + && X_FORWARDED_FOR.equals(headerKey)) { + takeNextValue = true + } else if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID == headerKey) { + // TODO: May think of removing this intermediate obj and directly create K2 Identifier. + NewRelicSecurity.getAgent.getSecurityMetaData.setFuzzRequestIdentifier(ServletHelper.parseFuzzRequestIdentifierHeader(headerValue)) + } + if (GenericHelper.CSEC_PARENT_ID == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(GenericHelper.CSEC_PARENT_ID, headerValue) + } + else if (ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST == headerKey) { + NewRelicSecurity.getAgent.getSecurityMetaData.addCustomAttribute(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, true) + } + + if (headerValue != null && headerValue.trim.nonEmpty) { + if (takeNextValue) { + agentMetaData.setClientDetectedFromXFF(true) + securityRequest.setClientIP(headerValue) + agentMetaData.getIps.add(securityRequest.getClientIP) + securityRequest.setClientPort(StringUtils.EMPTY) + takeNextValue = false + } + } + securityRequest.getHeaders.put(headerKey.toLowerCase, headerValue) + }) + } + + private def processResponseHeaders(headers: Headers, securityResp: HttpResponse): Unit = { + headers.foreach(header => { + if (header.name != null && header.name.nonEmpty) { + securityResp.getHeaders.put(header.name.toString.toLowerCase, header.value) + } + }) + } + + private def getContentType(headers: util.Map[String, String]): String = { + var contentType = StringUtils.EMPTY + if (headers.containsKey("content-type")) contentType = headers.get("content-type") + contentType + } + + private def getTraceHeader(headers: util.Map[String, String]): String = { + var data = StringUtils.EMPTY + if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) { + data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) + if (data == null || data.trim.isEmpty) data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase) + } + data + } + + private def construct[F[_] : Sync, T](t: => T): F[T] = Sync[F].delay(t) +} diff --git a/instrumentation-security/http4s-ember-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/EmberServerBuilderTest.scala b/instrumentation-security/http4s-ember-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/EmberServerBuilderTest.scala new file mode 100644 index 000000000..44e5ef126 --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/EmberServerBuilderTest.scala @@ -0,0 +1,136 @@ +package com.nr.agent.security.instrumentation.ember.server + +import cats.effect.IO +import com.newrelic.agent.security.introspec.{InstrumentationTestConfig, SecurityInstrumentationTestRunner, SecurityIntrospector} +import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, ServletHelper} +import com.newrelic.api.agent.security.schema.operation.RXSSOperation +import com.newrelic.api.agent.security.schema.{SecurityMetaData, VulnerabilityCaseType} +import org.http4s.dsl.io._ +import org.http4s.implicits._ +import org.http4s.{Header, HttpRoutes} +import org.junit.runner.RunWith +import org.junit.{After, Assert, Before, Test} +import org.typelevel.ci.CIString + +import java.net.{HttpURLConnection, URL} +import java.util +import java.util.UUID + +@RunWith(classOf[SecurityInstrumentationTestRunner]) +@InstrumentationTestConfig(includePrefixes = Array("org.http4s", "com.newrelic.agent.security.http4s.ember.server", "scala")) +class EmberServerBuilderTest { + + val hostname = "0.0.0.0" + val port: Int = SecurityInstrumentationTestRunner.getIntrospector.getRandomPort + val contentType: String = "text/plain" + + val emberServer = new Http4sTestServer(hostname, port, + HttpRoutes.of[IO] { + case _ -> Root / "hello" / name => + Ok(s"Hello, $name.").map(_.putHeaders(Header.Raw(CIString.apply("content-type"), contentType))) + }.orNotFound) + + @Before + def setup(): Unit = { + emberServer.start() + } + + @After + def reset(): Unit = { + emberServer.stop() + } + + + @Test + def emberServerTest(): Unit = { + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = false, "") + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + } + + @Test + def emberServerHeaderTest(): Unit = { + val headerValue: String = String.valueOf(UUID.randomUUID()) + + val introspector: SecurityIntrospector = SecurityInstrumentationTestRunner.getIntrospector + Http4sTestUtils.makeRequest(s"http://$hostname:$port/hello/bob", addCSECHeader = true, headerValue) + + val operations = introspector.getOperations + Assert.assertTrue(operations.size() > 0) + Assert.assertTrue(operations.get(0).isInstanceOf[RXSSOperation]) + + assertRXSSOperation(operations.get(0).asInstanceOf[RXSSOperation]) + assertMetaData(introspector.getSecurityMetaData) + assertCSECHeaders(headerValue, introspector.getSecurityMetaData.getRequest.getHeaders) + } + + private def assertCSECHeaders(headerValue: String, headers: util.Map[String, String]): Unit = { + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headers.containsKey(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID), headerValue + "a", headers.get(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", GenericHelper.CSEC_PARENT_ID), headers.containsKey(GenericHelper.CSEC_PARENT_ID)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", GenericHelper.CSEC_PARENT_ID), headerValue + "b", headers.get(GenericHelper.CSEC_PARENT_ID)) + Assert.assertTrue(String.format("Missing CSEC header: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + Assert.assertEquals(String.format("Invalid CSEC header value for: %s", ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER), String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue), headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase)) + } + + private def assertRXSSOperation(operation: RXSSOperation): Unit = { + Assert.assertFalse("LowSeverityHook should be disabled", operation.isLowSeverityHook) + Assert.assertEquals("Invalid event category.", VulnerabilityCaseType.REFLECTED_XSS, operation.getCaseType) + Assert.assertEquals("Invalid executed method name.", "withHttpApp", operation.getMethodName) + + Assert.assertFalse("request should not be empty", operation.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, operation.getRequest.getContentType) + Assert.assertFalse("Headers should not be empty", operation.getRequest.getHeaders.isEmpty) + Assert.assertEquals("Invalid Request body", "body extract", operation.getRequest.getBody.toString) + + + Assert.assertFalse("response should not be empty", operation.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, operation.getResponse.getResponseContentType) + Assert.assertFalse("Headers should not be empty", operation.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", operation.getResponse.getResponseBody.toString) + Assert.assertEquals("Invalid Response code", 200, operation.getResponse.getResponseCode) + } + + private def assertMetaData(metaData: SecurityMetaData): Unit = { + Assert.assertFalse("request should not be empty", metaData.getRequest.isEmpty) + Assert.assertEquals("Invalid Request content-type.", contentType, metaData.getRequest.getContentType) + Assert.assertEquals("Invalid protocol.", "http", metaData.getRequest.getProtocol) + + Assert.assertEquals("Invalid Request body", "body extract", metaData.getRequest.getBody.toString) + Assert.assertFalse("Headers should not be empty", metaData.getRequest.getHeaders.isEmpty) + + Assert.assertFalse("response should not be empty", metaData.getResponse.isEmpty) + Assert.assertEquals("Invalid response content-type.", contentType, metaData.getResponse.getResponseContentType) + Assert.assertEquals("Invalid Response code", 200, metaData.getResponse.getResponseCode) + Assert.assertFalse("Headers should not be empty", metaData.getResponse.getHeaders.isEmpty) + Assert.assertEquals("Invalid Response body", "Hello, bob.", metaData.getResponse.getResponseBody.toString) + } +} + +object Http4sTestUtils { + def makeRequest(url: String, addCSECHeader: Boolean, headerValue: String): Unit = { + val u: URL = new URL(url) + val conn = u.openConnection.asInstanceOf[HttpURLConnection] + + conn.setDoOutput(true) + conn.setRequestProperty("content-type", "text/plain") + + if (addCSECHeader) { + conn.setRequestProperty(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, headerValue + "a") + conn.setRequestProperty(GenericHelper.CSEC_PARENT_ID, headerValue + "b") + conn.setRequestProperty(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, String.format("%s;DUMMY_UUID/dummy-api-id/dummy-exec-id;", headerValue)) + } + + val stream = conn.getOutputStream + stream.write("body extract".getBytes) + + conn.connect() + println(conn.getResponseCode) + } +} diff --git a/instrumentation-security/http4s-ember-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/Http4sTestServer.scala b/instrumentation-security/http4s-ember-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/Http4sTestServer.scala new file mode 100644 index 000000000..d1eed636d --- /dev/null +++ b/instrumentation-security/http4s-ember-server-2.13_0.23/src/test/scala/com/nr/agent/security/instrumentation/ember/server/Http4sTestServer.scala @@ -0,0 +1,30 @@ +package com.nr.agent.security.instrumentation.ember.server + +import cats.effect.{IO, Resource} +import com.comcast.ip4s._ +import org.http4s.HttpApp +import org.http4s.server.Server +import org.http4s.ember.server.EmberServerBuilder +import cats.effect.unsafe.implicits.global + +class Http4sTestServer(val testServerHost: String, val port: Int, val httpApp: HttpApp[IO]) { + + var server: Server = _ + var finalizer: IO[Unit] = _ + + val serverResource: Resource[IO, Server] = EmberServerBuilder.default[IO] + .withHttpApp(httpApp) + .withHost(Host.fromString(testServerHost).orNull) + .withPort(Port.fromInt(port).get) + .build + + def start(): Unit = { + val materializedServer = serverResource.allocated.unsafeRunSync() + server = materializedServer._1 + finalizer = materializedServer._2 + } + + def stop(): Unit = finalizer.unsafeRunSync() + + def hostname: String = server.address.getHostName +} 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 785fae956..5539ebc18 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 @@ -31,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -65,10 +65,6 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(HttpConnection conn, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // Generate required URL @@ -145,17 +141,10 @@ private AbstractOperation preprocessSecurityHook(HttpConnection conn, String met } private void releaseLock() { - try { - GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } } 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 c383b4007..c78cf2b9d 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 @@ -35,7 +35,7 @@ public abstract class HttpClient_Instrumentation { public HttpResponse execute(HttpUriRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -55,7 +55,7 @@ public HttpResponse execute(HttpUriRequest request) throws Exception { } public HttpResponse execute(HttpUriRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -75,7 +75,7 @@ public HttpResponse execute(HttpUriRequest request, HttpContext context) throws } public HttpResponse execute(HttpHost target, HttpRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase @@ -103,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase @@ -132,7 +132,7 @@ public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext co public T execute(HttpUriRequest request, ResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -153,7 +153,7 @@ public T execute(HttpUriRequest request, ResponseHandler res public T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -174,7 +174,7 @@ public T execute(HttpUriRequest request, ResponseHandler res public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase @@ -203,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase @@ -251,10 +251,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest request, String uri, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // TODO : Need to check if this is required anymore in NR case. // // Add Security app topology header @@ -299,18 +295,11 @@ private AbstractOperation preprocessSecurityHook(HttpRequest request, String uri } private void releaseLock() { - try { - GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } } diff --git a/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/SecurityHelper.java b/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/SecurityHelper.java index ba4d5bd68..0ea1005ea 100644 --- a/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/SecurityHelper.java +++ b/instrumentation-security/httpclient-4.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient40/SecurityHelper.java @@ -3,27 +3,8 @@ public class SecurityHelper { public static final String METHOD_NAME_EXECUTE = "execute"; - public static final String NULL_STRING = "null"; public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SSRF_OPERATION_LOCK_APACHE4-"; - public static final String HTTP_CLIENT_4 = "HTTP-CLIENT-4"; - public static String getURI(String scheme, String host, int port, String path) { - StringBuilder sb = new StringBuilder(); - if (scheme != null) { - sb.append(scheme); - sb.append("://"); - } - if (host != null) { - sb.append(host); - if (port >= 0) { - sb.append(":"); - sb.append(port); - } - } - if (path != null) { - sb.append(path); - } - return sb.toString(); - } + public static final String HTTP_CLIENT_4 = "HTTP-CLIENT-4"; } diff --git a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/BasicRequestProducer_Instrumentation.java b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/BasicRequestProducer_Instrumentation.java index aa79e7d93..d56657e77 100644 --- a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/BasicRequestProducer_Instrumentation.java +++ b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/BasicRequestProducer_Instrumentation.java @@ -22,7 +22,9 @@ public class BasicRequestProducer_Instrumentation { public BasicRequestProducer_Instrumentation(final HttpRequest request, final AsyncEntityProducer dataProducer) { try { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(APACHE5_ASYNC_REQUEST_PRODUCER+this.hashCode(), request); + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(APACHE5_ASYNC_REQUEST_PRODUCER + this.hashCode(), request); + } } catch (Exception e) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, SecurityHelper.HTTPCLIENT_5_0, e.getMessage()), e, this.getClass().getName()); } 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 8c0e601cb..cfd2a3999 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 @@ -39,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -63,17 +63,10 @@ public Future execute( } private void releaseLock() { - try { - GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } } 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 e5b1a090c..7c4d96080 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 @@ -30,7 +30,7 @@ public class HttpClient_Instrumentation { public HttpResponse execute(ClassicHttpRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -50,7 +50,7 @@ public HttpResponse execute(ClassicHttpRequest request) throws Exception { } public HttpResponse execute(ClassicHttpRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -70,7 +70,7 @@ public HttpResponse execute(ClassicHttpRequest request, HttpContext context) thr } public ClassicHttpResponse execute(HttpHost target, ClassicHttpRequest request) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -96,7 +96,7 @@ public ClassicHttpResponse execute(HttpHost target, ClassicHttpRequest request) } public HttpResponse execute(HttpHost target, ClassicHttpRequest request, HttpContext context) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -123,7 +123,7 @@ public HttpResponse execute(HttpHost target, ClassicHttpRequest request, HttpCon public T execute(ClassicHttpRequest request, HttpClientResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -144,7 +144,7 @@ public T execute(ClassicHttpRequest request, HttpClientResponseHandler T execute(ClassicHttpRequest request, HttpContext context, HttpClientResponseHandler responseHandler) throws Exception { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -165,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -192,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -224,18 +224,11 @@ private static URI getUri(HttpHost target, HttpRequest request) throws URISyntax } private void releaseLock() { - try { - GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } } diff --git a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/SecurityHelper.java b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/SecurityHelper.java index 65de23af7..ae82bd666 100644 --- a/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/SecurityHelper.java +++ b/instrumentation-security/httpclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/httpclient50/SecurityHelper.java @@ -34,10 +34,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(HttpRequest request, String uri, String className, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // Add Security IAST header String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); @@ -45,7 +41,7 @@ public static AbstractOperation preprocessSecurityHook(HttpRequest request, Stri request.setHeader(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader); } - String csecParentId = getParentId(); + String csecParentId = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class); if(csecParentId!= null && !csecParentId.isEmpty()){ request.setHeader(GenericHelper.CSEC_PARENT_ID, csecParentId); } @@ -72,8 +68,4 @@ public static AbstractOperation preprocessSecurityHook(HttpRequest request, Stri } return null; } - - public static String getParentId(){ - return NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class); - } } 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 a86fa1c53..b2c0644cd 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 @@ -39,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(VulnerabilityCaseType.HTTP_REQUEST); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; // Preprocess Phase if (isLockAcquired) { @@ -63,12 +63,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private AbstractOperation preprocessSecurityHook(HttpRequest request, String uri, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - SSRFOperation operation = new SSRFOperation(uri, this.getClass().getName(), methodName); NewRelicSecurity.getAgent().registerOperation(operation); @@ -86,18 +80,11 @@ private AbstractOperation preprocessSecurityHook(HttpRequest request, String uri private void releaseLock() { - try { - GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.HTTP_REQUEST, SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME, this.hashCode()); } private static HttpRequest addSecurityHeader(AbstractOperation operation, HttpRequest req) { diff --git a/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpRequest_Instrumentation.java b/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpRequest_Instrumentation.java index 3feed9020..d6ad1d1ab 100644 --- a/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpRequest_Instrumentation.java +++ b/instrumentation-security/httpclient-jdk11/src/main/java/com/newrelic/agent/security/instrumentation/http/HttpRequest_Instrumentation.java @@ -20,7 +20,9 @@ public HttpRequest build() { HttpRequest req = null; try { req = Weaver.callOriginal(); - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME + req.hashCode(), this); + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null) { + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(SecurityHelper.NR_SEC_CUSTOM_ATTRIB_NAME + req.hashCode(), this); + } } catch (Exception e){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, SecurityHelper.HTTPCLIENT_JDK_11, e.getMessage()), e, this.getClass().getName()); } diff --git a/instrumentation-security/java-io-inputstream-jdk8/src/main/java/java/io/InputStream_Instrumentation.java b/instrumentation-security/java-io-inputstream-jdk8/src/main/java/java/io/InputStream_Instrumentation.java index 035c10fb3..647d23092 100644 --- a/instrumentation-security/java-io-inputstream-jdk8/src/main/java/java/io/InputStream_Instrumentation.java +++ b/instrumentation-security/java-io-inputstream-jdk8/src/main/java/java/io/InputStream_Instrumentation.java @@ -16,18 +16,14 @@ public abstract class InputStream_Instrumentation { private boolean acquireLockIfPossible(int hashCode) { - try { - if(InputStreamHelper.processRequestInputStreamHookData(hashCode)) { - return GenericHelper.acquireLockIfPossible(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } - } catch (Throwable ignored) {} + if(InputStreamHelper.processRequestInputStreamHookData(hashCode)) { + return GenericHelper.acquireLockIfPossible(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + } return false; } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public int read(byte[] b) throws IOException { diff --git a/instrumentation-security/java-io-inputstream-jdk9/src/main/java/com/newrelic/agent/security/instrumentation/javaio/io/InputStream_Instrumentation.java b/instrumentation-security/java-io-inputstream-jdk9/src/main/java/com/newrelic/agent/security/instrumentation/javaio/io/InputStream_Instrumentation.java index 1ad2093b4..31b55511c 100644 --- a/instrumentation-security/java-io-inputstream-jdk9/src/main/java/com/newrelic/agent/security/instrumentation/javaio/io/InputStream_Instrumentation.java +++ b/instrumentation-security/java-io-inputstream-jdk9/src/main/java/com/newrelic/agent/security/instrumentation/javaio/io/InputStream_Instrumentation.java @@ -18,18 +18,14 @@ public abstract class InputStream_Instrumentation { private boolean acquireLockIfPossible(int hashCode) { - try { - if(InputStreamHelper.processRequestInputStreamHookData(hashCode)) { - return GenericHelper.acquireLockIfPossible(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } - } catch (Throwable ignored) {} + if(InputStreamHelper.processRequestInputStreamHookData(hashCode)) { + return GenericHelper.acquireLockIfPossible(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); + } return false; } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(InputStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public int read(byte[] b) throws IOException { diff --git a/instrumentation-security/java-io-stream/src/main/java/java/io/BufferedReader_Instrumentation.java b/instrumentation-security/java-io-stream/src/main/java/java/io/BufferedReader_Instrumentation.java index 8edb7c538..4abc0536a 100644 --- a/instrumentation-security/java-io-stream/src/main/java/java/io/BufferedReader_Instrumentation.java +++ b/instrumentation-security/java-io-stream/src/main/java/java/io/BufferedReader_Instrumentation.java @@ -22,18 +22,14 @@ public abstract class BufferedReader_Instrumentation { private boolean acquireLockIfPossible(int hashCode) { - try { - if(IOStreamHelper.processRequestReaderHookData(hashCode)) { - return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); - } - } catch (Throwable ignored) {} + if(IOStreamHelper.processRequestReaderHookData(hashCode)) { + return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); + } return false; } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); } @WeaveAllConstructors diff --git a/instrumentation-security/java-io-stream/src/main/java/java/io/OutputStream_Instrumentation.java b/instrumentation-security/java-io-stream/src/main/java/java/io/OutputStream_Instrumentation.java index 0ec0a9829..a2aa3dfca 100644 --- a/instrumentation-security/java-io-stream/src/main/java/java/io/OutputStream_Instrumentation.java +++ b/instrumentation-security/java-io-stream/src/main/java/java/io/OutputStream_Instrumentation.java @@ -16,18 +16,14 @@ @Weave(type = MatchType.BaseClass, originalName = "java.io.OutputStream") public abstract class OutputStream_Instrumentation { private static boolean acquireLockIfPossible(int hashCode) { - try { - if(IOStreamHelper.processResponseOutputStreamHookData(hashCode)) { - return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_OUTPUT_STREAM, hashCode); - } - } catch (Throwable ignored) {} + if(IOStreamHelper.processResponseOutputStreamHookData(hashCode)) { + return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_OUTPUT_STREAM, hashCode); + } return false; } private static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_OUTPUT_STREAM, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_OUTPUT_STREAM, hashCode); } public void write(byte b[]) throws IOException { diff --git a/instrumentation-security/java-io-stream/src/main/java/java/io/PrintWriter_Instrumentation.java b/instrumentation-security/java-io-stream/src/main/java/java/io/PrintWriter_Instrumentation.java index 17a2e34ee..379e073d4 100644 --- a/instrumentation-security/java-io-stream/src/main/java/java/io/PrintWriter_Instrumentation.java +++ b/instrumentation-security/java-io-stream/src/main/java/java/io/PrintWriter_Instrumentation.java @@ -20,18 +20,14 @@ public abstract class PrintWriter_Instrumentation { private PrintWriter_Instrumentation(){} private static boolean acquireLockIfPossible(int hashCode) { - try { - if(IOStreamHelper.processResponseWriterHookData(hashCode)) { - return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_WRITER, hashCode); - } - } catch (Throwable ignored) {} + if(IOStreamHelper.processResponseWriterHookData(hashCode)) { + return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_WRITER, hashCode); + } return false; } private static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_WRITER, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_WRITER, hashCode); } public PrintWriter append(char c) { diff --git a/instrumentation-security/java-io-stream/src/main/java/java/io/Reader_Instrumentation.java b/instrumentation-security/java-io-stream/src/main/java/java/io/Reader_Instrumentation.java index 5563c953b..85eb17343 100644 --- a/instrumentation-security/java-io-stream/src/main/java/java/io/Reader_Instrumentation.java +++ b/instrumentation-security/java-io-stream/src/main/java/java/io/Reader_Instrumentation.java @@ -20,18 +20,14 @@ public abstract class Reader_Instrumentation { protected Object lock; private boolean acquireLockIfPossible(int hashCode) { - try { - if(IOStreamHelper.processRequestReaderHookData(hashCode)) { - return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); - } - } catch (Throwable ignored) {} + if(IOStreamHelper.processRequestReaderHookData(hashCode)) { + return GenericHelper.acquireLockIfPossible(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); + } return false; } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(IOStreamHelper.NR_SEC_CUSTOM_ATTRIB_NAME_READER, hashCode); } protected Reader_Instrumentation(){ 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 57029faad..fa48ed6a3 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 @@ -53,8 +53,7 @@ private static void registerExitOperation(AbstractOperation operation) { private static AbstractOperation preprocessSecurityHook(String[] cmdarray, Map environment) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - || cmdarray == null || cmdarray.length == 0 + if (cmdarray == null || cmdarray.length == 0 ) { return null; } 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 63c9611c3..e676426d0 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 @@ -107,7 +107,7 @@ private void registerExitOperation(boolean isLockAcquired, List preprocessSecurityHook (Enumeration names, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - names == null || !names.hasMoreElements()){ + if (names == null || !names.hasMoreElements()){ return null; } UserDataTranslationHelper.placeJNDIAdditionalTemplateData(); @@ -140,9 +138,7 @@ private List preprocessSecurityHook (Enumeration name private AbstractOperation preprocessSecurityHook (String name, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(name)){ + if (StringUtils.isBlank(name)){ return null; } UserDataTranslationHelper.placeJNDIAdditionalTemplateData(); @@ -159,15 +155,10 @@ private AbstractOperation preprocessSecurityHook (String name, String methodName } private void releaseLock() { - try { - GenericHelper.releaseLock(JNDIUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JNDIUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType http) { - try { - return GenericHelper.acquireLockIfPossible(http, JNDIUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(http, JNDIUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/instrumentation-security/javax-ldap/src/main/java/javax/naming/directory/DirContext_Instrumentation.java b/instrumentation-security/javax-ldap/src/main/java/javax/naming/directory/DirContext_Instrumentation.java index 927e7eb32..a21b80379 100644 --- a/instrumentation-security/javax-ldap/src/main/java/javax/naming/directory/DirContext_Instrumentation.java +++ b/instrumentation-security/javax-ldap/src/main/java/javax/naming/directory/DirContext_Instrumentation.java @@ -21,7 +21,7 @@ public abstract class DirContext_Instrumentation implements Context { public NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(name.toString(), filterExpr); @@ -40,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(VulnerabilityCaseType.LDAP); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(name, filterExpr); @@ -59,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(VulnerabilityCaseType.LDAP); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if (isLockAcquired) { operation = preprocessSecurityHook(name, filter); @@ -77,13 +77,9 @@ public NamingEnumeration search(String name, String filter, Search return returnVal; } - public NamingEnumeration - search(Name name, - String filter, - SearchControls cons) - throws NamingException { + public NamingEnumeration search(Name name, String filter, SearchControls cons) throws NamingException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(name.toString(), filter); @@ -103,7 +99,7 @@ public NamingEnumeration search(String name, String filter, Search private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent()) { return; } @@ -115,8 +111,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(String name, String filter) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isAnyBlank(filter)) { + if (StringUtils.isAnyBlank(filter)) { return null; } LDAPOperation ldapOperation = new LDAPOperation(name, filter, this.getClass().getName(), LDAPUtils.METHOD_SEARCH); @@ -134,18 +129,11 @@ private AbstractOperation preprocessSecurityHook(String name, String filter) { } private void releaseLock() { - try { - GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } - private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { - try { - return GenericHelper.acquireLockIfPossible(ldap, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.LDAP, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } 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 72e3f93cf..28d821f5b 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 @@ -19,11 +19,10 @@ public abstract class XPath_Instrumentation { abstract public String getPatternString(); - public XObject execute( - XPathContext xctxt, int contextNode, PrefixResolver namespaceContext) + public XObject execute(XPathContext xctxt, int contextNode, PrefixResolver namespaceContext) throws javax.xml.transform.TransformerException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(getPatternString(), "execute"); @@ -46,7 +45,7 @@ public XObject execute( PrefixResolver namespaceContext) throws javax.xml.transform.TransformerException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(getPatternString(), "execute"); @@ -66,7 +65,7 @@ public XObject execute( private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; @@ -77,9 +76,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -97,15 +94,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock("XPATH_OPERATION_LOCK_JAVAXPATH-"); - } catch (Throwable ignored) {} + GenericHelper.releaseLock("XPATH_OPERATION_LOCK_JAVAXPATH-"); } - private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, "XPATH_OPERATION_LOCK_JAVAXPATH-"); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.XPATH, "XPATH_OPERATION_LOCK_JAVAXPATH-"); } } 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 714cf3cba..f236ef07e 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 @@ -20,7 +20,7 @@ public abstract class XPath_Instrumentation { public String evaluate(String expression, InputSource source) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -43,7 +43,7 @@ public Object evaluate( InputSource source, QName returnType) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -63,7 +63,7 @@ public Object evaluate( public String evaluate(String expression, Object item) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -83,7 +83,7 @@ public String evaluate(String expression, Object item) public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(expression, "evaluate"); @@ -103,7 +103,7 @@ public Object evaluate(String expression, Object item, QName returnType) private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; @@ -116,9 +116,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -136,15 +134,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock("XPATH_OPERATION_LOCK_JAVAXPATH-"); - } catch (Throwable ignored) {} + GenericHelper.releaseLock("XPATH_OPERATION_LOCK_JAVAXPATH-"); } - private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, "XPATH_OPERATION_LOCK_JAVAXPATH-"); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.XPATH, "XPATH_OPERATION_LOCK_JAVAXPATH-"); } } 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 6b837641e..673a6ff6d 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 @@ -41,7 +41,7 @@ public List selectNodes(Object node) throws JaxenException { private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; @@ -54,9 +54,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -74,15 +72,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } 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 2a0ec1af5..993eee53a 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 @@ -21,7 +21,7 @@ public abstract class BaseXPath_Instrumentation { private final String exprText = Weaver.callOriginal(); public List selectNodes(Object node) throws JaxenException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.XPATH); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(this.exprText, XPATHUtils.METHOD_SELECT_NODES); @@ -41,7 +41,7 @@ public List selectNodes(Object node) throws JaxenException { private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; @@ -54,9 +54,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -74,15 +72,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } - private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.XPATH, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } 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 d813bcff0..0eb578d85 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 @@ -20,10 +20,8 @@ public class JCacheHelper { public static AbstractOperation preprocessSecurityHook(String command, List args, String klass, String method) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } JCacheOperation operation = new JCacheOperation(klass, method, command, args); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -50,15 +48,10 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashcode) { - try { - GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } - public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashcode) { - try { - return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); - } catch (Throwable ignored) {} - return false; + public static boolean acquireLockIfPossible(int hashcode) { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, NR_SEC_CUSTOM_ATTRIB_NAME, hashcode); } } 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 6672ebfed..76f6a94f5 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,7 +2,6 @@ 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; @@ -18,7 +17,7 @@ @Weave(type = MatchType.Interface, originalName = "javax.cache.Cache") public abstract class Cache_Instrumentation { public V get(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, Collections.singletonList(key), this.getClass().getName(), "get"); @@ -36,7 +35,7 @@ public V get(K key) { } public Map getAll(Set keys) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, new ArrayList() { { addAll(keys); } }, this.getClass().getName(), "getAll"); @@ -54,7 +53,7 @@ public Map getAll(Set keys) { } public boolean containsKey(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, Collections.singletonList(key), this.getClass().getName(), "containsKey"); @@ -72,7 +71,7 @@ public boolean containsKey(K key) { } public void loadAll(Set keys, boolean replaceExistingValues, CompletionListener completionListener) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.READ, new ArrayList() { { addAll(keys); } }, this.getClass().getName(), "loadAll"); @@ -88,7 +87,7 @@ public void loadAll(Set keys, boolean replaceExistingValues, Comple } public void put(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.WRITE, Arrays.asList(key, value), this.getClass().getName(), "put"); @@ -104,7 +103,7 @@ public void put(K key, V value) { } public V getAndPut(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.WRITE, Arrays.asList(key, value), this.getClass().getName(), "getAndPut"); @@ -122,7 +121,7 @@ public V getAndPut(K key, V value) { } public void putAll(Map map) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { List argList = new ArrayList<>(); @@ -144,7 +143,7 @@ public void putAll(Map map) { } public boolean putIfAbsent(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.WRITE, Arrays.asList(key, value), this.getClass().getName(), "putIfAbsent"); @@ -162,7 +161,7 @@ public boolean putIfAbsent(K key, V value) { } public boolean remove(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, Collections.singletonList(key), this.getClass().getName(), "remove"); @@ -180,7 +179,7 @@ public boolean remove(K key) { } public boolean remove(K key, V oldValue) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, Arrays.asList(key, oldValue), this.getClass().getName(), "remove"); @@ -198,7 +197,7 @@ public boolean remove(K key, V oldValue) { } public V getAndRemove(K key) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.DELETE, Collections.singletonList(key), this.getClass().getName(), "getAndRemove"); @@ -216,7 +215,7 @@ public V getAndRemove(K key) { } public boolean replace(K key, V oldValue) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.UPDATE, Arrays.asList(key, oldValue), this.getClass().getName(), "replace"); @@ -234,7 +233,7 @@ public boolean replace(K key, V oldValue) { } public boolean replace(K key, V oldValue, V newValue) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.UPDATE, Arrays.asList(key, oldValue, newValue), this.getClass().getName(), "replace"); @@ -252,7 +251,7 @@ public boolean replace(K key, V oldValue, V newValue) { } public V getAndReplace(K key, V value) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(this.hashCode()); AbstractOperation operation = null; if (isLockAcquired) { operation = JCacheHelper.preprocessSecurityHook(JCacheHelper.UPDATE, Arrays.asList(key, value), this.getClass().getName(), "getAndReplace"); @@ -270,7 +269,7 @@ public V getAndReplace(K key, V value) { } public void removeAll(Set keys) { - boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, this.hashCode()); + boolean isLockAcquired = JCacheHelper.acquireLockIfPossible(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-db2/src/main/java/com/ibm/db2/jcc/DB2DataSource.java b/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2DataSource.java index 773efdcd2..228839119 100644 --- a/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2DataSource.java +++ b/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2DataSource.java @@ -18,7 +18,7 @@ public abstract class DB2DataSource { public Connection getConnection(String userID, String pass) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.IBMDB2); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2Driver.java b/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2Driver.java index b73e686fb..d8f977a39 100644 --- a/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2Driver.java +++ b/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2Driver.java @@ -21,7 +21,7 @@ public abstract class DB2Driver { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.IBMDB2); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2SimpleDataSource.java b/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2SimpleDataSource.java index 130b3c2a8..b0352e5d3 100644 --- a/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2SimpleDataSource.java +++ b/instrumentation-security/jdbc-db2/src/main/java/com/ibm/db2/jcc/DB2SimpleDataSource.java @@ -18,7 +18,7 @@ public abstract class DB2SimpleDataSource { public Connection getConnection(String userID, String pass) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.IBMDB2); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java index c4680f51c..abb8a7e9c 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class AutoloadedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedBaseDataSource_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedBaseDataSource_Instrumentation.java index 965f63c89..eebf8b038 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedBaseDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedBaseDataSource_Instrumentation.java @@ -19,14 +19,14 @@ public abstract class EmbeddedBaseDataSource_Instrumentation { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java index cf7fdcef0..e4582fdc7 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.10.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class EmbeddedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java index c4680f51c..abb8a7e9c 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class AutoloadedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java index 4e4b34539..20cffcf67 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java @@ -19,14 +19,14 @@ public abstract class BasicEmbeddedDataSource40_Instrumentation { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java index cf7fdcef0..e4582fdc7 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.11.1.1/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class EmbeddedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/iapi/jdbc/AutoloadedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/iapi/jdbc/AutoloadedDriver_Instrumentation.java index 68483146c..cfa47bff4 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/iapi/jdbc/AutoloadedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/iapi/jdbc/AutoloadedDriver_Instrumentation.java @@ -22,7 +22,7 @@ public abstract class AutoloadedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java index 451b8161a..2974fef00 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/BasicEmbeddedDataSource40_Instrumentation.java @@ -21,14 +21,14 @@ public abstract class BasicEmbeddedDataSource40_Instrumentation { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java index cf7fdcef0..e4582fdc7 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.15.1.3/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class EmbeddedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java index c4680f51c..abb8a7e9c 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/AutoloadedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class AutoloadedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDataSource_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDataSource_Instrumentation.java index 4f3ce1878..1d0248696 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDataSource_Instrumentation.java @@ -19,14 +19,14 @@ public abstract class EmbeddedDataSource_Instrumentation { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java b/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java index cf7fdcef0..e4582fdc7 100644 --- a/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-embedded-derby-10.2.1.6/src/main/java/org/apache/derby/jdbc/EmbeddedDriver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class EmbeddedDriver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.DERBY); } return Weaver.callOriginal(); 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 3fdb82046..d6741bcac 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 @@ -45,7 +45,7 @@ public abstract class PreparedStatement_Instrumentation { private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || JdbcHelper.skipExistsEvent() ) { return; @@ -58,9 +58,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String sql, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()){ + if (sql == null || sql.trim().isEmpty()){ return null; } SQLOperation sqlOperation = new SQLOperation(this.getClass().getName(), methodName); @@ -100,12 +98,12 @@ private void releaseLock() { GenericHelper.releaseLock(JdbcHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType sqlDbCommand) { - return GenericHelper.acquireLockIfPossible(sqlDbCommand, JdbcHelper.getNrSecCustomAttribName()); + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND, JdbcHelper.getNrSecCustomAttribName()); } public ResultSet executeQuery() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { if(preparedSql == null){ @@ -126,7 +124,7 @@ public ResultSet executeQuery() throws SQLException { } public int executeUpdate() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { if(preparedSql == null){ @@ -147,7 +145,7 @@ public int executeUpdate() throws SQLException { } public boolean execute() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { if(preparedSql == null){ @@ -391,7 +389,7 @@ private void setObjectParams(int index, Object data) { objectParams.put(String.valueOf(index), data); } public void addBatch() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); 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 188de5713..9bee877f7 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 @@ -33,7 +33,7 @@ public abstract class Statement_Instrumentation { private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || JdbcHelper.skipExistsEvent() ) { return; @@ -46,9 +46,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String sql, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()){ + if (sql == null || sql.trim().isEmpty()){ return null; } SQLOperation sqlOperation = new SQLOperation(this.getClass().getName(), methodName); @@ -85,9 +83,7 @@ private AbstractOperation preprocessSecurityHook (String sql, String methodName) private AbstractOperation preprocessSecurityHook(BatchSQLOperation operation){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - operation == null || operation.isEmpty()){ + if (operation == null || operation.isEmpty()){ return null; } NewRelicSecurity.getAgent().registerOperation(operation); @@ -105,7 +101,7 @@ private AbstractOperation preprocessSecurityHook(BatchSQLOperation operation){ public ResultSet executeQuery(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_QUERY); @@ -126,12 +122,12 @@ private void releaseLock() { GenericHelper.releaseLock(JdbcHelper.getNrSecCustomAttribName()); } - private boolean acquireLockIfPossible(VulnerabilityCaseType sqlDbCommand) { - return GenericHelper.acquireLockIfPossible(sqlDbCommand, JdbcHelper.getNrSecCustomAttribName()); + private boolean acquireLockIfPossible() { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND, JdbcHelper.getNrSecCustomAttribName()); } public int executeUpdate(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -149,7 +145,7 @@ public int executeUpdate(String sql) throws SQLException { } public boolean execute(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -167,7 +163,7 @@ public boolean execute(String sql) throws SQLException { } public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -185,7 +181,7 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException } public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -203,7 +199,7 @@ public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { } public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -221,7 +217,7 @@ public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { } public int executeUpdate(String sql, String[] columnNames) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE_UPDATE); @@ -239,7 +235,7 @@ public int executeUpdate(String sql, String[] columnNames) throws SQLException { } public boolean execute(String sql, String[] columnNames) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -257,7 +253,7 @@ public boolean execute(String sql, String[] columnNames) throws SQLException { } public boolean execute(String sql, int[] columnIndexes) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(sql, JdbcHelper.METHOD_EXECUTE); @@ -275,7 +271,7 @@ public boolean execute(String sql, int[] columnIndexes) throws SQLException { } public void addBatch(String sql) throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); SQLOperation sqlOperation = null; if(isLockAcquired) { sqlOperation = new SQLOperation(this.getClass().getName(), JdbcHelper.METHOD_EXECUTE_BATCH); @@ -297,7 +293,7 @@ public void addBatch(String sql) throws SQLException { } public void clearBatch() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); if(isLockAcquired) { if (batchSQLOperation==null){ batchSQLOperation = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(JdbcHelper.NR_SEC_CUSTOM_ATTRIB_BATCH_SQL_NAME+hashCode(), BatchSQLOperation.class); @@ -316,7 +312,7 @@ public void clearBatch() throws SQLException { } public int[] executeBatch() throws SQLException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.SQL_DB_COMMAND); + boolean isLockAcquired = acquireLockIfPossible(); AbstractOperation operation = null; if(isLockAcquired) { if(batchSQLOperation==null|| batchSQLOperation.isEmpty()){ diff --git a/instrumentation-security/jdbc-generic/src/main/java/javax/sql/DataSource_Weaved.java b/instrumentation-security/jdbc-generic/src/main/java/javax/sql/DataSource_Weaved.java index 20b9f9b83..244dfb867 100644 --- a/instrumentation-security/jdbc-generic/src/main/java/javax/sql/DataSource_Weaved.java +++ b/instrumentation-security/jdbc-generic/src/main/java/javax/sql/DataSource_Weaved.java @@ -31,7 +31,7 @@ public abstract class DataSource_Weaved { private void postHookProcessing(Connection connection) { try { String vendor; - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { vendor = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, String.class); if(vendor == null || vendor.trim().isEmpty()){ vendor = JdbcHelper.detectDatabaseProduct(connection.getMetaData().getDatabaseProductName()); diff --git a/instrumentation-security/jdbc-h2/src/main/java/org/h2/Driver.java b/instrumentation-security/jdbc-h2/src/main/java/org/h2/Driver.java index 2bcf37500..5d3d9b3d2 100644 --- a/instrumentation-security/jdbc-h2/src/main/java/org/h2/Driver.java +++ b/instrumentation-security/jdbc-h2/src/main/java/org/h2/Driver.java @@ -20,7 +20,7 @@ public abstract class Driver { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.H2); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbc/JdbcConnection_Instrumentation.java b/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbc/JdbcConnection_Instrumentation.java index f0621db25..d875a7f44 100644 --- a/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbc/JdbcConnection_Instrumentation.java +++ b/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbc/JdbcConnection_Instrumentation.java @@ -12,7 +12,7 @@ public abstract class JdbcConnection_Instrumentation { @WeaveAllConstructors private JdbcConnection_Instrumentation() { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.H2); } } diff --git a/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbcx/JdbcDataSource_Instrumentation.java b/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbcx/JdbcDataSource_Instrumentation.java index bfab9dd45..354a51e96 100644 --- a/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbcx/JdbcDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-h2/src/main/java/org/h2/jdbcx/JdbcDataSource_Instrumentation.java @@ -18,14 +18,14 @@ public abstract class JdbcDataSource_Instrumentation { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.H2); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.H2); } return Weaver.callOriginal(); 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 4c41e222d..aa5212cf8 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 @@ -50,9 +50,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String sql, Map params, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()){ + if (sql == null || sql.trim().isEmpty()){ return null; } SQLOperation sqlOperation = new SQLOperation(this.getClass().getName(), methodName); @@ -74,9 +72,7 @@ private AbstractOperation preprocessSecurityHook (String sql, Map var3) throws SQLException { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.ORACLE); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/Driver_Instrumentation.java b/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/Driver_Instrumentation.java index e4714e60e..f59238cf1 100644 --- a/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/Driver_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/Driver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class Driver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.POSTGRES); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java b/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java index 257b60bf2..2959f3a00 100644 --- a/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-8.0-312.jdbc3/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java @@ -19,7 +19,7 @@ public abstract class BaseDataSource_Instrumentation { public Connection getConnection(String userID, String pass) throws Exception { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.POSTGRES); } return Weaver.callOriginal(); 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 3fb4d314f..973c18a74 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 @@ -50,9 +50,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String sql, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()){ + if (sql == null || sql.trim().isEmpty()){ return null; } SQLOperation sqlOperation = new SQLOperation(this.getClass().getName(), methodName); diff --git a/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/Driver_Instrumentation.java b/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/Driver_Instrumentation.java index e4714e60e..f59238cf1 100644 --- a/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/Driver_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/Driver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class Driver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.POSTGRES); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java b/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java index 257b60bf2..2959f3a00 100644 --- a/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-9.4.1207/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java @@ -19,7 +19,7 @@ public abstract class BaseDataSource_Instrumentation { public Connection getConnection(String userID, String pass) throws Exception { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.POSTGRES); } return Weaver.callOriginal(); 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 e032d4204..d775bc6c7 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 @@ -55,9 +55,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String sql, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()){ + if (sql == null || sql.trim().isEmpty()){ return null; } SQLOperation sqlOperation = new SQLOperation(this.getClass().getName(), methodName); diff --git a/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/Driver_Instrumentation.java b/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/Driver_Instrumentation.java index e4714e60e..f59238cf1 100644 --- a/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/Driver_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/Driver_Instrumentation.java @@ -20,7 +20,7 @@ public abstract class Driver_Instrumentation { public Connection connect(String url, Properties props) throws SQLException { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.POSTGRES); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java b/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java index 295fdfe24..daa5560bf 100644 --- a/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-postgresql-9.4.1208/src/main/java/org/postgresql/ds/common/BaseDataSource_Instrumentation.java @@ -19,7 +19,7 @@ public abstract class BaseDataSource_Instrumentation { public Connection getConnection(String userID, String pass) throws Exception { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.POSTGRES); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java index f510003af..22c203e2c 100644 --- a/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java +++ b/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -19,14 +19,14 @@ public abstract class SQLServerDataSource { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.MSSQL); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.MSSQL); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 66b99ce4f..a789122d8 100644 --- a/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/instrumentation-security/jdbc-sqlserver/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -19,7 +19,7 @@ public abstract class SQLServerDriver { public Connection connect(String url, Properties props) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.MSSQL); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDataSource_Instrumentation.java b/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDataSource_Instrumentation.java index 89cab48fc..35b7e9407 100644 --- a/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDataSource_Instrumentation.java +++ b/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDataSource_Instrumentation.java @@ -18,14 +18,14 @@ public abstract class SybDataSource_Instrumentation { public Connection getConnection() { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.SYBASE); } return Weaver.callOriginal(); } public Connection getConnection(String user, String password) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.SYBASE); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDriver_Instrumentation.java b/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDriver_Instrumentation.java index dec19cab5..a77a54ae7 100644 --- a/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDriver_Instrumentation.java +++ b/instrumentation-security/jdbc-sybase-6/src/main/java/com/sybase/jdbc3/jdbc/SybDriver_Instrumentation.java @@ -18,7 +18,7 @@ public abstract class SybDriver_Instrumentation { public Connection connect(String url, Properties props) { - if(NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(JDBCVendor.META_CONST_JDBC_VENDOR, JDBCVendor.SYBASE); } return Weaver.callOriginal(); diff --git a/instrumentation-security/jedis-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_1_4_0/JedisHelper.java b/instrumentation-security/jedis-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_1_4_0/JedisHelper.java index 1feeed71c..85e82d2d2 100644 --- a/instrumentation-security/jedis-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_1_4_0/JedisHelper.java +++ b/instrumentation-security/jedis-1.4.0/src/main/java/com/newrelic/agent/security/instrumentation/jedis_1_4_0/JedisHelper.java @@ -3,19 +3,19 @@ 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 java.util.List; public class JedisHelper { - public static final String NR_SEC_LOCK_ATTRIB_NAME = "JEDIS_OPERATION_LOCK_"; + private static final String NR_SEC_LOCK_ATTRIB_NAME = "JEDIS_OPERATION_LOCK_"; + public static AbstractOperation preprocessSecurityHook(String command, List args, String klass, String method) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } RedisOperation operation = new RedisOperation(klass, method, command, args); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -38,15 +38,10 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.CACHING_DATA_STORE, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } } 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 d78ef528b..9cdecde0b 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 @@ -14,10 +14,8 @@ public class JedisHelper { public static final String NR_SEC_LOCK_ATTRIB_NAME = "REDIS_SERIALISED_DATA_"; public static AbstractOperation preprocessSecurityHook(String command, List args, String klass, String method) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } RedisOperation operation = new RedisOperation(klass, method, command, args); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -39,15 +37,10 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } } 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 0b1b7983f..715d8ecbf 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 @@ -14,10 +14,8 @@ public class JedisHelper { public static final String NR_SEC_LOCK_ATTRIB_NAME = "REDIS_SERIALISED_DATA_"; public static AbstractOperation preprocessSecurityHook(String command, List args, String klass, String method) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } RedisOperation operation = new RedisOperation(klass, method, command, args); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -39,15 +37,10 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } } 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 ddc00efb2..450052e65 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 @@ -14,10 +14,8 @@ public class JedisHelper { public static final String NR_SEC_LOCK_ATTRIB_NAME = "REDIS_SERIALISED_DATA_"; public static AbstractOperation preprocessSecurityHook(String command, List args, String klass, String method) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } RedisOperation operation = new RedisOperation(klass, method, command, args); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -39,15 +37,10 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(NR_SEC_LOCK_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(cachingDataStore, NR_SEC_LOCK_ATTRIB_NAME, hashCode); } } 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 6e58136bb..d3fae0771 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 @@ -26,13 +26,16 @@ public abstract class ContainerResponse_Instrumentation { ContainerResponse_Instrumentation(final ContainerRequest requestContext, final OutboundJaxrsResponse response) { - if(response != null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); - } + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null) { + 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))); + 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))); + } } } @@ -41,7 +44,7 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); + isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } diff --git a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index 377b367dc..1dace5e70 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 @@ -9,6 +9,7 @@ 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.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; @@ -29,33 +30,27 @@ public class HttpRequestHelper { private static final String EMPTY = ""; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private 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 ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - 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"; - public static final String METHOD_GET_LOCAL_PORT = "getLocalPort"; - 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 FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; + private static final String HEADER_SEPARATOR = ";"; + private static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; + private static final String FIELD_REQUEST = "request"; + private static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; + private static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; + private static final String METHOD_GET_LOCAL_PORT = "getLocalPort"; + private static final String METHOD_GET_SCHEME = "getScheme"; + private static final String METHOD_GET_CONTENT_TYPE = "getContentType"; + private static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; + private 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 void preprocessSecurityHook(ContainerRequest requestContext) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(requestContext.getMethod()); HttpRequestHelper.processPropertiesDelegate(requestContext.getPropertiesDelegate(), securityRequest); @@ -78,7 +73,7 @@ public static void preprocessSecurityHook(ContainerRequest requestContext) { public static void postProcessSecurityHook(String className, OutboundMessageContext wrappedMessageContext) { try { - if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) + if (Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -117,7 +112,7 @@ private static Map getHeaders(OutboundMessageContext outboundMes } - public static void processHttpRequestHeader(ContainerRequest request, HttpRequest securityRequest){ + private static void processHttpRequestHeader(ContainerRequest request, HttpRequest securityRequest){ MultivaluedMap headers = request.getHeaders(); for (Map.Entry> header : headers.entrySet()) { boolean takeNextValue = false; @@ -173,7 +168,7 @@ private static String getHeaderValue(List values) { return finalValue.toString(); } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -193,14 +188,7 @@ private static boolean isRequestLockAcquired() { } public static boolean acquireRequestLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isRequestLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void 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 6271a01e4..69d0ae019 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 @@ -25,13 +25,16 @@ public abstract class ContainerResponse_Instrumentation { ContainerResponse_Instrumentation(final ContainerRequest requestContext, final OutboundJaxrsResponse response) { - if(response != null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); - } + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null) { + 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))); + 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))); + } } } @@ -40,7 +43,7 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); + isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index a060e849f..18e77b36c 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 @@ -9,6 +9,7 @@ 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.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; @@ -29,35 +30,30 @@ public class HttpRequestHelper { private static final String EMPTY = ""; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private 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 ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - 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"; - public static final String METHOD_GET_LOCAL_PORT = "getLocalPort"; - 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 FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; + private static final String HEADER_SEPARATOR = ";"; + private static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; + private static final String FIELD_REQUEST = "request"; + private static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; + private static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; + private static final String METHOD_GET_LOCAL_PORT = "getLocalPort"; + private static final String METHOD_GET_SCHEME = "getScheme"; + private static final String METHOD_GET_CONTENT_TYPE = "getContentType"; + private static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; + private static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; - public static final String CONTENT_TYPE = "content-type"; - public static final String HEADER_CONTENT_TYPE = "contenttype"; + private static final String CONTENT_TYPE = "content-type"; + private static final String HEADER_CONTENT_TYPE = "contenttype"; public static final String JERSEY_2 = "JERSEY-2"; public static void preprocessSecurityHook(ContainerRequest requestContext) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } + AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(requestContext.getMethod()); HttpRequestHelper.processPropertiesDelegate(requestContext.getPropertiesDelegate(), securityRequest); @@ -80,7 +76,7 @@ public static void preprocessSecurityHook(ContainerRequest requestContext) { public static void postProcessSecurityHook(String className, OutboundMessageContext wrappedMessageContext) { try { - if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { + if (Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -118,7 +114,7 @@ private static Map getHeaders(OutboundMessageContext outboundMes } - public static void processHttpRequestHeader(ContainerRequest request, HttpRequest securityRequest){ + private static void processHttpRequestHeader(ContainerRequest request, HttpRequest securityRequest){ MultivaluedMap headers = request.getHeaders(); for (Map.Entry> header : headers.entrySet()) { boolean takeNextValue = false; @@ -174,7 +170,7 @@ private static String getHeaderValue(List values) { return finalValue.toString(); } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -185,31 +181,12 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isRequestLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - public static boolean acquireRequestLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isRequestLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseRequestLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { @@ -220,7 +197,7 @@ public static String getNrSecCustomAttribForPostProcessing() { return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); } - public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { + private 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 = propertiesDelegate.getClass(); @@ -275,10 +252,6 @@ public static void registerInputStreamHashIfNeeded(int inputStreamHash){ public static void registerUserLevelCode(String frameworkName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); if (!securityMetaData.getMetaData().isUserLevelServiceMethodEncountered(frameworkName)) { securityMetaData.getMetaData().setUserLevelServiceMethodEncountered(true); 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 6271a01e4..69d0ae019 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 @@ -25,13 +25,16 @@ public abstract class ContainerResponse_Instrumentation { ContainerResponse_Instrumentation(final ContainerRequest requestContext, final OutboundJaxrsResponse response) { - if(response != null) { - NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); - } + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null) { + 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))); + 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))); + } } } @@ -40,7 +43,7 @@ public abstract class ContainerResponse_Instrumentation { public void close() { boolean isLockAcquired = false; try { - isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); + isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } diff --git a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/ContextHandler_Instrumentation.java b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/ContextHandler_Instrumentation.java index 6745182db..2cf8c917d 100644 --- a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/ContextHandler_Instrumentation.java +++ b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/ContextHandler_Instrumentation.java @@ -13,7 +13,7 @@ public abstract class ContextHandler_Instrumentation { public abstract ContextHandler.Context getServletContext(); public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if (isServletLockAcquired) { HttpServletHelper.preprocessSecurityHook(request); } @@ -21,7 +21,7 @@ public void doHandle(String target, Request baseRequest, HttpServletRequest requ Weaver.callOriginal(); } finally { if (isServletLockAcquired) { - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if (isServletLockAcquired) { @@ -36,19 +36,4 @@ protected void doStart() throws Exception { HttpServletHelper.gatherURLMappings(getServletContext()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) { - } - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) { - } - } } 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 bd8ca5aed..d95541647 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 @@ -7,6 +7,7 @@ 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.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; @@ -29,12 +30,12 @@ public class HttpServletHelper { 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 = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; public static final String JETTY_11 = "JETTY-11"; public static final String WILDCARD = "*"; public static final String SEPARATOR = "/"; - public static void processHttpRequestHeader(HttpServletRequest request, HttpRequest securityRequest) { + private static void processHttpRequestHeader(HttpServletRequest request, HttpRequest securityRequest) { Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { boolean takeNextValue = false; @@ -85,7 +86,7 @@ public static void processHttpRequestHeader(HttpServletRequest request, HttpRequ } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -96,34 +97,12 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) { - } - return false; - } - public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { @@ -132,15 +111,12 @@ private static String getNrSecCustomAttribName() { public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) { try { - if (!NewRelicSecurity.isHookProcessingActive() || httpServletRequest == null) { + if (httpServletRequest == null) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } + AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); diff --git a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/Server_Instrumentation.java b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/Server_Instrumentation.java index 57c5cc728..64b0b4e50 100644 --- a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/Server_Instrumentation.java +++ b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/Server_Instrumentation.java @@ -50,7 +50,7 @@ private void setApplicationConfig(Connector[] connectors) { public void handle(HttpChannel connection) { HttpServletRequest request = connection.getRequest(); HttpServletResponse response = connection.getResponse(); - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if (isServletLockAcquired) { HttpServletHelper.preprocessSecurityHook(request); } @@ -58,7 +58,7 @@ public void handle(HttpChannel connection) { Weaver.callOriginal(); } finally { if (isServletLockAcquired) { - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if (isServletLockAcquired) { @@ -70,7 +70,7 @@ public void handle(HttpChannel connection) { public void handleAsync(HttpChannel connection) { HttpServletRequest request = connection.getRequest(); HttpServletResponse response = connection.getResponse(); - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if (isServletLockAcquired) { HttpServletHelper.preprocessSecurityHook(request); } @@ -78,7 +78,7 @@ public void handleAsync(HttpChannel connection) { Weaver.callOriginal(); } finally { if (isServletLockAcquired) { - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if (isServletLockAcquired) { @@ -86,19 +86,4 @@ public void handleAsync(HttpChannel connection) { HttpServletHelper.SERVICE_ASYNC_METHOD_NAME); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) { - } - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) { - } - } } 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 b015e742f..5632b836b 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 @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.HttpRequest; 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.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; @@ -28,10 +29,10 @@ public class HttpServletHelper { private static final String EMPTY = ""; public static final String SERVICE_METHOD_NAME = "handle"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private 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) { + private static void processHttpRequestHeader(Request request, HttpRequest securityRequest) { HttpFields headers = request.getHeaders(); if (headers!=null){ Set headerKeys = headers.getFieldNamesCollection(); @@ -83,7 +84,7 @@ public static void processHttpRequestHeader(Request request, HttpRequest securit } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -94,34 +95,13 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) { - } - return false; - } public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { @@ -130,15 +110,12 @@ private static String getNrSecCustomAttribName() { public static void preprocessSecurityHook(Request request) { try { - if (!NewRelicSecurity.isHookProcessingActive() || request == null) { + if (request == null) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } + AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); diff --git a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/ContextHandler_Instrumentation.java b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/ContextHandler_Instrumentation.java index e8e17d5a6..975cf82d8 100644 --- a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/ContextHandler_Instrumentation.java +++ b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/ContextHandler_Instrumentation.java @@ -15,7 +15,7 @@ public abstract class ContextHandler_Instrumentation { public abstract ContextHandler.Context getServletContext(); public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if (isServletLockAcquired) { HttpServletHelper.preprocessSecurityHook(request); } @@ -23,7 +23,7 @@ public void doHandle(String target, Request baseRequest, HttpServletRequest requ Weaver.callOriginal(); } finally { if (isServletLockAcquired) { - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if (isServletLockAcquired) { @@ -40,18 +40,4 @@ protected void doStart() throws Exception { } } - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) { - } - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) { - } - } } 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 685b15fbf..a01ba5d19 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 @@ -7,6 +7,7 @@ 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.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; @@ -28,13 +29,13 @@ public class HttpServletHelper { 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 = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; public static final String JETTY_9 = "JETTY-9"; private static final String SEPARATOR = "/"; private static final String WILDCARD = "*"; - public static void processHttpRequestHeader(HttpServletRequest request, HttpRequest securityRequest) { + private static void processHttpRequestHeader(HttpServletRequest request, HttpRequest securityRequest) { Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { boolean takeNextValue = false; @@ -86,7 +87,7 @@ public static void processHttpRequestHeader(HttpServletRequest request, HttpRequ } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -97,34 +98,12 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) { - } - return false; - } - public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if (NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { @@ -133,15 +112,12 @@ private static String getNrSecCustomAttribName() { public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) { try { - if (!NewRelicSecurity.isHookProcessingActive() || httpServletRequest == null) { + if (httpServletRequest == null) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } + AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); diff --git a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/Server_Instrumentation.java b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/Server_Instrumentation.java index 117b989ca..a4cc74c31 100644 --- a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/Server_Instrumentation.java +++ b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/Server_Instrumentation.java @@ -50,7 +50,7 @@ private void setApplicationConfig(Connector[] connectors) { public void handle(HttpChannel connection) { HttpServletRequest request = connection.getRequest(); HttpServletResponse response = connection.getResponse(); - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if (isServletLockAcquired) { HttpServletHelper.preprocessSecurityHook(request); } @@ -58,7 +58,7 @@ public void handle(HttpChannel connection) { Weaver.callOriginal(); } finally { if (isServletLockAcquired) { - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if (isServletLockAcquired) { @@ -70,7 +70,7 @@ public void handle(HttpChannel connection) { public void handleAsync(HttpChannel connection) { HttpServletRequest request = connection.getRequest(); HttpServletResponse response = connection.getResponse(); - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if (isServletLockAcquired) { HttpServletHelper.preprocessSecurityHook(request); } @@ -78,7 +78,7 @@ public void handleAsync(HttpChannel connection) { Weaver.callOriginal(); } finally { if (isServletLockAcquired) { - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if (isServletLockAcquired) { @@ -87,18 +87,4 @@ public void handleAsync(HttpChannel connection) { } } - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) { - } - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) { - } - } } 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 3d3eda502..4bdf27aaa 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 @@ -53,9 +53,7 @@ private void registerExitOperation(boolean isProcessingAllowed, com.newrelic.api private AbstractOperation preprocessSecurityHook (String name, String filter, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(filter)){ + if (StringUtils.isBlank(filter)){ return null; } LDAPOperation ldapOperation = new LDAPOperation(name, filter, this.getClass().getName(), methodName); @@ -74,9 +72,7 @@ private AbstractOperation preprocessSecurityHook (String name, String filter, St } private void releaseLock() { - try { - GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { 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 76a624163..89c1e1352 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 @@ -52,9 +52,7 @@ private void registerExitOperation(boolean isProcessingAllowed, com.newrelic.api private AbstractOperation preprocessSecurityHook (String name, Filter filter, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - filter == null){ + if (filter == null){ return null; } LDAPOperation ldapOperation = new LDAPOperation(name, NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(LDAPUtils.getNrSecCustomAttribName(filter.hashCode()), String.class), this.getClass().getName(), methodName); @@ -73,15 +71,10 @@ private AbstractOperation preprocessSecurityHook (String name, Filter filter, St } private void releaseLock() { - try { - GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { - try { - return GenericHelper.acquireLockIfPossible(ldap, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(ldap, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/instrumentation-security/lettuce-4.3/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands_Instrumentation.java b/instrumentation-security/lettuce-4.3/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands_Instrumentation.java index ecd38c40e..cc91f86eb 100644 --- a/instrumentation-security/lettuce-4.3/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands_Instrumentation.java +++ b/instrumentation-security/lettuce-4.3/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands_Instrumentation.java @@ -65,10 +65,6 @@ private void registerExitOperation(boolean isProcessingAllowed, com.newrelic.api private AbstractOperation preprocessSecurityHook(RedisCommand_Instrumentation cmd, String methodDispatch) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } String type = cmd.getType().name(); CommandArgs_Instrumentation commandArgs = cmd.getArgs(); List arguments = new ArrayList<>(); @@ -91,15 +87,10 @@ private AbstractOperation preprocessSecurityHook(RedisCommand_Instrumentatio } private void releaseLock() { - try { - GenericHelper.releaseLock(LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore) { - try { - return GenericHelper.acquireLockIfPossible(cachingDataStore, LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(cachingDataStore, LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/instrumentation-security/lettuce-4.3/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_4_3/LettuceUtils.java b/instrumentation-security/lettuce-4.3/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_4_3/LettuceUtils.java index 84adf2afb..4f9c125e0 100644 --- a/instrumentation-security/lettuce-4.3/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_4_3/LettuceUtils.java +++ b/instrumentation-security/lettuce-4.3/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_4_3/LettuceUtils.java @@ -8,7 +8,4 @@ public class LettuceUtils { public static final String METHOD_DISPATCH = "dispatch"; public static final String LETTUCE_4_3 = "LETTUCE-4.3"; - public static String getNrSecCustomAttribName(int hashCode) { - return NR_SEC_CUSTOM_ATTR_FILTER_NAME + hashCode; - } } diff --git a/instrumentation-security/lettuce-5.0/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_6_0/LettuceUtils.java b/instrumentation-security/lettuce-5.0/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_6_0/LettuceUtils.java index dce2ac802..1006da578 100644 --- a/instrumentation-security/lettuce-5.0/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_6_0/LettuceUtils.java +++ b/instrumentation-security/lettuce-5.0/src/main/java/com/newrelic/agent/security/instrumentation/lettuce_6_0/LettuceUtils.java @@ -4,11 +4,7 @@ public class LettuceUtils { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REDIS_OPERATION_LOCK_LETTUCE-"; - public static final String NR_SEC_CUSTOM_ATTR_FILTER_NAME = "REDIS_FILTER-"; public static final String METHOD_DISPATCH = "dispatch"; - public static final String LETTUCE_5_0 = "LETTUCE-5.0"; - public static String getNrSecCustomAttribName(int hashCode) { - return NR_SEC_CUSTOM_ATTR_FILTER_NAME + hashCode; - } + public static final String LETTUCE_5_0 = "LETTUCE-5.0"; } 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 dd0c585f3..548d97e90 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 @@ -68,10 +68,6 @@ private void registerExitOperation(boolean isProcessingAllowed, com.newrelic.api private AbstractOperation preprocessSecurityHook(RedisCommand_Instrumentation cmd, String methodDispatch) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } String type = cmd.getType().name(); CommandArgs_Instrumentation commandArgs = cmd.getArgs(); List arguments = new ArrayList<>(); @@ -94,15 +90,10 @@ private AbstractOperation preprocessSecurityHook(RedisCommand_Instrumentatio } private void releaseLock() { - try { - GenericHelper.releaseLock(LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType cachingDataStore) { - try { - return GenericHelper.acquireLockIfPossible(cachingDataStore, LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(cachingDataStore, LettuceUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/KeyPairGenerator_Instrumentation.java b/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/KeyPairGenerator_Instrumentation.java index 3c8b09351..d940857b5 100644 --- a/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/KeyPairGenerator_Instrumentation.java +++ b/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/KeyPairGenerator_Instrumentation.java @@ -73,8 +73,7 @@ public static KeyPairGenerator getInstance(String algorithm, Provider provider) private static AbstractOperation preprocessSecurityHook(String algorithm, String provider, String className, String methodName, String category) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { + if (securityMetaData.getRequest().isEmpty()) { return null; } diff --git a/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/MessageDigest_Instrumentation.java b/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/MessageDigest_Instrumentation.java index a4621d93b..dfdc8d9e1 100644 --- a/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/MessageDigest_Instrumentation.java +++ b/instrumentation-security/low-priority-instrumentation/src/main/java/com/newrelic/agent/security/instrumentation/random/java/security/MessageDigest_Instrumentation.java @@ -73,8 +73,7 @@ public static MessageDigest getInstance(String algorithm, Provider provider) { private static AbstractOperation preprocessSecurityHook(String algorithm, String provider, String className, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { + if (securityMetaData.getRequest().isEmpty()) { return null; } 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 edf826045..c4648451c 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 @@ -23,10 +23,11 @@ public class Random_Instrumentation { public int nextInt() { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextInt"); } @@ -45,10 +46,11 @@ public int nextInt() { } public int nextInt(int bound) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextInt"); } @@ -67,10 +69,11 @@ public int nextInt(int bound) { } public void nextBytes(byte[] bytes) { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextBytes"); } @@ -87,10 +90,11 @@ public void nextBytes(byte[] bytes) { } public long nextLong() { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextLong"); } @@ -109,10 +113,11 @@ public long nextLong() { } public float nextFloat() { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextFloat"); } @@ -131,10 +136,11 @@ public float nextFloat() { } public double nextDouble() { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextDouble"); } @@ -153,10 +159,11 @@ public double nextDouble() { } public double nextGaussian() { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextGaussian"); } @@ -175,10 +182,11 @@ public double nextGaussian() { } public boolean nextBoolean() { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.RANDOM, hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(getClass().getName(), "nextBoolean"); } @@ -198,12 +206,6 @@ public boolean nextBoolean() { private AbstractOperation preprocessSecurityHook(String className, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - RandomOperation operation = null; Object obj = this; if (obj instanceof SecureRandom) { @@ -241,17 +243,10 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(RandomUtils.NR_SEC_RANDOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(RandomUtils.NR_SEC_RANDOM_ATTRIB_NAME, hashCode); } - private boolean acquireLockIfPossible(VulnerabilityCaseType random, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(random, RandomUtils.NR_SEC_RANDOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + private boolean acquireLockIfPossible(int hashCode) { + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.RANDOM, RandomUtils.NR_SEC_RANDOM_ATTRIB_NAME, hashCode); } } 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 fccfeca8c..94e6106c2 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 @@ -20,10 +20,9 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } + if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } T returnVal = null; @@ -41,10 +40,8 @@ public T execute(final ReadBinding binding) { public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } try { 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 9a11f881d..374342c26 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 @@ -20,10 +20,8 @@ public class CommandWriteOperation_Instrumentation { public T execute(final WriteBinding binding) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } T returnVal = null; @@ -41,10 +39,8 @@ public T execute(final WriteBinding binding) { public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } try { 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 eafa27c08..3f5ab8fff 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 @@ -49,12 +49,9 @@ public class MongoUtil { public static AbstractOperation recordMongoOperation(BsonDocument command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() && command != null) { - operation = new NoSQLOperation(command.toJson(), typeOfOperation, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - NewRelicSecurity.getAgent().registerOperation(operation); - } + operation = new NoSQLOperation(command.toJson(), typeOfOperation, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_0, e.getMessage()), e, MongoUtil.class.getName()); @@ -69,18 +66,15 @@ public static AbstractOperation recordMongoOperation(BsonDocument command, Strin public static AbstractOperation recordMongoOperation(List command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (BsonDocument cmd : command) { - if(cmd != null) { - operations.add(cmd.toJson()); - } + List operations = new ArrayList<>(); + for (BsonDocument cmd : command) { + if(cmd != null) { + operations.add(cmd.toJson()); } - operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_0, e.getMessage()), e, MongoUtil.class.getName()); @@ -106,43 +100,33 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static AbstractOperation recordWriteRequest(List writeRequest, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (WriteRequest request : writeRequest) { - if(request instanceof InsertRequest){ - InsertRequest insertRequest = (InsertRequest) request; - operations.add(insertRequest.getDocument().toJson()); - } else if (request instanceof DeleteRequest){ - DeleteRequest deleteRequest = (DeleteRequest) request; - operations.add(deleteRequest.getFilter().toJson()); - } else if (request instanceof UpdateRequest){ - UpdateRequest updateRequest = (UpdateRequest) request; - operations.add(updateRequest.getUpdate().toJson()); - operations.add(updateRequest.getFilter().toJson()); - } + List operations = new ArrayList<>(); + for (WriteRequest request : writeRequest) { + if(request instanceof InsertRequest){ + InsertRequest insertRequest = (InsertRequest) request; + operations.add(insertRequest.getDocument().toJson()); + } else if (request instanceof DeleteRequest){ + DeleteRequest deleteRequest = (DeleteRequest) request; + operations.add(deleteRequest.getFilter().toJson()); + } else if (request instanceof UpdateRequest){ + UpdateRequest updateRequest = (UpdateRequest) request; + operations.add(updateRequest.getUpdate().toJson()); + operations.add(updateRequest.getFilter().toJson()); } - operation = new NoSQLOperation(operations, OP_WRITE, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, OP_WRITE, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_0, e.getMessage()), e, MongoUtil.class.getName()); @@ -158,9 +142,7 @@ public static AbstractOperation getReadAbstractOperation(ReadOperation op AbstractOperation noSQLOperation = null; try { List operations; - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - } + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); if (operation instanceof AggregateOperation) { AggregateOperation aggregateOperation = (AggregateOperation) operation; noSQLOperation = recordMongoOperation(aggregateOperation.getPipeline(), MongoUtil.OP_AGGREGATE, className, methodName); 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 a33cbe032..e870106cc 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 @@ -30,18 +30,11 @@ private void registerExitOperation(boolean isProcessingAllowed, com.newrelic.api } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public T execute(ReadOperation operation, ReadPreference readPreference, ClientSession session) { 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 d0fc36015..af99491f6 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 @@ -20,10 +20,8 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } T returnVal = null; @@ -41,10 +39,8 @@ public T execute(final ReadBinding binding) { public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback callback) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - } if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } try { 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 b9c156603..af807e4da 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 @@ -61,8 +61,7 @@ public class MongoUtil { public static AbstractOperation recordMongoOperation(BsonDocument command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() && command != null) { + if (command != null) { operation = new NoSQLOperation(command.toJson(), typeOfOperation, klassName, methodName); NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); @@ -81,18 +80,16 @@ public static AbstractOperation recordMongoOperation(BsonDocument command, Strin public static AbstractOperation recordMongoOperation(List command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (BsonDocument cmd : command) { - if(cmd != null) { - operations.add(cmd.toJson()); - } + List operations = new ArrayList<>(); + for (BsonDocument cmd : command) { + if(cmd != null) { + operations.add(cmd.toJson()); } - operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); + } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_6, e.getMessage()), e, MongoUtil.class.getName()); @@ -118,43 +115,33 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static AbstractOperation recordWriteRequest(List writeRequest, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (WriteRequest request : writeRequest) { - if(request instanceof InsertRequest){ - InsertRequest insertRequest = (InsertRequest) request; - operations.add(insertRequest.getDocument().toJson()); - } else if (request instanceof DeleteRequest){ - DeleteRequest deleteRequest = (DeleteRequest) request; - operations.add(deleteRequest.getFilter().toJson()); - } else if (request instanceof UpdateRequest){ - UpdateRequest updateRequest = (UpdateRequest) request; - operations.add(updateRequest.getUpdate().toJson()); - operations.add(updateRequest.getFilter().toJson()); - } + List operations = new ArrayList<>(); + for (WriteRequest request : writeRequest) { + if(request instanceof InsertRequest){ + InsertRequest insertRequest = (InsertRequest) request; + operations.add(insertRequest.getDocument().toJson()); + } else if (request instanceof DeleteRequest){ + DeleteRequest deleteRequest = (DeleteRequest) request; + operations.add(deleteRequest.getFilter().toJson()); + } else if (request instanceof UpdateRequest){ + UpdateRequest updateRequest = (UpdateRequest) request; + operations.add(updateRequest.getUpdate().toJson()); + operations.add(updateRequest.getFilter().toJson()); } - operation = new NoSQLOperation(operations, OP_WRITE, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, OP_WRITE, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_6, e.getMessage()), e, MongoUtil.class.getName()); @@ -170,9 +157,7 @@ public static AbstractOperation getReadAbstractOperation(ReadOperation op AbstractOperation noSQLOperation = null; try { List operations; - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - } + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); if (operation instanceof AggregateOperation) { AggregateOperation aggregateOperation = (AggregateOperation) operation; noSQLOperation = recordMongoOperation(aggregateOperation.getPipeline(), MongoUtil.OP_AGGREGATE, className, methodName); 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 31b2762a0..ed9cb92b6 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 @@ -32,18 +32,11 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public T execute(ReadOperation operation, ReadPreference readPreference, @Nullable ClientSession session) { 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 b9d39d315..8744848cc 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 @@ -20,10 +20,9 @@ public class CommandReadOperation_Instrumentation { public T execute(final ReadBinding binding) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } + if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_READ, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } T returnVal = null; 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 1df90c4b5..1889a3bca 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 @@ -20,10 +20,8 @@ public class CommandWriteOperation_Instrumentation { public T execute(final WriteBinding binding) { AbstractOperation noSQLOperation = null; boolean isLockAcquired = MongoUtil.acquireLockIfPossible(VulnerabilityCaseType.NOSQL_DB_COMMAND, this.hashCode()); - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); - } if (isLockAcquired) { + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); noSQLOperation = MongoUtil.recordMongoOperation(command, MongoUtil.OP_WRITE, this.getClass().getName(), MongoUtil.METHOD_EXECUTE); } T returnVal = null; 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 b2c9efea7..6c6b8981d 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 @@ -59,8 +59,7 @@ public class MongoUtil { public static AbstractOperation recordMongoOperation(BsonDocument command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() && command != null) { + if (command != null) { operation = new NoSQLOperation(command.toJson(), typeOfOperation, klassName, methodName); NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); @@ -79,18 +78,15 @@ public static AbstractOperation recordMongoOperation(BsonDocument command, Strin public static AbstractOperation recordMongoOperation(List command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (BsonDocument cmd : command) { - if(cmd != null) { - operations.add(cmd.toJson()); - } + List operations = new ArrayList<>(); + for (BsonDocument cmd : command) { + if(cmd != null) { + operations.add(cmd.toJson()); } - operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_7, e.getMessage()), e, MongoUtil.class.getName()); @@ -116,18 +112,11 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static AbstractOperation recordWriteRequest(List writeRequest, String klassName, String methodName) { @@ -168,9 +157,8 @@ public static AbstractOperation getReadAbstractOperation(ReadOperation op AbstractOperation noSQLOperation = null; try { List operations; - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - } + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + if (operation instanceof AggregateOperation) { AggregateOperation aggregateOperation = (AggregateOperation) operation; noSQLOperation = recordMongoOperation(aggregateOperation.getPipeline(), MongoUtil.OP_AGGREGATE, className, methodName); 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 4e89a0475..6dd0d1814 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 @@ -33,18 +33,11 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public T execute(ReadOperation operation, ReadPreference readPreference, ReadConcern readConcern, @Nullable com.mongodb.client.ClientSession session) { 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 6ac31af4e..b0538ef40 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 @@ -49,8 +49,7 @@ public class MongoUtil { public static AbstractOperation recordMongoOperation(BsonDocument command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() && command != null) { + if (command != null) { operation = new NoSQLOperation(command.toJson(), typeOfOperation, klassName, methodName); NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); @@ -67,18 +66,15 @@ public static AbstractOperation recordMongoOperation(BsonDocument command, Strin public static AbstractOperation recordMongoOperation(List command, String typeOfOperation, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (BsonDocument cmd : command) { - if(cmd != null) { - operations.add(cmd.toJson()); - } + List operations = new ArrayList<>(); + for (BsonDocument cmd : command) { + if(cmd != null) { + operations.add(cmd.toJson()); } - operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, typeOfOperation, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_8, e.getMessage()), e, MongoUtil.class.getName()); @@ -104,43 +100,33 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType nosqlDbCommand, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(nosqlDbCommand, MongoUtil.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static AbstractOperation recordWriteRequest(List writeRequest, String klassName, String methodName) { NoSQLOperation operation = null; try { - if (NewRelicSecurity.isHookProcessingActive() && - !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { - List operations = new ArrayList<>(); - for (WriteRequest request : writeRequest) { - if(request instanceof InsertRequest){ - InsertRequest insertRequest = (InsertRequest) request; - operations.add(insertRequest.getDocument().toJson()); - } else if (request instanceof DeleteRequest){ - DeleteRequest deleteRequest = (DeleteRequest) request; - operations.add(deleteRequest.getFilter().toJson()); - } else if (request instanceof UpdateRequest){ - UpdateRequest updateRequest = (UpdateRequest) request; - operations.add(updateRequest.getUpdate().toJson()); - operations.add(updateRequest.getFilter().toJson()); - } + List operations = new ArrayList<>(); + for (WriteRequest request : writeRequest) { + if(request instanceof InsertRequest){ + InsertRequest insertRequest = (InsertRequest) request; + operations.add(insertRequest.getDocument().toJson()); + } else if (request instanceof DeleteRequest){ + DeleteRequest deleteRequest = (DeleteRequest) request; + operations.add(deleteRequest.getFilter().toJson()); + } else if (request instanceof UpdateRequest){ + UpdateRequest updateRequest = (UpdateRequest) request; + operations.add(updateRequest.getUpdate().toJson()); + operations.add(updateRequest.getFilter().toJson()); } - operation = new NoSQLOperation(operations, OP_WRITE, klassName, methodName); - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - NewRelicSecurity.getAgent().registerOperation(operation); } + operation = new NoSQLOperation(operations, OP_WRITE, klassName, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + NewRelicSecurity.getAgent().registerOperation(operation); } catch (Throwable e) { if (e instanceof NewRelicSecurityException) { NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, MONGODB_3_8, e.getMessage()), e, MongoUtil.class.getName()); @@ -235,9 +221,8 @@ public static AbstractOperation getReadAbstractOperation(ReadOperation op AbstractOperation noSQLOperation = null; try { List operations; - if (NewRelicSecurity.isHookProcessingActive()){ - NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); - } + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(4); + if (operation instanceof AggregateOperation) { AggregateOperation aggregateOperation = (AggregateOperation) operation; noSQLOperation = recordMongoOperation(aggregateOperation.getPipeline(), MongoUtil.OP_AGGREGATE, className, methodName); 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 4683aab38..40dfc179c 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 @@ -86,10 +86,6 @@ public static void processHttpRequestHeader(HttpRequest httpRequest, com.newreli } } - public static String getNrSecCustomAttribName(String customAttribute) { - return customAttribute + Thread.currentThread().getId(); - } - public static String getTraceHeader(Map headers) { String data = EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { @@ -124,9 +120,7 @@ public static void gatherURLMappings(HttpListener messageSource, List messageProcessors) { try { String path = messageSource.getPath(); @@ -123,9 +119,7 @@ public static void gatherURLMappings(HttpListener messageSource, List 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()) - ); + .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){ + if (server != null) { server.shutdown(); } } @@ -62,7 +73,6 @@ public void apiEndpointTest() { 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)); @@ -71,4 +81,40 @@ public void apiEndpointTest() { } } } -} + + @Test + public void routeTest() throws IOException, URISyntaxException { + service("test"); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertEquals("/*", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.NETTY_REACTOR.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void route1Test() throws IOException, URISyntaxException { + service("ws"); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertEquals("/ws", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.NETTY_REACTOR.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void route2Test() throws IOException, URISyntaxException { + service("echo/name"); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertEquals("/echo/{param}", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.NETTY_REACTOR.name(), metaData.getMetaData().getFramework()); + } + + @Trace(dispatcher = true) + private void service(String path) throws IOException, URISyntaxException { + URL u = new URL(String.format("http://localhost:%s/%s", PORT, path)); + HttpURLConnection conn = (HttpURLConnection) u.openConnection(); + + conn.setRequestProperty("content-type", "text/plain; charset=utf-8"); + conn.setRequestMethod("GET"); + conn.connect(); + System.out.println(conn.getResponseCode()); + + } +} \ No newline at end of file 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 index 958e51ceb..7f8ed55b0 100644 --- 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 @@ -2,8 +2,11 @@ import com.newrelic.agent.security.introspec.InstrumentationTestConfig; import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner; +import com.newrelic.api.agent.Trace; 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 io.netty.handler.codec.http.HttpMethod; import org.junit.AfterClass; import org.junit.Assert; @@ -14,6 +17,10 @@ import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -22,11 +29,15 @@ @InstrumentationTestConfig(includePrefixes = "reactor.netty.http.server") public class APIEndpointTest { private static DisposableServer server; + + private static int PORT; @BeforeClass public static void beforeClass() { + PORT = SecurityInstrumentationTestRunner.getIntrospector().getRandomPort(); server = HttpServer .create() - .port(SecurityInstrumentationTestRunner.getIntrospector().getRandomPort()) + .host("localhost") + .port(PORT) .route(r -> r .post("/file/{path}", (req, res) -> res.send()) .get("/echo/{param}", (req, res) -> res.send()) @@ -36,7 +47,7 @@ public static void beforeClass() { (req, res) -> res.send(req.receive().retain())) .ws("/ws", (req, res) -> res.send(req.receive().retain())) .get("/echo/{param}", (req, res) -> res.send()) - ).bindNow(); + ).bind().block(); } @AfterClass @@ -72,4 +83,40 @@ public void apiEndpointTest() { } } } + + @Test + public void routeTest() throws IOException, URISyntaxException { + service("test"); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertEquals("/*", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.NETTY_REACTOR.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void route1Test() throws IOException, URISyntaxException { + service("check"); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertEquals("/check", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.NETTY_REACTOR.name(), metaData.getMetaData().getFramework()); + } + + @Test + public void route2Test() throws IOException, URISyntaxException { + service("echo/name"); + SecurityMetaData metaData = SecurityInstrumentationTestRunner.getIntrospector().getSecurityMetaData(); + Assert.assertEquals("/echo/{param}", metaData.getRequest().getRoute()); + Assert.assertEquals(Framework.NETTY_REACTOR.name(), metaData.getMetaData().getFramework()); + } + + @Trace(dispatcher = true) + private void service(String path) throws IOException, URISyntaxException { + URL u = new URL(String.format("http://localhost:%s/%s", PORT, path)); + HttpURLConnection conn = (HttpURLConnection) u.openConnection(); + + conn.setRequestProperty("content-type", "text/plain; charset=utf-8"); + conn.setRequestMethod("GET"); + conn.connect(); + System.out.println(conn.getResponseCode()); + + } } 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 8234aaa1b..453f5fb12 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 @@ -33,10 +33,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(Request request, String uri, String methodName, String className) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // Add Security IAST header String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); @@ -73,17 +69,10 @@ public static AbstractOperation preprocessSecurityHook(Request request, String u } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } } 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 16bdab028..64635c53c 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 @@ -30,10 +30,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(Request request, String uri, String methodName, String className) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // Add Security IAST header String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); @@ -68,17 +64,10 @@ public static AbstractOperation preprocessSecurityHook(Request request, String u } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } } 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 b6db3e353..0110f2ba2 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 @@ -33,10 +33,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(Request request, String uri, String methodName, String className) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } // Add Security IAST header String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw(); @@ -73,17 +69,10 @@ public static AbstractOperation preprocessSecurityHook(Request request, String u } public static void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } public static boolean acquireLockIfPossible(VulnerabilityCaseType httpRequest, int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(httpRequest, NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } } 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 deb8b30f2..1cf6e8926 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 @@ -13,29 +13,18 @@ public class OkhttpHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "OKHTTP_OPERATION_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "OKHTTP_OPERATION_LOCK-"; public static final String METHOD_EXECUTE = "execute"; public static final String OKHTTP_3_0_0 = "OKHTTP-3.0.0"; - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - return false; - } - public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } @@ -58,7 +47,7 @@ public static AbstractOperation preprocessSecurityHook(String url, String classN public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || OkhttpHelper.skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } 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 954687e05..776224375 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 @@ -13,19 +13,11 @@ public class OkhttpHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "OKHTTP_OPERATION_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "OKHTTP_OPERATION_LOCK-"; public static final String METHOD_EXECUTE = "execute"; public static final String OKHTTP_3_5_0 = "OKHTTP-3.5.0"; - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - return false; - } public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); @@ -33,9 +25,7 @@ public static String getNrSecCustomAttribName() { public static AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } SSRFOperation ssrfOperation = new SSRFOperation(url, className, methodName); @@ -56,7 +46,7 @@ public static AbstractOperation preprocessSecurityHook(String url, String classN public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || OkhttpHelper.skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } 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 2274e5ef7..eccd82f4a 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 @@ -13,20 +13,11 @@ public class OkhttpHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "OKHTTP_OPERATION_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "OKHTTP_OPERATION_LOCK-"; public static final String METHOD_EXECUTE = "execute"; public static final String OKHTTP_4_0_0 = "OKHTTP-4.0.0"; - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - return false; - } - public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } @@ -34,9 +25,7 @@ public static String getNrSecCustomAttribName() { public static AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } SSRFOperation ssrfOperation = new SSRFOperation(url, className, methodName); @@ -57,7 +46,7 @@ public static AbstractOperation preprocessSecurityHook(String url, String classN public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || OkhttpHelper.skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } 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 efc73744b..3e2665289 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 @@ -26,23 +26,22 @@ class HandlerInvokerFactory[T] { class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef: HandlerDef) extends HandlerInvoker[A] { def call(call: => A): Handler = { + if (NewRelicSecurity.isHookProcessingActive){ + return underlyingInvoker.call(call) + } try { - if (NewRelicSecurity.isHookProcessingActive) { val stackTraceElement = new StackTraceElement(handlerDef.controller, handlerDef.method, null , -1) val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData securityMetaData.addCustomAttribute(GenericHelper.USER_CLASS_ENTITY, stackTraceElement) securityMetaData.getMetaData.setUserLevelServiceMethodEncountered(true) - } } 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) } 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 ced6c8e13..8467d4d61 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 @@ -25,23 +25,22 @@ class HandlerInvokerFactory[T] { class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef: HandlerDef) extends HandlerInvoker[A] { def call(call: => A): Handler = { + if (NewRelicSecurity.isHookProcessingActive){ + return underlyingInvoker.call(call) + } try { - if (NewRelicSecurity.isHookProcessingActive) { - val stackTraceElement = new StackTraceElement(handlerDef.controller, handlerDef.method, null , -1) - val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData - securityMetaData.addCustomAttribute(GenericHelper.USER_CLASS_ENTITY, stackTraceElement) - securityMetaData.getMetaData.setUserLevelServiceMethodEncountered(true) - } + val stackTraceElement = new StackTraceElement(handlerDef.controller, handlerDef.method, null , -1) + val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData + securityMetaData.addCustomAttribute(GenericHelper.USER_CLASS_ENTITY, stackTraceElement) + securityMetaData.getMetaData.setUserLevelServiceMethodEncountered(true) } 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) - } + 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) } 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 ca6b4fbf8..741223a5f 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 @@ -26,23 +26,22 @@ class HandlerInvokerFactory[T] { class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef: HandlerDef) extends HandlerInvoker[A] { def call(call: => A): Handler = { + if (NewRelicSecurity.isHookProcessingActive){ + return underlyingInvoker.call(call) + } try { - if (NewRelicSecurity.isHookProcessingActive) { val stackTraceElement = new StackTraceElement(handlerDef.controller, handlerDef.method, null , -1) val securityMetaData = NewRelicSecurity.getAgent.getSecurityMetaData securityMetaData.addCustomAttribute(GenericHelper.USER_CLASS_ENTITY, stackTraceElement) securityMetaData.getMetaData.setUserLevelServiceMethodEncountered(true) - } } 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) } 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 99d5ea4db..828fced63 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 @@ -29,7 +29,7 @@ public void execute(String sql) { Weaver.callOriginal(); } finally { if (isLockAcquired) { - releaseLock(); + R2dbcHelper.releaseLock(); } } registerExitOperation(isLockAcquired, operation); @@ -40,7 +40,7 @@ public void execute(String sql) { private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || R2dbcHelper.skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } @@ -52,9 +52,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(String sql, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()) { + if (sql == null || sql.trim().isEmpty()) { return null; } SQLOperation sqlOperation = new SQLOperation(this.getClass().getName(), methodName); @@ -76,10 +74,4 @@ private AbstractOperation preprocessSecurityHook(String sql, String methodName) return null; } - private void releaseLock() { - try { - R2dbcHelper.releaseLock(); - } catch (Throwable ignored) { - } - } } diff --git a/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/SessionClient_Instrumentation.java b/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/SessionClient_Instrumentation.java index fcd7c7ae9..fde21da04 100644 --- a/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/SessionClient_Instrumentation.java +++ b/instrumentation-security/r2dbc-h2/src/main/java/io/r2dbc/h2/client/SessionClient_Instrumentation.java @@ -9,7 +9,7 @@ @Weave(type = MatchType.ExactClass, originalName = "io.r2dbc.h2.client.SessionClient") public class SessionClient_Instrumentation { public SessionClient_Instrumentation(ConnectionInfo connectionInfo, boolean shutdownDatabaseOnClose) { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(R2DBCVendor.META_CONST_R2DBC_VENDOR, R2DBCVendor.H2); } } diff --git a/instrumentation-security/r2dbc-mariadb/src/main/java/org/mariadb/r2dbc/MariadbConnectionFactory_Instrumentation.java b/instrumentation-security/r2dbc-mariadb/src/main/java/org/mariadb/r2dbc/MariadbConnectionFactory_Instrumentation.java index f215eeefd..45175a35f 100644 --- a/instrumentation-security/r2dbc-mariadb/src/main/java/org/mariadb/r2dbc/MariadbConnectionFactory_Instrumentation.java +++ b/instrumentation-security/r2dbc-mariadb/src/main/java/org/mariadb/r2dbc/MariadbConnectionFactory_Instrumentation.java @@ -11,7 +11,7 @@ @Weave(type = MatchType.Interface, originalName = "org.mariadb.r2dbc.MariadbConnectionFactory") public class MariadbConnectionFactory_Instrumentation { public Mono create() { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(R2DBCVendor.META_CONST_R2DBC_VENDOR, R2DBCVendor.MARIA_DB); } return Weaver.callOriginal(); diff --git a/instrumentation-security/r2dbc-mssql/src/main/java/io/r2dbc/mssql/client/ReactorNettyClient_Instrumentation.java b/instrumentation-security/r2dbc-mssql/src/main/java/io/r2dbc/mssql/client/ReactorNettyClient_Instrumentation.java index 0f4f29a01..f5297b46e 100644 --- a/instrumentation-security/r2dbc-mssql/src/main/java/io/r2dbc/mssql/client/ReactorNettyClient_Instrumentation.java +++ b/instrumentation-security/r2dbc-mssql/src/main/java/io/r2dbc/mssql/client/ReactorNettyClient_Instrumentation.java @@ -12,7 +12,7 @@ @Weave(type = MatchType.ExactClass, originalName = "io.r2dbc.mssql.client.ReactorNettyClient") public class ReactorNettyClient_Instrumentation { public static Mono connect(ClientConfiguration configuration, String applicationName, UUID connectionId){ - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(R2DBCVendor.META_CONST_R2DBC_VENDOR, R2DBCVendor.MSSQL); } return Weaver.callOriginal(); diff --git a/instrumentation-security/r2dbc-mysql/src/main/java/dev/miku/r2dbc/mysql/client/Client_Instrumentation.java b/instrumentation-security/r2dbc-mysql/src/main/java/dev/miku/r2dbc/mysql/client/Client_Instrumentation.java index cb0a8737c..a0f4829ce 100644 --- a/instrumentation-security/r2dbc-mysql/src/main/java/dev/miku/r2dbc/mysql/client/Client_Instrumentation.java +++ b/instrumentation-security/r2dbc-mysql/src/main/java/dev/miku/r2dbc/mysql/client/Client_Instrumentation.java @@ -17,7 +17,7 @@ public class Client_Instrumentation { public static Mono connect( MySqlSslConfiguration ssl, SocketAddress address, boolean tcpKeepAlive, boolean tcpNoDelay, ConnectionContext context, @Nullable Duration connectTimeout) { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(R2DBCVendor.META_CONST_R2DBC_VENDOR, R2DBCVendor.MYSQL); } return Weaver.callOriginal(); diff --git a/instrumentation-security/r2dbc-oracle/src/main/java/oracle/r2dbc/impl/OracleConnectionImpl_Instrumentation.java b/instrumentation-security/r2dbc-oracle/src/main/java/oracle/r2dbc/impl/OracleConnectionImpl_Instrumentation.java index aaab9038b..2399e16ef 100644 --- a/instrumentation-security/r2dbc-oracle/src/main/java/oracle/r2dbc/impl/OracleConnectionImpl_Instrumentation.java +++ b/instrumentation-security/r2dbc-oracle/src/main/java/oracle/r2dbc/impl/OracleConnectionImpl_Instrumentation.java @@ -9,7 +9,7 @@ final class OracleConnectionImpl_Instrumentation { @WeaveAllConstructors OracleConnectionImpl_Instrumentation() { - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(R2DBCVendor.META_CONST_R2DBC_VENDOR, R2DBCVendor.ORACLE); } } diff --git a/instrumentation-security/r2dbc-postgresql/src/main/java/io/r2dbc/postgresql/client/ReactorNettyClient_Instrumentation.java b/instrumentation-security/r2dbc-postgresql/src/main/java/io/r2dbc/postgresql/client/ReactorNettyClient_Instrumentation.java index 0cffbafab..c1bbbc4f5 100644 --- a/instrumentation-security/r2dbc-postgresql/src/main/java/io/r2dbc/postgresql/client/ReactorNettyClient_Instrumentation.java +++ b/instrumentation-security/r2dbc-postgresql/src/main/java/io/r2dbc/postgresql/client/ReactorNettyClient_Instrumentation.java @@ -11,7 +11,7 @@ @Weave(originalName = "io.r2dbc.postgresql.client.ReactorNettyClient") public class ReactorNettyClient_Instrumentation { public static Mono connect(SocketAddress socketAddress, ConnectionSettings settings){ - if (NewRelicSecurity.isHookProcessingActive() && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + if (NewRelicSecurity.getAgent().getSecurityMetaData() != null && !NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(R2DBCVendor.META_CONST_R2DBC_VENDOR, R2DBCVendor.POSTGRES); } return Weaver.callOriginal(); 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 43efac8a5..f440ccad1 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 @@ -22,10 +22,11 @@ public class RestEasyHelper { 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 (!NewRelicSecurity.isHookProcessingActive()) { + return; } + List subResourceList = Collections.emptyList(); + 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())){ diff --git a/instrumentation-security/resteasy-3/src/main/java/com/newrelic/agent/security/instrumentation/resteasy3/RestEasyHelper.java b/instrumentation-security/resteasy-3/src/main/java/com/newrelic/agent/security/instrumentation/resteasy3/RestEasyHelper.java index 721c54b7e..542cabd27 100644 --- a/instrumentation-security/resteasy-3/src/main/java/com/newrelic/agent/security/instrumentation/resteasy3/RestEasyHelper.java +++ b/instrumentation-security/resteasy-3/src/main/java/com/newrelic/agent/security/instrumentation/resteasy3/RestEasyHelper.java @@ -14,9 +14,11 @@ public class RestEasyHelper { private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + private static final String RESTEASY_3 = "RESTEASY-3"; + private static final String ROUTE_DETECTION_COMPLETED = "ROUTE_DETECTION_COMPLETED"; + public static void gatherUrlMappings(String path, ResourceInvoker invoker) { try{ if(invoker instanceof ResourceMethodInvoker) { diff --git a/instrumentation-security/resteasy-4/src/main/java/com/newrelic/agent/security/instrumentation/resteasy4/RestEasyHelper.java b/instrumentation-security/resteasy-4/src/main/java/com/newrelic/agent/security/instrumentation/resteasy4/RestEasyHelper.java index 0f7f11e84..bcc5e42b1 100644 --- a/instrumentation-security/resteasy-4/src/main/java/com/newrelic/agent/security/instrumentation/resteasy4/RestEasyHelper.java +++ b/instrumentation-security/resteasy-4/src/main/java/com/newrelic/agent/security/instrumentation/resteasy4/RestEasyHelper.java @@ -13,8 +13,7 @@ import org.jboss.resteasy.spi.ResourceInvoker; public class RestEasyHelper { - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + private static final String RESTEASY_4 = "RESTEASY-4"; private static final String ROUTE_DETECTION_COMPLETED = "ROUTE_DETECTION_COMPLETED"; public static void gatherUrlMappings(String path, ResourceInvoker invoker) { @@ -30,8 +29,8 @@ public static void gatherUrlMappings(String path, ResourceInvoker invoker) { // case of SubResource else if(invoker instanceof ResourceLocatorInvoker) { String handler = invoker.getMethod().getDeclaringClass().getName(); - String finalPath = StringUtils.appendIfMissing(path, StringUtils.SEPARATOR) + WILDCARD; - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, finalPath, handler)); + String finalPath = StringUtils.appendIfMissing(path, StringUtils.SEPARATOR) + URLMappingsHelper.WILDCARD; + 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_4, ignored.getMessage()), ignored, RestEasyHelper.class.getName()); @@ -40,8 +39,7 @@ else if(invoker instanceof ResourceLocatorInvoker) { public static void getRequestRoute(String pathExpression, String path) { try { - if (NewRelicSecurity.isHookProcessingActive() && - !Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(ROUTE_DETECTION_COMPLETED, Boolean.class))){ + if (NewRelicSecurity.isHookProcessingActive() && !Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(ROUTE_DETECTION_COMPLETED, Boolean.class))){ SecurityMetaData metaData = NewRelicSecurity.getAgent().getSecurityMetaData(); boolean isServletFramework = metaData.getMetaData().getFramework().equals(Framework.SERVLET.name()); diff --git a/instrumentation-security/rhino-jsinjection/src/main/java/com/newrelic/agent/security/instrumentation/rhino/JSEngineUtils.java b/instrumentation-security/rhino-jsinjection/src/main/java/com/newrelic/agent/security/instrumentation/rhino/JSEngineUtils.java index 785c11091..564e453af 100644 --- a/instrumentation-security/rhino-jsinjection/src/main/java/com/newrelic/agent/security/instrumentation/rhino/JSEngineUtils.java +++ b/instrumentation-security/rhino-jsinjection/src/main/java/com/newrelic/agent/security/instrumentation/rhino/JSEngineUtils.java @@ -3,9 +3,6 @@ public class JSEngineUtils { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "JSENGINE_OPERATION_LOCK_RIHNO-"; - - public static final String NR_SEC_CUSTOM_ATTRIB_SCRIPT_NAME = "JSENGINE_RIHNO_SCRIPT-"; - public static final String METHOD_EXEC = "exec"; public static final String RHINO_JS_INJECTION = "RHINO-JS-INJECTION"; } 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 7a5c2ffbc..dc81f0af2 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 @@ -56,10 +56,6 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO private static AbstractOperation preprocessSecurityHook(int hashCode, String methodName, Context_Instrumentation context){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } if(StringUtils.isNotBlank(context.newScript)) { JSInjectionOperation jsInjectionOperation = new JSInjectionOperation(String.valueOf(context.newScript), "org.mozilla.javascript.Script", methodName); NewRelicSecurity.getAgent().registerOperation(jsInjectionOperation); @@ -77,15 +73,10 @@ private static AbstractOperation preprocessSecurityHook(int hashCode, String met } private static void releaseLock(int code) { - try { - GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME+code); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME+code); } private static boolean acquireLockIfPossible(VulnerabilityCaseType javascriptInjection, int code) { - try { - return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME+code); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(javascriptInjection, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME+code); } } 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 fd01d9a7b..744b94f3d 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 @@ -49,9 +49,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -69,15 +67,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } 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 272fe95d2..3839df633 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 @@ -3,16 +3,11 @@ import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.instrumentation.helpers.*; 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.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; -import com.newrelic.api.agent.security.utils.logging.LogLevel; -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration; import javax.servlet.http.HttpServletRequest; -import java.util.Collection; import java.util.Enumeration; import java.util.Map; @@ -91,71 +86,16 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, HttpServletHelper.getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(HttpServletHelper.getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } - public static void gatherURLMappings(ServletContext servletContext) { - try { - Map servletRegistrations = servletContext.getServletRegistrations(); - getJSPMappings(servletContext, SEPARATOR); - - for (ServletRegistration servletRegistration : servletRegistrations.values()) { - for (String s : servletRegistration.getMappings()) { - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, s, servletRegistration.getClassName())); - } - } - } catch (Exception e){ - NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, SERVLET_2_4, e.getMessage()), e, HttpServletHelper.class.getName()); - } - } - - public static void getJSPMappings(ServletContext servletContext, String dir) { - try { - 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); - } - else if(path.endsWith(".jsp") || path.endsWith(".jspx") || path.endsWith(".JSP") || path.endsWith(".JSPX")) { - URLMappingsHelper.addApplicationURLMapping(new ApplicationURLMapping(WILDCARD, path)); - } - } - } - } catch (Exception e){ - NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_WHILE_GETTING_APP_ENDPOINTS, SERVLET_2_4, e.getMessage()), e, HttpServletHelper.class.getName()); - } - } } diff --git a/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/ServletRequestCallback.java b/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/ServletRequestCallback.java index 8304dc8c9..01ba4a0b6 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/ServletRequestCallback.java +++ b/instrumentation-security/servlet-2.4/src/main/java/com/newrelic/agent/security/instrumentation/servlet24/ServletRequestCallback.java @@ -8,8 +8,9 @@ public class ServletRequestCallback { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_IS_OPERATION_LOCK-"; - private static final String REQUEST_STREAM_OR_READER_CALLED = "REQUEST_STREAM_OR_READER_CALLED"; + private static final String REQUEST_READER_HASH = "REQUEST_READER_HASH"; + private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; public static void registerReaderHashIfNeeded(int readerHash){ 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 1b5a12ea2..05148d40e 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 @@ -8,6 +8,7 @@ import com.newrelic.api.agent.security.schema.AgentMetaData; import com.newrelic.api.agent.security.schema.HttpRequest; 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.RXSSOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -25,7 +26,8 @@ public abstract class FilterChain_Instrumentation { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); + if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -33,7 +35,7 @@ public void doFilter(ServletRequest request, ServletResponse response) throws IO Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -43,9 +45,7 @@ public void doFilter(ServletRequest request, ServletResponse response) throws IO private void preprocessSecurityHook(ServletRequest request, ServletResponse response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); @@ -93,11 +93,7 @@ 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)) - ) { + if (Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { return; } if(NewRelic.getAgent().getTransaction().isWebTransaction()) { @@ -124,17 +120,4 @@ private void postProcessSecurityHook(ServletRequest request, ServletResponse res NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_2_4, e.getMessage()), e, FilterChain_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } 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 e4cdc168d..f4e6a1cea 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 @@ -27,7 +27,7 @@ public abstract class Filter_Instrumentation { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -35,7 +35,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -45,17 +45,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha private void preprocessSecurityHook(ServletRequest request, ServletResponse response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -94,9 +85,6 @@ 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; @@ -125,17 +113,4 @@ private void postProcessSecurityHook(ServletRequest request, ServletResponse res NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_2_4, e.getMessage()), e, Filter_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletOutputStream_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletOutputStream_Instrumentation.java index d2a8e6122..1f620f058 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletOutputStream_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletOutputStream_Instrumentation.java @@ -29,9 +29,7 @@ private boolean acquireLockIfPossible(int hashCode) { } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletResponseCallback.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(ServletResponseCallback.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } protected ServletOutputStream_Instrumentation(){} diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletRequest_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletRequest_Instrumentation.java index 0ab2eb230..dd5c5a2e0 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletRequest_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletRequest_Instrumentation.java @@ -31,7 +31,7 @@ public ServletInputStream_Instrumentation getInputStream() throws IOException { try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletRequestCallback.registerInputStreamHashIfNeeded(obj.hashCode()); } } finally { @@ -49,7 +49,7 @@ public BufferedReader getReader() throws IOException { try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_READER_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletRequestCallback.registerReaderHashIfNeeded(obj.hashCode()); // System.out.println("Allowing data gathering for servlet reader : " + obj.hashCode()); } diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletResponse_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletResponse_Instrumentation.java index 488132d21..f0a4c9407 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletResponse_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/ServletResponse_Instrumentation.java @@ -29,7 +29,7 @@ public ServletOutputStream_Instrumentation getOutputStream() throws IOException try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_OS_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletResponseCallback.registerOutputStreamHashIfNeeded(obj.hashCode()); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(getContentType()); } @@ -48,7 +48,7 @@ public PrintWriter getWriter() throws IOException{ try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_WRITER_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletResponseCallback.registerWriterHashIfNeeded(obj.hashCode()); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(getContentType()); } 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 be10a2e4d..448b91a53 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 @@ -31,7 +31,7 @@ public abstract class Servlet_Instrumentation { public void service(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -39,7 +39,7 @@ public void service(ServletRequest_Instrumentation request, ServletResponse_Inst Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -49,9 +49,7 @@ public void service(ServletRequest_Instrumentation request, ServletResponse_Inst private void preprocessSecurityHook(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); @@ -99,9 +97,6 @@ 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; @@ -130,17 +125,4 @@ private void postProcessSecurityHook(ServletRequest_Instrumentation request, Ser NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_2_4, e.getMessage()), e, Servlet_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } 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 204c7c31e..3537ce958 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 @@ -22,10 +22,11 @@ public class HttpServletResponse_Instrumentation { public void addCookie(Cookie cookie){ - boolean isLockAcquired = acquireLockIfPossible(cookie.hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(cookie, getClass().getName(), "addCookie"); } @@ -41,7 +42,7 @@ public void addCookie(Cookie cookie){ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() + if (securityMetaData.getRequest().isEmpty() ) { return null; } @@ -77,30 +78,11 @@ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className return null; } - private static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { - try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { - return; - } - NewRelicSecurity.getAgent().registerExitEvent(operation); - } catch (Throwable e) { - NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_2_4, e.getMessage()), e, HttpServletResponse_Instrumentation.class.getName()); - } - } - private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); } } diff --git a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpSession_Instrumentation.java b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpSession_Instrumentation.java index a5677d439..179adf063 100644 --- a/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpSession_Instrumentation.java +++ b/instrumentation-security/servlet-2.4/src/main/java/javax/servlet/http/HttpSession_Instrumentation.java @@ -18,10 +18,11 @@ public class HttpSession_Instrumentation { public void setAttribute(String name, Object value){ - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(name, value, getClass().getName(), "setAttribute"); } @@ -38,10 +39,11 @@ public void setAttribute(String name, Object value){ } public void putValue(String name, Object value){ - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(name, value, getClass().getName(), "putValue"); } @@ -60,8 +62,7 @@ public void putValue(String name, Object value){ private AbstractOperation preprocessSecurityHook(String name, Object value, String className, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { + if (securityMetaData.getRequest().isEmpty()) { return null; } @@ -84,8 +85,7 @@ private AbstractOperation preprocessSecurityHook(String name, Object value, Stri private static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { return; } NewRelicSecurity.getAgent().registerExitEvent(operation); @@ -95,17 +95,10 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); } } 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 1902c87c8..a5fe5e80d 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 @@ -64,7 +64,7 @@ public void testSessionPutValue() throws IOException, URISyntaxException { SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector(); List operations = introspector.getOperations(); - Assert.assertTrue("No operations detected", operations.size() > 0); + Assert.assertFalse(operations.isEmpty()); Assert.assertTrue("Unexpected operation count detected", operations.size() == 2 || operations.size() == 3); TrustBoundaryOperation targetOperation = null; for (AbstractOperation operation : operations) { @@ -90,7 +90,7 @@ public void testAddCookie() throws IOException, URISyntaxException { SecureCookieOperationSet targetOperation = null; targetOperation = verifySecureCookieOp(operations); - Assert.assertEquals(1, targetOperation.getOperations().size()); + Assert.assertFalse(targetOperation.getOperations().isEmpty()); Iterator secureCookieOps = targetOperation.getOperations().iterator(); Assert.assertTrue(secureCookieOps.hasNext()); @@ -106,7 +106,7 @@ public void testAddCookie1() throws IOException, URISyntaxException { List operations = introspector.getOperations(); SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); - Assert.assertEquals(1, targetOperation.getOperations().size()); + Assert.assertFalse(targetOperation.getOperations().isEmpty()); Iterator secureCookieOps = targetOperation.getOperations().iterator(); Assert.assertTrue(secureCookieOps.hasNext()); @@ -123,7 +123,7 @@ public void testAddSecureCookies() throws IOException, URISyntaxException { List operations = introspector.getOperations(); SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); - Assert.assertEquals(2, targetOperation.getOperations().size()); + Assert.assertFalse(targetOperation.getOperations().isEmpty()); for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { if (secureCookieOp.getName().equals("secure-cookie-1")) { @@ -142,7 +142,7 @@ public void testAddInSecureCookies() throws IOException, URISyntaxException { List operations = introspector.getOperations(); SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); - Assert.assertEquals(2, targetOperation.getOperations().size()); + Assert.assertFalse(targetOperation.getOperations().isEmpty()); for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { if (secureCookieOp.getName().equals("insecure-cookie-1")) { @@ -161,7 +161,7 @@ public void testAddMultiSecureCookies() throws IOException, URISyntaxException { List operations = introspector.getOperations(); SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); - Assert.assertEquals(2, targetOperation.getOperations().size()); + Assert.assertFalse(targetOperation.getOperations().isEmpty()); for (SecureCookieOperationSet.SecureCookieOperation secureCookieOp : targetOperation.getOperations()) { if (secureCookieOp.getName().equals("insecure-cookie")) { @@ -180,7 +180,7 @@ public void testSingleCookie() throws IOException, URISyntaxException { List operations = introspector.getOperations(); SecureCookieOperationSet targetOperation = verifySecureCookieOp(operations); - Assert.assertEquals(1, targetOperation.getOperations().size()); + Assert.assertTrue(!targetOperation.getOperations().isEmpty()); Iterator secureCookieOps = targetOperation.getOperations().iterator(); 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 b87171180..c53c9f1e7 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 @@ -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.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; import jakarta.servlet.ServletContext; @@ -14,7 +15,6 @@ import java.util.Collection; import java.util.Enumeration; -import java.util.Iterator; import java.util.Map; public class HttpServletHelper { @@ -92,31 +92,12 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { diff --git a/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/ServletRequestCallback.java b/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/ServletRequestCallback.java index ff884fffe..5510f6163 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/ServletRequestCallback.java +++ b/instrumentation-security/servlet-5.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet5/ServletRequestCallback.java @@ -8,7 +8,7 @@ public class ServletRequestCallback { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_IS_OPERATION_LOCK-"; - private static final String REQUEST_STREAM_OR_READER_CALLED = "REQUEST_STREAM_OR_READER_CALLED"; + private static final String REQUEST_READER_HASH = "REQUEST_READER_HASH"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; 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 1362bbe9c..d8483d4cf 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 @@ -25,7 +25,7 @@ public abstract class FilterChain_Instrumentation { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -33,7 +33,7 @@ public void doFilter(ServletRequest request, ServletResponse response) throws IO Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -43,17 +43,11 @@ public void doFilter(ServletRequest request, ServletResponse response) throws IO private void preprocessSecurityHook(ServletRequest request, ServletResponse response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -92,11 +86,7 @@ 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)) - ) { + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { return; } if(NewRelic.getAgent().getTransaction().isWebTransaction()) { @@ -123,17 +113,4 @@ private void postProcessSecurityHook(ServletRequest request, ServletResponse res NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_5_0, e.getMessage()), e, FilterChain_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } 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 e82bf14d1..47283c4e6 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 @@ -26,7 +26,7 @@ public abstract class Filter_Instrumentation { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -34,7 +34,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -44,17 +44,11 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha private void preprocessSecurityHook(ServletRequest request, ServletResponse response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -94,11 +88,7 @@ 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)) - ) { + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { return; } if(NewRelic.getAgent().getTransaction().isWebTransaction()) { @@ -126,17 +116,4 @@ private void postProcessSecurityHook(ServletRequest request, ServletResponse res NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_5_0, e.getMessage()), e, Filter_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java index 84d5a5530..95b3eb23c 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java @@ -29,9 +29,7 @@ private boolean acquireLockIfPossible(int hashCode) { } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletResponseCallback.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(ServletResponseCallback.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } protected ServletOutputStream_Instrumentation(){} diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java index be1093f2f..3edbc7215 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java @@ -31,7 +31,7 @@ public ServletInputStream_Instrumentation getInputStream() throws IOException { try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletRequestCallback.registerInputStreamHashIfNeeded(obj.hashCode()); } } finally { @@ -49,9 +49,8 @@ public BufferedReader getReader() throws IOException { try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_READER_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletRequestCallback.registerReaderHashIfNeeded(obj.hashCode()); - // System.out.println("Allowing data gathering for servlet reader : " + obj.hashCode()); } } finally { if(isLockAcquired) { diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java index 04dc2af8f..c9092df70 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java @@ -28,7 +28,7 @@ public ServletOutputStream_Instrumentation getOutputStream() throws IOException try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_OS_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletResponseCallback.registerOutputStreamHashIfNeeded(obj.hashCode()); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(getContentType()); } @@ -47,7 +47,7 @@ public PrintWriter getWriter() throws IOException{ try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_WRITER_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletResponseCallback.registerWriterHashIfNeeded(obj.hashCode()); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(getContentType()); } 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 803e80689..b4a82c2cb 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 @@ -31,7 +31,7 @@ public abstract class Servlet_Instrumentation { public void service(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -39,7 +39,7 @@ public void service(ServletRequest_Instrumentation request, ServletResponse_Inst Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -49,17 +49,11 @@ public void service(ServletRequest_Instrumentation request, ServletResponse_Inst private void preprocessSecurityHook(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -98,10 +92,7 @@ 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)) + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -129,17 +120,4 @@ private void postProcessSecurityHook(ServletRequest_Instrumentation request, Ser NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_5_0, e.getMessage()), e, Servlet_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } 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 186841c43..feede9471 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 @@ -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.SecureCookieOperationSet; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -19,10 +20,11 @@ public class HttpServletResponse_Instrumentation { public void addCookie(Cookie cookie){ - boolean isLockAcquired = acquireLockIfPossible(cookie.hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(cookie.hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(cookie, getClass().getName(), "addCookie"); } @@ -40,12 +42,6 @@ public void addCookie(Cookie cookie){ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - boolean isSecure = cookie.getSecure(); boolean isHttpOnly = cookie.isHttpOnly(); boolean sameSiteStrict = true; @@ -78,8 +74,7 @@ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className private static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() - ) { + if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { return; } NewRelicSecurity.getAgent().registerExitEvent(operation); @@ -89,17 +84,10 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SECURE_COOKIE, ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); } } diff --git a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java index aab23b14b..bc66c0e28 100644 --- a/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java +++ b/instrumentation-security/servlet-5.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java @@ -7,6 +7,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.TrustBoundaryOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,10 +19,11 @@ public class HttpSession_Instrumentation { public void setAttribute(String name, Object value){ - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(name, value, getClass().getName(), "setAttribute"); } @@ -59,12 +61,6 @@ public void putValue(String name, Object value){ private AbstractOperation preprocessSecurityHook(String name, Object value, String className, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - TrustBoundaryOperation operation = new TrustBoundaryOperation(name, value, className, methodName); operation.setLowSeverityHook(true); NewRelicSecurity.getAgent().registerOperation(operation); @@ -102,7 +98,7 @@ private void releaseLock(int hashCode) { private boolean acquireLockIfPossible(int hashCode) { try { - return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.TRUSTBOUNDARY, ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); } catch (Throwable ignored) { } return false; 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 9f198294e..d772551e4 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 @@ -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.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; import jakarta.servlet.ServletContext; @@ -101,22 +102,11 @@ public static boolean isServletLockAcquired() { } public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { diff --git a/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/ServletRequestCallback.java b/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/ServletRequestCallback.java index 3fc317d73..bc9e7e686 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/ServletRequestCallback.java +++ b/instrumentation-security/servlet-6.0/src/main/java/com/newrelic/agent/security/instrumentation/servlet6/ServletRequestCallback.java @@ -8,7 +8,7 @@ public class ServletRequestCallback { public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_IS_OPERATION_LOCK-"; - private static final String REQUEST_STREAM_OR_READER_CALLED = "REQUEST_STREAM_OR_READER_CALLED"; + private static final String REQUEST_READER_HASH = "REQUEST_READER_HASH"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; 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 d602a19d9..466c60a54 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 @@ -25,7 +25,7 @@ public abstract class FilterChain_Instrumentation { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -33,7 +33,7 @@ public void doFilter(ServletRequest request, ServletResponse response) throws IO Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -43,17 +43,11 @@ public void doFilter(ServletRequest request, ServletResponse response) throws IO private void preprocessSecurityHook(ServletRequest request, ServletResponse response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -93,10 +87,7 @@ 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)) + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -124,17 +115,4 @@ private void postProcessSecurityHook(ServletRequest request, ServletResponse res NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_6_0, e.getMessage()), e, FilterChain_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } 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 5edd9af5c..e3d1a8c27 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 @@ -26,7 +26,7 @@ public abstract class Filter_Instrumentation { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -34,7 +34,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -44,17 +44,12 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha private void preprocessSecurityHook(ServletRequest request, ServletResponse response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -94,10 +89,7 @@ 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)) + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -125,17 +117,4 @@ private void postProcessSecurityHook(ServletRequest request, ServletResponse res NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_6_0, e.getMessage()), e, Filter_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java index 8dbc64ca0..c9cedbb76 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletOutputStream_Instrumentation.java @@ -29,9 +29,7 @@ private boolean acquireLockIfPossible(int hashCode) { } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletResponseCallback.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(ServletResponseCallback.NR_SEC_CUSTOM_ATTRIB_NAME, hashCode); } protected ServletOutputStream_Instrumentation(){} diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java index cccc15bfa..79f3c7284 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletRequest_Instrumentation.java @@ -31,7 +31,7 @@ public ServletInputStream_Instrumentation getInputStream() throws IOException { try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_IS_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletRequestCallback.registerInputStreamHashIfNeeded(obj.hashCode()); } } finally { @@ -49,7 +49,7 @@ public BufferedReader getReader() throws IOException { try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_READER_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletRequestCallback.registerReaderHashIfNeeded(obj.hashCode()); // System.out.println("Allowing data gathering for servlet reader : " + obj.hashCode()); } diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java index 69fb2cf47..f1d3adf6d 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/ServletResponse_Instrumentation.java @@ -29,7 +29,7 @@ public ServletOutputStream_Instrumentation getOutputStream() throws IOException try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_OS_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletResponseCallback.registerOutputStreamHashIfNeeded(obj.hashCode()); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(getContentType()); } @@ -48,7 +48,7 @@ public PrintWriter getWriter() throws IOException{ try { isLockAcquired = GenericHelper.acquireLockIfPossible(SERVLET_GET_WRITER_OPERATION_LOCK); obj = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && obj != null) { + if (isLockAcquired && obj != null) { ServletResponseCallback.registerWriterHashIfNeeded(obj.hashCode()); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseContentType(getContentType()); } 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 3eb80fe5a..eac50ff96 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 @@ -31,7 +31,7 @@ public abstract class Servlet_Instrumentation { public void service(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServletHelper.acquireServletLockIfPossible(); if(isServletLockAcquired) { preprocessSecurityHook(request, response); } @@ -39,7 +39,7 @@ public void service(ServletRequest_Instrumentation request, ServletResponse_Inst Weaver.callOriginal(); } finally { if(isServletLockAcquired){ - releaseServletLock(); + HttpServletHelper.releaseServletLock(); } } if(isServletLockAcquired) { @@ -49,17 +49,11 @@ public void service(ServletRequest_Instrumentation request, ServletResponse_Inst private void preprocessSecurityHook(ServletRequest_Instrumentation request, ServletResponse_Instrumentation response) { try { - if (!NewRelicSecurity.isHookProcessingActive() - || !(request instanceof HttpServletRequest) - ) { + if (!(request instanceof HttpServletRequest)) { return; } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); @@ -98,10 +92,7 @@ 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)) + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -129,17 +120,4 @@ private void postProcessSecurityHook(ServletRequest_Instrumentation request, Ser NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServletHelper.SERVLET_6_0, e.getMessage()), e, Servlet_Instrumentation.class.getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServletHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - - private void releaseServletLock() { - try { - HttpServletHelper.releaseServletLock(); - } catch (Throwable e) {} - } } 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 c42a612f4..fe28b05b9 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 @@ -6,8 +6,8 @@ import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; 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.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.SecureCookieOperationSet; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -19,10 +19,11 @@ public class HttpServletResponse_Instrumentation { public void addCookie(Cookie cookie){ - boolean isLockAcquired = acquireLockIfPossible(cookie.hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(cookie.hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(cookie, getClass().getName(), "addCookie"); } @@ -40,12 +41,6 @@ public void addCookie(Cookie cookie){ private AbstractOperation preprocessSecurityHook(Cookie cookie, String className, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - //"https".equals(securityMetaData.getRequest().getProtocol()) || boolean isSecure = cookie.getSecure(); boolean isHttpOnly = cookie.isHttpOnly(); @@ -90,17 +85,10 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SECURE_COOKIE, ServletHelper.NR_SEC_HTTP_SERVLET_RESPONSE_ATTRIB_NAME, hashCode); } } diff --git a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java index 5924c863d..ce61930a9 100644 --- a/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java +++ b/instrumentation-security/servlet-6.0/src/main/java/jakarta/servlet/http/HttpSession_Instrumentation.java @@ -6,7 +6,7 @@ import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; 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.TrustBoundaryOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -18,10 +18,11 @@ public class HttpSession_Instrumentation { public void setAttribute(String name, Object value){ - boolean isLockAcquired = acquireLockIfPossible(hashCode()); + boolean isLockAcquired = false; AbstractOperation operation = null; boolean isOwaspHookEnabled = NewRelicSecurity.getAgent().isLowPriorityInstrumentationEnabled(); if (isOwaspHookEnabled && LowSeverityHelper.isOwaspHookProcessingNeeded()){ + isLockAcquired = acquireLockIfPossible(hashCode()); if (isLockAcquired) operation = preprocessSecurityHook(name, value, getClass().getName(), "setAttribute"); } @@ -39,12 +40,6 @@ public void setAttribute(String name, Object value){ private AbstractOperation preprocessSecurityHook(String name, Object value, String className, String methodName) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - ) { - return null; - } - TrustBoundaryOperation operation = new TrustBoundaryOperation(name, value, className, methodName); operation.setLowSeverityHook(true); NewRelicSecurity.getAgent().registerOperation(operation); @@ -74,17 +69,10 @@ private static void registerExitOperation(boolean isProcessingAllowed, AbstractO } private void releaseLock(int hashCode) { - try { - GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); } private boolean acquireLockIfPossible(int hashCode) { - try { - return GenericHelper.acquireLockIfPossible(ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.TRUSTBOUNDARY, ServletHelper.NR_SEC_HTTP_SESSION_ATTRIB_NAME, hashCode); } } 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 index d29563dc9..e626554f4 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -39,7 +40,7 @@ public HttpSolrServer_Instrumentation(String baseURL, HttpClient client, Respons } public NamedList request(final SolrRequest request, ResponseParser processor) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", request.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(request, "REQUEST"); 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 index 8d7596c8d..6aa23045d 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -39,7 +40,7 @@ public HttpSolrClient_Instrumentation(String baseURL, HttpClient client, Respons } public NamedList request(final SolrRequest request, final ResponseParser processor) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", request.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(request, "REQUEST"); 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 index 875a0d378..a05bdfee9 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -39,7 +40,7 @@ public HttpSolrClient_Instrumentation(String baseURL, HttpClient client, Respons } public NamedList request(final SolrRequest request, final ResponseParser processor, String collection) { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", request.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", request.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(request, "REQUEST"); 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 index 350b41f12..1a4e0c5ae 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -43,7 +44,7 @@ protected HttpSolrClient_Instrumentation(Builder builder) { 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()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", request.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(request, "REQUEST"); 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 index 662098275..297993f3e 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -42,7 +43,7 @@ protected Http2SolrClient_Instrumentation(String serverBaseUrl, Http2SolrClient. public NamedList request(SolrRequest solrRequest, String collection, Http2SolrClient.OnComplete onComplete) throws IOException, SolrServerException { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", solrRequest.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", solrRequest.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(solrRequest, "REQUEST"); 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 index a02577462..32a7387f9 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -43,7 +44,7 @@ protected HttpSolrClient_Instrumentation(Builder builder) { 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()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", request.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(request, "REQUEST"); 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 index 03e576a68..6f0ccd5ac 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -40,7 +41,7 @@ protected Http2SolrClient_Instrumentation(String serverBaseUrl, Http2SolrClient. } public NamedList request(SolrRequest solrRequest, String collection) throws SolrServerException, IOException { - boolean isLockAcquired = GenericHelper.acquireLockIfPossible("HTTP_SOLR_REQUEST-", solrRequest.hashCode()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", solrRequest.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(solrRequest, "REQUEST"); 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 index 7806af9b2..7c3b6efcd 100644 --- 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 @@ -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.schema.exceptions.NewRelicSecurityException; import com.newrelic.api.agent.security.schema.operation.SolrDbOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -43,7 +44,7 @@ protected HttpSolrClient_Instrumentation(Builder builder) { 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()); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.SOLR_DB_REQUEST, "HTTP_SOLR_REQUEST-", request.hashCode()); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSolrRequest(request, "REQUEST"); diff --git a/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/SprayHttpUtils.java b/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/SprayHttpUtils.java index ad55aa456..4061d0379 100644 --- a/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/SprayHttpUtils.java +++ b/instrumentation-security/spray-can-1.3.1/src/main/scala/spray/can/SprayHttpUtils.java @@ -22,7 +22,7 @@ public class SprayHttpUtils { - public static final String QUESTION_MARK = "?"; + private static final String QUESTION_MARK = "?"; private static final String X_FORWARDED_FOR = "x-forwarded-for"; public static final String SPRAY_CAN_1_3_1 = "SPRAY-CAN-1.3.1"; @@ -36,17 +36,9 @@ public static String getNrSecCustomAttribNameForResponse() { public static void preProcessRequestHook(HttpRequest request) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - com.newrelic.api.agent.security.schema.HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } - AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(request.method().name()); securityRequest.setProtocol(request.uri().scheme()); securityRequest.setUrl(processURL(request.uri())); @@ -70,7 +62,7 @@ public static void preProcessRequestHook(HttpRequest request) { } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = StringUtils.EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); diff --git a/instrumentation-security/spray-client/src/main/scala/spray/client/SendReceive_Instrumentation.java b/instrumentation-security/spray-client/src/main/scala/spray/client/SendReceive_Instrumentation.java index 96f6ac28f..56a33b5ce 100644 --- a/instrumentation-security/spray-client/src/main/scala/spray/client/SendReceive_Instrumentation.java +++ b/instrumentation-security/spray-client/src/main/scala/spray/client/SendReceive_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; @@ -73,28 +74,17 @@ private HttpRequest addSecurityHeaders(HttpRequest request, AbstractOperation op } return outboundRequest.getRequest(); } + private void releaseLock() { - try { - GenericHelper.releaseLock(SprayUtils.getNrSecCustomAttribName()); - } catch (Throwable ignored) { - } + GenericHelper.releaseLock(SprayUtils.getNrSecCustomAttribName()); } private boolean acquireLockIfPossible() { - try { - return GenericHelper.acquireLockIfPossible(SprayUtils.getNrSecCustomAttribName()); - } catch (Throwable ignored) { - } - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SprayUtils.getNrSecCustomAttribName()); } private AbstractOperation preprocessSecurityHook(HttpRequest httpRequest) { try { - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()) { - return null; - } - // Generate required URL URI methodURI = null; String uri = null; diff --git a/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/SprayHttpUtils.java b/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/SprayHttpUtils.java index 372f4afd3..b9091b002 100644 --- a/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/SprayHttpUtils.java +++ b/instrumentation-security/spray-http-1.3.1/src/main/scala/spray/SprayHttpUtils.java @@ -22,7 +22,7 @@ public class SprayHttpUtils { - public static final String QUESTION_MARK = "?"; + private static final String QUESTION_MARK = "?"; private static final String X_FORWARDED_FOR = "x-forwarded-for"; public static final String SPRAY_HTTP_1_3_1 = "SPRAY-HTTP-1.3.1"; @@ -36,17 +36,9 @@ public static String getNrSecCustomAttribNameForResponse() { public static void preProcessRequestHook(HttpRequest request) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - com.newrelic.api.agent.security.schema.HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } - AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(request.method().name()); securityRequest.setProtocol(request.uri().scheme()); securityRequest.setUrl(processURL(request.uri())); @@ -70,7 +62,7 @@ public static void preProcessRequestHook(HttpRequest request) { } } - public static String getTraceHeader(Map headers) { + private static String getTraceHeader(Map headers) { String data = StringUtils.EMPTY; if (headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER) || headers.containsKey(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER.toLowerCase())) { data = headers.get(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER); @@ -128,8 +120,7 @@ private static String processURL(Uri uri) { public static void postProcessSecurityHook(HttpResponse httpResponse, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if (!NewRelicSecurity.isHookProcessingActive()) { return; } NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(httpResponse.status().intValue()); diff --git a/instrumentation-security/spring-data-redis/src/main/java/org/springframework/data/redis/core/AbstractOperations_Instrumentation.java b/instrumentation-security/spring-data-redis/src/main/java/org/springframework/data/redis/core/AbstractOperations_Instrumentation.java index 2c7b52813..e0fc69138 100644 --- a/instrumentation-security/spring-data-redis/src/main/java/org/springframework/data/redis/core/AbstractOperations_Instrumentation.java +++ b/instrumentation-security/spring-data-redis/src/main/java/org/springframework/data/redis/core/AbstractOperations_Instrumentation.java @@ -28,7 +28,6 @@ byte[] rawHashValue(HV value) { } byte[] rawKey(Object key) { - System.out.println("raw key : "+key); byte[] returnValue = null; returnValue = Weaver.callOriginal(); @@ -47,7 +46,6 @@ byte[] rawString(String key) { } byte[] rawValue(Object value) { - System.out.println("raw value : "+value); byte[] returnValue = null; returnValue = Weaver.callOriginal(); @@ -57,8 +55,7 @@ byte[] rawValue(Object value) { } private void createRedisArgumentEntry(int hashCode, Object entry) { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ return; } NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(GenericHelper.NR_SEC_CUSTOM_SPRING_REDIS_ATTR + hashCode, entry); diff --git a/instrumentation-security/spring-webclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/spring/client5/SpringWebClientHelper.java b/instrumentation-security/spring-webclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/spring/client5/SpringWebClientHelper.java index 9c8a58a4a..272b8fa28 100644 --- a/instrumentation-security/spring-webclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/spring/client5/SpringWebClientHelper.java +++ b/instrumentation-security/spring-webclient-5.0/src/main/java/com/newrelic/agent/security/instrumentation/spring/client5/SpringWebClientHelper.java @@ -30,9 +30,7 @@ public static String getNrSecCustomAttribName() { public static AbstractOperation preprocessSecurityHook(URI url, HttpMethod method, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - url == null || url.getPath().isEmpty()) { + if (url == null || url.getPath().isEmpty()) { return null; } ArrayList springClientRequestURIs = NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(SPRING_WEB_CLIENT_REQUEST_LIST_CUSTOM_ATTRIB, ArrayList.class); @@ -61,7 +59,7 @@ public static AbstractOperation preprocessSecurityHook(URI url, HttpMethod metho public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } @@ -71,15 +69,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } } - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - return false; - } - public static ClientRequest addSecurityHeaders(ClientRequest request, AbstractOperation operation) { if (operation == null || request == null) { return null; diff --git a/instrumentation-security/spymemcached-2.12.0/src/main/java/com/newrelic/agent/security/instrumentation/spy/memcached/MemcachedHelper.java b/instrumentation-security/spymemcached-2.12.0/src/main/java/com/newrelic/agent/security/instrumentation/spy/memcached/MemcachedHelper.java index cef4b3e35..6c884a5df 100644 --- a/instrumentation-security/spymemcached-2.12.0/src/main/java/com/newrelic/agent/security/instrumentation/spy/memcached/MemcachedHelper.java +++ b/instrumentation-security/spymemcached-2.12.0/src/main/java/com/newrelic/agent/security/instrumentation/spy/memcached/MemcachedHelper.java @@ -20,10 +20,8 @@ public class MemcachedHelper { public static AbstractOperation preprocessSecurityHook(String type, String command, String key, Object val, String klass, String method) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()){ - return null; - } MemcachedOperation operation = new MemcachedOperation(command, Arrays.asList(key, val), type, klass, method); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -40,7 +38,7 @@ public static AbstractOperation preprocessSecurityHook(String type, String comma public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent()) { return; } NewRelicSecurity.getAgent().registerExitEvent(operation); 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 31a1a2bc5..a4a3e29fc 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 @@ -41,15 +41,8 @@ public void doFilter (HttpExchange exchange, Filter.Chain chain) throws IOExcept private void preprocessSecurityHook(HttpExchange exchange) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(exchange.getRequestMethod()); @@ -75,12 +68,10 @@ private void preprocessSecurityHook(HttpExchange exchange) { private void postProcessSecurityHook(HttpExchange exchange) { try { - if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ - return; - } - if (!NewRelicSecurity.isHookProcessingActive()) { + if(!NewRelicSecurity.isHookProcessingActive() && NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ return; } + HttpResponse securityResponse = NewRelicSecurity.getAgent().getSecurityMetaData().getResponse(); securityResponse.setResponseCode(exchange.getResponseCode()); HttpServerHelper.processHttpResponseHeaders(exchange.getResponseHeaders(), securityResponse); diff --git a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpExchange_Instrumentation.java b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpExchange_Instrumentation.java index 1ec038f9b..5a37ee375 100644 --- a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpExchange_Instrumentation.java +++ b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpExchange_Instrumentation.java @@ -17,7 +17,7 @@ public InputStream getRequestBody () { try { isLockAcquired = GenericHelper.acquireLockIfPossible(HttpServerHelper.SUN_NET_READER_OPERATION_LOCK); stream = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && stream != null) { + if (isLockAcquired && stream != null) { HttpServerHelper.registerInputStreamHashIfNeeded(stream.hashCode()); } } finally { @@ -34,7 +34,7 @@ public OutputStream getResponseBody () { try { isLockAcquired = GenericHelper.acquireLockIfPossible(HttpServerHelper.SUN_NET_WRITER_OPERATION_LOCK); stream = Weaver.callOriginal(); - if (isLockAcquired && NewRelicSecurity.isHookProcessingActive() && stream != null) { + if (isLockAcquired && stream != null) { HttpServerHelper.registerOutputStreamHashIfNeeded(stream.hashCode()); } } finally { 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 808f0e9be..f8dbc3530 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 @@ -20,7 +20,7 @@ @Weave(originalName = "com.sun.net.httpserver.HttpHandler", type = MatchType.Interface) public class HttpHandler_Instrumentation { public void handle (HttpExchange exchange) throws IOException { - boolean isServletLockAcquired = acquireServletLockIfPossible(); + boolean isServletLockAcquired = HttpServerHelper.acquireServletLockIfPossible(); if (isServletLockAcquired){ preprocessSecurityHook(exchange); @@ -31,7 +31,7 @@ public void handle (HttpExchange exchange) throws IOException { Weaver.callOriginal(); } finally { if (isServletLockAcquired){ - releaseServletLock(); + HttpServerHelper.releaseServletLock(); } } if (isServletLockAcquired){ @@ -41,15 +41,9 @@ public void handle (HttpExchange exchange) throws IOException { private void preprocessSecurityHook(HttpExchange exchange) { try { - if (!NewRelicSecurity.isHookProcessingActive()) { - return; - } SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - HttpRequest securityRequest = securityMetaData.getRequest(); - if (securityRequest.isRequestParsed()) { - return; - } + AgentMetaData securityAgentMetaData = securityMetaData.getMetaData(); securityRequest.setMethod(exchange.getRequestMethod()); @@ -74,10 +68,7 @@ private void preprocessSecurityHook(HttpExchange exchange) { } private void postProcessSecurityHook(HttpExchange exchange) { try { - if(NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ - return; - } - if (!NewRelicSecurity.isHookProcessingActive()) { + if(!NewRelicSecurity.isHookProcessingActive() && NewRelicSecurity.getAgent().getIastDetectionCategory().getRxssEnabled()){ return; } HttpResponse securityResponse = NewRelicSecurity.getAgent().getSecurityMetaData().getResponse(); @@ -105,16 +96,4 @@ private void postProcessSecurityHook(HttpExchange exchange) { NewRelicSecurity.getAgent().reportIncident(LogLevel.SEVERE, String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, HttpServerHelper.SUN_NET_HTTPSERVER, e.getMessage()), e, this.getClass().getName()); } } - - private boolean acquireServletLockIfPossible() { - try { - return HttpServerHelper.acquireServletLockIfPossible(); - } catch (Throwable ignored) {} - return false; - } - private void releaseServletLock() { - try { - HttpServerHelper.releaseServletLock(); - } catch (Throwable ignored) {} - } } diff --git a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpServerHelper.java b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpServerHelper.java index a3e938aeb..ebbba67ce 100644 --- a/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpServerHelper.java +++ b/instrumentation-security/sun-net-httpserver/src/main/java/com/sun/net/httpserver/HttpServerHelper.java @@ -9,6 +9,7 @@ import com.newrelic.api.agent.security.schema.HttpRequest; import com.newrelic.api.agent.security.schema.HttpResponse; import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import java.util.HashSet; @@ -138,31 +139,14 @@ public static void registerInputStreamHashIfNeeded(int inputStreamHash){ } public static boolean acquireServletLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && !isServletLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, getNrSecCustomAttribName()); } public static void releaseServletLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} + GenericHelper.releaseLock(getNrSecCustomAttribName()); } private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } - public static boolean isServletLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } public static String getProtocol(HttpExchange exchange){ if (exchange instanceof HttpsExchange){ 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 6ff09631d..aad804015 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 @@ -18,7 +18,7 @@ public class LDAPInterface_Instrumentation { public SearchResult search(final SearchRequest searchRequest) throws LDAPSearchException { - boolean isLockAcquired = acquireLockIfPossible(VulnerabilityCaseType.LDAP); + boolean isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.LDAP, LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); AbstractOperation operation = null; if(isLockAcquired) { operation = preprocessSecurityHook(searchRequest.getBaseDN(), searchRequest.getFilter().toString(), LDAPUtils.METHOD_SEARCH); @@ -29,7 +29,7 @@ public SearchResult search(final SearchRequest searchRequest) returnVal = Weaver.callOriginal(); } finally { if(isLockAcquired){ - releaseLock(); + GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } registerExitOperation(isLockAcquired, operation); @@ -38,7 +38,7 @@ public SearchResult search(final SearchRequest searchRequest) private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; @@ -51,9 +51,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String name, String filter, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isAnyBlank(filter)){ + if (StringUtils.isAnyBlank(filter)){ return null; } LDAPOperation ldapOperation = new LDAPOperation(name, filter, this.getClass().getName(), methodName); @@ -70,17 +68,4 @@ private AbstractOperation preprocessSecurityHook (String name, String filter, St return null; } - private void releaseLock() { - try { - GenericHelper.releaseLock(LDAPUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - } - - private boolean acquireLockIfPossible(VulnerabilityCaseType ldap) { - try { - 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/URLConnection_Instrumentation.java b/instrumentation-security/urlconnection/src/main/java/com/newrelic/agent/security/instrumentation/urlconnection/URLConnection_Instrumentation.java index 8d8487be8..3b2e02c50 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 @@ -135,8 +135,7 @@ private static void registerExitOperation(AbstractOperation operation) { private AbstractOperation preprocessSecurityHook(boolean currentCascadedCall, String callArgs, String protocol, String methodName) { try { SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty() - || callArgs == null || callArgs.trim().isEmpty() || currentCascadedCall + if (callArgs == null || callArgs.trim().isEmpty() || currentCascadedCall ) { return null; } 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 4436c41fe..73df8473e 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 @@ -4,7 +4,7 @@ import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; public class VertxClientHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_CORE_OPERATION_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_CORE_OPERATION_LOCK-"; public static final String METHOD_END = "end"; public static final String VERTX_CORE_3_3_0 = "VERTX-CORE-3.3.0"; 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 2e3565615..bbbecf480 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 @@ -61,7 +61,7 @@ public void end() { private AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } SSRFOperation operation = new SSRFOperation(url, className, methodName); 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 689089a31..e9635d094 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 @@ -4,7 +4,7 @@ import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; public class VertxClientHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_CORE_OPERATION_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_CORE_OPERATION_LOCK-"; public static final String METHOD_END = "end"; public static final String VERTX_CORE_3_4_0 = "VERTX-CORE-3.4.0"; 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 bc671b229..466880ce3 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 @@ -62,7 +62,7 @@ public void end() { } private AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } SSRFOperation operation = new SSRFOperation(url, className, methodName); diff --git a/instrumentation-security/vertx-core-3.7.1/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java b/instrumentation-security/vertx-core-3.7.1/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java index e3669b7cc..4500c2582 100644 --- a/instrumentation-security/vertx-core-3.7.1/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java +++ b/instrumentation-security/vertx-core-3.7.1/src/main/java/com/newrelic/agent/security/instrumentation/vertx/web/VertxClientHelper.java @@ -13,7 +13,7 @@ public class VertxClientHelper { - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_WEB_OPERATION_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME = "VERTX_WEB_OPERATION_LOCK-"; public static final String METHOD_END = "end"; @@ -22,14 +22,12 @@ public class VertxClientHelper { public static AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } - SSRFOperation operation = new SSRFOperation(url, - className, methodName); + SSRFOperation operation = new SSRFOperation(url, className, methodName); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(operation); return operation; } catch (Throwable e) { @@ -74,7 +72,7 @@ public static void addSecurityHeaders(MultiMap headers, AbstractOperation operat public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } @@ -84,15 +82,6 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp } } - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - return false; - } - public static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } 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 8c64cf881..596669557 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 @@ -90,7 +90,7 @@ public void end(Handler> handler){ } private AbstractOperation preprocessSecurityHook(String url, String className, String methodName) { try { - if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || url == null || url.trim().isEmpty()) { + if (url == null || url.trim().isEmpty()) { return null; } SSRFOperation operation = new SSRFOperation(url, className, methodName); 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 7250b91c6..df24e5043 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 @@ -44,7 +44,7 @@ public XObject execute(XPathContext var1, Node var2, PrefixResolver var3) throws private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { - if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || + if (operation == null || !isProcessingAllowed || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; @@ -57,9 +57,7 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook (String patternString, String methodName){ try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - StringUtils.isBlank(patternString)){ + if (StringUtils.isBlank(patternString)){ return null; } XPathOperation xPathOperation = new XPathOperation(patternString, this.getClass().getName(), methodName); @@ -78,15 +76,10 @@ private AbstractOperation preprocessSecurityHook (String patternString, String m } private void releaseLock() { - try { - GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} + GenericHelper.releaseLock(XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } private boolean acquireLockIfPossible(VulnerabilityCaseType xpath) { - try { - return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); - } catch (Throwable ignored) {} - return false; + return GenericHelper.acquireLockIfPossible(xpath, XPATHUtils.NR_SEC_CUSTOM_ATTRIB_NAME); } } diff --git a/newrelic-security-agent/build.gradle b/newrelic-security-agent/build.gradle index af21ca6ee..6e5bb864c 100644 --- a/newrelic-security-agent/build.gradle +++ b/newrelic-security-agent/build.gradle @@ -70,7 +70,6 @@ dependencies { shadowIntoJar 'org.apache.commons:commons-text:1.10.0' shadowIntoJar 'commons-net:commons-net:3.9.0' shadowIntoJar 'org.apache.commons:commons-compress:1.26.0' - shadowIntoJar 'com.squareup.okhttp3:okhttp:4.10.0' shadowIntoJar 'org.apache.commons:commons-collections4:4.4' shadowIntoJar 'org.unbescape:unbescape:1.1.6.RELEASE' shadowIntoJar 'commons-codec:commons-codec:1.15' @@ -78,6 +77,7 @@ dependencies { shadowIntoJar 'net.openhft:zero-allocation-hashing:0.16' shadowIntoJar 'com.github.oshi:oshi-core:6.4.1' shadowIntoJar 'com.google.code.gson:gson:2.10.1' + shadowIntoJar 'org.apache.httpcomponents:httpclient:4.5.14' implementation "com.newrelic.agent.java:newrelic-api:${nrAPIVersion}" } @@ -121,7 +121,7 @@ task relocatedShadowJar(type: ShadowJar) { "org.json", "com.fasterxml", "org.java_websocket", "com.google", "org.unbescape", "org.apache.commons", "okio", "okhttp3", "org.slf4j", "net.openhft", "oshi", "com.sun.jna", "kotlin", "com.damnhandy", "org.joda", "io.opentelemetry", "org.everit", "org.jetbrains", "org.intellij", - "org.junit", "org.hamcrest", "org.yaml", "junit" + "org.junit", "org.hamcrest", "org.yaml", "junit", "org.apache.http" ].each { relocate(it, "com.newrelic.agent.security.deps.$it") } 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 b847535f1..8c3258d10 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,13 +1,10 @@ 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.models.collectorconfig.ScanControllers; @@ -21,13 +18,10 @@ import com.newrelic.agent.security.util.IUtilConstants; import com.newrelic.api.agent.NewRelic; 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; @@ -43,8 +37,6 @@ public class AgentConfig { - public static final String CLEANING_STATUS_SNAPSHOTS_FROM_LOG_DIRECTORY_MAX_S_FILE_COUNT_REACHED_REMOVED_S = "Cleaning status-snapshots from snapshots directory, max %s file count reached removed : %s"; - 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"; @@ -226,6 +218,8 @@ private void readScanSchedule() throws RestrictionModeException { } else { throw new RestrictionModeException(INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE); } + } else { + agentMode.getScanSchedule().setNextScanTime(new Date(Instant.now().toEpochMilli())); } agentMode.getScanSchedule().setDataCollectionTime(agentMode.getScanSchedule().getNextScanTime()); if(agentMode.getScanSchedule().isCollectSamples()){ @@ -410,37 +404,6 @@ 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()) { - FileUtils.deleteQuietly(snapshotDir.toFile()); - } - CommonUtils.forceMkdirs(snapshotDir, DIRECTORY_PERMISSION); - } - - private void keepMaxStatusLogFiles(int max) { - Collection statusFiles = FileUtils.listFiles(new File(osVariables.getSnapshotDir()), FileFilterUtils.trueFileFilter(), null); - if (statusFiles.size() >= max) { - File[] sortedStatusFiles = statusFiles.toArray(new File[0]); - Arrays.sort(sortedStatusFiles, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR); - FileUtils.deleteQuietly(sortedStatusFiles[0]); - logger.log(LogLevel.INFO, String.format(CLEANING_STATUS_SNAPSHOTS_FROM_LOG_DIRECTORY_MAX_S_FILE_COUNT_REACHED_REMOVED_S, max, sortedStatusFiles[0].getAbsolutePath()), AgentConfig.class.getName()); - } - } - - public void setupSnapshotDir() { - try { - createSnapshotDirectory(); - keepMaxStatusLogFiles(100); - } catch (Exception e) { - logger.log(LogLevel.WARNING, String.format("Snapshot directory creation failed !!! Please check file permissions. error:%s ", e.getMessage()), e, AgentConfig.class.getName()); - } - } - public String getGroupName() { return groupName; } 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 596ce452f..6ae37d8f6 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 @@ -104,7 +104,7 @@ public void setLinkingMetadata(Map linkingMetadata) { } public boolean isAgentActive() { - return isAgentActive && AgentConfig.getInstance().isNRSecurityEnabled(); + return isAgentActive; } public void setAgentActive(boolean agentActive) { @@ -148,6 +148,11 @@ public void initStatusLogValues() { AgentUtils.getInstance().getStatusLogValues().put("server-name", NOT_AVAILABLE); AgentUtils.getInstance().getStatusLogValues().put("app-location", NOT_AVAILABLE); AgentUtils.getInstance().getStatusLogValues().put("framework", NOT_AVAILABLE); + + Map statusLogValues = AgentUtils.getInstance().getStatusLogValues(); + logger.logInit(LogLevel.INFO, String.format("CSEC HOME: %s, permissions read & write: %s", statusLogValues.get("csec-home"), statusLogValues.get("csec-home-permissions")), AgentInfo.class.getName()); + logger.logInit(LogLevel.INFO, String.format("Agent location: %s", statusLogValues.get("agent-location")), AgentInfo.class.getName()); + logger.logInit(LogLevel.INFO, String.format("Current working directory: %s, permissions read & write: %s", statusLogValues.get("cwd"), statusLogValues.get("cwd-permissions")), AgentInfo.class.getName()); } public boolean agentStatTrigger(boolean clean){ 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 35835467e..1dc26ef1e 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 @@ -7,10 +7,12 @@ import com.newrelic.agent.security.instrumentator.utils.AgentUtils; import com.newrelic.agent.security.instrumentator.utils.CallbackUtils; import com.newrelic.agent.security.instrumentator.utils.INRSettingsKey; +import com.newrelic.agent.security.intcodeagent.apache.httpclient.IastHttpClient; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.utils.IastExclusionUtils; import com.newrelic.agent.security.intcodeagent.utils.RestrictionUtility; import com.newrelic.api.agent.security.Agent; +import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.DeployedApplication; import com.newrelic.agent.security.intcodeagent.models.javaagent.ExitEventBean; @@ -25,7 +27,6 @@ import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.*; import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.Nullable; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; @@ -122,6 +123,10 @@ public Object call() throws Exception { return null; } + if(!securityMetaData.getRequest().getIsGrpc() && !isReplayEndpointConfirmed()) { + IastHttpClient.getInstance().tryToEstablishApplicationEndpoint(securityMetaData.getRequest()); + } + JavaAgentEventBean eventBean = prepareEvent(securityMetaData.getRequest(), securityMetaData.getMetaData(), operation.getCaseType(), securityMetaData.getFuzzRequestIdentifier()); setGenericProperties(operation, eventBean); @@ -262,6 +267,16 @@ public Object call() throws Exception { return null; } + private boolean isReplayEndpointConfirmed() { + Map applicationConnectionConfig = NewRelicSecurity.getAgent().getApplicationConnectionConfig(); + for (Map.Entry connectionConfig : applicationConnectionConfig.entrySet()) { + if (connectionConfig.getValue().isConfirmed()) { + return true; + } + } + return false; + } + private JavaAgentEventBean prepareSolrDbRequestEvent(JavaAgentEventBean eventBean, SolrDbOperation solrDbOperation) { JSONArray params = new JSONArray(); JSONObject request = new JSONObject(); @@ -318,7 +333,6 @@ public boolean isPrimitiveType(Class clazz) { clazz == String.class; } - @Nullable private JavaAgentEventBean processFileOperationEvent(JavaAgentEventBean eventBean, FileOperation fileOperationalBean) { prepareFileEvent(eventBean, fileOperationalBean); String URL = StringUtils.substringBefore(securityMetaData.getRequest().getUrl(), QUESTION_CHAR); 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 4832c2412..31ebfa7a7 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 @@ -182,7 +182,7 @@ public void startDataRequestSchedule(long delay, TimeUnit timeUnit){ } 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()); + logger.log(LogLevel.INFO, String.format("IAST data pull request is scheduled at %s", AgentConfig.getInstance().getAgentMode().getScanSchedule().getDataCollectionTime()), IASTDataTransferRequestProcessor.class.getName()); future = executorService.scheduleWithFixedDelay(this::task, initialDelay, delay, timeUnit); } catch (Throwable ignored){} } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RequestUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RequestUtils.java deleted file mode 100644 index b518f2d63..000000000 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RequestUtils.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.newrelic.agent.security.instrumentator.httpclient; - -import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; -import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; -import com.newrelic.api.agent.security.instrumentation.helpers.ICsecApiConstants; -import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; -import com.newrelic.api.agent.security.utils.logging.LogLevel; -import com.newrelic.agent.security.intcodeagent.models.FuzzRequestBean; -import okhttp3.*; -import okhttp3.Request.Builder; -import okhttp3.internal.http.HttpMethod; -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -public class RequestUtils { - - private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); - public static final String ERROR_IN_FUZZ_REQUEST_GENERATION = "Error in fuzz request generation {}"; - public static final String APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; - - public static Request generateHeadRequest(FuzzRequestBean httpRequest, String endpoint) { - try { - logger.log(LogLevel.FINEST, String.format("Generate HEAD request : %s%s", endpoint, httpRequest.getUrl()), RequestUtils.class.getName()); - StringBuilder url = new StringBuilder(endpoint); - url.append(httpRequest.getUrl()); - Request request = new Request.Builder() - .url(url.toString()) - .head() // Use HEAD to fetch only headers without the body - .headers(Headers.of((Map) httpRequest.getHeaders())) - .addHeader(ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST, "true") - .build(); - return request; - } catch (Exception e) { - logger.log(LogLevel.FINEST, String.format("Error while Generating HEAD request : %s", JsonConverter.toJSON(httpRequest.getUrl())), RequestUtils.class.getName()); - } - return null; - } - - - public static boolean refineEndpoints(FuzzRequestBean httpRequest, String endpoint) { - Request request = generateHeadRequest(httpRequest, endpoint); - return RestClient.getInstance().isListening(request); - } - - public static Request generateK2Request(FuzzRequestBean httpRequest, String endpoint) { - try { - logger.log(LogLevel.FINER, String.format("Firing request : %s", JsonConverter.toJSON(httpRequest)), RequestUtils.class.getName()); - StringBuilder url = new StringBuilder(endpoint); - url.append(httpRequest.getUrl()); - RequestBody requestBody = null; - - if (StringUtils.isNotBlank(httpRequest.getContentType())) { - if (httpRequest.getParameterMap() != null && !httpRequest.getParameterMap().isEmpty() && StringUtils.startsWith(httpRequest.getContentType(), APPLICATION_X_WWW_FORM_URLENCODED)) { - FormBody.Builder builder = new FormBody.Builder(); - for (Entry param : httpRequest.getParameterMap().entrySet()) { - for (int i = 0; i < param.getValue().length; i++) { - builder.add(param.getKey(), param.getValue()[i]); - } - } - requestBody = builder.build(); - } else if( StringUtils.isNotBlank(httpRequest.getBody().toString())) { - requestBody = RequestBody.create(httpRequest.getBody().toString(), - MediaType.parse(httpRequest.getContentType())); - } - } - if (requestBody == null && HttpMethod.permitsRequestBody(httpRequest.getMethod())) { - requestBody = RequestBody.create(httpRequest.getBody().toString(), null); - } - - Builder requestBuilder = new Request.Builder(); - requestBuilder = requestBuilder.url(url.toString()); - - if (HttpMethod.permitsRequestBody(httpRequest.getMethod())) { - requestBuilder = requestBuilder.method(httpRequest.getMethod(), requestBody); - } else { - requestBuilder = requestBuilder.method(httpRequest.getMethod(), null); - } - requestBuilder = requestBuilder.headers(Headers.of((Map) httpRequest.getHeaders())); - - return requestBuilder.build(); - } catch (Exception e){ - logger.log(LogLevel.FINEST, String.format(ERROR_IN_FUZZ_REQUEST_GENERATION, e.toString()), RequestUtils.class.getSimpleName()); - } - return null; - } - public static String extractNRCsecFuzzReqHeader(FuzzRequestBean httpRequest) { - if( httpRequest == null) { - return null; - } - try { - for (Map.Entry header : httpRequest.getHeaders().entrySet()) { - String key = header.getKey().toLowerCase(); - if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID.equals(key)){ - return header.getValue(); - } - } - } catch (Exception e){ - return null; - } - return null; - } - public static String extractNRCsecFuzzReqHeader(Headers headers) { - if (headers == null){ - return null; - } - try{ - for (Map.Entry> header : headers.toMultimap().entrySet()) { - String key = header.getKey().toLowerCase(); - if (ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID.equals(key)){ - return com.newrelic.api.agent.security.schema.StringUtils.join(header.getValue().toArray(new String[0])); - } - } - } catch (Exception e){ - return null; - } - return null; - } - - -} 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 deleted file mode 100644 index 726ea5f3e..000000000 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/RestClient.java +++ /dev/null @@ -1,247 +0,0 @@ -package com.newrelic.agent.security.instrumentator.httpclient; - -import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; -import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; -import com.newrelic.agent.security.intcodeagent.models.FuzzRequestBean; -import com.newrelic.api.agent.security.NewRelicSecurity; -import com.newrelic.api.agent.security.utils.logging.LogLevel; -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.ServletHelper; -import okhttp3.*; -import okhttp3.OkHttpClient.Builder; -import org.jetbrains.annotations.NotNull; - -import javax.net.ssl.*; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.security.cert.CertificateException; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class RestClient { - - - public static final String REQUEST_FIRED_SUCCESS = "Request Fired successfuly : %s "; - public static final String REQUEST_SUCCESS_S_RESPONSE_S_S = "Request Fired successfuly : %s :: response : %s : %s"; - public static final String CALL_FAILED_REQUEST_S_REASON = "Call failed : request %s reason : %s "; - - public static final String CALL_FAILED_REQUEST_S_REASON_S = "Call failed : request %s reason : %s : body : %s"; - public static final String FIRING_REQUEST_METHOD_S = "Firing request :: Method : %s"; - public static final String FIRING_REQUEST_URL_S = "Firing request :: URL : %s"; - public static final String FIRING_REQUEST_HEADERS_S = "Firing request :: Headers : %s"; - - private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); - - public static RestClient instance; - - private boolean isConnected = true; - - private static final Object lock = new Object(); - - private final X509TrustManager x509TrustManager = new X509TrustManager() { - @Override - public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) - throws CertificateException { - } - - @Override - public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) - throws CertificateException { - } - - @Override - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return new java.security.cert.X509Certificate[] {}; - } - }; - - // Create a trust manager that does not validate certificate chains - private final TrustManager[] trustAllCerts = new TrustManager[]{ - x509TrustManager - }; - - private final ThreadLocal clientThreadLocal = new ThreadLocal() { - @Override - protected OkHttpClient initialValue() { - - Builder builder = new OkHttpClient.Builder(); - try { - ConnectionPool connectionPool = new ConnectionPool(1, 5, TimeUnit.MINUTES); - builder = builder.connectionPool(connectionPool); - builder = builder.callTimeout(5, TimeUnit.SECONDS); - - // Install the all-trusting trust manager - final SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); - sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); - // Create an ssl socket factory with our all-trusting manager - final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); - builder = builder.sslSocketFactory(sslSocketFactory, x509TrustManager); - builder.addInterceptor(new Interceptor() { - @NotNull - @Override - public Response intercept(@NotNull Chain chain) throws IOException { - Request request = chain.request(); - Response response = chain.proceed(request); - RestClient.getInstance().setConnected(!(response.code() == 503 || response.code() == 504)); - return response; - } - }); - - builder = builder.hostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - - return builder.build(); - } - }; - - private RestClient() { - } - - public static RestClient getInstance() { - if (instance == null) { - synchronized (lock) { - if (instance == null) { - instance = new RestClient(); - } - } - } - return instance; - } - - public OkHttpClient getClient() { - return clientThreadLocal.get(); - } - - public void fireRequest(FuzzRequestBean httpRequest, List endpoints, int repeatCount, String fuzzRequestId){ - - int responseCode = 999; - if(endpoints.isEmpty()){ - Request request = RequestUtils.generateK2Request(httpRequest, String.format(IAgentConstants.ENDPOINT_LOCALHOST_S, httpRequest.getProtocol(), httpRequest.getServerPort())); - if (request != null) { - try { - responseCode = RestClient.getInstance().fireRequest(request, repeatCount + endpoints.size() -1, fuzzRequestId); - } catch (SSLException e) { - logger.log(LogLevel.FINER, String.format(CALL_FAILED_REQUEST_S_REASON, request, e.getMessage()), e, RestClient.class.getName()); - logger.postLogMessageIfNecessary(LogLevel.WARNING, - String.format(CALL_FAILED_REQUEST_S_REASON, fuzzRequestId, e.getMessage()), - 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(); - fuzzFailEvent.setFuzzHeader(request.header(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)); - EventSendPool.getInstance().sendEvent(fuzzFailEvent); - } - } - return; - } - for (String endpoint : endpoints) { - Request request = RequestUtils.generateK2Request(httpRequest, endpoint); - try { - if (request != null) { - responseCode = RestClient.getInstance().fireRequest(request, repeatCount + endpoints.size() -1, fuzzRequestId); - } - if(responseCode == 301){continue;} - break; - } catch (SSLException e){ - logger.log(LogLevel.FINER, String.format(CALL_FAILED_REQUEST_S_REASON, e.getMessage(), request), e, RestClient.class.getName()); - } - } - - - } - - public boolean isListening(Request request) { - if(request == null){ - return false; - } - - OkHttpClient client = clientThreadLocal.get(); - Call call = client.newCall(request); - try(Response response = call.execute()) { - if(response.isSuccessful()){ - logger.log(LogLevel.FINER, String.format("Server is reachable url: %s", request.url()), RestClient.class.getName()); - return true; - } - if (client.connectionPool() != null) { - client.connectionPool().evictAll(); - } - } catch (IOException e) { - logger.log(LogLevel.FINER, String.format("Server is not reachable url: %s", request.url()), RestClient.class.getName()); - return false; - } - return false; - } - - public int fireRequest(Request request, int repeatCount, String fuzzRequestId) throws SSLException { - OkHttpClient client = clientThreadLocal.get(); - - logger.log(LogLevel.FINER, String.format(FIRING_REQUEST_METHOD_S, request.method()), RestClient.class.getName()); - logger.log(LogLevel.FINER, String.format(FIRING_REQUEST_URL_S, request.url()), RestClient.class.getName()); - logger.log(LogLevel.FINER, String.format(FIRING_REQUEST_HEADERS_S, request.headers()), RestClient.class.getName()); - - Call call = client.newCall(request); - try (Response response = call.execute()){ - logger.log(LogLevel.FINER, String.format(REQUEST_FIRED_SUCCESS, request), RestClient.class.getName()); - if (response.code() >= 500) { - logger.postLogMessageIfNecessary(LogLevel.WARNING, - String.format(RestClient.CALL_FAILED_REQUEST_S_REASON_S, fuzzRequestId, response, response.body().string()), null, - RestRequestProcessor.class.getName()); - } - else if(response.code() >= 400){ - String responseBody = response.body().string(); - RestRequestThreadPool.getInstance().getProcessedIds().putIfAbsent(fuzzRequestId, new HashSet<>()); - logger.postLogMessageIfNecessary(LogLevel.WARNING, - String.format(RestClient.CALL_FAILED_REQUEST_S_REASON_S, fuzzRequestId, response, responseBody), null, - RestRequestProcessor.class.getName()); - } else if(response.isSuccessful()){ - RestRequestThreadPool.getInstance().getProcessedIds().putIfAbsent(fuzzRequestId, new HashSet<>()); - }else { - logger.log(LogLevel.FINER, String.format(REQUEST_SUCCESS_S_RESPONSE_S_S, request, response, response.body().string()), RestClient.class.getName()); - } - response.body().close(); - if (client.connectionPool() != null) { - client.connectionPool().evictAll(); - } - return response.code(); - } catch (SSLException e){ - logger.log(LogLevel.FINE, String.format("Request failed due to SSL Exception %s : reason %s", request, e.getMessage()), e, RestClient.class.getName()); - throw e; - } catch (InterruptedIOException e){ - if(repeatCount >= 0){ - return fireRequest(request, --repeatCount, fuzzRequestId); - } - } catch (IOException e) { - - logger.log(LogLevel.FINER, String.format(CALL_FAILED_REQUEST_S_REASON, e.getMessage(), request), e, RestClient.class.getName()); - logger.postLogMessageIfNecessary(LogLevel.WARNING, - String.format(CALL_FAILED_REQUEST_S_REASON, e.getMessage(), fuzzRequestId), - 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(); - fuzzFailEvent.setFuzzHeader(request.header(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID)); - EventSendPool.getInstance().sendEvent(fuzzFailEvent); - } catch (Exception e){ - logger.log(LogLevel.FINER, String.format(CALL_FAILED_REQUEST_S_REASON, e.getMessage(), request), e, RestClient.class.getName()); - } - - return 999; - } - - public boolean isConnected() { - return isConnected; - } - - public void setConnected(boolean connected) { - isConnected = connected; - } -} 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 94bd988eb..7df98a506 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 @@ -5,6 +5,7 @@ import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.instrumentator.utils.CallbackUtils; +import com.newrelic.agent.security.intcodeagent.apache.httpclient.IastHttpClient; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.utils.IastExclusionUtils; @@ -115,15 +116,7 @@ public Boolean call() throws InterruptedException { MonitorGrpcFuzzFailRequestQueueThread.submitNewTask(); GrpcClientRequestReplayHelper.getInstance().addToRequestQueue(new ControlCommandDto(controlCommand.getId(), httpRequest, payloadList)); } else { - boolean postSSL = false; - List endpoints = prepareAllEndpoints(NewRelicSecurity.getAgent().getApplicationConnectionConfig(), httpRequest); - logger.log(LogLevel.FINER, String.format("Endpoints to fire : %s", endpoints), RestRequestProcessor.class.getSimpleName()); - if (endpoints.isEmpty()){ - endpoints = prepareAllEndpoints(httpRequest); - logger.log(LogLevel.FINER, String.format("Endpoints to fire in empty: %s", endpoints), RestRequestProcessor.class.getSimpleName()); - postSSL = true; - } - RestClient.getInstance().fireRequest(httpRequest, endpoints, repeatCount + endpoints.size() -1, controlCommand.getId()); + IastHttpClient.getInstance().replay(NewRelicSecurity.getAgent().getApplicationConnectionConfig(), httpRequest, controlCommand.getId()); } return true; } catch (JsonProcessingException e){ @@ -146,42 +139,6 @@ public Boolean call() throws InterruptedException { return true; } - private List prepareAllEndpoints(FuzzRequestBean httpRequest) { - List endpoitns = new ArrayList<>(); - endpoitns.add(String.format(ENDPOINT_LOCALHOST_S, httpRequest.getProtocol(), httpRequest.getServerPort())); - endpoitns.add(String.format(ENDPOINT_LOCALHOST_S, toggleProtocol(httpRequest.getProtocol()), httpRequest.getServerPort())); - return endpoitns; - } - - private List prepareAllEndpoints(Map applicationConnectionConfig, FuzzRequestBean httpRequest) { - List endpoints = new ArrayList<>(); - for (Map.Entry connectionConfig : applicationConnectionConfig.entrySet()) { - ServerConnectionConfiguration connectionConfiguration = connectionConfig.getValue(); - if(!connectionConfig.getValue().isConfirmed()){ - if (RequestUtils.refineEndpoints(httpRequest, String.format(ENDPOINT_LOCALHOST_S, connectionConfiguration.getProtocol(), connectionConfiguration.getPort()))) { - updateServerConnectionConfiguration(connectionConfiguration, connectionConfiguration.getProtocol()); - endpoints.add(connectionConfiguration.getEndpoint()); - } else if (RequestUtils.refineEndpoints(httpRequest, String.format(ENDPOINT_LOCALHOST_S, toggleProtocol(connectionConfiguration.getProtocol()), connectionConfiguration.getPort()))) { - updateServerConnectionConfiguration(connectionConfiguration, toggleProtocol(connectionConfiguration.getProtocol())); - endpoints.add(connectionConfiguration.getEndpoint()); - } - } else { - endpoints.add(connectionConfiguration.getEndpoint()); - } - } - return endpoints; - } - - private void updateServerConnectionConfiguration(ServerConnectionConfiguration connectionConfiguration, String protocol) { - connectionConfiguration.setEndpoint(String.format(ENDPOINT_LOCALHOST_S, protocol, connectionConfiguration.getPort())); - connectionConfiguration.setProtocol(protocol); - connectionConfiguration.setConfirmed(true); - } - - private String toggleProtocol(String value) { - return StringUtils.equalsAnyIgnoreCase(value, "https")? "http": "https"; - } - public static void processControlCommand(IntCodeControlCommand command) { RestRequestThreadPool.getInstance().executor .submit(new RestRequestProcessor(command, MAX_REPETITION)); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OSVariables.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OSVariables.java index c2b90e79b..f50784071 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OSVariables.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/os/OSVariables.java @@ -11,8 +11,6 @@ public class OSVariables { private String logDirectory; private String tmpDirectory; - private String snapshotDir; - private String osArch; private File rootDir; @@ -81,14 +79,6 @@ public void setRootDir(File rootDir) { this.rootDir = rootDir; } - public String getSnapshotDir() { - return snapshotDir; - } - - public void setSnapshotDir(String snapshotDir) { - this.snapshotDir = snapshotDir; - } - /*public String getPolicyConfigPath() { return policyConfigPath; } 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 86964a2a6..959b97c16 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 @@ -15,7 +15,6 @@ public class OsVariablesInstance { public static final String LANGUAGE_AGENT = "language-agent"; public static final String TMP = "tmp"; - public static final String SNAPSHOTS = "snapshots"; private static OsVariablesInstance instance; @@ -29,7 +28,6 @@ private OsVariablesInstance() { 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.setPolicyConfigPath(Paths.get(k2root.toString(), CONFIG, LANGUAGE_AGENT).toString()); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java new file mode 100644 index 000000000..5e2d549a4 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java @@ -0,0 +1,427 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.agent.security.AgentInfo; +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.http.ReadResult; +import com.newrelic.api.agent.security.schema.http.RequestLayout; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.StatusLine; +import org.apache.http.Header; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.HttpHostConnectException; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.ssl.TrustStrategy; + +import javax.net.ssl.SSLContext; +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; + +import static com.newrelic.api.agent.security.instrumentation.helpers.ICsecApiConstants.NR_CSEC_JAVA_HEAD_REQUEST; + + +public class ApacheHttpClientWrapper { + public static final String SEPARATOR_QUESTION_MARK = "?"; + public static final String SUFFIX_SLASH = "/"; + private final ApacheProxyManager proxyManager; + private final PoolingHttpClientConnectionManager connectionManager; + private final CloseableHttpClient httpClient; + public static final String APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; + + public static final String GZIP_ENCODING = "gzip"; + + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + /** + * NR data posting client + * */ + public ApacheHttpClientWrapper(ApacheProxyManager proxyManager, SSLContext sslContext, int defaultTimeoutInMillis) { + this.proxyManager = proxyManager; + this.connectionManager = createHttpClientConnectionManager(sslContext); + this.httpClient = createHttpClient(defaultTimeoutInMillis); + } + + /** + * IAST request repeater client + * */ + public ApacheHttpClientWrapper(int requestTimeoutInMillis) { + this.proxyManager = null; + SSLContext sslContext = null; + try { + final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + sslContext = SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy) + .build(); + } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException exception){ + + } + this.connectionManager = createHttpClientConnectionManager(sslContext); + this.httpClient = HttpClientBuilder.create() + .disableDefaultUserAgent() + .disableContentCompression() + .disableCookieManagement() + .disableAuthCaching() + .disableConnectionState() + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .setDefaultRequestConfig(RequestConfig.custom() + // Timeout in millis until a connection is established. + .setConnectTimeout(requestTimeoutInMillis) + // Timeout in millis when requesting a connection from the connection manager. + // This timeout should be longer than the connect timeout to avoid potential ConnectionPoolTimeoutExceptions. + .setConnectionRequestTimeout(requestTimeoutInMillis * 2) + // Timeout in millis for non-blocking socket I/O operations (aka max inactivity between two consecutive data packets). + .setSocketTimeout(requestTimeoutInMillis) + .build()) + .setDefaultSocketConfig(SocketConfig.custom() + // Timeout in millis for non-blocking socket I/O operations. + .setSoTimeout(requestTimeoutInMillis) + .setSoKeepAlive(true) + .build()) + .addInterceptorFirst(new ReplayRequestLoggingInterceptor()) + .addInterceptorLast(new ReplayResponseLoggingInterceptor()) + .setConnectionManager(connectionManager).build(); + } + + private static final String USER_AGENT_HEADER_VALUE = initUserHeaderValue(); + + private static String initUserHeaderValue() { + String arch = "unknown"; + String javaVersion = "unknown"; + try { + arch = System.getProperty("os.arch"); + javaVersion = System.getProperty("java.version"); + } catch (Exception ignored) { + } + return MessageFormat.format("NewRelic-SecurityJavaAgent/{0} ({1}) (java {1} {2})", AgentInfo.getInstance().getBuildInfo().getCollectorVersion(), AgentInfo.getInstance().getBuildInfo().getBuildNumber(), javaVersion, arch); + } + + private static PoolingHttpClientConnectionManager createHttpClientConnectionManager(SSLContext sslContext) { + // Using the pooling manager here for thread safety. + PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager( + RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslContext != null ? + new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE) : SSLConnectionSocketFactory.getSocketFactory()) + .build()); + + // We only allow one connection at a time to the backend. + // Anymore and the agent hangs during the initial request to the connect endpoint. + httpClientConnectionManager.setMaxTotal(1); + httpClientConnectionManager.setDefaultMaxPerRoute(1); + + return httpClientConnectionManager; + } + + private CloseableHttpClient createHttpClient(int requestTimeoutInMillis) { + HttpClientBuilder builder = HttpClientBuilder.create() + .setUserAgent(USER_AGENT_HEADER_VALUE) + .setDefaultHeaders(Arrays.
asList( + new BasicHeader("Connection", "Keep-Alive"), + new BasicHeader("CONTENT-TYPE", "application/json"))) + .setSSLHostnameVerifier(new DefaultHostnameVerifier()) + .setDefaultRequestConfig(RequestConfig.custom() + // Timeout in millis until a connection is established. + .setConnectTimeout(requestTimeoutInMillis) + // Timeout in millis when requesting a connection from the connection manager. + // This timeout should be longer than the connect timeout to avoid potential ConnectionPoolTimeoutExceptions. + .setConnectionRequestTimeout(requestTimeoutInMillis * 2) + // Timeout in millis for non-blocking socket I/O operations (aka max inactivity between two consecutive data packets). + .setSocketTimeout(requestTimeoutInMillis) + .build()) + .setDefaultSocketConfig(SocketConfig.custom() + // Timeout in millis for non-blocking socket I/O operations. + .setSoTimeout(requestTimeoutInMillis) + .setSoKeepAlive(true) + .build()) + .setConnectionManager(connectionManager); + + if (proxyManager.getProxy() != null) { + builder.setProxy(proxyManager.getProxy()); + } + + return builder.build(); + } + + public void shutdown() { + connectionManager.closeIdleConnections(0, TimeUnit.SECONDS); + } + + private HttpContext createContext() { + return proxyManager.updateContext(HttpClientContext.create()); + } + + public ReadResult execute(String api, List pathParams, Map queryParams, + Map headers, byte[] body) throws IOException, URISyntaxException { + RequestLayout requestLayout = null; + try { + requestLayout = getRequestConfigurations(api); + } catch (ApacheHttpExceptionWrapper e) { + logger.log(LogLevel.WARNING, "Error while getting request configurations for API: " + api, ApacheHttpClientWrapper.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, "Error while getting request configurations for API: " + api, e, ApacheHttpClientWrapper.class.getName()); + return null; + } + HttpUriRequest request; + try { + request = buildHttpRequest(requestLayout, pathParams, queryParams, headers, body); + } catch (ApacheHttpExceptionWrapper e) { + logger.log(LogLevel.WARNING, "Error while building request for API: " + api + "with content requestLayout : " + requestLayout +" pathParams: "+ pathParams+" queryParams: "+ queryParams+" headers: "+ headers+" body: "+ Arrays.toString(body), ApacheHttpClientWrapper.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, "Error while building request for API: " + api + "with content requestLayout : " + requestLayout +" pathParams: "+ pathParams+" queryParams: "+ queryParams+" headers: "+ headers+" body: "+ Arrays.toString(body), e, ApacheHttpClientWrapper.class.getName()); + return null; + } + logger.log(LogLevel.FINEST, "Executing request: " + request, ApacheHttpClientWrapper.class.getName()); + + try (CloseableHttpResponse response = httpClient.execute(request, createContext())) { + return mapResponseToResult(response); + } catch (HttpHostConnectException hostConnectException) { + String message = "HttpHostConnectException Error while executing request %s message : %s"; + logger.log(LogLevel.FINE, String.format(message, request, hostConnectException.getMessage()), ApacheHttpClientWrapper.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, String.format(message, request, hostConnectException.getMessage()), hostConnectException, ApacheHttpClientWrapper.class.getName()); + throw hostConnectException; + } catch (ApacheHttpExceptionWrapper e) { + logger.log(LogLevel.WARNING, "Error while reading response for request: " + request, ApacheHttpClientWrapper.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, "Error while reading response for request: " + request, e, ApacheHttpClientWrapper.class.getName()); + return null; + } + } + + public ReadResult execute(HttpRequest httpRequest, String endpoint, String fuzzRequestId) throws IOException, URISyntaxException, ApacheHttpExceptionWrapper { + return execute(httpRequest, endpoint, fuzzRequestId, false); + } + + + public ReadResult execute(HttpRequest httpRequest, String endpoint, String fuzzRequestId, boolean addEventIgnoreHeader) throws IOException, URISyntaxException, ApacheHttpExceptionWrapper { + HttpUriRequest request = buildIastFuzzRequest(httpRequest, endpoint, addEventIgnoreHeader); + logger.log(LogLevel.FINEST, String.format("Executing request %s: %s", fuzzRequestId, request), ApacheHttpClientWrapper.class.getName()); + + try (CloseableHttpResponse response = httpClient.execute(request)) { + return mapResponseToResult(response); + } catch (IOException hostConnectException) { + String message = "IOException Error while executing request %s: %s message : %s"; + logger.log(LogLevel.FINE, String.format(message, fuzzRequestId, request, hostConnectException.getMessage()), ApacheHttpClientWrapper.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, String.format(message, fuzzRequestId, request, hostConnectException.getMessage()), hostConnectException, ApacheHttpClientWrapper.class.getName()); + throw hostConnectException; + } + } + + private HttpUriRequest buildIastFuzzRequest(HttpRequest httpRequest, String endpoint, boolean addEventIgnoreHeader) throws URISyntaxException, UnsupportedEncodingException, ApacheHttpExceptionWrapper { + RequestBuilder requestBuilder = getRequestBuilder(httpRequest.getMethod()); + String requestUrl = httpRequest.getUrl(); + if (StringUtils.isBlank(requestUrl)) { + throw new ApacheHttpExceptionWrapper("Request URL is empty"); + } + requestBuilder.setUri(createURL(endpoint, requestUrl)); + if(StringUtils.startsWith(httpRequest.getContentType(), APPLICATION_X_WWW_FORM_URLENCODED)){ + requestBuilder.setEntity(new UrlEncodedFormEntity(buildFormParameters(httpRequest.getParameterMap()))); + } + setHeader(requestBuilder, httpRequest.getHeaders()); + if(addEventIgnoreHeader) { + requestBuilder.setHeader(NR_CSEC_JAVA_HEAD_REQUEST, "true"); + } + + if (httpRequest.getBody() != null && StringUtils.isNotBlank(httpRequest.getBody())) { + requestBuilder.setEntity(new StringEntity(httpRequest.getBody().toString())); + } + + return requestBuilder.build(); + } + + private URI createURL(String endpoint, String requestUrl) { + if (StringUtils.isBlank(requestUrl)) { + return URI.create(endpoint); + } + if (StringUtils.endsWith(endpoint, SUFFIX_SLASH) && StringUtils.startsWith(requestUrl, SUFFIX_SLASH)) { + return URI.create(endpoint + requestUrl.substring(1)); + } else if (StringUtils.endsWith(endpoint, SUFFIX_SLASH) || StringUtils.startsWith(requestUrl, SUFFIX_SLASH)) { + return URI.create(endpoint + requestUrl); + } else { + return URI.create(endpoint + SUFFIX_SLASH + requestUrl); + } + } + + private List buildFormParameters(Map parameterMap) { + List formParameters = new ArrayList<>(); + for (Map.Entry formData : parameterMap.entrySet()) { + for (String value : formData.getValue()) { + formParameters.add(new BasicNameValuePair(formData.getKey(), value)); + } + } + return formParameters; + } + + private HttpUriRequest buildHttpRequest(RequestLayout requestLayout, List pathParams, Map queryParams, Map headers, byte[] body) + throws URISyntaxException, ApacheHttpExceptionWrapper { + RequestBuilder requestBuilder = getRequestBuilder(requestLayout.getMethod()); + String apiPath = setPathParams(requestLayout.getPath(), pathParams); + URI uri = setQueryParams(requestLayout.getEndpoint(), apiPath, queryParams); + requestBuilder.setUri(uri); + setHeader(requestBuilder, headers); + requestBuilder.setEntity(new ByteArrayEntity(body)); + return requestBuilder.build(); + } + + private static RequestBuilder getRequestBuilder(String method) throws ApacheHttpExceptionWrapper { + RequestBuilder requestBuilder = null; + switch (method){ + case "GET": + requestBuilder = RequestBuilder.get(); + break; + case "POST": + requestBuilder = RequestBuilder.post(); + break; + case "PUT": + requestBuilder = RequestBuilder.put(); + break; + case "DELETE": + requestBuilder = RequestBuilder.delete(); + break; + case "HEAD": + requestBuilder = RequestBuilder.head(); + break; + case "OPTIONS": + requestBuilder = RequestBuilder.options(); + break; + case "PATCH": + requestBuilder = RequestBuilder.patch(); + break; + case "TRACE": + requestBuilder = RequestBuilder.trace(); + break; + default: + throw new ApacheHttpExceptionWrapper("Unsupported HTTP method: " + method); + } + return requestBuilder; + } + + private void setHeader(RequestBuilder requestBuilder, Map headers) throws ApacheHttpExceptionWrapper { + if(headers == null) { + throw new ApacheHttpExceptionWrapper("Headers are null"); + } + for (Map.Entry entry : headers.entrySet()) { + if(StringUtils.isBlank(entry.getKey()) || StringUtils.isBlank(entry.getValue()) || entry.getKey().equalsIgnoreCase("content-length")) { + continue; + } + requestBuilder.setHeader(entry.getKey(), entry.getValue()); + } + } + + + private String setPathParams(String path, List pathParams) { + if(pathParams == null || pathParams.isEmpty()) { + return path; + } + return String.format(path, pathParams.toArray(new String[pathParams.size()])); + } + + private URI setQueryParams(String endpoint, String uri, Map queryParams) throws URISyntaxException { + URIBuilder builder = new URIBuilder(endpoint); + builder.setPath(uri); + if (queryParams == null) { + return builder.build(); + } + + for (Map.Entry param : queryParams.entrySet()) { + builder.addParameter(param.getKey(), param.getValue()); + } + return builder.build(); + } + + private RequestLayout getRequestConfigurations(String api) throws ApacheHttpExceptionWrapper { + if(StringUtils.isBlank(api)){ + throw new ApacheHttpExceptionWrapper("Unsupported API"); + } + return CommunicationApis.get(api); + } + + private ReadResult mapResponseToResult(HttpResponse response) throws IOException, ApacheHttpExceptionWrapper { + StatusLine statusLine = response.getStatusLine(); + if (statusLine == null) { + throw new ApacheHttpExceptionWrapper("HttpClient returned null status line"); + } + + return ReadResult.create( + statusLine.getStatusCode(), + readResponseBody(response)); + } + + /** + * Returns the first Proxy-Authenticate header + * for indicating to the user that their proxy configuration isn't set up correctly. + * + * @param response The HttpResponse from the client + * @return The value of the header. + */ + private String getFirstProxyAuthenticateHeader(HttpResponse response) { + String proxyAuthenticateValue = null; + Header proxyAuthenticateHeader = response.getFirstHeader("Proxy-Authenticate"); + if (proxyAuthenticateHeader != null) { + proxyAuthenticateValue = proxyAuthenticateHeader.getValue(); + } + return proxyAuthenticateValue; + } + + private String readResponseBody(HttpResponse response) throws IOException, ApacheHttpExceptionWrapper { + HttpEntity entity = response.getEntity(); + if (entity == null) { + throw new ApacheHttpExceptionWrapper("The http response entity was null"); + } + try ( + InputStream is = entity.getContent(); + BufferedReader in = getBufferedReader(response, is) + ) { + StringBuilder responseBody = new StringBuilder(); + String line; + while ((line = in.readLine()) != null) { + responseBody.append(line); + } + return responseBody.toString(); + } + } + + private BufferedReader getBufferedReader(HttpResponse response, InputStream is) throws IOException { + Header encodingHeader = response.getFirstHeader("content-encoding"); + if (encodingHeader != null) { + String encoding = encodingHeader.getValue(); + if (GZIP_ENCODING.equals(encoding)) { + is = new GZIPInputStream(is); + } + } + return new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpExceptionWrapper.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpExceptionWrapper.java new file mode 100644 index 000000000..8a267aa33 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpExceptionWrapper.java @@ -0,0 +1,11 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +public class ApacheHttpExceptionWrapper extends Exception { + public ApacheHttpExceptionWrapper(String message) { + super(message); + } + + public ApacheHttpExceptionWrapper(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheProxyManager.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheProxyManager.java new file mode 100644 index 000000000..23b818a18 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheProxyManager.java @@ -0,0 +1,55 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.api.agent.Logger; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.protocol.HttpContext; + +import java.text.MessageFormat; +import java.util.logging.Level; + +public class ApacheProxyManager { + private final HttpHost proxy; + private final Credentials proxyCredentials; + private final Logger logger; + + public ApacheProxyManager(String proxyHost, Integer proxyPort, String proxyScheme, String proxyUser, String proxyPassword, Logger logger) { + this.logger = logger; + + if (proxyHost != null && proxyPort != null) { + logger.log(Level.FINE, MessageFormat.format("Using proxy host {0}:{1}", proxyHost, Integer.toString(proxyPort))); + proxy = new HttpHost(proxyHost, proxyPort, proxyScheme); + proxyCredentials = getProxyCredentials(proxyUser, proxyPassword); + } else { + proxy = null; + proxyCredentials = null; + } + } + + private Credentials getProxyCredentials(final String proxyUser, final String proxyPass) { + if (proxyUser != null && proxyPass != null) { + logger.log(Level.INFO, MessageFormat.format("Setting Proxy Authenticator for user {0}", proxyUser)); + return new UsernamePasswordCredentials(proxyUser, proxyPass); + } + return null; + } + + public HttpHost getProxy() { + return proxy; + } + + public HttpContext updateContext(HttpClientContext httpClientContext) { + if (proxy != null && proxyCredentials != null) { + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), proxyCredentials); + httpClientContext.setCredentialsProvider(credentialsProvider); + } + + return httpClientContext; + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheSSLManager.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheSSLManager.java new file mode 100644 index 000000000..77730ca0b --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheSSLManager.java @@ -0,0 +1,89 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.utils.ResourceUtils; +import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.http.ssl.SSLContextBuilder; + +import javax.net.ssl.SSLContext; +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.LinkedList; + +public class ApacheSSLManager { + + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + public static SSLContext createSSLContext(String caBundlePath) { + SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); + try { + if (StringUtils.isNotBlank(caBundlePath)) { + logger.log(LogLevel.INFO, String.format("Using ca_bundle_path: %s", caBundlePath), ApacheSSLManager.class.getName()); + sslContextBuilder.loadTrustMaterial(getKeyStore(caBundlePath), null); + } else { + logger.log(LogLevel.INFO, "Using nr custom ca from agent resources", ApacheSSLManager.class.getName()); + sslContextBuilder.loadTrustMaterial(getKeyStore(ResourceUtils.getResourceStreamFromAgentJar("nr-custom-ca.pem")), null); + } + return sslContextBuilder.build(); + } catch (Exception e) { + logger.log(LogLevel.WARNING, "Unable to create SSL context", e , ApacheSSLManager.class.getName()); + return null; + } + } + + private static KeyStore getKeyStore(InputStream caBundleResourceStream) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{ + KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); + logger.log(LogLevel.FINER, "SSL Keystore Provider: " + keystore.getProvider().getName(), ApacheSSLManager.class.getName()); + + Collection caCerts = new LinkedList<>(); + + try (InputStream is = new BufferedInputStream(caBundleResourceStream)) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + while (is.available() > 0) { + try { + caCerts.add((X509Certificate) cf.generateCertificate(is)); + } catch (Throwable t) { + logger.log(LogLevel.SEVERE, + "Unable to generate ca_bundle_path certificate. Verify the certificate format. Will not process further certs.", t, ApacheSSLManager.class.getName()); + break; + } + } + } + + logger.log( + !caCerts.isEmpty() ? LogLevel.INFO : LogLevel.SEVERE, + String.format("Read ca_bundle_path and found %s certificates.", + caCerts.size()), ApacheSSLManager.class.getName()); + + // Initialize the keystore + keystore.load(null, null); + + int i = 1; + for (X509Certificate caCert : caCerts) { + if (caCert != null) { + String alias = "ca_bundle_path_" + i; + keystore.setCertificateEntry(alias, caCert); + + logger.log(LogLevel.FINEST, String.format("Installed certificate {0} at alias: {1}", i, alias), ApacheSSLManager.class.getName()); + } + i++; + } + return keystore; + } + + private static KeyStore getKeyStore(String caBundlePath) + throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { + logger.log(LogLevel.FINEST, String.format("Checking ca_bundle_path at: %s", caBundlePath), ApacheSSLManager.class.getName()); + return getKeyStore(new FileInputStream(caBundlePath)); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/CommunicationApis.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/CommunicationApis.java new file mode 100644 index 000000000..b5da47524 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/CommunicationApis.java @@ -0,0 +1,27 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.api.agent.security.schema.http.RequestLayout; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class CommunicationApis { + + public static final String GET_POLICY = "getPolicy"; + + public static final Map REQUEST_CONFIG = Collections.unmodifiableMap( + new HashMap() {{ + put(GET_POLICY, new RequestLayout(GET_POLICY)); + }} + ); + + public static RequestLayout get(String api) { + RequestLayout result = REQUEST_CONFIG.get(api); + if(result == null) { + //TODO throw exception + } + return result; + } + +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java new file mode 100644 index 000000000..97130132d --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java @@ -0,0 +1,118 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool; +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.models.FuzzRequestBean; +import com.newrelic.api.agent.security.instrumentation.helpers.AppServerInfoHelper; +import com.newrelic.api.agent.security.schema.AppServerInfo; +import com.newrelic.api.agent.security.schema.HttpRequest; +import com.newrelic.api.agent.security.schema.ServerConnectionConfiguration; +import com.newrelic.api.agent.security.schema.http.ReadResult; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.*; + +public class IastHttpClient { + + public static final String ENDPOINT_HTTP_LOCALHOST_S = "http://localhost:%s"; + public static final String ENDPOINT_HTTPS_LOCALHOST_S = "https://localhost:%s"; + + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + + private ApacheHttpClientWrapper httpClient; + private boolean connected = false; + + private IastHttpClient() { + httpClient = new ApacheHttpClientWrapper(30000); + } + + public void setConnected(boolean connected) { + this.connected = connected; + } + + public boolean isConnected() { + return this.connected; + } + + private static final class InstanceHolder { + static final IastHttpClient instance = new IastHttpClient(); + } + + public static IastHttpClient getInstance() { + return InstanceHolder.instance; + } + + public void replay(Map applicationConnectionConfig, FuzzRequestBean httpRequest, String fuzzRequestId) { + List endpoints = getAllEndpoints(applicationConnectionConfig); + logger.log(LogLevel.FINEST, String.format("Replaying request %s with endpoints %s", fuzzRequestId, endpoints), IastHttpClient.class.getName()); + for (String endpoint : endpoints) { + try { + ReadResult result = httpClient.execute(httpRequest, endpoint, fuzzRequestId); + RestRequestThreadPool.getInstance().getProcessedIds().putIfAbsent(fuzzRequestId, new HashSet<>()); + if(200 <= result.getStatusCode() && result.getStatusCode() < 300) { + logger.log(LogLevel.FINEST, "Replay Request " + fuzzRequestId + " passed with status code " + result.getStatusCode() + " and response: " + result.getResponseBody(), IastHttpClient.class.getName()); + break; + } else { + logger.log(LogLevel.FINE, "Replay Request " + fuzzRequestId + " failed with status code " + result.getStatusCode() + " and reason: " + result.getResponseBody(), IastHttpClient.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.FINE, "Request " + fuzzRequestId + " failed with status code " + result.getStatusCode() + " and reason: " + result.getResponseBody(), null, IastHttpClient.class.getName()); + } + } catch (Exception e) { + String message = "Error while replaying control command %s with message : %s"; + logger.log(LogLevel.FINE, String.format(message, fuzzRequestId, e.getMessage()), IastHttpClient.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, String.format(message, fuzzRequestId, e.getMessage()), e, ApacheHttpClientWrapper.class.getName()); + } + } + } + + public void tryToEstablishApplicationEndpoint(HttpRequest request) { + + int serverPort = request.getServerPort(); + if(serverPort > 0){ + Map endpoints = prepareEndpoints(serverPort); + for (Map.Entry endpoint : endpoints.entrySet()) { + try { + ReadResult result = httpClient.execute(request, endpoint.getValue(), null, true); + int statusCode = result.getStatusCode(); + if ((statusCode >= 200 && statusCode < 300) || + statusCode == 401 || statusCode == 402 || + statusCode == 406 || statusCode == 409) { + ServerConnectionConfiguration serverConnectionConfiguration = new ServerConnectionConfiguration(serverPort, endpoint.getKey(), endpoint.getValue(), true); + AppServerInfo appServerInfo = AppServerInfoHelper.getAppServerInfo(); + appServerInfo.getConnectionConfiguration().put(serverPort, serverConnectionConfiguration); + logger.log(LogLevel.FINER, String.format("setting up new connection configuration for port %s : %s", serverPort, serverConnectionConfiguration.getEndpoint()), IastHttpClient.class.getName()); + return; + } + } catch (ApacheHttpExceptionWrapper | IOException | URISyntaxException e) { + String message = "Error while executing request for connection endpoint detection %s message : %s"; + logger.log(LogLevel.FINE, String.format(message, request, e.getMessage()), IastHttpClient.class.getName()); + logger.postLogMessageIfNecessary(LogLevel.WARNING, String.format(message, request, e.getMessage()), e, ApacheHttpClientWrapper.class.getName()); + } + } + } + + } + + private static Map prepareEndpoints(int serverPort) { + Map endpoints = new HashMap<>(); + endpoints.put("http", String.format(ENDPOINT_HTTP_LOCALHOST_S, serverPort)); + endpoints.put("https", String.format(ENDPOINT_HTTPS_LOCALHOST_S, serverPort)); + return endpoints; + } + + private List getAllEndpoints(Map applicationConnectionConfig) { + List endpoints = new ArrayList<>(); + for (Map.Entry connectionConfig : applicationConnectionConfig.entrySet()) { + ServerConnectionConfiguration connectionConfiguration = connectionConfig.getValue(); + if(connectionConfig.getValue().isConfirmed()){ + endpoints.add(connectionConfiguration.getEndpoint()); + } + } + return endpoints; + } + +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ReplayRequestLoggingInterceptor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ReplayRequestLoggingInterceptor.java new file mode 100644 index 000000000..18483dc1a --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ReplayRequestLoggingInterceptor.java @@ -0,0 +1,19 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpRequestInterceptor; +import org.apache.http.protocol.HttpContext; + +import java.io.IOException; + +public class ReplayRequestLoggingInterceptor implements HttpRequestInterceptor { + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + @Override + public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException { + logger.log(LogLevel.FINEST, String.format("Replaying request %s", httpRequest.getRequestLine()), IastHttpClient.class.getName()); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ReplayResponseLoggingInterceptor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ReplayResponseLoggingInterceptor.java new file mode 100644 index 000000000..e34eb5be9 --- /dev/null +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ReplayResponseLoggingInterceptor.java @@ -0,0 +1,18 @@ +package com.newrelic.agent.security.intcodeagent.apache.httpclient; + +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.utils.logging.LogLevel; +import org.apache.http.*; +import org.apache.http.protocol.HttpContext; + +import java.io.IOException; + +public class ReplayResponseLoggingInterceptor implements HttpResponseInterceptor { + private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); + + @Override + public void process(HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException { + logger.log(LogLevel.FINEST, String.format("Response of the replay request %s", httpResponse.getStatusLine()), IastHttpClient.class.getName()); + IastHttpClient.getInstance().setConnected(httpResponse.getStatusLine().getStatusCode() != 503 && httpResponse.getStatusLine().getStatusCode() != 504); + } +} diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/executor/CustomScheduledThreadPoolExecutor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/executor/CustomScheduledThreadPoolExecutor.java index 1a1936165..e2240e30d 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/executor/CustomScheduledThreadPoolExecutor.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/executor/CustomScheduledThreadPoolExecutor.java @@ -1,7 +1,5 @@ package com.newrelic.agent.security.intcodeagent.executor; -import org.jetbrains.annotations.NotNull; - import java.util.concurrent.*; public class CustomScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor { @@ -10,15 +8,15 @@ public CustomScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize); } - public CustomScheduledThreadPoolExecutor(int corePoolSize, @NotNull ThreadFactory threadFactory) { + public CustomScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, threadFactory); } - public CustomScheduledThreadPoolExecutor(int corePoolSize, @NotNull RejectedExecutionHandler handler) { + public CustomScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) { super(corePoolSize, handler); } - public CustomScheduledThreadPoolExecutor(int corePoolSize, @NotNull ThreadFactory threadFactory, @NotNull RejectedExecutionHandler handler) { + public CustomScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, threadFactory, handler); } 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 ffaef9139..7c60edb90 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 @@ -155,7 +155,7 @@ public void log(LogLevel logLevel, String event, Throwable throwableEvent, Strin } public void logInit(LogLevel logLevel, String event, String logSourceClassName) { - postLogMessage(logLevel, event, null, logSourceClassName); +// postLogMessage(logLevel, event, null, logSourceClassName); if (!isInitLoggingActive || logLevel.getLevel() == 1 || logLevel.getLevel() > InitLogWriter.defaultLogLevel) { return; } @@ -166,7 +166,7 @@ public void logInit(LogLevel logLevel, String event, String logSourceClassName) } public void logInit(LogLevel logLevel, String event, Throwable throwableEvent, String logSourceClassName) { - postLogMessage(logLevel, event, throwableEvent, logSourceClassName); +// postLogMessage(logLevel, event, throwableEvent, logSourceClassName); if (!isInitLoggingActive || logLevel.getLevel() == 1 || logLevel.getLevel() > InitLogWriter.defaultLogLevel) { return; } 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 308d513da..11e915ef1 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 @@ -2,11 +2,11 @@ import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.dispatcher.DispatcherPool; -import com.newrelic.agent.security.instrumentator.httpclient.RestClient; import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool; 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.apache.httpclient.IastHttpClient; 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; @@ -39,19 +39,7 @@ public class HealthCheckScheduleThread { - public static final String STATUS_TIMESTAMP = "timestamp"; - public static final String CAN_T_WRITE_STATUS_LOG_FILE_S_REASON_S = "Can't write status log file : %s , reason : %s "; - public static final String LAST_5_ERRORS = "last-5-errors"; - public static final String LAST_5_HC = "last-5-hc"; - public static final String K_2_AGENT_STATUS_LOG = "java-security-collector-status-%s.log"; - public static final String LATEST_PROCESS_STATS = "latest-process-stats"; - public static final String LATEST_SERVICE_STATS = "latest-service-stats"; - public static final String VALIDATOR_SERVER_STATUS = "validator-server-status"; - public static final String ENFORCED_POLICY = "enforced-policy"; - public static final String WEBSOCKET = "websocket"; - public static final String SEPARATOR = ": "; - public static final String CAN_T_CREATE_STATUS_LOG_FILE = "Can't create status log file!!!"; private static HealthCheckScheduleThread instance; private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance(); @@ -97,8 +85,6 @@ public void run() { } catch (Throwable e) { logger.log(LogLevel.WARNING, "Error while trying to verify connection: ", e, HealthCheckScheduleThread.class.getName()); - } finally { - writeStatusLogFile(sendJaHealthCheck); } } }; @@ -137,44 +123,6 @@ public boolean cancelTask(boolean forceCancel) { return false; } - private void writeStatusLogFile(JAHealthCheck sendJaHealthCheck) { - JAHealthCheck writerHealthCheck = 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); - if (statusLog.createNewFile()) { - Map substitutes = AgentUtils.getInstance().getStatusLogValues(); - substitutes.put(STATUS_TIMESTAMP, Instant.now().toString()); - JAHealthCheck finalWriterHealthCheck = writerHealthCheck; - substitutes.put(LATEST_PROCESS_STATS, finalWriterHealthCheck.getStats().keySet().stream() - .map(key -> key + SEPARATOR + finalWriterHealthCheck.getStats().get(key)) - .collect(Collectors.joining(StringUtils.LF, StringUtils.EMPTY, StringUtils.EMPTY))); - substitutes.put(LATEST_SERVICE_STATS, finalWriterHealthCheck.getServiceStatus().keySet().stream() - .map(key -> key + SEPARATOR + finalWriterHealthCheck.getServiceStatus().get(key)) - .collect(Collectors.joining(StringUtils.LF, StringUtils.EMPTY, StringUtils.EMPTY))); - substitutes.put(LAST_5_ERRORS, StringUtils.joinWith(StringUtils.LF, AgentUtils.getInstance().getStatusLogMostRecentErrors().toArray())); - substitutes.put(LAST_5_HC, StringUtils.joinWith(StringUtils.LF, AgentUtils.getInstance().getStatusLogMostRecentHCs().toArray())); - substitutes.put(VALIDATOR_SERVER_STATUS, finalWriterHealthCheck.getServiceStatus().getOrDefault(WEBSOCKET, StringUtils.EMPTY).toString()); - substitutes.put(ENFORCED_POLICY, JsonConverter.toJSON(AgentUtils.getInstance().getAgentPolicy())); - StringSubstitutor substitutor = new StringSubstitutor(substitutes); - FileUtils.writeStringToFile(statusLog, substitutor.replace(IAgentConstants.STATUS_FILE_TEMPLATE), StandardCharsets.UTF_8); - isStatusLoggingActive = true; - } else { - isStatusLoggingActive = false; - logger.log(LogLevel.SEVERE, CAN_T_CREATE_STATUS_LOG_FILE, HealthCheckScheduleThread.class.getName()); - } - } catch (IOException e) { - String error = String.format(CAN_T_WRITE_STATUS_LOG_FILE_S_REASON_S, statusLog, e.getMessage()); - isStatusLoggingActive = false; - logger.log(LogLevel.SEVERE, error, e, HealthCheckScheduleThread.class.getName()); - } - } private static Map getServiceStatus() { Map serviceStatus = new HashMap<>(); @@ -194,7 +142,7 @@ private static Map getServiceStatus() { serviceStatus.put("agentActiveStat", AgentInfo.getInstance().isAgentActive() ? "OK" : "Error"); - serviceStatus.put("iastRestClient", RestClient.getInstance().isConnected() ? "OK" : "Error"); + serviceStatus.put("iastRestClient", IastHttpClient.getInstance().isConnected() ? "OK" : "Error"); return serviceStatus; } 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 5a11e43d3..a2beb2de4 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 @@ -571,13 +571,5 @@ public interface IAgentConstants { String NR_APM_TRACE_ID = "trace.id"; String NR_APM_SPAN_ID = "span.id"; - String HTTP_STR = "http"; - String HTTPS_STR = "https"; - String ENDPOINT_LOCALHOST_S = "%s://localhost:%s"; - - String SSL_EXCEPTION_FAILURE_MESSAGE = "SSL Exception raised for url : %s"; - 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/utils/RestrictionUtility.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/RestrictionUtility.java index 44516dc62..94dd4e5a1 100644 --- 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 @@ -13,7 +13,6 @@ 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; @@ -315,14 +314,14 @@ private static Map> parseJsonNode(JsonNode node, String base return requestBodyParameters; } - private static @NotNull String getBase(String baseKey, String key) { + private static String getBase(String baseKey, String key) { if(StringUtils.isBlank(baseKey)){ return key; } return baseKey + "." + key; } - private static @NotNull String getBase(String baseKey, int index) { + private static String getBase(String baseKey, int index) { if(StringUtils.isBlank(baseKey)){ return "[]"; } 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 302fe4f11..165380ec6 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 @@ -154,7 +154,7 @@ private void triggerNrSecurity() { info.initialiseHC(); config.populateAgentPolicy(); config.populateAgentPolicyParameters(); - config.setupSnapshotDir(); +// config.setupSnapshotDir(); info.initStatusLogValues(); setInitialised(true); populateLinkingMetadata(); @@ -890,29 +890,10 @@ public void setApplicationConnectionConfig(int port, String scheme) { AppServerInfo appServerInfo = AppServerInfoHelper.getAppServerInfo(); ServerConnectionConfiguration serverConnectionConfiguration = new ServerConnectionConfiguration(port, scheme); appServerInfo.getConnectionConfiguration().put(port, serverConnectionConfiguration); -// verifyConnectionAndPut(port, scheme, appServerInfo); - } - - private boolean isConnectionSuccessful(int port, String scheme) { - try { - java.net.URL endpoint = new URL(String.format("%s://localhost:%s", scheme, port)); - HttpURLConnection connection = (HttpURLConnection) endpoint.openConnection(); - - // Set the request method to HEAD (you won't download the whole content) - connection.setRequestMethod("HEAD"); - - int responseCode = connection.getResponseCode(); - - if (responseCode == HttpURLConnection.HTTP_OK) { - return true; - } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) { - return true; - } else { - return false; - } - } catch (IOException e) { - return false; + if(logger != null) { + logger.log(LogLevel.FINER, String.format("Unconfirmed connection configuration for port %d and scheme %s added.", port, scheme), this.getClass().getName()); } +// verifyConnectionAndPut(port, scheme, appServerInfo); } public ServerConnectionConfiguration getApplicationConnectionConfig(int port) { diff --git a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java index cfe7f0b2e..9d4414194 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java @@ -7,6 +7,7 @@ package com.newrelic.api.agent.security; +import com.newrelic.agent.security.AgentConfig; import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.security.instrumentation.helpers.ThreadLocalLockHelper; import com.newrelic.api.agent.security.schema.SecurityMetaData; @@ -35,7 +36,7 @@ public static SecurityAgent getAgent(){ * {@code false} otherwise. */ public static boolean isHookProcessingActive(){ - return !ThreadLocalLockHelper.isLockHeldByCurrentThread() && isAgentInitComplete && Agent.getInstance().isSecurityActive() && !isInternalThread() + return AgentConfig.getInstance().isNRSecurityEnabled() && isAgentInitComplete && Agent.getInstance().isSecurityActive() && !ThreadLocalLockHelper.isLockHeldByCurrentThread() && !isInternalThread() && NewRelic.getAgent().getTransaction() != null && NewRelic.getAgent().getTransaction().getSecurityMetaData() instanceof SecurityMetaData; // (Agent.getInstance().getSecurityMetaData() != null); 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 ffc269e9a..5b742396f 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 @@ -146,6 +146,7 @@ public static void checkEntryOfFileIntegrity(List fileNames) { if (fbean.isIntegrityBreached(file)) { //Lock release is required here, as this register operation inside lock is intentional ThreadLocalLockHelper.releaseLock(); + NewRelicSecurity.getAgent().getSecurityMetaData().getMetaData().setFromJumpRequiredInStackTrace(3); NewRelicSecurity.getAgent().registerOperation(fbean); } } @@ -159,33 +160,6 @@ public static void checkEntryOfFileIntegrity(List fileNames) { } } - public static boolean isFileLockAcquired() { - try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); - } catch (Throwable ignored) {} - return false; - } - - public static boolean acquireFileLockIfPossible() { - try { - if (NewRelicSecurity.isHookProcessingActive() && - !isFileLockAcquired()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), true); - return true; - } - } catch (Throwable ignored){} - return false; - } - - public static void releaseFileLock() { - try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(), null); - } - } catch (Throwable ignored){} - } - 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 c68d6a1bb..ca295a500 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 @@ -47,30 +47,37 @@ public static boolean isLockAcquired(String nrSecCustomAttrName) { public static boolean isLockAcquired(String nrSecCustomAttrName, int hashCode) { try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(nrSecCustomAttrName, hashCode), Boolean.class)); + return Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(nrSecCustomAttrName, hashCode), Boolean.class)); } catch (Throwable ignored) {} return false; } - public static boolean acquireLockIfPossible(VulnerabilityCaseType caseType, String nrSecCustomAttrName, int hashCode) { - boolean enabled = false; - if(!NewRelicSecurity.isHookProcessingActive()) { + private static boolean isLockAcquirePossible(VulnerabilityCaseType caseType) { + if (!NewRelicSecurity.isHookProcessingActive()){ + return false; + } + if (caseType == null){ + return true; + } + if (caseType.equals(VulnerabilityCaseType.REFLECTED_XSS) && NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isRequestParsed()){ + return false; + } + if (!caseType.equals(VulnerabilityCaseType.REFLECTED_XSS) && NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()) { return false; } + boolean enabled = false; switch (caseType) { case SYSTEM_COMMAND: enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getCommandInjectionEnabled(); break; case FILE_OPERATION: + case FILE_INTEGRITY: 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; @@ -81,20 +88,15 @@ public static boolean acquireLockIfPossible(VulnerabilityCaseType caseType, Stri enabled = NewRelicSecurity.getAgent().getIastDetectionCategory().getLdapInjectionEnabled(); break; case XPATH: + case XQUERY_INJECTION: 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: @@ -108,13 +110,27 @@ public static boolean acquireLockIfPossible(VulnerabilityCaseType caseType, Stri if(enabled) { return false; } - return acquireLockIfPossible(nrSecCustomAttrName, hashCode); + return true; + } + + public static boolean acquireLockIfPossible(VulnerabilityCaseType caseType, String nrSecCustomAttrName, int hashCode) { + try { + if(!isLockAcquirePossible(caseType)) { + return false; + } + if (!isLockAcquired(nrSecCustomAttrName, hashCode)) { + NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(nrSecCustomAttrName, hashCode), true); + return true; + } + } catch (Exception e) { + return false; + } + return false; } public static boolean acquireLockIfPossible(String nrSecCustomAttrName, int hashCode) { try { - if (NewRelicSecurity.isHookProcessingActive() && - !isLockAcquired(nrSecCustomAttrName, hashCode)) { + if (NewRelicSecurity.isHookProcessingActive() && !isLockAcquired(nrSecCustomAttrName, hashCode)) { NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(nrSecCustomAttrName, hashCode), true); return true; } @@ -124,8 +140,8 @@ public static boolean acquireLockIfPossible(String nrSecCustomAttrName, int hash public static void releaseLock(String nrSecCustomAttrName, int hashCode) { try { - if(NewRelicSecurity.isHookProcessingActive()) { - NewRelicSecurity.getAgent().getSecurityMetaData().addCustomAttribute(getNrSecCustomAttribName(nrSecCustomAttrName, hashCode), null); + if(NewRelicSecurity.getAgent().getSecurityMetaData() != null) { + NewRelicSecurity.getAgent().getSecurityMetaData().removeCustomAttribute(getNrSecCustomAttribName(nrSecCustomAttrName, hashCode)); } } catch (Throwable ignored){} } 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 265ce1e79..242a8dbce 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 @@ -67,8 +67,7 @@ public static boolean skipExistsEvent() { public static boolean isLockAcquired() { try { - return NewRelicSecurity.isHookProcessingActive() && - Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); + return Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); } catch (Throwable ignored) {} return false; } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/LowSeverityHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/LowSeverityHelper.java index fc2957184..848814281 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/LowSeverityHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/LowSeverityHelper.java @@ -39,7 +39,7 @@ public static boolean addRrequestUriToEventFilter(HttpRequest request) { public static boolean isOwaspHookProcessingNeeded(){ SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if(NewRelicSecurity.isHookProcessingActive() && securityMetaData != null && !securityMetaData.getRequest().isEmpty()) { + if(securityMetaData != null && !securityMetaData.getRequest().isEmpty()) { String requestURL = securityMetaData.getRequest().getUrl(); return (securityMetaData.getFuzzRequestIdentifier() != null && securityMetaData.getFuzzRequestIdentifier().getK2Request()) || (StringUtils.isNotBlank(requestURL) && !LowSeverityHelper.checkIfLowSeverityEventAlreadyEncountered(requestURL.hashCode(), securityMetaData.getRequest().getMethod())); 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 680dec0ec..2a21e91a8 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 @@ -18,7 +18,7 @@ public class R2dbcHelper { public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) { try { if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || com.newrelic.api.agent.security.instrumentation.helpers.R2dbcHelper.skipExistsEvent() + NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent() ) { return; } @@ -30,9 +30,7 @@ public static void registerExitOperation(boolean isProcessingAllowed, AbstractOp public static AbstractOperation preprocessSecurityHook(String sql, String methodName, String className, Map params, boolean isPrepared) { try { - if (!NewRelicSecurity.isHookProcessingActive() || - NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || - sql == null || sql.trim().isEmpty()) { + if (sql == null || sql.trim().isEmpty()) { return null; } SQLOperation sqlOperation = new SQLOperation(className, methodName); @@ -56,23 +54,6 @@ public static AbstractOperation preprocessSecurityHook(String sql, String method return null; } - public static boolean skipExistsEvent() { - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) { - return true; - } - - 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(VulnerabilityCaseType sqlDbCommand) { return GenericHelper.acquireLockIfPossible(sqlDbCommand, getNrSecCustomAttribName()); } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/ServerConnectionConfiguration.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/ServerConnectionConfiguration.java index 0db051003..d0abfa269 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/ServerConnectionConfiguration.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/ServerConnectionConfiguration.java @@ -17,9 +17,17 @@ public ServerConnectionConfiguration() { public ServerConnectionConfiguration(int port, String scheme) { this.port = port; this.protocol = scheme; + this.endpoint = String.format("%s://localhost:%s", scheme, port); this.confirmed = false; } + public ServerConnectionConfiguration(int port, String scheme, String endpoint, boolean confirmed) { + this.port = port; + this.protocol = scheme; + this.endpoint = endpoint; + this.confirmed = confirmed; + } + public Integer getPort() { return port; } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/http/ReadResult.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/http/ReadResult.java new file mode 100644 index 000000000..92f6efd4f --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/http/ReadResult.java @@ -0,0 +1,24 @@ +package com.newrelic.api.agent.security.schema.http; + +public class ReadResult { + private final int statusCode; + private final String responseBody; + + ReadResult(int statusCode, String responseBody) { + this.statusCode = statusCode; + this.responseBody = responseBody; + } + + public int getStatusCode() { + return statusCode; + } + + public String getResponseBody() { + return responseBody; + } + + public static ReadResult create(int statusCode, String responseBody) { + return new ReadResult(statusCode, responseBody); + } + +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/http/RequestLayout.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/http/RequestLayout.java new file mode 100644 index 000000000..4d04bad01 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/http/RequestLayout.java @@ -0,0 +1,65 @@ +package com.newrelic.api.agent.security.schema.http; + +public class RequestLayout { + + private String api; + + private String method; + + private String endpoint; + private String path; + private String contentType; + private String contentEncoding; + + public RequestLayout(String api) { + this.api = api; + } + + public String getApi() { + return api; + } + + public void setApi(String api) { + this.api = api; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getContentEncoding() { + return contentEncoding; + } + + public void setContentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/settings.gradle b/settings.gradle index 64dd79da8..afec08f66 100644 --- a/settings.gradle +++ b/settings.gradle @@ -217,4 +217,21 @@ 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 +include 'instrumentation:websphere-liberty-profile-environment-8.5.5.5' +include 'instrumentation:http4s-blaze-server-2.12_0.21' +include 'instrumentation:http4s-blaze-server-2.12_0.22' +include 'instrumentation:http4s-blaze-server-2.12_0.23' +include 'instrumentation:http4s-blaze-server-2.13_0.21' +include 'instrumentation:http4s-blaze-server-2.13_0.22' +include 'instrumentation:http4s-blaze-server-2.13_0.23' +include 'instrumentation:http4s-blaze-client-2.12_0.21' +include 'instrumentation:http4s-blaze-client-2.12_0.22' +include 'instrumentation:http4s-blaze-client-2.12_0.23' +include 'instrumentation:http4s-blaze-client-2.13_0.21' +include 'instrumentation:http4s-blaze-client-2.13_0.22' +include 'instrumentation:http4s-blaze-client-2.13_0.23' +include 'instrumentation:http4s-ember-server-2.12_0.23' +include 'instrumentation:http4s-ember-server-2.13_0.23' +include 'instrumentation:http4s-ember-client-2.13_0.23' +include 'instrumentation:http4s-ember-client-2.12_0.23' +include 'instrumentation:apache-pekko-http-core-2.13_1' \ No newline at end of file