Merge pull request #5590 from github/sauyon/java-spring-errors

Add models for Spring validation.Errors
This commit is contained in:
Anders Schack-Mulligen
2021-07-01 14:29:49 +02:00
committed by GitHub
14 changed files with 654 additions and 45 deletions

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* Added additional taint steps modeling the Spring `validation.Errors` class (`org.springframework.validation.Errors`).

View File

@@ -86,6 +86,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.Optional
private import semmle.code.java.frameworks.spring.SpringHttp
private import semmle.code.java.frameworks.spring.SpringUtil
private import semmle.code.java.frameworks.spring.SpringValidation
private import semmle.code.java.frameworks.spring.SpringWebClient
private import semmle.code.java.frameworks.spring.SpringBeans
private import semmle.code.java.security.ResponseSplitting

View File

@@ -34,6 +34,7 @@ import semmle.code.java.frameworks.spring.SpringRef
import semmle.code.java.frameworks.spring.SpringReplacedMethod
import semmle.code.java.frameworks.spring.SpringSet
import semmle.code.java.frameworks.spring.SpringUtil
import semmle.code.java.frameworks.spring.SpringValidation
import semmle.code.java.frameworks.spring.SpringValue
import semmle.code.java.frameworks.spring.SpringXMLElement
import semmle.code.java.frameworks.spring.metrics.MetricSpringBean

View File

@@ -0,0 +1,25 @@
/** Definitions of flow steps through utility methods of `org.springframework.validation.Errors`. */
import java
private import semmle.code.java.dataflow.ExternalFlow
private class SpringValidationErrorModel extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"org.springframework.validation;Errors;true;addAllErrors;;;Argument[0];Argument[-1];taint",
"org.springframework.validation;Errors;true;getAllErrors;;;Argument[-1];ReturnValue;taint",
"org.springframework.validation;Errors;true;getFieldError;;;Argument[-1];ReturnValue;taint",
"org.springframework.validation;Errors;true;getFieldErrors;;;Argument[-1];ReturnValue;taint",
"org.springframework.validation;Errors;true;getGlobalError;;;Argument[-1];ReturnValue;taint",
"org.springframework.validation;Errors;true;getGlobalErrors;;;Argument[-1];ReturnValue;taint",
"org.springframework.validation;Errors;true;reject;;;Argument[0];Argument[-1];taint",
"org.springframework.validation;Errors;true;reject;;;ArrayElement of Argument[1];Argument[-1];taint",
"org.springframework.validation;Errors;true;reject;;;Argument[2];Argument[-1];taint",
"org.springframework.validation;Errors;true;rejectValue;;;Argument[1];Argument[-1];taint",
"org.springframework.validation;Errors;true;rejectValue;;;Argument[3];Argument[-1];taint",
"org.springframework.validation;Errors;true;rejectValue;(java.lang.String,java.lang.String,java.lang.Object[],java.lang.String);;ArrayElement of Argument[2];Argument[-1];taint",
"org.springframework.validation;Errors;true;rejectValue;(java.lang.String,java.lang.String,java.lang.String);;Argument[2];Argument[-1];taint"
]
}
}

View File

@@ -0,0 +1,78 @@
import org.springframework.validation.Errors;
class ValidationErrorsTest {
Object source() { return null; }
Errors sourceErrs() { return (Errors)source(); }
Errors errors() { return null; }
void sink(Object o) {}
void test() {
Errors es0 = errors();
es0.addAllErrors(sourceErrs());
sink(es0); // $hasTaintFlow
sink(sourceErrs().getAllErrors()); // $hasTaintFlow
sink(sourceErrs().getFieldError()); // $hasTaintFlow
sink(sourceErrs().getFieldError("field")); // $hasTaintFlow
sink(sourceErrs().getGlobalError()); // $hasTaintFlow
sink(sourceErrs().getGlobalErrors()); // $hasTaintFlow
Errors es1 = errors();
es1.reject((String)source());
sink(es1); // $hasTaintFlow
Errors es2 = errors();
es2.reject((String)source(), null, "");
sink(es2); // $hasTaintFlow
Errors es3 = errors();
es3.reject((String)source(), null, "");
sink(es3); // $hasTaintFlow
{
Errors es4 = errors();
Object[] in = { (String)source() };
es4.reject("", in, "");
sink(in); // $hasTaintFlow
}
{
Errors es5 = errors();
es5.reject("", null, (String)source());
sink(es5); // $hasTaintFlow
}
Errors es6 = errors();
es6.reject((String)source(), "");
sink(es6); // $hasTaintFlow
Errors es7 = errors();
es7.reject("", (String)source());
sink(es7); // $hasTaintFlow
Errors es8 = errors();
es8.rejectValue("", (String)source(), null, "");
sink(es8); // $hasTaintFlow
Errors es9 = errors();
Object[] in = {source()};
es9.rejectValue("", "", in, "");
sink(es9); // $hasTaintFlow
Errors es10 = errors();
es10.rejectValue("", "", null, (String)source());
sink(es10); // $hasTaintFlow
Errors es11 = errors();
es11.rejectValue("", (String)source(), "");
sink(es11); // $hasTaintFlow
Errors es12 = errors();
es12.rejectValue("", "", (String)source());
sink(es12); // $hasTaintFlow
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8

View File

@@ -0,0 +1,52 @@
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import TestUtilities.InlineExpectationsTest
class ValueFlowConf extends DataFlow::Configuration {
ValueFlowConf() { this = "qltest:valueFlowConf" }
override predicate isSource(DataFlow::Node n) {
n.asExpr().(MethodAccess).getMethod().hasName("source")
}
override predicate isSink(DataFlow::Node n) {
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
}
}
class TaintFlowConf extends TaintTracking::Configuration {
TaintFlowConf() { this = "qltest:taintFlowConf" }
override predicate isSource(DataFlow::Node n) {
n.asExpr().(MethodAccess).getMethod().hasName("source")
}
override predicate isSink(DataFlow::Node n) {
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
}
}
class HasFlowTest extends InlineExpectationsTest {
HasFlowTest() { this = "HasFlowTest" }
override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasValueFlow" and
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
sink.getLocation() = location and
element = sink.toString() and
value = ""
)
or
tag = "hasTaintFlow" and
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf |
conf.hasFlow(src, sink) and not any(ValueFlowConf c).hasFlow(src, sink)
|
sink.getLocation() = location and
element = sink.toString() and
value = ""
)
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-2017 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
*
* https://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 org.springframework.context;
public interface MessageSourceResolvable {
String[] getCodes();
default Object[] getArguments() {
return null;
}
default String getDefaultMessage() {
return null;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2002-2019 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
*
* https://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 org.springframework.context.support;
import java.io.Serializable;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.lang.Nullable;
public class DefaultMessageSourceResolvable implements MessageSourceResolvable, Serializable {
public DefaultMessageSourceResolvable(String code) {}
public DefaultMessageSourceResolvable(String[] codes) {}
public DefaultMessageSourceResolvable(String[] codes, String defaultMessage) {}
public DefaultMessageSourceResolvable(String[] codes, Object[] arguments) {}
public DefaultMessageSourceResolvable(
@Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) {}
public DefaultMessageSourceResolvable(MessageSourceResolvable resolvable) {}
public String getCode() {
return null;
}
@Override
public String[] getCodes() {
return null;
}
@Override
public Object[] getArguments() {
return null;
}
@Override
public String getDefaultMessage() {
return null;
}
public boolean shouldRenderDefaultMessage() {
return false;
}
@Override
public String toString() {
return null;
}
@Override
public boolean equals(@Nullable Object other) {
return false;
}
@Override
public int hashCode() {
return 0;
}
protected final String resolvableToString() {
return null;
}
}

View File

@@ -1,50 +1,188 @@
// Generated automatically from org.springframework.util.ObjectUtils for testing purposes
/*
* Copyright 2002-2019 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
*
* https://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 org.springframework.util;
abstract public class ObjectUtils
{
public ObjectUtils(){}
public static <A, O extends A> A[] addObjectToArray(A[] p0, O p1){ return null; }
public static <E extends Enum<? extends Object>> E caseInsensitiveValueOf(E[] p0, String p1){ return null; }
public static Object unwrapOptional(Object p0){ return null; }
public static Object[] toObjectArray(Object p0){ return null; }
public static String getDisplayString(Object p0){ return null; }
public static String getIdentityHexString(Object p0){ return null; }
public static String identityToString(Object p0){ return null; }
public static String nullSafeClassName(Object p0){ return null; }
public static String nullSafeToString(Object p0){ return null; }
public static String nullSafeToString(Object[] p0){ return null; }
public static String nullSafeToString(boolean[] p0){ return null; }
public static String nullSafeToString(byte[] p0){ return null; }
public static String nullSafeToString(char[] p0){ return null; }
public static String nullSafeToString(double[] p0){ return null; }
public static String nullSafeToString(float[] p0){ return null; }
public static String nullSafeToString(int[] p0){ return null; }
public static String nullSafeToString(long[] p0){ return null; }
public static String nullSafeToString(short[] p0){ return null; }
public static boolean containsConstant(Enum<? extends Object>[] p0, String p1){ return false; }
public static boolean containsConstant(Enum<? extends Object>[] p0, String p1, boolean p2){ return false; }
public static boolean containsElement(Object[] p0, Object p1){ return false; }
public static boolean isArray(Object p0){ return false; }
public static boolean isCheckedException(Throwable p0){ return false; }
public static boolean isCompatibleWithThrowsClause(Throwable p0, Class<? extends Object>... p1){ return false; }
public static boolean isEmpty(Object p0){ return false; }
public static boolean isEmpty(Object[] p0){ return false; }
public static boolean nullSafeEquals(Object p0, Object p1){ return false; }
public static int hashCode(boolean p0){ return 0; }
public static int hashCode(double p0){ return 0; }
public static int hashCode(float p0){ return 0; }
public static int hashCode(long p0){ return 0; }
public static int nullSafeHashCode(Object p0){ return 0; }
public static int nullSafeHashCode(Object[] p0){ return 0; }
public static int nullSafeHashCode(boolean[] p0){ return 0; }
public static int nullSafeHashCode(byte[] p0){ return 0; }
public static int nullSafeHashCode(char[] p0){ return 0; }
public static int nullSafeHashCode(double[] p0){ return 0; }
public static int nullSafeHashCode(float[] p0){ return 0; }
public static int nullSafeHashCode(int[] p0){ return 0; }
public static int nullSafeHashCode(long[] p0){ return 0; }
public static int nullSafeHashCode(short[] p0){ return 0; }
import org.springframework.lang.Nullable;
public abstract class ObjectUtils {
public static boolean isCheckedException(Throwable ex) {
return false;
}
public static boolean isCompatibleWithThrowsClause(
Throwable ex, @Nullable Class<?>... declaredExceptions) {
return false;
}
public static boolean isArray(@Nullable Object obj) {
return false;
}
public static boolean isEmpty(@Nullable Object[] array) {
return false;
}
public static boolean isEmpty(@Nullable Object obj) {
return false;
}
public static Object unwrapOptional(@Nullable Object obj) {
return null;
}
public static boolean containsElement(@Nullable Object[] array, Object element) {
return false;
}
public static boolean containsConstant(Enum<?>[] enumValues, String constant) {
return false;
}
public static boolean containsConstant(
Enum<?>[] enumValues, String constant, boolean caseSensitive) {
return false;
}
public static <E extends Enum<?>> E caseInsensitiveValueOf(E[] enumValues, String constant) {
return null;
}
public static <A, O extends A> A[] addObjectToArray(@Nullable A[] array, @Nullable O obj) {
return null;
}
public static Object[] toObjectArray(@Nullable Object source) {
return null;
}
public static boolean nullSafeEquals(@Nullable Object o1, @Nullable Object o2) {
return false;
}
public static int nullSafeHashCode(@Nullable Object obj) {
return 0;
}
public static int nullSafeHashCode(@Nullable Object[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable boolean[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable byte[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable char[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable double[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable float[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable int[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable long[] array) {
return 0;
}
public static int nullSafeHashCode(@Nullable short[] array) {
return 0;
}
public static int hashCode(boolean bool) {
return 0;
}
public static int hashCode(double dbl) {
return 0;
}
public static int hashCode(float flt) {
return 0;
}
public static int hashCode(long lng) {
return 0;
}
public static String identityToString(@Nullable Object obj) {
return null;
}
public static String getIdentityHexString(Object obj) {
return null;
}
public static String getDisplayString(@Nullable Object obj) {
return null;
}
public static String nullSafeClassName(@Nullable Object obj) {
return null;
}
public static String nullSafeToString(@Nullable Object obj) {
return null;
}
public static String nullSafeToString(@Nullable Object[] array) {
return null;
}
public static String nullSafeToString(@Nullable boolean[] array) {
return null;
}
public static String nullSafeToString(@Nullable byte[] array) {
return null;
}
public static String nullSafeToString(@Nullable char[] array) {
return null;
}
public static String nullSafeToString(@Nullable double[] array) {
return null;
}
public static String nullSafeToString(@Nullable float[] array) {
return null;
}
public static String nullSafeToString(@Nullable int[] array) {
return null;
}
public static String nullSafeToString(@Nullable long[] array) {
return null;
}
public static String nullSafeToString(@Nullable short[] array) {
return null;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2018 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
*
* https://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 org.springframework.validation;
import java.util.List;
import org.springframework.lang.Nullable;
public interface Errors {
String getObjectName();
void setNestedPath(String nestedPath);
String getNestedPath();
void pushNestedPath(String subPath);
void popNestedPath() throws IllegalStateException;
void reject(String errorCode);
void reject(String errorCode, String defaultMessage);
void reject(String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage);
void rejectValue(@Nullable String field, String errorCode);
void rejectValue(@Nullable String field, String errorCode, String defaultMessage);
void rejectValue(
@Nullable String field,
String errorCode,
@Nullable Object[] errorArgs,
@Nullable String defaultMessage);
void addAllErrors(Errors errors);
boolean hasErrors();
int getErrorCount();
List<ObjectError> getAllErrors();
boolean hasGlobalErrors();
int getGlobalErrorCount();
List<ObjectError> getGlobalErrors();
ObjectError getGlobalError();
boolean hasFieldErrors();
int getFieldErrorCount();
List<FieldError> getFieldErrors();
FieldError getFieldError();
boolean hasFieldErrors(String field);
int getFieldErrorCount(String field);
List<FieldError> getFieldErrors(String field);
FieldError getFieldError(String field);
Object getFieldValue(String field);
Class<?> getFieldType(String field);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2002-2018 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
*
* https://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 org.springframework.validation;
import org.springframework.lang.Nullable;
public class FieldError extends ObjectError {
public FieldError(String objectName, String field, String defaultMessage) { super("", ""); }
public FieldError(
String objectName,
String field,
@Nullable Object rejectedValue,
boolean bindingFailure,
@Nullable String[] codes,
@Nullable Object[] arguments,
@Nullable String defaultMessage) { super("", ""); }
public String getField() {
return null;
}
@Nullable
public Object getRejectedValue() {
return null;
}
public boolean isBindingFailure() {
return false;
}
@Override
public boolean equals(@Nullable Object other) {
return false;
}
@Override
public int hashCode() {
return 0;
}
@Override
public String toString() {
return null;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2002-2019 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
*
* https://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 org.springframework.validation;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.lang.Nullable;
public class ObjectError extends DefaultMessageSourceResolvable {
public ObjectError(String objectName, String defaultMessage) { super(""); }
public ObjectError(
String objectName,
@Nullable String[] codes,
@Nullable Object[] arguments,
@Nullable String defaultMessage) { super(""); }
public String getObjectName() {
return null;
}
public void wrap(Object source) {}
public <T> T unwrap(Class<T> sourceType) {
return null;
}
public boolean contains(Class<?> sourceType) {
return false;
}
@Override
public boolean equals(@Nullable Object other) {
return false;
}
@Override
public int hashCode() {
return 0;
}
@Override
public String toString() {
return "";
}
}