Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ dependencies {
// to instrument the integration test
iastIntegrationTestImplementation project(':dd-java-agent:agent-iast:iast-test-fixtures')
iastIntegrationTestImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0'
iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0'))
// Provide real (non-shadowed) jetty for the test server bootstrap
iastIntegrationTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826'
iastIntegrationTestImplementation group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.4.56.v20240826'
iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:apache-httpcore:apache-httpcore-4.0'))
iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-common'))
iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0'))
iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:java:java-lang:java-lang-1.8'))
iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:java:java-net:java-net-1.8'))
iastIntegrationTestRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import datadog.trace.agent.test.base.HttpServer
import foo.bar.VulnerableUrlBuilder
import okhttp3.HttpUrl
import okhttp3.Request
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder

import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
class IastHttpClientIntegrationTest extends IastHttpServerTest<Server> {

static final CLIENTS = [
'org.apache.http.impl.client.AutoRetryHttpClient',
Expand All @@ -20,28 +26,58 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
@Override
HttpServer server() {
final controller = new SsrfController()
return httpServer {
handlers {
prefix('/ssrf/execute') {
final msg = controller.apacheSsrf(
VulnerableUrlBuilder.url(request),
(String) request.getParameter('clientClassName'),
(String) request.getParameter('method'),
(String) request.getParameter('requestType'),
(String) request.getParameter('scheme')
)
response.status(200).send(msg)
}

// Use _raw_ jetty API, so the jetty instrumentation is applied
// (the :dd-java-agent:testing has a shadowed jetty server.)
return new HttpServer() {
Server jettyServer
int port

@Override
void start() {
jettyServer = new Server(0) // 0 = random port

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS)
context.setContextPath('/')
jettyServer.setHandler(context)

// Add servlet for the /ssrf/execute endpoint
context.addServlet(new ServletHolder(new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
final msg = controller.apacheSsrf(
VulnerableUrlBuilder.url(req),
req.getParameter('clientClassName'),
req.getParameter('method'),
req.getParameter('requestType'),
req.getParameter('scheme')
)
resp.setStatus(200)
resp.writer.write(msg)
}
}), '/ssrf/execute')

jettyServer.start()
port = ((ServerConnector) jettyServer.connectors[0]).localPort
}
}.asHttpServer()

@Override
void stop() {
jettyServer?.stop()
}

@Override
URI address() {
return new URI("http://localhost:${port}/")
}
}
}

void 'ssrf is present: #suite'() {
setup:
final url = suite.url(address)
final request = new Request.Builder().url(url).get().build()


when:
def response = client.newCall(request).execute()

Expand All @@ -52,6 +88,9 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
assert to != null
hasVulnerability(vul -> vul.type == VulnerabilityType.SSRF && suite.evidenceMatches(vul.evidence))

cleanup:
response?.close()

where:
suite << createTestSuite()
}
Expand Down Expand Up @@ -129,7 +168,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
}

private static enum TaintedTarget {
URL{
URL {
void addTainted(HttpUrl.Builder builder, TestSuite suite) {
builder.addQueryParameter('url', suite.scheme + '://inexistent/test?1=1')
}
Expand All @@ -138,7 +177,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
return assertTainted(evidence, 'url', suite.scheme + '://inexistent/test?1=1')
}
},
SCHEME{
SCHEME {
void addTainted(HttpUrl.Builder builder, TestSuite suite) {
// already added by the test
}
Expand All @@ -147,7 +186,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
return assertTainted(evidence, 'scheme', suite.scheme)
}
},
HOST{
HOST {
void addTainted(HttpUrl.Builder builder, TestSuite suite) {
builder.addQueryParameter('host', 'inexistent')
}
Expand All @@ -156,7 +195,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
return assertTainted(evidence, 'host', 'inexistent')
}
},
PATH{
PATH {
void addTainted(HttpUrl.Builder builder, TestSuite suite) {
builder.addQueryParameter('path', '/test')
}
Expand All @@ -165,7 +204,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest<HttpServer> {
return assertTainted(evidence, 'path', '/test')
}
},
QUERY{
QUERY {
void addTainted(HttpUrl.Builder builder, TestSuite suite) {
builder.addQueryParameter('query', '?1=1')
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package foo.bar;

import datadog.trace.agent.test.server.http.TestHttpServer.HandlerApi.RequestApi;
import javax.servlet.http.HttpServletRequest;

/** Class to be instrumented by IAST call sites containing methods to work with urls */
public abstract class VulnerableUrlBuilder {

private VulnerableUrlBuilder() {}

public static String url(RequestApi request) {
final String url = (String) request.getParameter("url");
public static String url(HttpServletRequest request) {
final String url = request.getParameter("url");
if (url != null) {
return url;
}
final String scheme = (String) request.getParameter("scheme");
final String scheme = request.getParameter("scheme");
final boolean https = "https".equals(scheme);
final String host = (String) request.getParameter("host");
final String host = request.getParameter("host");
if (host != null) {
return (https ? "https://" : "http://") + host + "/test?1=1";
}
final String path = (String) request.getParameter("path");
final String path = request.getParameter("path");
if (path != null) {
return (https ? "https://inexistent/" : "http://inexistent/") + path + "?1=1";
}
final String query = (String) request.getParameter("query");
final String query = request.getParameter("query");
if (query != null) {
return (https ? "https://inexistent/test" : "http://inexistent/test") + query;
}
Expand Down
5 changes: 0 additions & 5 deletions dd-java-agent/instrumentation/dropwizard/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ dependencies {
testImplementation project(':dd-java-agent:instrumentation:rs:jax-rs:jax-rs-annotations:jax-rs-annotations-2')
testImplementation project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')

// Don't want to conflict with jetty from the test server.
testImplementation(project(':dd-java-agent:instrumentation-testing')) {
exclude group: 'org.eclipse.jetty', module: 'jetty-server'
}

// First version with DropwizardTestSupport:
testImplementation group: 'io.dropwizard', name: 'dropwizard-testing', version: '0.8.0'
testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,10 @@ dependencies {
implementation(project(':dd-java-agent:instrumentation:jetty:jetty-client:jetty-client-common')) {
transitive = false
}
testImplementation(project(':dd-java-agent:instrumentation-testing')) {
// explicitly declared below.
exclude group: 'org.eclipse.jetty'
}
testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31')
testImplementation group: 'org.eclipse.jetty', name: 'jetty-client', version: '9.1.0.v20131115'
testImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.1.0.v20131115'

latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-client', version: '9.+'
latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+'
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ org.eclipse.jetty:jetty-http:9.1.0.v20131115=compileClasspath,testCompileClasspa
org.eclipse.jetty:jetty-http:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
org.eclipse.jetty:jetty-io:9.1.0.v20131115=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-io:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
org.eclipse.jetty:jetty-server:9.1.0.v20131115=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-server:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
org.eclipse.jetty:jetty-server:9.1.0.v20131115=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.1.0.v20131115=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
org.gmetrics:GMetrics:2.1.0=codenarc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ dependencies {
implementation project(":dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0")
compileOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.0.4.v20130625'

// Don't want to conflict with jetty from the test server.
testImplementation(project(':dd-java-agent:instrumentation-testing')) {
exclude group: 'org.eclipse.jetty', module: 'jetty-server'
}
testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31')

testImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.0.4.v20130625'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ dependencies {
testFixturesImplementation(project(':dd-java-agent:instrumentation-testing')) {
exclude group: 'org.eclipse.jetty', module: 'jetty-server'
}
// Don't want to conflict with jetty from the test server.
testImplementation(project(':dd-java-agent:instrumentation-testing')) {
exclude group: 'org.eclipse.jetty', module: 'jetty-server'
}

testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31')

String jetty9Version = '9.0.0.v20130308'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.apache.jasper.JasperException
import org.eclipse.jetty.http.HttpStatus

class JSPInstrumentationBasicTests extends JSPTestBase {
def "non-erroneous GET #test test"() {
Expand Down Expand Up @@ -72,7 +71,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -149,7 +148,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -222,7 +221,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -305,7 +304,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.INTERNAL_SERVER_ERROR_500
res.code() == HTTP_INTERNAL_ERROR

cleanup:
res.close()
Expand Down Expand Up @@ -380,7 +379,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -503,7 +502,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -561,7 +560,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.INTERNAL_SERVER_ERROR_500
res.code() == HTTP_INTERNAL_ERROR

cleanup:
res.close()
Expand All @@ -581,7 +580,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase {
Response res = client.newCall(req).execute()

then:
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK
assertTraces(1) {
trace(1) {
span {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import datadog.trace.bootstrap.instrumentation.api.Tags
import okhttp3.Request
import okhttp3.Response
import org.apache.jasper.JasperException
import org.eclipse.jetty.http.HttpStatus

class JSPInstrumentationForwardTests extends JSPTestBase {
def "non-erroneous GET forward to #forwardTo"() {
Expand Down Expand Up @@ -97,7 +96,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -171,7 +170,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -324,7 +323,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -449,7 +448,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.OK_200
res.code() == HTTP_OK

cleanup:
res.close()
Expand Down Expand Up @@ -535,7 +534,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.INTERNAL_SERVER_ERROR_500
res.code() == HTTP_INTERNAL_ERROR

cleanup:
res.close()
Expand Down Expand Up @@ -604,7 +603,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase {
}
}
}
res.code() == HttpStatus.NOT_FOUND_404
res.code() == HTTP_NOT_FOUND

cleanup:
res.close()
Expand Down
Loading