diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/FlowUtils.qll b/java/ql/src/experimental/Security/CWE/CWE-094/FlowUtils.qll new file mode 100644 index 000000000000..5371c51aa8f0 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/FlowUtils.qll @@ -0,0 +1,14 @@ +import java +import semmle.code.java.dataflow.FlowSources + +/** + * Holds if `fromNode` to `toNode` is a dataflow step that returns data from + * a bean by calling one of its getters. + */ +predicate hasGetterFlow(DataFlow::Node fromNode, DataFlow::Node toNode) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof GetterMethod and + ma.getQualifier() = fromNode.asExpr() and + ma = toNode.asExpr() + ) +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp new file mode 100644 index 000000000000..a8d3cd0fe70e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp @@ -0,0 +1,61 @@ + + + + +

+Jakarta Expression Language (EL) is an expression language for Java applications. +There is a single language specification and multiple implementations +such as Glassfish, Juel, Apache Commons EL, etc. +The language allows invocation of methods available in the JVM. +If an expression is built using attacker-controlled data, +and then evaluated, it may allow the attacker to run arbitrary code. +

+
+ + +

+It is generally recommended to avoid using untrusted data in an EL expression. +Before using untrusted data to build an EL expression, the data should be validated +to ensure it is not evaluated as expression language. If the EL implementation offers +configuring a sandbox for EL expressions, they should be run in a restrictive sandbox +that allows accessing only explicitly allowed classes. If the EL implementation +does not support sandboxing, consider using other expression language implementations +with sandboxing capabilities such as Apache Commons JEXL or the Spring Expression Language. +

+
+ + +

+The following example shows how untrusted data is used to build and run an expression +using the JUEL interpreter: +

+ + +

+JUEL does not support running expressions in a sandbox. To prevent running arbitrary code, +incoming data has to be checked before including it in an expression. The next example +uses a Regex pattern to check whether a user tries to run an allowed expression or not: +

+ + +
+ + +
  • + Eclipse Foundation: + Jakarta Expression Language. +
  • +
  • + Jakarta EE documentation: + Jakarta Expression Language API +
  • +
  • + OWASP: + Expression Language Injection. +
  • +
  • + JUEL: + Home page +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql new file mode 100644 index 000000000000..8190ec3d61f1 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql @@ -0,0 +1,20 @@ +/** + * @name Jakarta Expression Language injection + * @description Evaluation of a user-controlled expression + * may lead to arbitrary code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/javaee-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import JakartaExpressionInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, JakartaExpressionInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Jakarta Expression Language injection from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll new file mode 100644 index 000000000000..430909743647 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll @@ -0,0 +1,108 @@ +import java +import FlowUtils +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate an expression. + */ +class JakartaExpressionInjectionConfig extends TaintTracking::Configuration { + JakartaExpressionInjectionConfig() { this = "JakartaExpressionInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { + any(TaintPropagatingCall c).taintFlow(fromNode, toNode) or + hasGetterFlow(fromNode, toNode) + } +} + +/** + * A sink for Expresssion Language injection vulnerabilities, + * i.e. method calls that run evaluation of an expression. + */ +private class ExpressionEvaluationSink extends DataFlow::ExprNode { + ExpressionEvaluationSink() { + exists(MethodAccess ma, Method m, Expr taintFrom | + ma.getMethod() = m and taintFrom = this.asExpr() + | + m.getDeclaringType() instanceof ValueExpression and + m.hasName(["getValue", "setValue"]) and + ma.getQualifier() = taintFrom + or + m.getDeclaringType() instanceof MethodExpression and + m.hasName("invoke") and + ma.getQualifier() = taintFrom + or + m.getDeclaringType() instanceof LambdaExpression and + m.hasName("invoke") and + ma.getQualifier() = taintFrom + or + m.getDeclaringType() instanceof ELProcessor and + m.hasName(["eval", "getValue", "setValue"]) and + ma.getArgument(0) = taintFrom + or + m.getDeclaringType() instanceof ELProcessor and + m.hasName("setVariable") and + ma.getArgument(1) = taintFrom + ) + } +} + +/** + * Defines method calls that propagate tainted expressions. + */ +private class TaintPropagatingCall extends Call { + Expr taintFromExpr; + + TaintPropagatingCall() { + taintFromExpr = this.getArgument(1) and + ( + exists(Method m | this.(MethodAccess).getMethod() = m | + m.getDeclaringType() instanceof ExpressionFactory and + m.hasName(["createValueExpression", "createMethodExpression"]) and + taintFromExpr.getType() instanceof TypeString + ) + or + exists(Constructor c | this.(ConstructorCall).getConstructor() = c | + c.getDeclaringType() instanceof LambdaExpression and + taintFromExpr.getType() instanceof ValueExpression + ) + ) + } + + /** + * Holds if `fromNode` to `toNode` is a dataflow step that propagates + * tainted data. + */ + predicate taintFlow(DataFlow::Node fromNode, DataFlow::Node toNode) { + fromNode.asExpr() = taintFromExpr and toNode.asExpr() = this + } +} + +private class JakartaType extends RefType { + JakartaType() { getPackage().hasName(["javax.el", "jakarta.el"]) } +} + +private class ELProcessor extends JakartaType { + ELProcessor() { hasName("ELProcessor") } +} + +private class ExpressionFactory extends JakartaType { + ExpressionFactory() { hasName("ExpressionFactory") } +} + +private class ValueExpression extends JakartaType { + ValueExpression() { hasName("ValueExpression") } +} + +private class MethodExpression extends JakartaType { + MethodExpression() { hasName("MethodExpression") } +} + +private class LambdaExpression extends JakartaType { + LambdaExpression() { hasName("LambdaExpression") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll index 561d7e46ae90..89d7cb496a41 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll @@ -1,4 +1,5 @@ import java +import FlowUtils import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking @@ -16,7 +17,7 @@ class JexlInjectionConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { any(TaintPropagatingJexlMethodCall c).taintFlow(fromNode, toNode) or - returnsDataFromBean(fromNode, toNode) + hasGetterFlow(fromNode, toNode) } } @@ -152,18 +153,6 @@ private predicate createsJexlEngine(DataFlow::Node fromNode, DataFlow::Node toNo ) } -/** - * Holds if `fromNode` to `toNode` is a dataflow step that returns data from - * a bean by calling one of its getters. - */ -private predicate returnsDataFromBean(DataFlow::Node fromNode, DataFlow::Node toNode) { - exists(MethodAccess ma, Method m | ma.getMethod() = m | - m instanceof GetterMethod and - ma.getQualifier() = fromNode.asExpr() and - ma = toNode.asExpr() - ) -} - /** * A methods in the `JexlEngine` class that gets or sets a property with a JEXL expression. */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java b/java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java new file mode 100644 index 000000000000..3dfaaead68a5 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java @@ -0,0 +1,10 @@ +String input = getRemoteUserInput(); +String pattern = "(inside|outside)\\.(temperature|humidity)"; +if (!input.matches(pattern)) { + throw new IllegalArgumentException("Unexpected expression"); +} +String expression = "${" + input + "}"; +ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); +ValueExpression e = factory.createValueExpression(context, expression, Object.class); +SimpleContext context = getContext(); +Object result = e.getValue(context); diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java new file mode 100644 index 000000000000..27afa0fcb497 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java @@ -0,0 +1,5 @@ +String expression = "${" + getRemoteUserInput() + "}"; +ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); +ValueExpression e = factory.createValueExpression(context, expression, Object.class); +SimpleContext context = getContext(); +Object result = e.getValue(context); \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected new file mode 100644 index 000000000000..390871b54cf1 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected @@ -0,0 +1,46 @@ +edges +| JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:25:31:25:40 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:32:24:32:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:40:24:40:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:48:24:48:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:59:24:59:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:67:24:67:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:75:24:75:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:85:24:85:33 | expression : String | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:95:24:95:33 | expression : String | +| JakartaExpressionInjection.java:32:24:32:33 | expression : String | JakartaExpressionInjection.java:34:28:34:37 | expression | +| JakartaExpressionInjection.java:40:24:40:33 | expression : String | JakartaExpressionInjection.java:42:32:42:41 | expression | +| JakartaExpressionInjection.java:48:24:48:33 | expression : String | JakartaExpressionInjection.java:53:13:53:28 | lambdaExpression | +| JakartaExpressionInjection.java:59:24:59:33 | expression : String | JakartaExpressionInjection.java:61:32:61:41 | expression | +| JakartaExpressionInjection.java:67:24:67:33 | expression : String | JakartaExpressionInjection.java:69:43:69:52 | expression | +| JakartaExpressionInjection.java:75:24:75:33 | expression : String | JakartaExpressionInjection.java:79:13:79:13 | e | +| JakartaExpressionInjection.java:85:24:85:33 | expression : String | JakartaExpressionInjection.java:89:13:89:13 | e | +| JakartaExpressionInjection.java:95:24:95:33 | expression : String | JakartaExpressionInjection.java:99:13:99:13 | e | +nodes +| JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| JakartaExpressionInjection.java:25:31:25:40 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:32:24:32:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:34:28:34:37 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:40:24:40:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:42:32:42:41 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:48:24:48:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:53:13:53:28 | lambdaExpression | semmle.label | lambdaExpression | +| JakartaExpressionInjection.java:59:24:59:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:61:32:61:41 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:67:24:67:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:69:43:69:52 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:75:24:75:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:79:13:79:13 | e | semmle.label | e | +| JakartaExpressionInjection.java:85:24:85:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:89:13:89:13 | e | semmle.label | e | +| JakartaExpressionInjection.java:95:24:95:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:99:13:99:13 | e | semmle.label | e | +#select +| JakartaExpressionInjection.java:34:28:34:37 | expression | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:34:28:34:37 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:42:32:42:41 | expression | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:42:32:42:41 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:53:13:53:28 | lambdaExpression | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:53:13:53:28 | lambdaExpression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:61:32:61:41 | expression | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:61:32:61:41 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:69:43:69:52 | expression | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:69:43:69:52 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:79:13:79:13 | e | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:79:13:79:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:89:13:89:13 | e | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:89:13:89:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:99:13:99:13 | e | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:99:13:99:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java new file mode 100644 index 000000000000..ae5b6a8d5e41 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java @@ -0,0 +1,103 @@ +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.function.Consumer; + +import javax.el.ELContext; +import javax.el.ELManager; +import javax.el.ELProcessor; +import javax.el.ExpressionFactory; +import javax.el.LambdaExpression; +import javax.el.MethodExpression; +import javax.el.StandardELContext; +import javax.el.ValueExpression; + +public class JakartaExpressionInjection { + + // calls a consumer with a string received from a socket + private static void testWithSocket(Consumer action) throws IOException { + try (ServerSocket serverSocket = new ServerSocket(0)) { + try (Socket socket = serverSocket.accept()) { + byte[] bytes = new byte[1024]; + int n = socket.getInputStream().read(bytes); + String expression = new String(bytes, 0, n); + action.accept(expression); + } + } + } + + // BAD (untrusted input to ELProcessor.eval) + private static void testWithELProcessorEval() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.eval(expression); + }); + } + + // BAD (untrusted input to ELProcessor.getValue) + private static void testWithELProcessorGetValue() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.getValue(expression, Object.class); + }); + } + + // BAD (untrusted input to LambdaExpression.invoke) + private static void testWithLambdaExpressionInvoke() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = ELManager.getExpressionFactory(); + StandardELContext context = new StandardELContext(factory); + ValueExpression valueExpression = factory.createValueExpression(context, expression, Object.class); + LambdaExpression lambdaExpression = new LambdaExpression(new ArrayList<>(), valueExpression); + lambdaExpression.invoke(context, new Object[0]); + }); + } + + // BAD (untrusted input to ELProcessor.setValue) + private static void testWithELProcessorSetValue() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.setValue(expression, new Object()); + }); + } + + // BAD (untrusted input to ELProcessor.setVariable) + private static void testWithELProcessorSetVariable() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.setVariable("test", expression); + }); + } + + // BAD (untrusted input to ValueExpression.getValue when it was created by JUEL) + private static void testWithJuelValueExpressionGetValue() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + ELContext context = new de.odysseus.el.util.SimpleContext(); + ValueExpression e = factory.createValueExpression(context, expression, Object.class); + e.getValue(context); + }); + } + + // BAD (untrusted input to ValueExpression.setValue when it was created by JUEL) + private static void testWithJuelValueExpressionSetValue() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + ELContext context = new de.odysseus.el.util.SimpleContext(); + ValueExpression e = factory.createValueExpression(context, expression, Object.class); + e.setValue(context, new Object()); + }); + } + + // BAD (untrusted input to MethodExpression.invoke when it was created by JUEL) + private static void testWithJuelMethodExpressionInvoke() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + ELContext context = new de.odysseus.el.util.SimpleContext(); + MethodExpression e = factory.createMethodExpression(context, expression, Object.class, new Class[0]); + e.invoke(context, new Object[0]); + }); + } + +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref new file mode 100644 index 000000000000..3154ee5ccad4 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/options b/java/ql/test/experimental/query-tests/security/CWE-094/options index a8e30ce30b40..ec3354ea41ce 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/options +++ b/java/ql/test/experimental/query-tests/security/CWE-094/options @@ -1,2 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine - +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2 \ No newline at end of file diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ELContext.java b/java/ql/test/stubs/java-ee-el/javax/el/ELContext.java new file mode 100644 index 000000000000..ce3840c69c8d --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ELContext.java @@ -0,0 +1,3 @@ +package javax.el; + +public class ELContext {} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ELManager.java b/java/ql/test/stubs/java-ee-el/javax/el/ELManager.java new file mode 100644 index 000000000000..7d24f739a3f8 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ELManager.java @@ -0,0 +1,5 @@ +package javax.el; + +public class ELManager { + public static ExpressionFactory getExpressionFactory() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java b/java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java new file mode 100644 index 000000000000..95895fabc648 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java @@ -0,0 +1,8 @@ +package javax.el; + +public class ELProcessor { + public Object eval(String expression) { return null; } + public Object getValue(String expression, Class expectedType) { return null; } + public void setValue(String expression, Object value) {} + public void setVariable(String var, String expression) {} +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java b/java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java new file mode 100644 index 000000000000..31ff79169acb --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java @@ -0,0 +1,17 @@ +package javax.el; + +public class ExpressionFactory { + public MethodExpression createMethodExpression(ELContext context, String expression, Class expectedReturnType, + Class[] expectedParamTypes) { + + return null; + } + + public ValueExpression createValueExpression(ELContext context, String expression, Class expectedType) { + return null; + } + + public ValueExpression createValueExpression(Object instance, Class expectedType) { + return null; + } +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java b/java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java new file mode 100644 index 000000000000..4be01e9d2e4b --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java @@ -0,0 +1,8 @@ +package javax.el; + +import java.util.List; + +public class LambdaExpression { + public LambdaExpression(List formalParameters, ValueExpression expression) {} + public Object invoke(Object... args) { return null; } +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java b/java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java new file mode 100644 index 000000000000..ac50ece80e36 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java @@ -0,0 +1,5 @@ +package javax.el; + +public class MethodExpression { + public Object invoke(ELContext context, Object[] params) { return null; } +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java b/java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java new file mode 100644 index 000000000000..22e3f2a9fc13 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java @@ -0,0 +1,5 @@ +package javax.el; + +public class StandardELContext extends ELContext { + public StandardELContext(ExpressionFactory factory) {} +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java b/java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java new file mode 100644 index 000000000000..9a231215640a --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java @@ -0,0 +1,6 @@ +package javax.el; + +public class ValueExpression { + public Object getValue(ELContext context) { return null; } + public void setValue(ELContext context, Object value) {} +} diff --git a/java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java b/java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java new file mode 100644 index 000000000000..a555cf88dee0 --- /dev/null +++ b/java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java @@ -0,0 +1,5 @@ +package de.odysseus.el; + +import javax.el.ExpressionFactory; + +public class ExpressionFactoryImpl extends ExpressionFactory {} diff --git a/java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java b/java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java new file mode 100644 index 000000000000..aa4f449e5fa5 --- /dev/null +++ b/java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java @@ -0,0 +1,5 @@ +package de.odysseus.el.util; + +import javax.el.ELContext; + +public class SimpleContext extends ELContext {}