mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Add full integration test for Ratpack example
Signed-off-by: Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/ratpack-1.9.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/netty-4.1.x
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/ratpack-1.9.x:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/netty-4.1.x
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.POJONode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializable;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import ratpack.core.handling.Context;
|
||||
import ratpack.core.http.TypedData;
|
||||
import ratpack.core.form.Form;
|
||||
import ratpack.core.form.UploadedFile;
|
||||
import ratpack.core.parse.Parse;
|
||||
import ratpack.exec.Promise;
|
||||
import ratpack.func.Action;
|
||||
import ratpack.func.Function;
|
||||
import ratpack.func.MultiValueMap;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static ratpack.jackson.Jackson.jsonNode;
|
||||
|
||||
class IntegrationTest {
|
||||
|
||||
static class Pojo {
|
||||
String value;
|
||||
|
||||
String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
void sink(Object o) {}
|
||||
|
||||
String taint() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void test1(Context ctx) {
|
||||
bindJson(ctx, Pojo.class)
|
||||
.then(pojo ->{
|
||||
sink(pojo); //$hasTaintFlow
|
||||
sink(pojo.value); //$hasTaintFlow
|
||||
sink(pojo.getValue()); //$hasTaintFlow
|
||||
});
|
||||
}
|
||||
|
||||
void test2(Context ctx) {
|
||||
bindForm(ctx, Pojo.class, defaults -> defaults.put("another", "potato"))
|
||||
.then(pojo ->{
|
||||
sink(pojo); //$hasTaintFlow
|
||||
sink(pojo.value); //$hasTaintFlow
|
||||
sink(pojo.getValue()); //$hasTaintFlow
|
||||
});
|
||||
}
|
||||
|
||||
void test3() {
|
||||
Object value = extractSingleValueIfPossible(ImmutableList.of("a", taint()));
|
||||
sink(value); //$hasTaintFlow
|
||||
}
|
||||
|
||||
void test4(Context ctx) {
|
||||
parseToForm(ctx, Pojo.class)
|
||||
.map(pojoForm -> {
|
||||
Map<String, Object> mergedParams = new HashMap<>();
|
||||
filterAndMerge(pojoForm, mergedParams, name -> false);
|
||||
return mergedParams;
|
||||
}).then(pojoMap -> {
|
||||
sink(pojoMap); //$hasTaintFlow
|
||||
sink(pojoMap.get("value")); //$hasTaintFlow
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Promise<T> bindJson(Context ctx, Class<T> type) {
|
||||
return ctx.getRequest().getBody()
|
||||
.map(data -> {
|
||||
String dataText = data.getText();
|
||||
|
||||
try {
|
||||
return ctx.parse(data, jsonNode(objectMapper));
|
||||
} catch (Exception e) {
|
||||
String msg = "Unable to parse json data while binding type " + type.getCanonicalName() + " [jsonData: " + dataText + "]";
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
})
|
||||
.map(json ->
|
||||
bind(ctx, json, type)
|
||||
);
|
||||
}
|
||||
|
||||
private <T> T bind(Context ctx, JsonNode input, Class<T> type) {
|
||||
T value;
|
||||
try {
|
||||
value = objectMapper.convertValue(input, type);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to convert input to " + type.getName(), e);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static Promise<Form> parseToForm(Context ctx, Class<?> type) {
|
||||
return ctx.getRequest().getBody()
|
||||
.map(data -> {
|
||||
try {
|
||||
return ctx.parse(data, Form.form());
|
||||
} catch (Exception e) {
|
||||
String msg = "Unable to parse form data while binding type " + type.getCanonicalName() + " [formData: " + data.getText() + "]";
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Promise<T> bindForm(Context ctx, Class<T> type, Action<? super ImmutableMap.Builder<String, Object>> defaults) {
|
||||
return parseToForm(ctx, type)
|
||||
.map(form -> {
|
||||
ObjectNode input = toObjectNode(form, defaults, s -> false);
|
||||
Map<String, List<UploadedFile>> filesMap = form.files().getAll();
|
||||
filesMap.forEach((name, files) -> {
|
||||
ArrayNode array = input.putArray(name);
|
||||
files.forEach(f -> array.add(new POJONode(new UploadedFileWrapper(f))));
|
||||
});
|
||||
return bind(ctx, input, type);
|
||||
});
|
||||
}
|
||||
|
||||
private ObjectNode toObjectNode(MultiValueMap<String, String> params, Action<? super ImmutableMap.Builder<String, Object>> defaults, Predicate<String> paramFilter) throws Exception {
|
||||
Map<String, Object> mergedParams = new HashMap<>(defaults.with(ImmutableMap.builder()).build());
|
||||
filterAndMerge(params, mergedParams, paramFilter);
|
||||
return objectMapper.valueToTree(mergedParams);
|
||||
}
|
||||
|
||||
private static void filterAndMerge(MultiValueMap<String, String> params, Map<String, Object> defaults, Predicate<String> filter) {
|
||||
params.asMultimap().asMap().forEach((name, values) -> {
|
||||
if (!isEmptyAndHasDefault(name, values, defaults) && !filter.test(name)) {
|
||||
defaults.put(name, extractSingleValueIfPossible(values));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isEmptyAndHasDefault(String name, Collection<String> values, Map<String, Object> defaults) {
|
||||
// STUB - This is to make the compiler happy
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Object extractSingleValueIfPossible(Collection<String> values) {
|
||||
return values.size() == 1 ? values.iterator().next() : ImmutableList.copyOf(values);
|
||||
}
|
||||
|
||||
private static class UploadedFileWrapper implements JsonSerializable {
|
||||
|
||||
private final UploadedFile file;
|
||||
|
||||
private UploadedFileWrapper(UploadedFile file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Object gen, Object serializers) throws IOException {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWithType(Object gen, Object serializers, Object typeSer) throws IOException {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,8 +101,12 @@ class Resource {
|
||||
sink(form.get("questionable_parameter")); //$hasTaintFlow
|
||||
sink(form.getAll().get("questionable_parameter").get(0)); //$hasTaintFlow
|
||||
sink(form.getAll("questionable_parameter").get(0)); //$hasTaintFlow
|
||||
sink(form.asMultimap().get("questionable_parameter")); //$hasTaintFlow // fails!
|
||||
sink(form.asMultimap().asMap()); //$hasTaintFlow // fails!
|
||||
sink(form.asMultimap().get("questionable_parameter")); //$hasTaintFlow
|
||||
sink(form.asMultimap().asMap()); //$hasTaintFlow
|
||||
form.asMultimap().asMap().forEach((name, values) -> {
|
||||
sink(name); //$hasTaintFlow
|
||||
sink(values); //$hasTaintFlow
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ package com.fasterxml.jackson.core;
|
||||
import java.util.Iterator;
|
||||
|
||||
public interface TreeNode {
|
||||
JsonParser.NumberType numberType();
|
||||
default JsonParser.NumberType numberType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
int size();
|
||||
|
||||
@@ -35,6 +37,8 @@ public interface TreeNode {
|
||||
|
||||
TreeNode at(String jsonPointerExpression) throws IllegalArgumentException;
|
||||
|
||||
JsonParser traverse();
|
||||
default JsonParser traverse() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
10
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/JsonSerializable.java
generated
Normal file
10
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/JsonSerializable.java
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
// This interface does not actually have these types.. This is a significantly oversimplified stub.
|
||||
public interface JsonSerializable {
|
||||
public void serialize(Object gen, Object serializers) throws IOException;
|
||||
|
||||
public void serializeWithType(Object gen, Object serializers, Object typeSer) throws IOException;
|
||||
}
|
||||
10
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ArrayNode.java
generated
Normal file
10
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ArrayNode.java
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
package com.fasterxml.jackson.databind.node;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public abstract class ArrayNode extends ContainerNode<ArrayNode> {
|
||||
|
||||
public ArrayNode add(JsonNode value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
7
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/BaseJsonNode.java
generated
Normal file
7
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/BaseJsonNode.java
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
package com.fasterxml.jackson.databind.node;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public abstract class BaseJsonNode extends JsonNode {
|
||||
|
||||
}
|
||||
5
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ContainerNode.java
generated
Normal file
5
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ContainerNode.java
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.fasterxml.jackson.databind.node;
|
||||
|
||||
public abstract class ContainerNode<T extends ContainerNode<T>> extends BaseJsonNode {
|
||||
|
||||
}
|
||||
9
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ObjectNode.java
generated
Normal file
9
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ObjectNode.java
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.fasterxml.jackson.databind.node;
|
||||
|
||||
public abstract class ObjectNode extends ContainerNode<ObjectNode> {
|
||||
public ArrayNode putArray(String propertyName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
76
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/POJONode.java
generated
Normal file
76
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/POJONode.java
generated
Normal file
@@ -0,0 +1,76 @@
|
||||
package com.fasterxml.jackson.databind.node;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.List;
|
||||
|
||||
public class POJONode extends ValueNode {
|
||||
protected final Object _value;
|
||||
|
||||
public POJONode(Object v) {
|
||||
_value = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JsonNode> T deepCopy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode get(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode path(String fieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode path(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode findValue(String fieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode findPath(String fieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode findParent(String fieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findValuesAsText(String fieldName, List<String> foundSoFar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
5
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ValueNode.java
generated
Normal file
5
java/ql/test/stubs/jackson-databind-2.12/com/fasterxml/jackson/databind/node/ValueNode.java
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.fasterxml.jackson.databind.node;
|
||||
|
||||
public abstract class ValueNode extends BaseJsonNode {
|
||||
|
||||
}
|
||||
32
java/ql/test/stubs/ratpack-1.9.x/ratpack/jackson/Jackson.java
generated
Normal file
32
java/ql/test/stubs/ratpack-1.9.x/ratpack/jackson/Jackson.java
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ratpack.jackson;
|
||||
|
||||
import ratpack.func.Nullable;
|
||||
import ratpack.core.parse.Parse;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
|
||||
public abstract class Jackson {
|
||||
|
||||
private Jackson() {
|
||||
}
|
||||
|
||||
public static Parse<JsonNode, JsonParseOpts> jsonNode(@Nullable ObjectMapper objectMapper) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
27
java/ql/test/stubs/ratpack-1.9.x/ratpack/jackson/JsonParseOpts.java
generated
Normal file
27
java/ql/test/stubs/ratpack-1.9.x/ratpack/jackson/JsonParseOpts.java
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ratpack.jackson;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface JsonParseOpts {
|
||||
|
||||
Optional<ObjectMapper> getObjectMapper();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user