Skip to content

Commit 20ccb52

Browse files
authored
Merge pull request github#4299 from torque59/play-framework
Initial support for Java - Play Framework > 2.6.x
2 parents 8d29207 + a35f6d0 commit 20ccb52

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2378
-1
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added support for the Play framework core library (`play.mvc.*`); adding additional remote flow sources.

java/ql/src/semmle/code/java/dataflow/FlowSources.qll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import semmle.code.java.frameworks.JaxWS
1818
import semmle.code.java.frameworks.javase.WebSocket
1919
import semmle.code.java.frameworks.android.Android
2020
import semmle.code.java.frameworks.android.Intent
21+
import semmle.code.java.frameworks.play.Play
2122
import semmle.code.java.frameworks.spring.SpringWeb
2223
import semmle.code.java.frameworks.spring.SpringController
2324
import semmle.code.java.frameworks.spring.SpringWebClient
@@ -129,6 +130,12 @@ private class SpringMultipartRequestSource extends RemoteFlowSource {
129130
override string getSourceType() { result = "Spring MultipartRequest getter" }
130131
}
131132

133+
private class PlayParameterSource extends RemoteFlowSource {
134+
PlayParameterSource() { exists(PlayActionMethodQueryParameter p | p = this.asParameter()) }
135+
136+
override string getSourceType() { result = "Play Query Parameters" }
137+
}
138+
132139
private class SpringMultipartFileSource extends RemoteFlowSource {
133140
SpringMultipartFileSource() {
134141
exists(MethodAccess ma, Method m |
@@ -264,6 +271,7 @@ private class RemoteTaintedMethod extends Method {
264271
this instanceof HttpServletRequestGetRequestURIMethod or
265272
this instanceof HttpServletRequestGetRequestURLMethod or
266273
this instanceof HttpServletRequestGetRemoteUserMethod or
274+
this instanceof PlayRequestGetMethod or
267275
this instanceof SpringWebRequestGetMethod or
268276
this instanceof SpringRestTemplateResponseEntityMethod or
269277
this instanceof ServletRequestGetBodyMethod or
@@ -283,6 +291,13 @@ private class RemoteTaintedMethod extends Method {
283291
}
284292
}
285293

294+
private class PlayRequestGetMethod extends Method {
295+
PlayRequestGetMethod() {
296+
this.getDeclaringType() instanceof PlayMvcHttpRequestHeader and
297+
this.hasName(["queryString", "getQueryString", "header", "getHeader"])
298+
}
299+
}
300+
286301
private class SpringWebRequestGetMethod extends Method {
287302
SpringWebRequestGetMethod() {
288303
exists(SpringWebRequest swr | this = swr.getAMethod() |
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/**
2+
* Provides classes and predicates for working with the Play framework.
3+
*/
4+
5+
import java
6+
7+
/**
8+
* The `play.mvc.Result` class.
9+
*/
10+
class PlayMvcResultClass extends Class {
11+
PlayMvcResultClass() { this.hasQualifiedName("play.mvc", "Result") }
12+
}
13+
14+
/**
15+
* The `play.mvc.Results` class.
16+
*/
17+
class PlayMvcResultsClass extends Class {
18+
PlayMvcResultsClass() { this.hasQualifiedName("play.mvc", "Results") }
19+
}
20+
21+
/**
22+
* The `play.mvc.Http$RequestHeader` class.
23+
*/
24+
class PlayMvcHttpRequestHeader extends RefType {
25+
PlayMvcHttpRequestHeader() { this.hasQualifiedName("play.mvc", "Http$RequestHeader") }
26+
}
27+
28+
/**
29+
* A `play.mvc.BodyParser<>$Of` annotation.
30+
*/
31+
class PlayBodyParserAnnotation extends Annotation {
32+
PlayBodyParserAnnotation() { this.getType().hasQualifiedName("play.mvc", "BodyParser<>$Of") }
33+
}
34+
35+
/**
36+
* A `play.filters.csrf.AddCSRFToken` annotation.
37+
*/
38+
class PlayAddCsrfTokenAnnotation extends Annotation {
39+
PlayAddCsrfTokenAnnotation() {
40+
this.getType().hasQualifiedName("play.filters.csrf", "AddCSRFToken")
41+
}
42+
}
43+
44+
/**
45+
* The type `play.libs.F.Promise<Result>`.
46+
*/
47+
class PlayAsyncResultPromise extends Member {
48+
PlayAsyncResultPromise() {
49+
exists(Class c |
50+
c.hasQualifiedName("play.libs", "F") and
51+
this = c.getAMember() and
52+
this.getQualifiedName() = "F.Promise<Result>"
53+
)
54+
}
55+
}
56+
57+
/**
58+
* The type `java.util.concurrent.CompletionStage<Result>`.
59+
*/
60+
class PlayAsyncResultCompletionStage extends Type {
61+
PlayAsyncResultCompletionStage() {
62+
this.hasName("CompletionStage<Result>") and
63+
this.getCompilationUnit().getPackage().hasName("java.util.concurrent")
64+
}
65+
}
66+
67+
/**
68+
* The class `play.mvc.Controller` or a class that transitively extends it.
69+
*/
70+
class PlayController extends Class {
71+
PlayController() {
72+
this.extendsOrImplements*(any(Class t | t.hasQualifiedName("play.mvc", "Controller")))
73+
}
74+
}
75+
76+
/**
77+
* A Play framework controller action method. These are mappings to route files.
78+
*
79+
* Sample Route - `POST /login @com.company.Application.login()`.
80+
*
81+
* Example - class gets `index` and `login` as valid action methods.
82+
* ```java
83+
* public class Application extends Controller {
84+
* public Result index(String username, String password) {
85+
* return ok("It works!");
86+
* }
87+
*
88+
* public Result login() {
89+
* return ok("Log me In!");
90+
* }
91+
* }
92+
* ```
93+
*/
94+
class PlayControllerActionMethod extends Method {
95+
PlayControllerActionMethod() {
96+
this = any(PlayController c).getAMethod() and
97+
(
98+
this.getReturnType() instanceof PlayAsyncResultPromise or
99+
this.getReturnType() instanceof PlayMvcResultClass or
100+
this.getReturnType() instanceof PlayAsyncResultCompletionStage
101+
)
102+
}
103+
}
104+
105+
/**
106+
* A Play framework action method parameter. These are a source of user input.
107+
*
108+
* Example - `username` and `password` are action method parameters.
109+
* ```java
110+
* public class Application extends Controller {
111+
* public Result index(String username, String password) {
112+
* return ok("It works!");
113+
* }
114+
* }
115+
* ```
116+
*/
117+
class PlayActionMethodQueryParameter extends Parameter {
118+
PlayActionMethodQueryParameter() {
119+
exists(PlayControllerActionMethod a |
120+
a.isPublic() and
121+
this = a.getAParameter()
122+
)
123+
}
124+
}
125+
126+
/**
127+
* A PlayFramework HttpRequestHeader method, some of these are `headers`, `getQueryString`, `getHeader`.
128+
*/
129+
class PlayMvcHttpRequestHeaderMethods extends Method {
130+
PlayMvcHttpRequestHeaderMethods() { this.getDeclaringType() instanceof PlayMvcHttpRequestHeader }
131+
132+
/**
133+
* Gets a reference to the `getQueryString` method.
134+
*/
135+
MethodAccess getAQueryStringAccess() {
136+
this.hasName("getQueryString") and result = this.getAReference()
137+
}
138+
}
139+
140+
/**
141+
* A PlayFramework results method, some of these are `ok`, `status`, `redirect`.
142+
*/
143+
class PlayMvcResultsMethods extends Method {
144+
PlayMvcResultsMethods() { this.getDeclaringType() instanceof PlayMvcResultsClass }
145+
146+
/**
147+
* Gets a reference to the `play.mvc.Results.ok` method.
148+
*/
149+
MethodAccess getAnOkAccess() { this.hasName("ok") and result = this.getAReference() }
150+
151+
/**
152+
* Gets a reference to the `play.mvc.Results.redirect` method.
153+
*/
154+
MethodAccess getARedirectAccess() { this.hasName("redirect") and result = this.getAReference() }
155+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import java.util.concurrent.CompletableFuture;
2+
import java.util.concurrent.CompletionStage;
3+
import play.filters.csrf.AddCSRFToken;
4+
import play.libs.F;
5+
import play.mvc.BodyParser;
6+
import play.mvc.Controller;
7+
import play.mvc.Http.*;
8+
import play.mvc.Result;
9+
10+
public class PlayResource extends Controller {
11+
12+
@AddCSRFToken
13+
public Result index() {
14+
response().setHeader("X-Play-QL", "1");
15+
return ok("It works!");
16+
}
17+
18+
@BodyParser.Of()
19+
public Result session_redirect_me(String uri) {
20+
String url = request().getQueryString("url");
21+
return redirect(url);
22+
}
23+
24+
public F.Promise<Result> async_promise(String token) {
25+
return F.Promise.pure(ok(token));
26+
}
27+
28+
public CompletionStage<Result> async_completionstage(String uri) {
29+
return CompletableFuture.completedFuture(ok("Async completion Stage"));
30+
}
31+
32+
public String not_playactionmethod(String no_action) {
33+
String return_code = no_action;
34+
return return_code;
35+
}
36+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/google-android-9.0.0
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.10:${testdir}/../../../stubs/akka-2.6.x

java/ql/test/library-tests/dataflow/taintsources/remote.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
| IntentSources.java:33:20:33:33 | getIntent(...) | IntentSources.java:33:20:33:33 | getIntent(...) |
2424
| IntentSources.java:33:20:33:33 | getIntent(...) | IntentSources.java:33:20:33:55 | getStringExtra(...) |
2525
| IntentSources.java:33:20:33:33 | getIntent(...) | IntentSources.java:34:29:34:35 | trouble |
26+
| PlayResource.java:19:37:19:46 | uri | PlayResource.java:19:37:19:46 | uri |
27+
| PlayResource.java:20:18:20:48 | getQueryString(...) | ../../../stubs/playframework-2.6.x/play/mvc/Results.java:634:33:634:42 | url |
28+
| PlayResource.java:20:18:20:48 | getQueryString(...) | PlayResource.java:20:18:20:48 | getQueryString(...) |
29+
| PlayResource.java:20:18:20:48 | getQueryString(...) | PlayResource.java:21:21:21:23 | url |
30+
| PlayResource.java:24:42:24:53 | token | ../../../stubs/playframework-2.6.x/play/mvc/Results.java:94:27:94:40 | content |
31+
| PlayResource.java:24:42:24:53 | token | PlayResource.java:24:42:24:53 | token |
32+
| PlayResource.java:24:42:24:53 | token | PlayResource.java:25:30:25:34 | token |
33+
| PlayResource.java:28:56:28:65 | uri | PlayResource.java:28:56:28:65 | uri |
2634
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:4:30:4:40 | path |
2735
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:20:5:31 | ... + ... |
2836
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:28:5:31 | path |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| resources/Resource.java:19:37:19:46 | uri |
2+
| resources/Resource.java:24:42:24:53 | token |
3+
| resources/Resource.java:28:56:28:65 | uri |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import semmle.code.java.frameworks.play.Play
2+
3+
from PlayActionMethodQueryParameter p
4+
select p
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| resources/Resource.java:12:3:12:15 | AddCSRFToken |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import semmle.code.java.frameworks.play.Play
2+
3+
from PlayAddCsrfTokenAnnotation token
4+
select token

0 commit comments

Comments
 (0)