Initial support for Play Framework > 2.6.x

This commit is contained in:
Francis Alexander
2020-09-18 16:54:11 +05:30
parent 7544bc872a
commit ddc544aa07
40 changed files with 4683 additions and 1 deletions

View File

@@ -17,6 +17,8 @@ import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.javase.WebSocket
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.frameworks.play.PlayController
import semmle.code.java.frameworks.play.PlayHTTPRequestHeader
import semmle.code.java.frameworks.spring.SpringWeb
import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.frameworks.spring.SpringWebClient
@@ -122,6 +124,18 @@ private class SpringMultipartRequestSource extends RemoteFlowSource {
override string getSourceType() { result = "Spring MultipartRequest getter" }
}
class PlayParameterSource extends RemoteFlowSource {
PlayParameterSource() {
exists(PlayActionQueryParameter p | p = this.asParameter())
or
exists(PlayHTTPRequestHeaderMethods m |
m.hasName("getQueryString") and m.getAParameter() = this.asParameter()
)
}
override string getSourceType() { result = "Play Query Parameters" }
}
private class SpringMultipartFileSource extends RemoteFlowSource {
SpringMultipartFileSource() {
exists(MethodAccess ma, Method m |
@@ -245,6 +259,7 @@ private class RemoteTaintedMethod extends Method {
this instanceof HttpServletRequestGetRequestURIMethod or
this instanceof HttpServletRequestGetRequestURLMethod or
this instanceof HttpServletRequestGetRemoteUserMethod or
this instanceof PlayRequestGetMethod or
this instanceof SpringWebRequestGetMethod or
this instanceof SpringRestTemplateResponseEntityMethod or
this instanceof ServletRequestGetBodyMethod or
@@ -264,6 +279,13 @@ private class RemoteTaintedMethod extends Method {
}
}
private class PlayRequestGetMethod extends PlayHTTPRequestHeaderMethods {
PlayRequestGetMethod() {
this.hasName("Header") or
this.hasName("getQueryString")
}
}
private class SpringWebRequestGetMethod extends Method {
SpringWebRequestGetMethod() {
exists(SpringWebRequest swr | this = swr.getAMethod() |

View File

@@ -0,0 +1,9 @@
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.play.PlayController
import semmle.code.java.frameworks.play.PlayAddCSRFToken
import semmle.code.java.frameworks.play.PlayAsyncResult
import semmle.code.java.frameworks.play.PlayBodyParser
import semmle.code.java.frameworks.play.PlayHTTPRequestHeader
import semmle.code.java.frameworks.play.PlayMVCResult
import semmle.code.java.frameworks.play.PlayMVCResults

View File

@@ -0,0 +1,13 @@
import java
/**
* Play Framework AddCSRFToken
*
* @description Gets the methods using AddCSRFToken annotation.
* (https://www.playframework.com/documentation/2.6.x/JavaBodyParsers#Choosing-an-explicit-body-parser)
*/
class PlayAddCSRFTokenAnnotation extends Annotation {
PlayAddCSRFTokenAnnotation() {
this.getType().hasQualifiedName("play.filters.csrf", "AddCSRFToken")
}
}

View File

@@ -0,0 +1,30 @@
import java
/**
* Play Framework Async Promise of Generic Result
*
* @description Gets the Promise<Result> Generic Type of (play.libs.F), This is async in 2.6x and below.
* (https://www.playframework.com/documentation/2.5.1/api/java/play/libs/F.Promise.html)
*/
class PlayAsyncResultPromise extends Member {
PlayAsyncResultPromise() {
exists(Class c |
c.hasQualifiedName("play.libs", "F") and
this = c.getAMember() and
this.getQualifiedName() = "F.Promise<Result>"
)
}
}
/**
* Play Framework Async Generic Result extending generic promise API called CompletionStage.
*
* @description Gets the CompletionStage<Result> Generic Type of (java.util.concurrent)
* (https://www.playframework.com/documentation/2.6.x/JavaAsync)
*/
class PlayAsyncResultCompletionStage extends Type {
PlayAsyncResultCompletionStage() {
this.hasName("CompletionStage<Result>") and
this.getCompilationUnit().getPackage().hasName("java.util.concurrent")
}
}

View File

@@ -0,0 +1,11 @@
import java
/**
* Play Framework Explicit Body Parser
*
* @description Gets the methods using the explicit body parser annotation. The methods are usually controller action methods
* (https://www.playframework.com/documentation/2.8.x/JavaBodyParsers#Choosing-an-explicit-body-parser)
*/
class PlayBodyParserAnnotation extends Annotation {
PlayBodyParserAnnotation() { this.getType().hasQualifiedName("play.mvc", "BodyParser<>$Of") }
}

View File

@@ -0,0 +1,55 @@
import java
import semmle.code.java.frameworks.play.PlayAsyncResult
import semmle.code.java.frameworks.play.PlayMVCResult
/**
* Play MVC Framework Controller
*
* @description Gets the play.mvc.Controller class
*/
class PlayMVCControllerClass extends Class {
PlayMVCControllerClass() { this.hasQualifiedName("play.mvc", "Controller") }
}
/**
* Play Framework Controller which extends/implements
*
* @description Gets the classes which extends play.mvc.controller rescursively.
*/
class PlayController extends Class {
PlayController() {
exists(Class t | this.extendsOrImplements*(t) and t instanceof PlayMVCControllerClass)
}
}
/**
* Play Framework Controller Action Methods
*
* @description Gets the controller action methods defined against it.
* (https://www.playframework.com/documentation/2.8.x/JavaActions)
* @tip Checking for Public methods usually retrieves direct controller mapped methods defined in routes.
*/
class PlayControllerActionMethod extends Method {
PlayControllerActionMethod() {
exists(PlayController controller |
this = controller.getAMethod() and
(
this.getReturnType() instanceof PlayAsyncResultPromise or
this.getReturnType() instanceof PlayMVCResult or
this.getReturnType() instanceof PlayAsyncResultCompletionStage
)
)
}
}
/**
* Play Action-Method parameters, these are essentially part of routes.
*/
class PlayActionQueryParameter extends Parameter {
PlayActionQueryParameter() {
exists(PlayControllerActionMethod a |
a.isPublic() and
this = a.getAParameter()
)
}
}

View File

@@ -0,0 +1,20 @@
import java
/**
* Play MVC Framework HTTP Request Header
*
* @description Member of play.mvc.HTTP. Gets the play.mvc.HTTP$RequestHeader class/interface
*/
class PlayMVCHTTPRequestHeader extends RefType {
PlayMVCHTTPRequestHeader() { this.hasQualifiedName("play.mvc", "Http$RequestHeader") }
}
/**
* Play Framework HTTP$RequestHeader Methods
*
* @description Gets the methods of play.mvc.HTTP$RequestHeader like - headers, getQueryString, getHeader, uri
* (https://www.playframework.com/documentation/2.6.0/api/java/play/mvc/Http.RequestHeader.html)
*/
class PlayHTTPRequestHeaderMethods extends Method {
PlayHTTPRequestHeaderMethods() { this.getDeclaringType() instanceof PlayMVCHTTPRequestHeader }
}

View File

@@ -0,0 +1,11 @@
import java
/**
* Play MVC Framework Result
*
* @description Gets the play.mvc.Result class - Used to set a HTTP result with a status code, a set of HTTP headers and a body to be sent to the web client.
* (https://www.playframework.com/documentation/2.8.x/JavaActions)
*/
class PlayMVCResult extends Class {
PlayMVCResult() { this.hasQualifiedName("play.mvc", "Result") }
}

View File

@@ -0,0 +1,35 @@
import java
/**
* Play MVC Framework Results
*
* @description Gets the play.mvc.Results class - Helper utilities to generate results
* (https://www.playframework.com/documentation/2.8.x/JavaActions)
*/
class PlayMVCResults extends Class {
PlayMVCResults() { this.hasQualifiedName("play.mvc", "Results") }
}
/**
* Play Framework mvc.Results Methods
*
* @description Gets the methods of play.mvc.Results like - ok, status, redirect etc.
* (https://www.playframework.com/documentation/2.5.8/api/java/play/mvc/Results.html)
*/
class PlayHTTPResultsMethods extends Method {
PlayHTTPResultsMethods() { this.getDeclaringType() instanceof PlayMVCResults }
/**
* Gets all references to play.mvc.Results ok method
*/
MethodAccess ok() {
exists(MethodAccess ma | ma = this.getAReference() and this.hasName("ok") | result = ma)
}
/**
* Gets all references to play.mvc.Results redirect method
*/
MethodAccess redirect() {
exists(MethodAccess ma | ma = this.getAReference() and this.hasName("redirect") | result = ma)
}
}

View File

@@ -0,0 +1,14 @@
import play.mvc.Controller;
import play.mvc.Result;
import play.filters.csrf.AddCSRFToken;
import java.util.concurrent.CompletionStage;
public class PlayResource extends Controller {
@AddCSRFToken
public Result play_index(String username, String password) {
String append_token = "password" + password;
ok("Working");
}
}

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.2.3
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.10:${testdir}/../../../stubs/akka-2.6.x

View File

@@ -5,6 +5,10 @@
| A.java:41:5:41:53 | getInputStream(...) | A.java:41:5:41:53 | getInputStream(...) |
| A.java:42:5:42:45 | getInputStream(...) | A.java:42:5:42:45 | getInputStream(...) |
| A.java:43:5:43:47 | getHostName(...) | A.java:43:5:43:47 | getHostName(...) |
| PlayResource.java:10:30:10:44 | username | PlayResource.java:10:30:10:44 | username |
| PlayResource.java:10:47:10:61 | password | PlayResource.java:10:47:10:61 | password |
| PlayResource.java:10:47:10:61 | password | PlayResource.java:11:31:11:51 | ... + ... |
| PlayResource.java:10:47:10:61 | password | PlayResource.java:11:44:11:51 | password |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:4:30:4:40 | path |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:20:5:31 | ... + ... |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:28:5:31 | path |

View File

@@ -0,0 +1,6 @@
package akka.util;
/** XML utilities. */
public class ByteString {
}

View File

@@ -0,0 +1,3 @@
package com.fasterxml.jackson.core;
public class JsonEncoding {}

View File

@@ -0,0 +1,6 @@
package com.fasterxml.jackson.databind;
public class JsonNode {
public JsonNode() {
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2009-2016 Lightbend Inc. <https://www.lightbend.com>
*/
package play;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
//import play.inject.Injector; -> Scala stuff
//import play.libs.Scala;
/**
* A Play application.
*
* Application creation is handled by the framework engine.
*/
public interface Application {
/**
* Get the underlying Scala application.
*
* @
*/
//play.api.Application getWrappedApplication();
/**
* Get the application configuration.
*
* @
*/
//Configuration configuration();
/**
* Get the injector for this application.
*
* @
*/
//Injector injector();
/**
* Get the application path.
*
* @
*/
default File path() {
}
/**
* Get the application classloader.
*
* @
*/
default ClassLoader classloader() {
}
/**
* Get a file relative to the application root path.
*
* @param relativePath relative path of the file to fetch
* @
*/
default File getFile(String relativePath) {
}
/**
* Get a resource from the classpath.
*
* @param relativePath relative path of the resource to fetch
* @
*/
default URL resource(String relativePath) {
}
/**
* Get a resource stream from the classpath.
*
* @param relativePath relative path of the resource to fetch
* @
*/
default InputStream resourceAsStream(String relativePath) {
}
}

View File

@@ -0,0 +1,20 @@
package play;
/**
* High-level API to access Play global features.
*
* @deprecated Please use dependency injection. Deprecated since 2.5.0.
*/
@Deprecated
public class Play {
/**
* @deprecated inject the {@link play.Application} instead. Deprecated since 2.5.0.
* @return Deprecated
*/
@Deprecated
public static Application application() {
}
//private static play.api.Application privateCurrent() { }
}

View File

@@ -0,0 +1,6 @@
package play.api.mvc;
/** Scala dummy */
public class Request<RequestBody> {
}

View File

@@ -0,0 +1,6 @@
package play.api.mvc;
/** Scala dummy */
public class RequestHeader {
}

View File

@@ -0,0 +1,6 @@
package play.api.mvc;
/** XML utilities. */
public class StatusHeader {
}

View File

@@ -0,0 +1,6 @@
package play.core.j;
/** XML utilities. */
public class JavaContextComponents {
}

View File

@@ -0,0 +1,6 @@
package play.core.j;
/** Scala dummy */
public class RequestImpl {
}

View File

@@ -0,0 +1,11 @@
package play.filters.csrf;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** This action adds a CSRF token to the request and response if not already there. */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface AddCSRFToken {}

View File

@@ -0,0 +1,6 @@
package play.http;
/** XML utilities. */
public abstract class HttpEntity {
}

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.i18n;
import java.util.*;
import java.util.stream.Stream;
//import play.Application;
//import play.libs.*;
//import scala.collection.immutable.Seq;
import static java.util.stream.Collectors.toList;
/** A Lang supported by the application. */
public class Lang /* extends play.api.i18n.Lang */ {
}

View File

@@ -0,0 +1,5 @@
package play.i18n;
/** A Lang supported by the application. */
public class Langs {
}

View File

@@ -0,0 +1,13 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.i18n;
/**
* A Messages will produce messages using a specific language.
*
* <p>This interface that is typically backed by MessagesImpl, but does not return MessagesApi.
*/
public interface Messages {
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.i18n;
//import javax.inject.Singleton;
/**
* A Messages will produce messages using a specific language.
*
* <p>This interface that is typically backed by MessagesImpl, but does not return MessagesApi.
*/
//@Singleton
public class MessagesApi {
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.libs;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Supplier;
//import scala.concurrent.ExecutionContext;
/** Defines a set of functional programming style helpers. */
public class F {
public static class Promise<A> { } // this is needed for play.libs.F for Play 2.3.x
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.libs;
//import javax.inject.Inject;
import java.io.File;
import java.nio.file.Path;
/** Contains TemporaryFile and TemporaryFileCreator operations. */
public final class Files {
/** This creates temporary files when Play needs to keep overflow data on the filesystem. */
public interface TemporaryFileCreator {
TemporaryFile create(String prefix, String suffix);
TemporaryFile create(Path path);
boolean delete(TemporaryFile temporaryFile);
// Needed for RawBuffer compatibility
}
/** A temporary file created by a TemporaryFileCreator. */
public interface TemporaryFile {
/** @return the path to the temporary file. */
Path path();
/**
* @return the temporaryFile as a java.io.File.
* @deprecated Use path() over file().
*/
@Deprecated
File file();
TemporaryFileCreator temporaryFileCreator();
default TemporaryFile moveTo(File to) {
}
TemporaryFile moveTo(File to, boolean replace);
TemporaryFile atomicMoveWithFallback(File to);
}
/** A temporary file creator that delegates to a Scala TemporaryFileCreator. */
public static class DelegateTemporaryFileCreator implements TemporaryFileCreator {
//private final play.api.libs.Files.TemporaryFileCreator temporaryFileCreator;
//@Inject
/* public DelegateTemporaryFileCreator(
play.api.libs.Files.TemporaryFileCreator temporaryFileCreator) {
*///}
public TemporaryFile create(String prefix, String suffix) {
}
public TemporaryFile create(Path path) {
}
public boolean delete(TemporaryFile temporaryFile) {
}
//public play.api.libs.Files.TemporaryFileCreator asScala() {}
}
/** Delegates to the Scala implementation. */
public static class DelegateTemporaryFile implements TemporaryFile {
public Path path() {
}
public File file() {
}
public TemporaryFileCreator temporaryFileCreator() {
}
public TemporaryFile moveTo(File to, boolean replace) {
}
public TemporaryFile atomicMoveWithFallback(File to) {
}
}
/**
* A temporary file creator that uses the Scala play.api.libs.Files.SingletonTemporaryFileCreator
* class behind the scenes.
*/
public static class SingletonTemporaryFileCreator implements TemporaryFileCreator {
public TemporaryFile create(String prefix, String suffix) {
}
public TemporaryFile create(Path path) {
}
public boolean delete(TemporaryFile temporaryFile) {
}
}
private static final TemporaryFileCreator instance = new Files.SingletonTemporaryFileCreator();
/** @return the singleton instance of SingletonTemporaryFileCreator. */
public static TemporaryFileCreator singletonTemporaryFileCreator() {
}
}

View File

@@ -0,0 +1,6 @@
package play.libs;
/** XML utilities. */
public class XML {
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.libs.typedmap;
//import play.api.libs.typedmap.TypedKey$;
/**
* A TypedKey is a key that can be used to get and set values in a {@link TypedMap} or any object
* with typed keys. This class uses reference equality for comparisons, so each new instance is
* different key.
*/
public final class TypedKey<A> {
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.libs.typedmap;
import play.libs.typedmap.TypedKey;
import java.util.Optional;
/**
* A TypedMap is an immutable map containing typed values. Each entry is associated with a {@link
* TypedKey} that can be used to look up the value. A <code>TypedKey</code> also defines the type of
* the value, e.g. a <code>TypedKey&lt;String&gt;</code> would be associated with a <code>String
* </code> value.
*
* <p>Instances of this class are created with the {@link #empty()} method.
*
* <p>The elements inside TypedMaps cannot be enumerated. This is a decision designed to enforce
* modularity. It's not possible to accidentally or intentionally access a value in a TypedMap
* without holding the corresponding {@link TypedKey}.
*/
public final class TypedMap {
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.mvc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A body parser parses the HTTP request body content. */
public interface BodyParser<A> {
/**
* Return an accumulator to parse the body of the given HTTP request.
*
* <p>The accumulator should either produce a result if an error was encountered, or the parsed
* body.
*
* @param request The request to create the body parser for.
* @return The accumulator to parse the body.
*/
/** Specify the body parser to use for an Action method. */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Of {
/**
* The class of the body parser to use.
*
* @return the class
*/
//Class<? extends BodyParser> value();
}
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package play.mvc;
/**
* Any action result.
*/
public class Call {
/**
* Retrieves the real (Scala-based) result.
*/
// play.api.mvc.Result toScala();
}

View File

@@ -0,0 +1,110 @@
package play.mvc;
import play.i18n.Lang;
import play.mvc.Http.HeaderNames;
import play.mvc.Http.Response;
import play.mvc.Http.Context;
import play.mvc.Http.Request;
import play.mvc.Http.Session;
import play.mvc.Http.Status;
import play.mvc.Http.Flash;
/**
* Superclass for a Java-based controller.
*/
public abstract class Controller extends Results implements Status, HeaderNames {
/**
* Returns the current HTTP context.
*/
public static Context ctx() {
}
/**
* Returns the current HTTP request.
*/
public static Request request() {
}
/**
* Returns the current lang.
*/
public static Lang lang() {
}
/**
* Change durably the lang for the current user
* @param code New lang code to use (e.g. "fr", "en-US", etc.)
* @
*/
public static boolean changeLang(String code) {
}
/**
* Change durably the lang for the current user
* @param lang New Lang object to use
* @
*/
public static boolean changeLang(Lang lang) {
}
/**
* Clear the lang for the current user.
*/
public static void clearLang() {
}
/**
* Returns the current HTTP response.
*/
public static Response response() {
}
/**
* Returns the current HTTP session.
*/
public static Session session() {
}
/**
* Puts a new value into the current session.
*/
public static void session(String key, String value) {
}
/**
* Returns a value from the session.
*/
public static String session(String key) {
}
/**
* Returns the current HTTP flash scope.
*/
public static Flash flash() {
}
/**
* Puts a new value into the flash scope.
*/
public static void flash(String key, String value) {
}
/**
* Returns a value from the flash scope.
*/
public static String flash(String key) {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
/*
* Copyright (C) Lightbend Inc. <https://www.lightbend.com>
*/
package play.mvc;
/** Any action result. */
public class Result {
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
/*
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package play.twirl.api;
/**
* Play twirl Content result. (Part of scala)
*/
public class Content {
}