Skip to content

Commit

Permalink
Merge branch 'refs/heads/main' into develop
Browse files Browse the repository at this point in the history
# Conflicts:
#	instrumentation-security/play-2.13_2.7/src/test/java/com/nr/agent/security/instrumentation/play2_7/APIEndpointTest.java
#	instrumentation-security/play-2.6/src/test/java/com/nr/agent/security/instrumentation/play26/APIEndpointTest.java
#	newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/URLMappingsHelper.java
  • Loading branch information
IshikaDawda committed Aug 9, 2024
2 parents 223eb4f + ec05bab commit 568def9
Show file tree
Hide file tree
Showing 20 changed files with 348 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private static void configureRepo(MavenArtifactRepository repo, String projectVe
private static void configurePom(MavenPom pom) {
pom.getUrl().set("https://github.com/newrelic/csec-java-agent");
pom.licenses(spec -> spec.license(license -> {
license.getName().set("New Relic Pre-Release Software License");
license.getName().set("New Relic Software License, Version 1.0");
license.getUrl().set("https://github.com/newrelic/csec-java-agent/blob/main/LICENSE.md");
license.getDistribution().set("repo");
}));
Expand Down
2 changes: 1 addition & 1 deletion gradle/script/java.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ test {
}

dependencies {
testImplementation("junit:junit:4.12")
testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito:mockito-core:3.9.0")
testImplementation("org.hamcrest:hamcrest-library:1.3")
testImplementation(project(":test-annotations"))
Expand Down
6 changes: 4 additions & 2 deletions instrumentation-security-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ dependencies {
implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}")
implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}")
implementation("com.newrelic.agent.java:newrelic-agent:${nrAgentVersion}")
implementation 'org.apache.commons:commons-text:1.7'
implementation ('org.apache.commons:commons-text:1.10.0')
implementation("com.newrelic.agent.java:agent-bridge:${nrAPIVersion}")
implementation("com.newrelic.agent.java:agent-bridge-datastore:${nrAPIVersion}")
implementation("commons-net:commons-net:3.9.0")
implementation("org.mockftpserver:MockFtpServer:3.1.0")

api("org.apache.httpcomponents:httpclient:4.5.13")
api("org.apache.httpcomponents:httpclient:4.5.13"){
exclude(module: 'commons-codec', group: 'commons-codec')
}
api("org.nanohttpd:nanohttpd:2.3.1")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.nr.agent.security.instrumentation.netty_reactor;

import com.newrelic.agent.security.introspec.InstrumentationTestConfig;
import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner;
import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper;
import com.newrelic.api.agent.security.schema.ApplicationURLMapping;
import io.netty.handler.codec.http.HttpMethod;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.http.server.HttpServer;
import reactor.ipc.netty.tcp.BlockingNettyContext;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@RunWith(SecurityInstrumentationTestRunner.class)
@InstrumentationTestConfig(includePrefixes = "reactor.ipc.netty.http.server")
public class APIEndpointTest {
private static BlockingNettyContext server;
@BeforeClass
public static void beforeClass() throws Exception {
server = HttpServer
.create(SecurityInstrumentationTestRunner.getIntrospector().getRandomPort())
.startRouter(r -> r
.post("/file/{path}", (req, res) -> res.send())
.get("/echo/{param}", (req, res) -> res.send())
.get("/check", (req, res) -> res.sendString(Mono.just("Check Response data sent...")))
.route(
httpServerRequest -> httpServerRequest.uri().equals("/test") && httpServerRequest.method().equals(HttpMethod.GET),
(req, res) -> res.send(req.receive().retain()))
.ws("/ws", (req, res) -> res.send(req.receive().retain()))
.get("/echo/{param}", (req, res) -> res.send())
);
}

@AfterClass
public static void afterClass() throws Exception {
if (server != null){
server.shutdown();
}
}

@Test
public void apiEndpointTest() {
String handler = "com.nr.agent.security.instrumentation.netty_reactor.APIEndpointTest$$Lambda$";
String wsHandler = "reactor.ipc.netty.http.server.HttpServerRoutes$$Lambda$";
Map<String, String> expectedMappings = new HashMap<>();
expectedMappings.put("/file/{path}", "POST");
expectedMappings.put("/echo/{param}", "GET");
expectedMappings.put("/check", "GET");
expectedMappings.put("/*", "*");
expectedMappings.put("/ws", "GET");

Set<ApplicationURLMapping> actualMappings = URLMappingsHelper.getApplicationURLMappings();
for (ApplicationURLMapping actualMapping : actualMappings) {
Assert.assertNotNull(actualMapping.getMethod());
Assert.assertNotNull(actualMapping.getPath());
Assert.assertNotNull(actualMapping.getHandler());


Assert.assertEquals(expectedMappings.get(actualMapping.getPath()), actualMapping.getMethod());
if (!actualMapping.getPath().equals("/ws")) {
Assert.assertTrue(actualMapping.getHandler().startsWith(handler));
} else {
Assert.assertTrue(actualMapping.getHandler().startsWith(wsHandler));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.nr.agent.security.instrumentation.netty_reactor;

import com.newrelic.agent.security.introspec.InstrumentationTestConfig;
import com.newrelic.agent.security.introspec.SecurityInstrumentationTestRunner;
import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper;
import com.newrelic.api.agent.security.schema.ApplicationURLMapping;
import io.netty.handler.codec.http.HttpMethod;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Mono;
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@RunWith(SecurityInstrumentationTestRunner.class)
@InstrumentationTestConfig(includePrefixes = "reactor.netty.http.server")
public class APIEndpointTest {
private static DisposableServer server;
@BeforeClass
public static void beforeClass() {
server = HttpServer
.create()
.port(SecurityInstrumentationTestRunner.getIntrospector().getRandomPort())
.route(r -> r
.post("/file/{path}", (req, res) -> res.send())
.get("/echo/{param}", (req, res) -> res.send())
.get("/check", (req, res) -> res.sendString(Mono.just("Check Response data sent...")))
.route(
httpServerRequest -> httpServerRequest.uri().equals("/test") && httpServerRequest.method().equals(HttpMethod.GET),
(req, res) -> res.send(req.receive().retain()))
.ws("/ws", (req, res) -> res.send(req.receive().retain()))
.get("/echo/{param}", (req, res) -> res.send())
).bindNow();
}

@AfterClass
public static void afterClass() throws Exception {
if (server != null){
server.dispose();
}
}

@Test
public void apiEndpointTest() {
String handler = "com.nr.agent.security.instrumentation.netty_reactor.APIEndpointTest$$Lambda$";
String wsHandler = "reactor.netty.http.server.HttpServerRoutes$$Lambda$";
Map<String, String> expectedMappings = new HashMap<>();
expectedMappings.put("/file/{path}", "POST");
expectedMappings.put("/echo/{param}", "GET");
expectedMappings.put("/check", "GET");
expectedMappings.put("/*", "*");
expectedMappings.put("/ws", "GET");

Set<ApplicationURLMapping> actualMappings = URLMappingsHelper.getApplicationURLMappings();
for (ApplicationURLMapping actualMapping : actualMappings) {
Assert.assertNotNull(actualMapping.getMethod());
Assert.assertNotNull(actualMapping.getPath());
Assert.assertNotNull(actualMapping.getHandler());


Assert.assertEquals(expectedMappings.get(actualMapping.getPath()), actualMapping.getMethod());
if (!actualMapping.getPath().equals("/ws")) {
Assert.assertTrue(actualMapping.getHandler().startsWith(handler));
} else {
Assert.assertTrue(actualMapping.getHandler().startsWith(wsHandler));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.newrelic.agent.security.instrumentation.play2_13

import com.newrelic.api.agent.security.NewRelicSecurity
import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper
import com.newrelic.api.agent.security.schema.Framework
import com.newrelic.api.agent.security.utils.logging.LogLevel
import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver}
import play.api.mvc.Handler
Expand All @@ -35,6 +36,16 @@ class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef
} catch {
case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_DETECTING_USER_CLASS, "PLAY-2.13_2.7"), t, this.getClass.getName)
}

// route detection
try {
if (NewRelicSecurity.isHookProcessingActive) {
NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.setRoute(handlerDef.path)
NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFramework(Framework.PLAY)
}
} catch {
case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "PLAY-2.13_2.7"), t, this.getClass.getName)
}
underlyingInvoker.call(call)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper;
import com.newrelic.api.agent.security.instrumentation.helpers.URLMappingsHelper;
import com.newrelic.api.agent.security.schema.ApplicationURLMapping;
import com.newrelic.api.agent.security.schema.Framework;
import com.newrelic.api.agent.security.schema.SecurityMetaData;
import com.newrelic.security.test.marker.Java17IncompatibleTest;
import org.junit.Assert;
Expand Down Expand Up @@ -41,18 +42,17 @@ public class APIEndpointTest {

@BeforeClass
public static void setupMappings() {
expectedMappings.put("/hello", SimpleJavaController.class.getName());
expectedMappings.put("/scalaHello", SimpleScalaController.class.getName());
expectedMappings.put("/post", SimpleJavaController.class.getName());
expectedMappings.put("/index", SimpleJavaController.class.getName());
expectedMappings.put("/simple", SimpleJavaController.class.getName());
expectedMappings.put("/hello", SimpleJavaController.class.getName() + ".hello");
expectedMappings.put("/scalaHello", SimpleScalaController.class.getName() + ".scalaHello");
expectedMappings.put("/post/$data<[^/]+>", SimpleJavaController.class.getName() + ".post(data:String)");
expectedMappings.put("/post1/$data<[a-zA-Z]+>", SimpleJavaController.class.getName() + ".post(data:String)");
expectedMappings.put("/index", SimpleJavaController.class.getName() + ".index");
expectedMappings.put("/simple", SimpleJavaController.class.getName() + ".simple");
}

@Test
public void testControllerActions() throws IOException {
HttpURLConnection conn = ((HttpURLConnection) serverRule.getEndpoint("/hello").openConnection());
conn.connect();
System.out.println(conn.getResponseCode());
makeRequest("/hello");

Set<ApplicationURLMapping> actualMappings = URLMappingsHelper.getApplicationURLMappings();
Assert.assertNotNull(actualMappings);
Expand All @@ -64,23 +64,60 @@ public void testControllerActions() throws IOException {
// verification of user-class entity
SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector();
SecurityMetaData metaData = introspector.getSecurityMetaData();
verifyUserClassDetection(metaData, "hello");

// verification of route detection
Assert.assertEquals("/hello", metaData.getRequest().getRoute());
Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework());
}

@Test
public void testRouteDetection() throws IOException {
makeRequest("/post/data");

SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector();
SecurityMetaData metaData = introspector.getSecurityMetaData();

verifyUserClassDetection(metaData, "post");
Assert.assertEquals("/post/$data<[^/]+>", metaData.getRequest().getRoute());
Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework());
}

@Test
public void testRouteDetection1() throws IOException {
makeRequest("/post1/data");

SecurityIntrospector introspector = SecurityInstrumentationTestRunner.getIntrospector();
SecurityMetaData metaData = introspector.getSecurityMetaData();

verifyUserClassDetection(metaData, "post");
Assert.assertEquals("/post1/$data<[a-zA-Z]+>", metaData.getRequest().getRoute());
Assert.assertEquals(Framework.PLAY.name(), metaData.getMetaData().getFramework());
}

private void makeRequest(String path) throws IOException {
HttpURLConnection conn = ((HttpURLConnection) serverRule.getEndpoint(path).openConnection());
conn.connect();
System.out.println(conn.getResponseCode());
}

private void verifyUserClassDetection(SecurityMetaData metaData, String methodName) {
Assert.assertNotNull(metaData.getMetaData());
Assert.assertTrue(metaData.getMetaData().isUserLevelServiceMethodEncountered());

StackTraceElement element = metaData.getCustomAttribute(GenericHelper.USER_CLASS_ENTITY, StackTraceElement.class);
Assert.assertNotNull(element);
Assert.assertEquals(SimpleJavaController.class.getName(), element.getClassName());
Assert.assertEquals("hello", element.getMethodName());
Assert.assertEquals(methodName, element.getMethodName());
}

private void assertMappings(ApplicationURLMapping actualMapping){
Assert.assertNotNull(actualMapping.getPath());
Assert.assertNotNull(actualMapping.getHandler());
Assert.assertNotNull(actualMapping.getMethod());

String path = actualMapping.getPath();
String handler = expectedMappings.get(path);
String method = !path.equals("/post") ? "GET" : "POST";
String method = "GET";

Assert.assertEquals(handler, actualMapping.getHandler());
Assert.assertEquals(method, actualMapping.getMethod());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ GET /hello com.nr.agent.security.instrumentation.play2_7.SimpleJava
GET /index com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.index
GET /simple com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.simple
GET /scalaHello com.nr.agent.security.instrumentation.play2_7.SimpleScalaController.scalaHello
POST /post com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.post(data: String)
GET /post/:data com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.post(data: String)
GET /post1/$data<[a-zA-Z]+> com.nr.agent.security.instrumentation.play2_7.SimpleJavaController.post(data: String)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
package com.newrelic.agent.security.instrumentation.play24

import com.newrelic.api.agent.security.NewRelicSecurity
import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper
import com.newrelic.api.agent.security.instrumentation.helpers.{GenericHelper, URLMappingsHelper}
import com.newrelic.api.agent.security.schema.{Framework, SecurityMetaData}
import com.newrelic.api.agent.security.utils.logging.LogLevel
import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver}
import play.api.mvc.Handler
Expand All @@ -34,6 +35,16 @@ class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef
} catch {
case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_DETECTING_USER_CLASS, "PLAY-2.4"), t, this.getClass.getName)
}

// route detection
try {
if (NewRelicSecurity.isHookProcessingActive) {
NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.setRoute(handlerDef.path)
NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFramework(Framework.PLAY)
}
} catch {
case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "PLAY-2.4"), t, this.getClass.getName)
}
underlyingInvoker.call(call)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.newrelic.agent.security.instrumentation.play26

import com.newrelic.api.agent.security.NewRelicSecurity
import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper
import com.newrelic.api.agent.security.schema.Framework
import com.newrelic.api.agent.security.utils.logging.LogLevel
import com.newrelic.api.agent.weaver.{MatchType, Weave, Weaver}
import play.api.mvc.Handler
Expand All @@ -35,6 +36,16 @@ class NewRelicWrapperInvoker[A](underlyingInvoker: HandlerInvoker[A], handlerDef
} catch {
case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_DETECTING_USER_CLASS, "PLAY-2.6"), t, this.getClass.getName)
}

// route detection
try {
if (NewRelicSecurity.isHookProcessingActive) {
NewRelicSecurity.getAgent.getSecurityMetaData.getRequest.setRoute(handlerDef.path)
NewRelicSecurity.getAgent.getSecurityMetaData.getMetaData.setFramework(Framework.PLAY)
}
} catch {
case t: Throwable => NewRelicSecurity.getAgent.log(LogLevel.FINEST, String.format(GenericHelper.ERROR_WHILE_GETTING_ROUTE_FOR_INCOMING_REQUEST, "PLAY-2.6"), t, this.getClass.getName)
}
underlyingInvoker.call(call)
}
}
Loading

0 comments on commit 568def9

Please sign in to comment.