diff --git a/Changelog.md b/Changelog.md index 3ec4c627e..926f06d2e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,95 @@ Noteworthy changes to the agent are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.5.0] - 2024-9-25 +### New features +- Json Version bump to 1.2.9. +- [PR-327](https://github.com/newrelic/csec-java-agent/pull/327) Application endpoint detection for gRPC Server [NR-303616](https://new-relic.atlassian.net/browse/NR-303616) +- [PR-326](https://github.com/newrelic/csec-java-agent/pull/326) Add IAST Scan start time and Traffic Start Time in Health Check [NR-308822](https://new-relic.atlassian.net/browse/NR-308822) +- [PR-320](https://github.com/newrelic/csec-java-agent/pull/320) Add feature to allow IAST Scan Scheduling. [NR-301534](https://new-relic.atlassian.net/browse/NR-301534) + Configuration via yaml: + ```yaml + security: + scan_schedule: + # The delay field specifies the delay in minutes before the IAST scan starts. This allows to schedule the scan to start at a later time. + delay: 0 #In minutes, default is 0 min + + # The duration field specifies the duration of the IAST scan in minutes. This determines how long the scan will run. + duration: 0 #In minutes, default is forever + + # The schedule field specifies a cron expression that defines when the IAST scan should start. + #schedule: "" #By default, schedule is inactive + + # Allow continuously sample collection of IAST events + always_sample_traces: false # Default is false + ``` +- [PR-320](https://github.com/newrelic/csec-java-agent/pull/320) Add feature to ignore IAST Scan of certain APIs, categories, or parameters. [NR-301856](https://new-relic.atlassian.net/browse/NR-301856) + Configuration via yaml: + ```yaml + security: + # The exclude_from_iast_scan configuration allows to specify APIs, parameters, and categories that should not be scanned by Security Agents. + exclude_from_iast_scan: + # The api field specifies list of APIs using regular expression (regex) patterns that follow the syntax of Perl 5. The regex pattern should provide a complete match for the URL without the endpoint. + # Example: + # api: + # - .*account.* + # - .*/\api\/v1\/.*?\/login + api: [] + + # The parameters configuration allows users to specify headers, query parameters, and body keys that should be excluded from IAST scans. + # Example: + # http_request_parameters: + # header: + # - X-Forwarded-For + # query: + # - username + # - password + # body: + # - account.email + # - account.contact + http_request_parameters: + # A list of HTTP header keys. If a request includes any headers with these keys, the corresponding IAST scan will be skipped. + header: [] + # A list of query parameter keys. The presence of these parameters in the request's query string will lead to skipping the IAST scan. + query: [] + # A list of keys within the request body. If these keys are found in the body content, the IAST scan will be omitted. + body: [] + + # The iast_detection_category configuration allows to specify which categories of vulnerabilities should not be detected by Security Agents. + # If any of these categories are set to true, Security Agents will not generate events or flag vulnerabilities for that category. + iast_detection_category: + insecure_settings: false + invalid_file_access: false + sql_injection: false + nosql_injection: false + ldap_injection: false + javascript_injection: false + command_injection: false + xpath_injection: false + ssrf: false + rxss: false + ``` +- [PR-321](https://github.com/newrelic/csec-java-agent/pull/321) Add feature to rate limit the IAST replay requests. [NR-304574](https://new-relic.atlassian.net/browse/NR-304574) + ```yaml + security: + scan_controllers: + # The scan_request_rate_limit configuration allows to specify maximum number of replay request played per minute. + iast_scan_request_rate_limit: 3600 # Number of IAST replay request played per minute, Default is 3600 + ``` +- [PR-315](https://github.com/newrelic/csec-java-agent/pull/315) GraphQL Support : The security agent now also supports GraphQL Version 16.0.0 and above, default is disabled. [NR-299885](https://new-relic.atlassian.net/browse/NR-299885) + +### Fixes +- [PR-322](https://github.com/newrelic/csec-java-agent/pull/322) Report Application endpoints immediately upon detecting new endpoints. [NR-287324](https://new-relic.atlassian.net/browse/NR-287324) +- [PR-323](https://github.com/newrelic/csec-java-agent/pull/323) Extract Server Configuration to resolve IAST localhost connection with application for WebSphere Liberty server [NR-303483](https://new-relic.atlassian.net/browse/NR-303483) +- [PR-327](https://github.com/newrelic/csec-java-agent/pull/327) Fix for User Class Detection in gRPC Server [NR-303616](https://new-relic.atlassian.net/browse/NR-303616) +- [PR-328](https://github.com/newrelic/csec-java-agent/pull/328) Fix for multiple Reflected Events observed in Jersey Framework [NR-307644](https://new-relic.atlassian.net/browse/NR-307644) +- [PR-325](https://github.com/newrelic/csec-java-agent/pull/325) Fix for incorrect Application endpoints detected for Servlet Framework [NR-303615](https://new-relic.atlassian.net/browse/NR-303615) +- [PR-320](https://github.com/newrelic/csec-java-agent/pull/320) Report only uncaught exceptions in IAST Error inbox. [NR-313412](https://new-relic.atlassian.net/browse/NR-313412) + +### Deprecations +- Status File Used for Debugging: This feature has been deprecated. All debugging capabilities have been moved to either Init Logging or [Error Inbox](https://docs.newrelic.com/docs/errors-inbox/errors-inbox/) and will be removed in a future agent release. [NR-293966](https://new-relic.atlassian.net/browse/NR-293966) + + ## [1.4.1] - 2024-8-14 ### Adds - [PR-296](https://github.com/newrelic/csec-java-agent/pull/296) Apache Solr Support: The security agent now also supports Apache Solr Version 4.0.0 and above. [NR-288599](https://new-relic.atlassian.net/browse/NR-288599) diff --git a/README.md b/README.md index 9bafd1a4c..dc2647886 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The agent automatically instruments the following frameworks. - Resin 3.1.9 to 4.0.x - Jetty 9.3.0.M1 to latest - Mule ESB 3.6 to 3.9.x -- gRPC 1.4.0 to latest** +- gRPC 1.4.0 to latest [**](#grpc-instrumentation) - Jersey 2.0 to latest - Akka Server 10.0 to latest (with scala 2.11 and above) - Spray Can 1.3.1 to latest (with scala 2.11 and above) @@ -42,8 +42,18 @@ The agent automatically instruments the following frameworks. - Netty Server 4.0.0.Final to latest - Netty Reactor Server 0.7.0.RELEASE to latest - Vertx web 3.2.0 to latest - -** IAST for **gRPC** requires the dependency [protobuf-java-util](https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util) for IAST request replay. +- GraphQL 16.0.0 to latest [**](#graphql-instrumentation) + +#### gRPC Instrumentation +IAST for **gRPC** requires the dependency [protobuf-java-util](https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util) for IAST request replay. + +#### GraphQL Instrumentation +By default, GraphQL instrumentation is disabled in IAST as it is an experimental feature. To take advantage of this feature enable GraphQL instrumentation, update your configuration by adding the following settings under the class_transformer section: +```yaml +class_transformer: + com.newrelic.instrumentation.security.graphql-java-16.2: + enabled: true +``` ### Java Native Operations diff --git a/gradle.properties b/gradle.properties index 904fdfffb..31b3918f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # The agent version. -agentVersion=1.4.2 +agentVersion=1.5.0 jsonVersion=1.2.9 # Updated exposed NR APM API version. nrAPIVersion=8.12.0 diff --git a/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle b/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle index bb0a864d5..fc1b714d1 100644 --- a/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle +++ b/instrumentation-security/graalvm-jsinjection-22.0.0/build.gradle @@ -13,6 +13,7 @@ jar { verifyInstrumentation { passesOnly 'org.graalvm.js:js:[22.0.0,)' + exclude('org.graalvm.js:js:24.1.0') // excludeRegex '.*-rc[0-9]+' } diff --git a/instrumentation-security/graphql-java-16.2/build.gradle b/instrumentation-security/graphql-java-16.2/build.gradle index 2ac60f459..ee706f615 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' } + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.graphql-java-16.2', 'Enabled': 'false' } } verifyInstrumentation { diff --git a/instrumentation-security/jedis-1.4.0/build.gradle b/instrumentation-security/jedis-1.4.0/build.gradle index 0646a65ca..aed46fd2d 100644 --- a/instrumentation-security/jedis-1.4.0/build.gradle +++ b/instrumentation-security/jedis-1.4.0/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:1.4.0") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { diff --git a/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle b/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle index 285624fd5..613c97e0c 100644 --- a/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle +++ b/instrumentation-security/jedis-2.7.1_2.7.2/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:2.7.1") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { diff --git a/instrumentation-security/jedis-3.0.0/build.gradle b/instrumentation-security/jedis-3.0.0/build.gradle index ebc2c0673..fc133df28 100644 --- a/instrumentation-security/jedis-3.0.0/build.gradle +++ b/instrumentation-security/jedis-3.0.0/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:3.0.0") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { diff --git a/instrumentation-security/jedis-4.0.0/build.gradle b/instrumentation-security/jedis-4.0.0/build.gradle index 3a727d375..27d4f895f 100644 --- a/instrumentation-security/jedis-4.0.0/build.gradle +++ b/instrumentation-security/jedis-4.0.0/build.gradle @@ -7,7 +7,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("redis.clients:jedis:4.0.0") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } verifyInstrumentation { diff --git a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java index 09844d08b..cf8c9867d 100644 --- a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java +++ b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java @@ -7,14 +7,12 @@ package com.newrelic.agent.security.instrumentation.jersey2; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.server.ContainerRequest; -import java.io.OutputStream; - @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ApplicationHandler") public abstract class ApplicationHandler_Handler { @@ -24,6 +22,7 @@ public void handle(ContainerRequest requestContext) { if (requestContext != null) { isRequestLockAcquired = HttpRequestHelper.acquireRequestLockIfPossible(); if (isRequestLockAcquired) { + GenericHelper.acquireLockIfPossible(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.preprocessSecurityHook(requestContext); HttpRequestHelper.registerUserLevelCode("JERSEY"); } @@ -32,6 +31,7 @@ public void handle(ContainerRequest requestContext) { } finally { if(isRequestLockAcquired){ HttpRequestHelper.releaseRequestLock(); + GenericHelper.releaseLock(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); } } } diff --git a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java index 0718f51b8..6e58136bb 100644 --- a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java +++ b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java @@ -19,9 +19,6 @@ import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.server.ContainerRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import static com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper.SERVLET_GET_IS_OPERATION_LOCK; @@ -33,7 +30,7 @@ public abstract class ContainerResponse_Instrumentation { NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); } - if(response != null && response.getContext() != null && response.getContext().hasEntity()){ + if(GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()) && response != null && response.getContext() != null && response.getContext().hasEntity()){ Object responseObject = response.getContext().getEntity(); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(String.valueOf(responseObject))); } @@ -45,7 +42,7 @@ public void close() { boolean isLockAcquired = false; try { isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); - if(isLockAcquired) { + if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } Weaver.callOriginal(); diff --git a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index 247508404..377b367dc 100644 --- a/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java +++ b/instrumentation-security/jersey-2.16/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java @@ -13,7 +13,6 @@ import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; import com.newrelic.api.agent.security.utils.logging.LogLevel; -import jdk.nashorn.internal.codegen.CompilerConstants; import org.glassfish.jersey.internal.PropertiesDelegate; import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.server.ContainerRequest; @@ -28,17 +27,12 @@ public class HttpRequestHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REQUEST_LOCK-"; - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING = "JERSEY_LOCK_POST_PROCESSING-"; public static final String HEADER_SEPARATOR = ";"; - public static final String GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "GRIZZLY_REQUEST_PROPERTIES_DELEGATE"; - public static final String GRIZZLY_REQUEST = "GRIZZLY_REQUEST"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - public static final String ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST = "org.glassfish.grizzly.http.server.Request"; public static final String FIELD_REQUEST = "request"; public static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; public static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; @@ -46,18 +40,11 @@ public class HttpRequestHelper { public static final String METHOD_GET_SCHEME = "getScheme"; public static final String METHOD_GET_CONTENT_TYPE = "getContentType"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; - public static final String TRACING_AWARE_PROPERTIES_DELEGATE = "TRACING_AWARE_PROPERTIES_DELEGATE"; public static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; public static final String JERSEY_2_16 = "JERSEY-2.16"; - public static Class grizzlyRequestPropertiesDelegateKlass = null; - - public static Class grizzlyRequest = null; - - public static Class tracingAwarePropertiesDelegateKlass = null; - public static void preprocessSecurityHook(ContainerRequest requestContext) { try { if (!NewRelicSecurity.isHookProcessingActive()) { @@ -91,7 +78,7 @@ public static void preprocessSecurityHook(ContainerRequest requestContext) { public static void postProcessSecurityHook(String className, OutboundMessageContext wrappedMessageContext) { try { - if (!NewRelicSecurity.isHookProcessingActive() + if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class)) ) { return; } @@ -197,7 +184,7 @@ public static String getTraceHeader(Map headers) { return data; } - public static boolean isRequestLockAcquired() { + private static boolean isRequestLockAcquired() { try { return NewRelicSecurity.isHookProcessingActive() && Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute(getNrSecCustomAttribName(), Boolean.class)); @@ -228,20 +215,24 @@ private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } + public static String getNrSecCustomAttribForPostProcessing() { + return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); + } + public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { if(StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE)){ try { - Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); + Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); Field requestField = grizzlyRequestPropertiesDelegateKlass.getDeclaredField(FIELD_REQUEST); requestField.setAccessible(true); Object requestObject = requestField.get(propertiesDelegate); - Class requestClass = requestObject.getClass(); + + Class requestClass = requestObject.getClass(); Method getRemoteAddr = requestClass.getMethod(METHOD_GET_REMOTE_ADDR); Method getRemotePort = requestClass.getMethod(METHOD_GET_REMOTE_PORT); Method getLocalPort = requestClass.getMethod(METHOD_GET_LOCAL_PORT); Method getScheme = requestClass.getMethod(METHOD_GET_SCHEME); Method getContentType = requestClass.getMethod(METHOD_GET_CONTENT_TYPE); - getContentType = requestClass.getMethod(METHOD_GET_CONTENT_TYPE); securityRequest.setClientIP(String.valueOf(getRemoteAddr.invoke(requestObject))); securityRequest.setClientPort(String.valueOf(getRemotePort.invoke(requestObject))); securityRequest.setServerPort((int) getLocalPort.invoke(requestObject)); @@ -255,7 +246,7 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } else if (StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE)){ try { - Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); + Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); Field propertiesDelegateField = tracingAwarePropertiesDelegateKlass.getDeclaredField(FIELD_PROPERTIES_DELEGATE); propertiesDelegateField.setAccessible(true); Object propertiesDelegateObject = propertiesDelegateField.get(propertiesDelegate); diff --git a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java index d3ccc680e..19fb1f5d3 100644 --- a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java +++ b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java @@ -56,7 +56,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SecurityInstrumentationTestRunner.class) -@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2", "org.glassfish.jersey"}) +@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2"}) @Category({ Java9IncompatibleTest.class, Java11IncompatibleTest.class, Java17IncompatibleTest.class }) public class JerseyTests { @@ -203,6 +203,7 @@ private void assertOperation(List operations, boolean hasHead assertEquals(MediaType.TEXT_HTML, response.getResponseContentType()); assertEquals(2, responseBody.length); assertEquals(responseBody[0], response.getResponseBody().toString()); + assertFalse(hashCode.isEmpty()); assertEquals(Collections.singleton(Integer.parseInt(responseBody[1])), hashCode); } private static void getRandomPort() diff --git a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java index 299b050d7..41b746c17 100644 --- a/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java +++ b/instrumentation-security/jersey-2.16/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java @@ -19,28 +19,13 @@ public class Resource { @GET @Path("/sync") public String syncEndpoint(@DefaultValue("param") @QueryParam("param") final String param) { - return param; + return "sync result"; } @GET @Path("/async") public void resume(@DefaultValue("1") @QueryParam("sleep") final int sleepMillis, @Suspended final AsyncResponse response) { - new Thread(new Runnable() { - @Override - public void run() { - String result = veryExpensiveOperation(sleepMillis); - response.resume(result); - } - - private String veryExpensiveOperation(int sleepMillis) { - long currentTime = System.currentTimeMillis(); - long endTime = currentTime + sleepMillis; - while (currentTime < endTime) { - currentTime = System.currentTimeMillis(); - } - return "async resume at " + System.currentTimeMillis(); - } - }).start(); + response.resume("async result"); } } diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java index 09844d08b..dfa9ac4dd 100644 --- a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java +++ b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java @@ -7,14 +7,12 @@ package com.newrelic.agent.security.instrumentation.jersey2; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.server.ContainerRequest; -import java.io.OutputStream; - @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ApplicationHandler") public abstract class ApplicationHandler_Handler { @@ -24,6 +22,7 @@ public void handle(ContainerRequest requestContext) { if (requestContext != null) { isRequestLockAcquired = HttpRequestHelper.acquireRequestLockIfPossible(); if (isRequestLockAcquired) { + GenericHelper.acquireLockIfPossible(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.preprocessSecurityHook(requestContext); HttpRequestHelper.registerUserLevelCode("JERSEY"); } @@ -31,6 +30,7 @@ public void handle(ContainerRequest requestContext) { Weaver.callOriginal(); } finally { if(isRequestLockAcquired){ + GenericHelper.releaseLock(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.releaseRequestLock(); } } diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java index f1f898aa3..6271a01e4 100644 --- a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java +++ b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java @@ -29,7 +29,7 @@ public abstract class ContainerResponse_Instrumentation { NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); } - if(response != null && response.getContext() != null && response.getContext().hasEntity()){ + if(GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()) && response != null && response.getContext() != null && response.getContext().hasEntity()){ Object responseObject = response.getContext().getEntity(); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(String.valueOf(responseObject))); } @@ -41,7 +41,7 @@ public void close() { boolean isLockAcquired = false; try { isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); - if(isLockAcquired) { + if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } Weaver.callOriginal(); diff --git a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index 72c7e6ed2..a060e849f 100644 --- a/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java +++ b/instrumentation-security/jersey-2/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java @@ -27,17 +27,12 @@ public class HttpRequestHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REQUEST_LOCK-"; - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING = "JERSEY_LOCK_POST_PROCESSING-"; public static final String HEADER_SEPARATOR = ";"; - public static final String GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "GRIZZLY_REQUEST_PROPERTIES_DELEGATE"; - public static final String GRIZZLY_REQUEST = "GRIZZLY_REQUEST"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - public static final String ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST = "org.glassfish.grizzly.http.server.Request"; public static final String FIELD_REQUEST = "request"; public static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; public static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; @@ -45,7 +40,6 @@ public class HttpRequestHelper { public static final String METHOD_GET_SCHEME = "getScheme"; public static final String METHOD_GET_CONTENT_TYPE = "getContentType"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; - public static final String TRACING_AWARE_PROPERTIES_DELEGATE = "TRACING_AWARE_PROPERTIES_DELEGATE"; public static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; @@ -53,12 +47,6 @@ public class HttpRequestHelper { public static final String HEADER_CONTENT_TYPE = "contenttype"; public static final String JERSEY_2 = "JERSEY-2"; - public static Class grizzlyRequestPropertiesDelegateKlass = null; - - public static Class grizzlyRequest = null; - - public static Class tracingAwarePropertiesDelegateKlass = null; - public static void preprocessSecurityHook(ContainerRequest requestContext) { try { if (!NewRelicSecurity.isHookProcessingActive()) { @@ -92,8 +80,7 @@ public static void preprocessSecurityHook(ContainerRequest requestContext) { public static void postProcessSecurityHook(String className, OutboundMessageContext wrappedMessageContext) { try { - if (!NewRelicSecurity.isHookProcessingActive() - ) { + if (!NewRelicSecurity.isHookProcessingActive() || Boolean.TRUE.equals(NewRelicSecurity.getAgent().getSecurityMetaData().getCustomAttribute("RXSS_PROCESSED", Boolean.class))) { return; } ServletHelper.executeBeforeExitingTransaction(); @@ -229,14 +216,19 @@ private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } + public static String getNrSecCustomAttribForPostProcessing() { + return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); + } + public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { if(StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE)){ try { - Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); + Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); Field requestField = grizzlyRequestPropertiesDelegateKlass.getDeclaredField(FIELD_REQUEST); requestField.setAccessible(true); Object requestObject = requestField.get(propertiesDelegate); - Class requestClass = requestObject.getClass(); + + Class requestClass = requestObject.getClass(); Method getRemoteAddr = requestClass.getMethod(METHOD_GET_REMOTE_ADDR); Method getRemotePort = requestClass.getMethod(METHOD_GET_REMOTE_PORT); Method getLocalPort = requestClass.getMethod(METHOD_GET_LOCAL_PORT); @@ -255,7 +247,7 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } else if (StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE)){ try { - Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); + Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); Field propertiesDelegateField = tracingAwarePropertiesDelegateKlass.getDeclaredField(FIELD_PROPERTIES_DELEGATE); propertiesDelegateField.setAccessible(true); Object propertiesDelegateObject = propertiesDelegateField.get(propertiesDelegate); diff --git a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java index f418c45e8..fe5b4e607 100644 --- a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java +++ b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java @@ -56,7 +56,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SecurityInstrumentationTestRunner.class) -@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2", "org.glassfish.jersey"}) +@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2"}) @Category({ Java9IncompatibleTest.class, Java11IncompatibleTest.class, Java17IncompatibleTest.class }) public class JerseyTests { @@ -206,6 +206,7 @@ private void assertOperation(List operations, boolean hasHead assertEquals(MediaType.TEXT_HTML, response.getResponseContentType()); assertEquals(2, responseBody.length); assertEquals(responseBody[0], response.getResponseBody().toString()); + assertFalse(hashCode.isEmpty()); assertEquals(Collections.singleton(Integer.parseInt(responseBody[1])), hashCode); } private static void getRandomPort() diff --git a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java index 299b050d7..41b746c17 100644 --- a/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java +++ b/instrumentation-security/jersey-2/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java @@ -19,28 +19,13 @@ public class Resource { @GET @Path("/sync") public String syncEndpoint(@DefaultValue("param") @QueryParam("param") final String param) { - return param; + return "sync result"; } @GET @Path("/async") public void resume(@DefaultValue("1") @QueryParam("sleep") final int sleepMillis, @Suspended final AsyncResponse response) { - new Thread(new Runnable() { - @Override - public void run() { - String result = veryExpensiveOperation(sleepMillis); - response.resume(result); - } - - private String veryExpensiveOperation(int sleepMillis) { - long currentTime = System.currentTimeMillis(); - long endTime = currentTime + sleepMillis; - while (currentTime < endTime) { - currentTime = System.currentTimeMillis(); - } - return "async resume at " + System.currentTimeMillis(); - } - }).start(); + response.resume("async result"); } } diff --git a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java index a810e8bb6..97097940f 100644 --- a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java +++ b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ApplicationHandler_Handler.java @@ -7,14 +7,12 @@ package com.newrelic.agent.security.instrumentation.jersey2; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import org.glassfish.jersey.server.ContainerRequest; -import java.io.OutputStream; - @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ApplicationHandler") public final class ApplicationHandler_Handler { @@ -24,6 +22,7 @@ public void handle(final ContainerRequest request) { if (request != null) { isRequestLockAcquired = HttpRequestHelper.acquireRequestLockIfPossible(); if (isRequestLockAcquired) { + GenericHelper.acquireLockIfPossible(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.preprocessSecurityHook(request); HttpRequestHelper.registerUserLevelCode("JERSEY"); } @@ -31,6 +30,7 @@ public void handle(final ContainerRequest request) { Weaver.callOriginal(); } finally { if(isRequestLockAcquired){ + GenericHelper.releaseLock(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()); HttpRequestHelper.releaseRequestLock(); } } diff --git a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java index 7990a24c4..6271a01e4 100644 --- a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java +++ b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/ContainerResponse_Instrumentation.java @@ -19,17 +19,17 @@ import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.server.ContainerRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper.SERVLET_GET_IS_OPERATION_LOCK; @Weave(type = MatchType.ExactClass, originalName = "org.glassfish.jersey.server.ContainerResponse") public abstract class ContainerResponse_Instrumentation { ContainerResponse_Instrumentation(final ContainerRequest requestContext, final OutboundJaxrsResponse response) { - if(response != null && response.getContext() != null && response.getContext().hasEntity()){ + if(response != null) { + NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseCode(response.getStatus()); + } + + if(GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing()) && response != null && response.getContext() != null && response.getContext().hasEntity()){ Object responseObject = response.getContext().getEntity(); NewRelicSecurity.getAgent().getSecurityMetaData().getResponse().setResponseBody(new StringBuilder(String.valueOf(responseObject))); } @@ -41,7 +41,7 @@ public void close() { boolean isLockAcquired = false; try { isLockAcquired = GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.REFLECTED_XSS, SERVLET_GET_IS_OPERATION_LOCK); - if(isLockAcquired) { + if(isLockAcquired && GenericHelper.isLockAcquired(HttpRequestHelper.getNrSecCustomAttribForPostProcessing())) { HttpRequestHelper.postProcessSecurityHook(this.getClass().getName(), getWrappedMessageContext()); } Weaver.callOriginal(); diff --git a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java index 62bc4f3f6..14d88c1af 100644 --- a/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java +++ b/instrumentation-security/jersey-3/src/main/java/com/newrelic/agent/security/instrumentation/jersey2/HttpRequestHelper.java @@ -27,17 +27,12 @@ public class HttpRequestHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String CONTAINER_RESPONSE_METHOD_NAME = "ContainerResponse"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "REQUEST_LOCK-"; - private static final String WILDCARD = "*"; - private static final String SEPARATOR = "/"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; + private static final String NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING = "JERSEY_LOCK_POST_PROCESSING-"; public static final String HEADER_SEPARATOR = ";"; - public static final String GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "GRIZZLY_REQUEST_PROPERTIES_DELEGATE"; - public static final String GRIZZLY_REQUEST = "GRIZZLY_REQUEST"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE = "org.glassfish.jersey.grizzly2.httpserver.GrizzlyRequestPropertiesDelegate"; - public static final String ORG_GLASSFISH_GRIZZLY_HTTP_SERVER_REQUEST = "org.glassfish.grizzly.http.server.Request"; public static final String FIELD_REQUEST = "request"; public static final String METHOD_GET_REMOTE_ADDR = "getRemoteAddr"; public static final String METHOD_GET_REMOTE_PORT = "getRemotePort"; @@ -45,18 +40,11 @@ public class HttpRequestHelper { public static final String METHOD_GET_SCHEME = "getScheme"; public static final String METHOD_GET_CONTENT_TYPE = "getContentType"; public static final String ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE = "org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate"; - public static final String TRACING_AWARE_PROPERTIES_DELEGATE = "TRACING_AWARE_PROPERTIES_DELEGATE"; public static final String FIELD_PROPERTIES_DELEGATE = "propertiesDelegate"; private static final String REQUEST_INPUTSTREAM_HASH = "REQUEST_INPUTSTREAM_HASH"; public static final String JERSEY_3 = "JERSEY-3"; - public static Class grizzlyRequestPropertiesDelegateKlass = null; - - public static Class grizzlyRequest = null; - - public static Class tracingAwarePropertiesDelegateKlass = null; - public static void preprocessSecurityHook(ContainerRequest requestContext) { try { if (!NewRelicSecurity.isHookProcessingActive()) { @@ -227,14 +215,19 @@ private static String getNrSecCustomAttribName() { return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } + public static String getNrSecCustomAttribForPostProcessing() { + return NR_SEC_CUSTOM_ATTRIB_NAME_POST_PROCESSING + Thread.currentThread().getId(); + } + public static void processPropertiesDelegate(PropertiesDelegate propertiesDelegate, HttpRequest securityRequest) { if(StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_GRIZZLY_REQUEST_PROPERTIES_DELEGATE)){ try { - Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); + Class grizzlyRequestPropertiesDelegateKlass = propertiesDelegate.getClass(); Field requestField = grizzlyRequestPropertiesDelegateKlass.getDeclaredField(FIELD_REQUEST); requestField.setAccessible(true); Object requestObject = requestField.get(propertiesDelegate); - Class requestClass = requestObject.getClass(); + + Class requestClass = requestObject.getClass(); Method getRemoteAddr = requestClass.getMethod(METHOD_GET_REMOTE_ADDR); Method getRemotePort = requestClass.getMethod(METHOD_GET_REMOTE_PORT); Method getLocalPort = requestClass.getMethod(METHOD_GET_LOCAL_PORT); @@ -253,7 +246,7 @@ public static void processPropertiesDelegate(PropertiesDelegate propertiesDelega } else if (StringUtils.equals(propertiesDelegate.getClass().getName(), ORG_GLASSFISH_JERSEY_GRIZZLY_2_HTTPSERVER_TRACING_AWARE_PROPERTIES_DELEGATE)){ try { - Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); + Class tracingAwarePropertiesDelegateKlass = propertiesDelegate.getClass(); Field propertiesDelegateField = tracingAwarePropertiesDelegateKlass.getDeclaredField(FIELD_PROPERTIES_DELEGATE); propertiesDelegateField.setAccessible(true); Object propertiesDelegateObject = propertiesDelegateField.get(propertiesDelegate); diff --git a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java index 85ec2d538..0ccf39689 100644 --- a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java +++ b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/JerseyTests.java @@ -55,7 +55,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SecurityInstrumentationTestRunner.class) -@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2", "org.glassfish.jersey"}) +@InstrumentationTestConfig(includePrefixes = {"com.newrelic.agent.security.instrumentation.jersey2"}) @Category({Java8IncompatibleTest.class, Java11IncompatibleTest.class}) public class JerseyTests { @@ -203,6 +203,7 @@ private void assertOperation(List operations, boolean hasHead assertEquals(MediaType.TEXT_HTML, response.getResponseContentType()); assertEquals(2, responseBody.length); assertEquals(responseBody[0], response.getResponseBody().toString()); + assertFalse(hashCode.isEmpty()); assertEquals(Collections.singleton(Integer.parseInt(responseBody[1])), hashCode); } private static void getRandomPort() diff --git a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java index 921a6350c..a9a8777c9 100644 --- a/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java +++ b/instrumentation-security/jersey-3/src/test/java/com/nr/agent/security/instrumentation/jersey2/resources/Resource.java @@ -19,28 +19,13 @@ public class Resource { @GET @Path("/sync") public String syncEndpoint(@DefaultValue("param") @QueryParam("param") final String param) { - return param; + return "sync result"; } @GET @Path("/async") public void resume(@DefaultValue("1") @QueryParam("sleep") final int sleepMillis, @Suspended final AsyncResponse response) { - new Thread(new Runnable() { - @Override - public void run() { - String result = veryExpensiveOperation(sleepMillis); - response.resume(result); - } - - private String veryExpensiveOperation(int sleepMillis) { - long currentTime = System.currentTimeMillis(); - long endTime = currentTime + sleepMillis; - while (currentTime < endTime) { - currentTime = System.currentTimeMillis(); - } - return "async resume at " + System.currentTimeMillis(); - } - }).start(); + response.resume("async result"); } } diff --git a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java index b6b51e2e1..bd8ca5aed 100644 --- a/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java +++ b/instrumentation-security/jetty-11/src/main/java/com/newrelic/agent/security/instrumentation/jetty11/HttpServletHelper.java @@ -127,7 +127,7 @@ public static void releaseServletLock() { } private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; + return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) { 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 18bbf3726..b015e742f 100644 --- a/instrumentation-security/jetty-12/src/main/java/com/newrelic/agent/security/instrumentation/jetty12/server/HttpServletHelper.java +++ b/instrumentation-security/jetty-12/src/main/java/com/newrelic/agent/security/instrumentation/jetty12/server/HttpServletHelper.java @@ -26,11 +26,9 @@ public class HttpServletHelper { private static final String X_FORWARDED_FOR = "x-forwarded-for"; private static final String EMPTY = ""; - public static final String QUESTION_MARK = "?"; public static final String SERVICE_METHOD_NAME = "handle"; - public static final String SERVICE_ASYNC_METHOD_NAME = "handleAsync"; - public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "JETTY_SERVLET_LOCK-"; + public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SERVLET_LOCK-"; public static final String JETTY_12 = "JETTY-12"; public static void processHttpRequestHeader(Request request, HttpRequest securityRequest) { @@ -127,7 +125,7 @@ public static void releaseServletLock() { } private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; + return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static void preprocessSecurityHook(Request request) { 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 0d41aceeb..685b15fbf 100644 --- a/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/HttpServletHelper.java +++ b/instrumentation-security/jetty-9/src/main/java/com/newrelic/agent/security/instrumentation/jetty9/HttpServletHelper.java @@ -128,7 +128,7 @@ public static void releaseServletLock() { } private static String getNrSecCustomAttribName() { - return NR_SEC_CUSTOM_ATTRIB_NAME; + return NR_SEC_CUSTOM_ATTRIB_NAME + Thread.currentThread().getId(); } public static void preprocessSecurityHook(HttpServletRequest httpServletRequest) { diff --git a/instrumentation-security/lettuce-4.3/build.gradle b/instrumentation-security/lettuce-4.3/build.gradle index dc25f4434..acefbd653 100644 --- a/instrumentation-security/lettuce-4.3/build.gradle +++ b/instrumentation-security/lettuce-4.3/build.gradle @@ -3,7 +3,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation("biz.paluch.redis:lettuce:4.4.0.Final") - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } jar { diff --git a/instrumentation-security/lettuce-5.0/build.gradle b/instrumentation-security/lettuce-5.0/build.gradle index 79018d90d..7feeb4409 100644 --- a/instrumentation-security/lettuce-5.0/build.gradle +++ b/instrumentation-security/lettuce-5.0/build.gradle @@ -3,7 +3,7 @@ dependencies { implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}") implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}") implementation group: 'io.lettuce', name: 'lettuce-core', version: '5.0.3.RELEASE' - testImplementation('org.testcontainers:testcontainers:1.17.1') + testImplementation('org.testcontainers:testcontainers:1.20.1') } jar { diff --git a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java index c558f3348..06b0c88ea 100644 --- a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java +++ b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java @@ -80,9 +80,6 @@ private static void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // TODO: need to update UserClassEntity - ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); } catch (Throwable ignored){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_6, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); diff --git a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java index 20217b344..8ab323966 100644 --- a/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java +++ b/instrumentation-security/mule-3.6/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java @@ -74,9 +74,6 @@ private void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // TODO: need to update UserClassEntity - ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); } catch (Throwable ignored){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_6, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); diff --git a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java index 8b10829fc..cdcec7a2f 100644 --- a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java +++ b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/HttpRequestToMuleEvent_Instrumentation.java @@ -80,9 +80,6 @@ private static void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // TODO: need to update UserClassEntity - ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); } catch (Throwable ignored){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_7, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); diff --git a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java index 556231e27..228220de6 100644 --- a/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java +++ b/instrumentation-security/mule-3.7/src/main/java/org/mule/module/http/internal/listener/async/RequestHandler_Instrumentation.java @@ -75,9 +75,6 @@ private void preprocessSecurityHook(HttpRequestContext requestContext) { // TODO: Create OutBoundHttp data here : Skipping for now. securityRequest.setContentType(MuleHelper.getContentType(httpRequest)); - - // TODO: need to update UserClassEntity - ServletHelper.registerUserLevelCode(MuleHelper.LIBRARY_NAME); securityRequest.setRequestParsed(true); } catch (Throwable ignored){ NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format(GenericHelper.ERROR_GENERATING_HTTP_REQUEST, MuleHelper.MULE_3_7, ignored.getMessage()), ignored, HttpRequestToMuleEvent_Instrumentation.class.getName()); 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 a3fed3d43..39475f565 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentConfig.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/AgentConfig.java @@ -90,8 +90,6 @@ public long instantiate() throws RestrictionModeException { groupName = applyRequiredGroup(); Agent.getCustomNoticeErrorParameters().put(IUtilConstants.SECURITY_MODE, groupName); // Enable low severity hooks - // Set required LogLevel - logLevel = applyRequiredLogLevel(); //Instantiation call please do not move or repeat this. osVariables = OsVariablesInstance.instantiate().getOsVariables(); @@ -100,6 +98,9 @@ public long instantiate() throws RestrictionModeException { //Do not repeat this task logger.initialiseLogger(); + // Set required LogLevel + logLevel = applyRequiredLogLevel(); + iastTestIdentifier = NewRelic.getAgent().getConfig().getValue(IUtilConstants.IAST_TEST_IDENTIFIER); instantiateAgentMode(groupName); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java index 6b892b330..a08ba5e68 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/AgentUtils.java @@ -4,6 +4,7 @@ import com.newrelic.agent.security.instrumentator.httpclient.IASTDataTransferRequestProcessor; import com.newrelic.agent.security.intcodeagent.constants.AgentServices; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.websocket.WSUtils; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.DeployedApplication; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; @@ -651,6 +652,10 @@ private void applyNRPolicyOverride() { public static void sendApplicationURLMappings() { + if (!WSUtils.isConnected()){ + NewRelicSecurity.getAgent().reportURLMapping(); + return; + } ApplicationURLMappings applicationURLMappings = new ApplicationURLMappings(URLMappingsHelper.getApplicationURLMappings()); applicationURLMappings.setApplicationUUID(AgentInfo.getInstance().getApplicationUUID()); logger.logInit(LogLevel.INFO, String.format("Collected application url mappings %s", applicationURLMappings), Agent.class.getName()); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java index 46db8e43d..ffaef9139 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/filelogging/FileLoggerThreadPool.java @@ -29,7 +29,7 @@ public class FileLoggerThreadPool { protected boolean isLoggingToStdOut = false; - private static OSVariables osVariables = OsVariablesInstance.getInstance().getOsVariables(); + private static OSVariables osVariables; private FileLoggerThreadPool() throws IOException { maxfiles = LogFileHelper.logFileCount(); @@ -41,6 +41,7 @@ private FileLoggerThreadPool() throws IOException { */ public void initialiseLogger() { // load the settings + osVariables = OsVariablesInstance.getInstance().getOsVariables(); int queueSize = 15000; int maxPoolSize = 1; int corePoolSize = 1;