Skip to content

Commit dabf00e

Browse files
committed
Add Tests to Ratpack Framework Support
1 parent f5c3723 commit dabf00e

File tree

33 files changed

+3519
-59
lines changed

33 files changed

+3519
-59
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Provides classes and predicates related to `ratpack.*`.
3+
*/
4+
5+
import java
6+
7+
/**
8+
* Ratpack methods that access user-supplied request data.
9+
*/
10+
abstract class RatpackGetRequestDataMethod extends Method { }
11+
12+
/**
13+
* The interface `ratpack.http.Request`.
14+
* https://ratpack.io/manual/current/api/ratpack/http/Request.html
15+
*/
16+
class RatpackRequest extends RefType {
17+
RatpackRequest() {
18+
hasQualifiedName("ratpack.http", "Request") or
19+
hasQualifiedName("ratpack.core.http", "Request")
20+
}
21+
}
22+
23+
/**
24+
* Methods on `ratpack.http.Request` that return user tainted data.
25+
*/
26+
class RatpackHttpRequestGetMethod extends RatpackGetRequestDataMethod {
27+
RatpackHttpRequestGetMethod() {
28+
getDeclaringType() instanceof RatpackRequest and
29+
hasName([
30+
"getContentLength", "getCookies", "oneCookie", "getHeaders", "getPath", "getQuery",
31+
"getQueryParams", "getRawUri", "getUri"
32+
])
33+
}
34+
}
35+
36+
/**
37+
* The interface `ratpack.http.TypedData`.
38+
* https://ratpack.io/manual/current/api/ratpack/http/TypedData.html
39+
*/
40+
class RatpackTypedData extends RefType {
41+
RatpackTypedData() {
42+
hasQualifiedName("ratpack.http", "TypedData") or
43+
hasQualifiedName("ratpack.core.http", "TypedData")
44+
}
45+
}
46+
47+
/**
48+
* Methods on `ratpack.http.TypedData` that return user tainted data.
49+
*/
50+
class RatpackHttpTypedDataGetMethod extends RatpackGetRequestDataMethod {
51+
RatpackHttpTypedDataGetMethod() {
52+
getDeclaringType() instanceof RatpackTypedData and
53+
hasName(["getBuffer", "getBytes", "getContentType", "getInputStream", "getText"])
54+
}
55+
}
56+
57+
/**
58+
* Methods on `ratpack.http.TypedData` that taint the parameter passed in.
59+
*/
60+
class RatpackHttpTypedDataWriteMethod extends Method {
61+
RatpackHttpTypedDataWriteMethod() {
62+
getDeclaringType() instanceof RatpackTypedData and
63+
hasName("writeTo")
64+
}
65+
}
66+
67+
/**
68+
* The interface `ratpack.form.UploadedFile`.
69+
* https://ratpack.io/manual/current/api/ratpack/form/UploadedFile.html
70+
*/
71+
class RatpackUploadFile extends RefType {
72+
RatpackUploadFile() {
73+
hasQualifiedName("ratpack.form", "UploadedFile") or
74+
hasQualifiedName("ratpack.core.form", "UploadedFile")
75+
}
76+
}
77+
78+
class RatpackUploadFileGetMethod extends RatpackGetRequestDataMethod {
79+
RatpackUploadFileGetMethod() {
80+
getDeclaringType() instanceof RatpackUploadFile and
81+
hasName("getFileName")
82+
}
83+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import java
2+
private import semmle.code.java.dataflow.DataFlow
3+
private import semmle.code.java.dataflow.FlowSteps
4+
5+
/** A reference type that extends a parameterization the Promise type. */
6+
class RatpackPromise extends RefType {
7+
RatpackPromise() {
8+
getSourceDeclaration().getASourceSupertype*().hasQualifiedName("ratpack.exec", "Promise")
9+
}
10+
}
11+
12+
class RatpackPromiseMapMethod extends Method {
13+
RatpackPromiseMapMethod() {
14+
getDeclaringType() instanceof RatpackPromise and
15+
hasName("map")
16+
}
17+
}
18+
19+
class RatpackPromiseMapMethodAccess extends MethodAccess {
20+
RatpackPromiseMapMethodAccess() { getMethod() instanceof RatpackPromiseMapMethod }
21+
}
22+
23+
class RatpackPromiseThenMethod extends Method {
24+
RatpackPromiseThenMethod() {
25+
getDeclaringType() instanceof RatpackPromise and
26+
hasName("then")
27+
}
28+
}
29+
30+
class RatpackPromiseThenMethodAccess extends MethodAccess {
31+
RatpackPromiseThenMethodAccess() { getMethod() instanceof RatpackPromiseThenMethod }
32+
}
33+
34+
private class RatpackPromiseTaintPreservingCallable extends AdditionalTaintStep {
35+
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
36+
stepFromFunctionalExpToPromise(node1, node2) or
37+
stepFromPromiseToFunctionalArgument(node1, node2)
38+
}
39+
40+
/**
41+
* Tracks taint from return from lambda function to the outer `Promise`.
42+
*/
43+
private predicate stepFromFunctionalExpToPromise(DataFlow::Node node1, DataFlow::Node node2) {
44+
exists(FunctionalExpr fe |
45+
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
46+
node2.asExpr().(RatpackPromiseMapMethodAccess).getArgument(0) = fe
47+
)
48+
}
49+
50+
/**
51+
* Tracks taint from the previous `Promise` to the first argument of lambda passed to `map` or `then`.
52+
*/
53+
private predicate stepFromPromiseToFunctionalArgument(DataFlow::Node node1, DataFlow::Node node2) {
54+
exists(RatpackPromiseMapMethodAccess ma |
55+
node1.asExpr() = ma.getQualifier() and
56+
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
57+
)
58+
or
59+
exists(RatpackPromiseThenMethodAccess ma |
60+
node1.asExpr() = ma.getQualifier() and
61+
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
62+
)
63+
}
64+
}

java/ql/src/semmle/code/java/frameworks/ratpack/RatpackHttp.qll

Lines changed: 0 additions & 59 deletions
This file was deleted.

java/ql/test/library-tests/frameworks/ratpack/flow.expected

Whitespace-only changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import java
2+
import semmle.code.java.dataflow.TaintTracking
3+
import semmle.code.java.dataflow.FlowSources
4+
import semmle.code.java.security.XSS
5+
import semmle.code.java.security.UrlRedirect
6+
import TestUtilities.InlineExpectationsTest
7+
8+
class Conf extends TaintTracking::Configuration {
9+
Conf() { this = "qltest:frameworks:ratpack" }
10+
11+
override predicate isSource(DataFlow::Node n) {
12+
n.asExpr().(MethodAccess).getMethod().hasName("taint")
13+
or
14+
n instanceof RemoteFlowSource
15+
}
16+
17+
override predicate isSink(DataFlow::Node n) {
18+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
19+
}
20+
}
21+
22+
class HasFlowTest extends InlineExpectationsTest {
23+
HasFlowTest() { this = "HasFlowTest" }
24+
25+
override string getARelevantTag() { result = "hasTaintFlow" }
26+
27+
override predicate hasActualResult(Location location, string element, string tag, string value) {
28+
tag = "hasTaintFlow" and
29+
exists(DataFlow::Node src, DataFlow::Node sink, Conf conf | conf.hasFlow(src, sink) |
30+
sink.getLocation() = location and
31+
element = sink.toString() and
32+
value = ""
33+
)
34+
}
35+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/ratpack-1.9.x:${testdir}/../../../stubs/jackson-databind-2.10:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/netty-4.1.x
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import ratpack.core.handling.Context;
2+
import ratpack.core.http.TypedData;
3+
4+
class Resource {
5+
6+
void sink(Object o) {}
7+
8+
void test1(Context ctx) {
9+
sink(ctx.getRequest().getContentLength()); //$hasTaintFlow
10+
sink(ctx.getRequest().getCookies()); //$hasTaintFlow
11+
sink(ctx.getRequest().oneCookie("Magic-Cookie")); //$hasTaintFlow
12+
sink(ctx.getRequest().getHeaders()); //$hasTaintFlow
13+
sink(ctx.getRequest().getPath()); //$hasTaintFlow
14+
sink(ctx.getRequest().getQuery()); //$hasTaintFlow
15+
sink(ctx.getRequest().getQueryParams()); //$hasTaintFlow
16+
sink(ctx.getRequest().getRawUri()); //$hasTaintFlow
17+
sink(ctx.getRequest().getUri()); //$hasTaintFlow
18+
}
19+
20+
void test2(TypedData td) {
21+
sink(td.getText()); //$hasTaintFlow
22+
}
23+
24+
void test2(Context ctx) {
25+
ctx.getRequest().getBody().map(TypedData::getText).then(this::sink); //$hasTaintFlow
26+
}
27+
}

java/ql/test/stubs/guava-30.0/com/google/common/reflect/TypeToken.java

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)