-
Notifications
You must be signed in to change notification settings - Fork 278
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
plugins { | ||
id 'java' | ||
id 'org.springframework.boot' version '2.7.15' | ||
id 'io.spring.dependency-management' version '1.0.15.RELEASE' | ||
id 'java-test-fixtures' | ||
} | ||
|
||
apply from: "$rootDir/gradle/java.gradle" | ||
description = 'ASM Standalone Billing Tests.' | ||
|
||
java { | ||
sourceCompatibility = '1.8' | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
implementation 'org.springframework.boot:spring-boot-starter-web' | ||
implementation group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' | ||
implementation group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' | ||
implementation project(':dd-trace-api') | ||
testImplementation project(':dd-smoke-tests') | ||
testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) | ||
} | ||
|
||
tasks.withType(Test).configureEach { | ||
dependsOn "bootJar" | ||
jvmArgs "-Ddatadog.smoketest.springboot.shadowJar.path=${tasks.bootJar.archiveFile.get()}" | ||
} |
25 changes: 25 additions & 0 deletions
25
...sm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/AppConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package datadog.smoketest.asmstandalonebilling; | ||
|
||
import java.util.EnumSet; | ||
import javax.servlet.ServletContext; | ||
import javax.servlet.ServletException; | ||
import javax.servlet.SessionTrackingMode; | ||
import org.springframework.boot.web.servlet.ServletContextInitializer; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class AppConfig { | ||
@Bean | ||
public ServletContextInitializer servletContextInitializer() { | ||
return new SessionTrackingConfig(); | ||
} | ||
|
||
private class SessionTrackingConfig implements ServletContextInitializer { | ||
@Override | ||
public void onStartup(ServletContext servletContext) throws ServletException { | ||
EnumSet<SessionTrackingMode> sessionTrackingModes = EnumSet.of(SessionTrackingMode.COOKIE); | ||
servletContext.setSessionTrackingModes(sessionTrackingModes); | ||
} | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
...m-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/Controller.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package datadog.smoketest.asmstandalonebilling; | ||
|
||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; | ||
import io.opentracing.Span; | ||
import io.opentracing.util.GlobalTracer; | ||
import java.io.IOException; | ||
import javax.servlet.http.HttpServletResponse; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
@RestController | ||
@RequestMapping("/rest-api") | ||
public class Controller { | ||
|
||
@GetMapping("/greetings") | ||
public String greetings(@RequestParam(name = "forceKeep", required = false) boolean forceKeep) { | ||
if (forceKeep) { | ||
forceKeepSpan(); | ||
} | ||
return "Hello I'm service " + System.getProperty("dd.service.name"); | ||
} | ||
|
||
@GetMapping("/appsec/{id}") | ||
public String pathParam( | ||
@PathVariable("id") String id, | ||
@RequestParam(name = "url", required = false) String url, | ||
@RequestParam(name = "forceKeep", required = false) boolean forceKeep) { | ||
if (forceKeep) { | ||
forceKeepSpan(); | ||
} | ||
if (url != null) { | ||
RestTemplate restTemplate = new RestTemplate(); | ||
return restTemplate.getForObject(url, String.class); | ||
} | ||
return id; | ||
} | ||
|
||
@GetMapping("/iast") | ||
@SuppressFBWarnings | ||
public void write( | ||
@RequestParam(name = "injection", required = false) String injection, | ||
@RequestParam(name = "url", required = false) String url, | ||
@RequestParam(name = "forceKeep", required = false) boolean forceKeep, | ||
final HttpServletResponse response) { | ||
if (forceKeep) { | ||
forceKeepSpan(); | ||
} | ||
if (injection != null) { | ||
try { | ||
response.getWriter().write(injection); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
if (url != null) { | ||
RestTemplate restTemplate = new RestTemplate(); | ||
restTemplate.getForObject(url, String.class); | ||
} | ||
} | ||
|
||
/** | ||
* @GetMapping("/forcekeep") public String forceKeep() { return "Span " + forceKeepSpan() + " will | ||
* be kept alive"; } @GetMapping("/call") public String call( @RequestParam(name = "url", required | ||
* = false) String url, @RequestParam(name = "forceKeep", required = false) boolean forceKeep) { | ||
* if (forceKeep) { forceKeepSpan(); } if (url != null) { RestTemplate restTemplate = new | ||
* RestTemplate(); return restTemplate.getForObject(url, String.class); } return "No url | ||
* provided"; } | ||
*/ | ||
private String forceKeepSpan() { | ||
// TODO: Configure the keep alive in dd-trace-api | ||
final Span span = GlobalTracer.get().activeSpan(); | ||
if (span != null) { | ||
span.setTag("manual.keep", true); | ||
return span.context().toSpanId(); | ||
} | ||
return null; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...e-billing/src/main/java/datadog/smoketest/asmstandalonebilling/SpringbootApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package datadog.smoketest.asmstandalonebilling; | ||
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class SpringbootApplication { | ||
public static void main(String[] args) { | ||
SpringApplication.run(SpringbootApplication.class, args); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
...roovy/datadog/smoketest/asmstandalonebilling/AbstractAsmStandaloneBillingSmokeTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package datadog.smoketest.asmstandalonebilling | ||
|
||
import datadog.smoketest.AbstractServerSmokeTest | ||
import datadog.trace.api.sampling.PrioritySampling | ||
import datadog.trace.test.agent.decoder.DecodedTrace | ||
|
||
abstract class AbstractAsmStandaloneBillingSmokeTest extends AbstractServerSmokeTest { | ||
|
||
@Override | ||
File createTemporaryFile(int processIndex) { | ||
return null | ||
} | ||
|
||
@Override | ||
String logLevel() { | ||
return 'debug' | ||
} | ||
|
||
@Override | ||
Closure decodedTracesCallback() { | ||
return {} // force traces decoding | ||
} | ||
|
||
protected ProcessBuilder createProcess(String[] properties){ | ||
createProcess(-1, properties) | ||
} | ||
|
||
|
||
protected ProcessBuilder createProcess(int processIndex, String[] properties){ | ||
def port = processIndex == -1 ? httpPort : httpPorts[processIndex] | ||
String springBootShadowJar = System.getProperty("datadog.smoketest.springboot.shadowJar.path") | ||
List<String> command = [] | ||
command.add(javaPath()) | ||
command.addAll(defaultJavaProperties) | ||
command.addAll(properties) | ||
command.addAll((String[]) ['-jar', springBootShadowJar, "--server.port=${port}"]) | ||
ProcessBuilder processBuilder = new ProcessBuilder(command) | ||
processBuilder.directory(new File(buildDirectory)) | ||
// Spring will print all environment variables to the log, which may pollute it and affect log assertions. | ||
processBuilder.environment().clear() | ||
return processBuilder | ||
} | ||
|
||
protected DecodedTrace getServiceTrace(String serviceName) { | ||
return traces.find { trace -> | ||
trace.spans.find { span -> | ||
span.service == serviceName | ||
} | ||
} | ||
} | ||
|
||
protected checkRootSpanPrioritySampling(DecodedTrace trace, byte priority) { | ||
return trace.spans[0].metrics['_sampling_priority_v1'] == priority | ||
} | ||
|
||
protected hasAppsecPropagationTag(DecodedTrace trace) { | ||
return trace.spans[0].meta['_dd.p.appsec'] == "1" | ||
} | ||
|
||
protected hasApmDisabledTag(DecodedTrace trace) { | ||
return trace.spans[0].metrics['_dd.apm.enabled'] == 0 | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
...roovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSamplingSmokeTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package datadog.smoketest.asmstandalonebilling | ||
|
||
import datadog.trace.api.sampling.PrioritySampling | ||
import okhttp3.Request | ||
|
||
class AsmStandaloneBillingSamplingSmokeTest extends AbstractAsmStandaloneBillingSmokeTest { | ||
|
||
@Override | ||
ProcessBuilder createProcessBuilder(){ | ||
final String[] processProperties = [ | ||
"-Ddd.experimental.appsec.standalone.enabled=true", | ||
"-Ddd.iast.enabled=true", | ||
"-Ddd.iast.detection.mode=FULL", | ||
"-Ddd.iast.debug.enabled=true", | ||
"-Ddd.service.name=asm-standalone-billing-sampling-spring-smoketest-app", | ||
] | ||
return createProcess(processProperties) | ||
} | ||
|
||
void 'test force keep call using time sampling'() { | ||
setup: | ||
final vulnerableUrl = "http://localhost:${httpPorts[0]}/rest-api/iast?injection=xss" | ||
final vulnerableRequest = new Request.Builder().url(vulnerableUrl).get().build() | ||
final forceKeepUrl = "http://localhost:${httpPorts[0]}/rest-api/greetings?forceKeep=true" | ||
final forceKeepRequest = new Request.Builder().url(forceKeepUrl).get().build() | ||
final noForceKeepUrl = "http://localhost:${httpPorts[0]}/rest-api/greetings" | ||
final noForceKeepRequest = new Request.Builder().url(noForceKeepUrl).get().build() | ||
|
||
when: "firs request with ASM events" | ||
final vulnerableResponse = client.newCall(vulnerableRequest).execute() | ||
|
||
then: "First trace should have a root span with USER_KEEP sampling priority due to ASM events" | ||
vulnerableResponse.successful | ||
waitForTraceCount(1) | ||
assert traces.size() == 1 | ||
checkRootSpanPrioritySampling(traces[0], PrioritySampling.USER_KEEP) | ||
hasAppsecPropagationTag(traces[0]) | ||
|
||
when: "Request without ASM events and no force kept span" | ||
final noForceKeepResponse = client.newCall(noForceKeepRequest).execute() | ||
|
||
then: "This trace should enter into the sampling mechanism and have a root span with SAMPLER_KEEP sampling priority as it's the first span checked in a minute" | ||
noForceKeepResponse.successful | ||
waitForTraceCount(2) | ||
assert traces.size() == 2 | ||
checkRootSpanPrioritySampling(traces[1], PrioritySampling.SAMPLER_KEEP) | ||
!hasAppsecPropagationTag(traces[1]) | ||
|
||
when: "Request without ASM events and force kept span" | ||
final forceKeepResponse = client.newCall(forceKeepRequest).execute() | ||
|
||
then: "This trace should have a root span with USER_KEEP sampling priority as although it's not the first span checked in a minute, it's force kept'" | ||
forceKeepResponse.successful | ||
waitForTraceCount(3) | ||
assert traces.size() == 3 | ||
checkRootSpanPrioritySampling(traces[2], PrioritySampling.USER_KEEP) | ||
!hasAppsecPropagationTag(traces[2]) | ||
|
||
when: "Second request without ASM events and no force kept span" | ||
final noForceKeepResponse2 = client.newCall(noForceKeepRequest).execute() | ||
|
||
then: "This trace should enter into the sampling mechanism and have a root span with SAMPLER_DROP sampling priority as it's not the first span checked in a minute" | ||
noForceKeepResponse2.successful | ||
waitForTraceCount(4) | ||
assert traces.size() == 4 | ||
checkRootSpanPrioritySampling(traces[3], PrioritySampling.SAMPLER_DROP) | ||
!hasAppsecPropagationTag(traces[3]) | ||
} | ||
} |
Oops, something went wrong.