Skip to content

Commit 84a6aa5

Browse files
committed
WIP
1 parent 46d0949 commit 84a6aa5

File tree

5 files changed

+168
-0
lines changed

5 files changed

+168
-0
lines changed

dd-smoke-tests/resteasy/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies {
1616
implementation group: 'org.jboss.resteasy', name: 'resteasy-undertow', version:'3.1.0.Final'
1717
implementation group: 'org.jboss.resteasy', name: 'resteasy-cdi', version:'3.1.0.Final'
1818
implementation group: 'org.jboss.weld.servlet', name: 'weld-servlet', version: '2.4.8.Final'
19+
implementation 'org.jboss.resteasy:resteasy-jackson2-provider:3.1.0.Final'
1920

2021
implementation group: 'javax.el', name: 'javax.el-api', version:'3.0.0'
2122

@@ -24,6 +25,7 @@ dependencies {
2425

2526
testImplementation project(':dd-smoke-tests')
2627
testImplementation(testFixtures(project(":dd-smoke-tests:iast-util")))
28+
testImplementation project(':dd-smoke-tests:appsec')
2729
}
2830

2931
tasks.withType(Test).configureEach {

dd-smoke-tests/resteasy/src/main/java/smoketest/resteasy/App.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package smoketest.resteasy;
22

3+
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
34
import java.util.HashSet;
45
import java.util.Set;
56
import javax.ws.rs.core.Application;
7+
import org.jboss.resteasy.plugins.providers.StringTextStar;
68

79
public class App extends Application {
810

911
private Set<Object> singletons = new HashSet<Object>();
1012

1113
public App() {
1214
singletons.add(new Resource());
15+
singletons.add(new StringTextStar()); // Writer for String
16+
singletons.add(new JacksonJsonProvider()); // Writer for json
1317
}
1418

1519
@Override
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package smoketest.resteasy;
2+
3+
import java.util.List;
4+
5+
public class RequestBody {
6+
private List<KeyValue> main;
7+
private Object nullable;
8+
9+
public List<KeyValue> getMain() {
10+
return main;
11+
}
12+
13+
public void setMain(List<KeyValue> main) {
14+
this.main = main;
15+
}
16+
17+
public Object getNullable() {
18+
return nullable;
19+
}
20+
21+
public void setNullable(Object nullable) {
22+
this.nullable = nullable;
23+
}
24+
25+
public static class KeyValue {
26+
private String key;
27+
private Double value;
28+
29+
public String getKey() {
30+
return key;
31+
}
32+
33+
public void setKey(String key) {
34+
this.key = key;
35+
}
36+
37+
public Double getValue() {
38+
return value;
39+
}
40+
41+
public void setValue(Double value) {
42+
this.value = value;
43+
}
44+
}
45+
}

dd-smoke-tests/resteasy/src/main/java/smoketest/resteasy/Resource.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import java.util.List;
77
import java.util.Set;
88
import java.util.SortedSet;
9+
import javax.ws.rs.Consumes;
910
import javax.ws.rs.CookieParam;
1011
import javax.ws.rs.GET;
1112
import javax.ws.rs.HeaderParam;
13+
import javax.ws.rs.POST;
1214
import javax.ws.rs.Path;
1315
import javax.ws.rs.PathParam;
1416
import javax.ws.rs.Produces;
@@ -94,4 +96,18 @@ public Response responseLocation(@QueryParam("param") String param) throws URISy
9496
public Response getCookie() throws SQLException {
9597
return Response.ok().cookie(new NewCookie("user-id", "7")).build();
9698
}
99+
100+
@Path("/api_security/response")
101+
@POST
102+
@Produces(MediaType.APPLICATION_JSON)
103+
@Consumes(MediaType.APPLICATION_JSON)
104+
public Response bodyJson(RequestBody input) {
105+
return Response.ok(input).build();
106+
}
107+
108+
@GET
109+
@Path("/api_security/sampling/{i}")
110+
public Response apiSecuritySamplingWithStatus(@PathParam("i") int i) {
111+
return Response.status(i).header("content-type", "text/plain").entity("Hello!\n").build();
112+
}
97113
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package smoketest
2+
3+
import datadog.smoketest.appsec.AbstractAppSecServerSmokeTest
4+
import datadog.trace.agent.test.utils.OkHttpUtils
5+
import datadog.trace.api.Platform
6+
import groovy.json.JsonOutput
7+
import groovy.json.JsonSlurper
8+
import okhttp3.MediaType
9+
import okhttp3.Request
10+
import okhttp3.RequestBody
11+
import okhttp3.Response
12+
import spock.lang.IgnoreIf
13+
14+
import java.util.zip.GZIPInputStream
15+
16+
@IgnoreIf({
17+
System.getProperty("java.vendor").contains("IBM") && System.getProperty("java.version").contains("1.8.")
18+
})
19+
class ResteasyAppsecSmokeTest extends AbstractAppSecServerSmokeTest {
20+
21+
@Override
22+
ProcessBuilder createProcessBuilder() {
23+
String jarPath = System.getProperty("datadog.smoketest.resteasy.jar.path")
24+
25+
List<String> command = new ArrayList<>()
26+
command.add(javaPath())
27+
command.addAll(defaultJavaProperties)
28+
command.addAll(defaultAppSecProperties)
29+
if (Platform.isJavaVersionAtLeast(17)) {
30+
command.addAll(["--add-opens", "java.base/java.lang=ALL-UNNAMED"])
31+
}
32+
command.addAll(["-jar", jarPath, Integer.toString(httpPort)])
33+
ProcessBuilder processBuilder = new ProcessBuilder(command)
34+
processBuilder.directory(new File(buildDirectory))
35+
}
36+
37+
void 'API Security samples only one request per endpoint'() {
38+
given:
39+
def url = "http://localhost:${httpPort}/hello/api_security/sampling/200?test=value"
40+
def request = new Request.Builder()
41+
.url(url)
42+
.addHeader('X-My-Header', "value")
43+
.get()
44+
.build()
45+
46+
when:
47+
List<Response> responses = (1..3).collect {
48+
client.newCall(request).execute()
49+
}
50+
51+
then:
52+
responses.each {
53+
assert it.code() == 200
54+
}
55+
waitForTraceCount(3)
56+
def spans = rootSpans.toList().toSorted { it.span.duration }
57+
spans.size() == 3
58+
def sampledSpans = spans.findAll {
59+
it.meta.keySet().any {
60+
it.startsWith('_dd.appsec.s.req.')
61+
}
62+
}
63+
sampledSpans.size() == 1
64+
def span = sampledSpans[0]
65+
span.meta.containsKey('_dd.appsec.s.req.query')
66+
span.meta.containsKey('_dd.appsec.s.req.params')
67+
span.meta.containsKey('_dd.appsec.s.req.headers')
68+
}
69+
70+
71+
void 'test response schema extraction'() {
72+
given:
73+
def url = "http://localhost:${httpPort}/hello/api_security/response"
74+
def client = OkHttpUtils.clientBuilder().build()
75+
def body = [
76+
"main" : [["key": "id001", "value": 1345.67], ["value": 1567.89, "key": "id002"]],
77+
"nullable": null,
78+
]
79+
def request = new Request.Builder()
80+
.url(url)
81+
.post(RequestBody.create(MediaType.get('application/json'), JsonOutput.toJson(body)))
82+
.build()
83+
84+
when:
85+
final response = client.newCall(request).execute()
86+
waitForTraceCount(1)
87+
88+
then:
89+
response.code() == 200
90+
def span = rootSpans.first()
91+
span.meta.containsKey('_dd.appsec.s.res.headers')
92+
span.meta.containsKey('_dd.appsec.s.res.body')
93+
final schema = new JsonSlurper().parse(unzip(span.meta.get('_dd.appsec.s.res.body')))
94+
assert schema == [["main": [[[["key": [8], "value": [16]]]], ["len": 2]], "nullable": [1]]]
95+
}
96+
97+
private static byte[] unzip(final String text) {
98+
final inflaterStream = new GZIPInputStream(new ByteArrayInputStream(text.decodeBase64()))
99+
return inflaterStream.getBytes()
100+
}
101+
}

0 commit comments

Comments
 (0)