[Java] CWE-348: Use of less trusted source

This commit is contained in:
haby0
2021-04-08 17:14:03 +08:00
parent a9527fd913
commit 3f0a3266aa
20 changed files with 885 additions and 10 deletions

View File

@@ -0,0 +1,74 @@
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UseOfLessTrustedSource {
private static final Logger log = LoggerFactory.getLogger(UseOfLessTrustedSource.class);
@GetMapping(value = "bad1")
@ResponseBody
public String bad1(HttpServletRequest request) {
String remoteAddr = "";
if (request != null) {
remoteAddr = request.getHeader("X-FORWARDED-FOR");
remoteAddr = remoteAddr.split(",")[0];
if (remoteAddr == null || "".equals(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
}
return remoteAddr;
}
@GetMapping(value = "bad2")
public void bad2(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
log.debug("getClientIP header X-Forwarded-For:{}", ip);
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("Proxy-Client-IP");
log.debug("getClientIP header Proxy-Client-IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
log.debug("getClientIP header WL-Proxy-Client-IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
log.debug("getClientIP header HTTP_CLIENT_IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
log.debug("getClientIP header HTTP_X_FORWARDED_FOR:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("X-Real-IP");
log.debug("getClientIP header X-Real-IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getRemoteAddr();
log.debug("getRemoteAddr IP:{}", ip);
}
System.out.println("client ip is: " + ip);
}
@GetMapping(value = "good1")
@ResponseBody
public String good1(HttpServletRequest request) {
String remoteAddr = "";
if (request != null) {
remoteAddr = request.getHeader("X-FORWARDED-FOR");
remoteAddr = remoteAddr.split(",")[remoteAddr.split(",").length - 1]; // good
if (remoteAddr == null || "".equals(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
}
return remoteAddr;
}
}

View File

@@ -0,0 +1,38 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The software obtains the original client IP address through the http header <code>X-Forwarded-For</code>, which is used to ensure
security or track it in the log for statistical or other reasons. Attackers can use <code>X-Forwarded-For </code> Spoofing software.</p>
</overview>
<recommendation>
<p>When the software is not using a proxy server, get the last ip.</p>
</recommendation>
<example>
<p>The following examples show the bad case and the good case respectively. Bad case, such as <code>bad1</code> to <code>bad2</code>.
In the <code>bad1</code> method, the value of <code>X-Forwarded-For</code> in <code>header</code> is split, and the first value of
the split array is obtained. Good case, such as <code>good1</code>, split the value of <code>X-Forwarded-For</code> in <code>header</code>
and get the last value of the split array.</p>
<sample src="UseOfLessTrustedSource.java" />
</example>
<references>
<li>Prevent IP address spoofing with X-Forwarded-For header when using AWS ELB and Clojure Ring:
<a href="https://www.dennis-schneider.com/blog/prevent-ip-address-spoofing-with-x-forwarded-for-header-and-aws-elb-in-clojure-ring/">
Prevent IP address spoofing with...</a>
</li>
<li>Security Rule Zero: A Warning about X-Forwarded-For:
<a href="https://www.f5.com/company/blog/security-rule-zero-a-warning-about-x-forwarded-for">
Security Rule Zero: A Warning about X-Forwarded-For</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,44 @@
/**
* @name X-Forwarded-For spoofing
* @description The software obtains the client ip through `X-Forwarded-For`,
* and the attacker can modify the value of `X-Forwarded-For` to forge the ip.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/use-of-less-trusted-source
* @tags security
* external/cwe/cwe-348
*/
import java
import UseOfLessTrustedSourceLib
import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
class UseOfLessTrustedSourceConfig extends TaintTracking::Configuration {
UseOfLessTrustedSourceConfig() { this = "UseOfLessTrustedSourceConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof UseOfLessTrustedSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof UseOfLessTrustedSink }
/**
* When using `,` split request data and not taking the first value of
* the array, it is considered as `good`.
*/
override predicate isSanitizer(DataFlow::Node node) {
exists(ArrayAccess aa, MethodAccess ma | aa.getArray() = ma |
ma.getQualifier() = node.asExpr() and
ma.getMethod() instanceof SplitMethod and
not aa.getIndexExpr().toString() = "0"
)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, UseOfLessTrustedSourceConfig conf
where
conf.hasFlowPath(source, sink) and
source.getNode().getEnclosingCallable() = sink.getNode().getEnclosingCallable() and
xffIsFirstGet(source.getNode())
select sink.getNode(), source, sink, "X-Forwarded-For spoofing might include code from $@.",
source.getNode(), "this user input"

View File

@@ -0,0 +1,88 @@
import java
import DataFlow
import semmle.code.java.dataflow.DataFlow
import experimental.semmle.code.java.Logging
/** A data flow source of the value of the `x-forwarded-for` field in the `header`. */
class UseOfLessTrustedSource extends DataFlow::Node {
UseOfLessTrustedSource() {
exists(MethodAccess ma |
ma.getMethod().hasName("getHeader") and
ma.getArgument(0).toString().toLowerCase() = "\"x-forwarded-for\"" and
ma = this.asExpr()
)
}
}
/** A data flow sink of method return or log output or local print. */
class UseOfLessTrustedSink extends DataFlow::Node {
UseOfLessTrustedSink() {
exists(ReturnStmt rs | rs.getResult() = this.asExpr())
or
exists(MethodAccess ma |
ma.getMethod().getName() in ["print", "println"] and
(
ma.getMethod().getDeclaringType().hasQualifiedName("java.io", "PrintWriter") or
ma.getMethod().getDeclaringType().hasQualifiedName("java.io", "PrintStream")
) and
ma.getAnArgument() = this.asExpr()
)
or
exists(LoggingCall lc | lc.getAnArgument() = this.asExpr())
}
}
/** A method that split string. */
class SplitMethod extends Method {
SplitMethod() {
this.getNumberOfParameters() = 1 and
this.hasQualifiedName("java.lang", "String", "split")
}
}
/**
* A call to the ServletRequest.getHeader method and the argument are
* `wl-proxy-client-ip`/`proxy-client-ip`/`http_client_ip`/`http_x_forwarded_for`/`x-real-ip`.
*/
class HeaderIpCall extends MethodAccess {
HeaderIpCall() {
this.getMethod().hasName("getHeader") and
this.getMethod()
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("javax.servlet", "ServletRequest") and
this.getArgument(0).toString().toLowerCase() in [
"\"wl-proxy-client-ip\"", "\"proxy-client-ip\"", "\"http_client_ip\"",
"\"http_x_forwarded_for\"", "\"x-real-ip\""
]
}
}
/** A call to `ServletRequest.getRemoteAddr` method. */
class RemoteAddrCall extends MethodAccess {
RemoteAddrCall() {
this.getMethod().hasName("getRemoteAddr") and
this.getMethod()
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("javax.servlet", "ServletRequest")
}
}
/** The first one in the method to get the ip value through `x-forwarded-for`. */
predicate xffIsFirstGet(Node node) {
exists(HeaderIpCall hic |
node.getEnclosingCallable() = hic.getEnclosingCallable() and
node.getLocation().getEndLine() < hic.getLocation().getEndLine()
)
or
exists(RemoteAddrCall rac |
node.getEnclosingCallable() = rac.getEnclosingCallable() and
node.getLocation().getEndLine() < rac.getLocation().getEndLine()
)
or
not exists(HeaderIpCall hic, RemoteAddrCall rac |
node.getEnclosingCallable() = hic.getEnclosingCallable() and
node.getEnclosingCallable() = rac.getEnclosingCallable()
)
}

View File

@@ -0,0 +1,14 @@
edges
| UseOfLessTrustedSource.java:19:26:19:61 | getHeader(...) : String | UseOfLessTrustedSource.java:25:16:25:25 | remoteAddr |
| UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) : String | UseOfLessTrustedSource.java:32:60:32:61 | ip |
| UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) : String | UseOfLessTrustedSource.java:58:28:58:48 | ... + ... |
nodes
| UseOfLessTrustedSource.java:19:26:19:61 | getHeader(...) : String | semmle.label | getHeader(...) : String |
| UseOfLessTrustedSource.java:25:16:25:25 | remoteAddr | semmle.label | remoteAddr |
| UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) : String | semmle.label | getHeader(...) : String |
| UseOfLessTrustedSource.java:32:60:32:61 | ip | semmle.label | ip |
| UseOfLessTrustedSource.java:58:28:58:48 | ... + ... | semmle.label | ... + ... |
#select
| UseOfLessTrustedSource.java:25:16:25:25 | remoteAddr | UseOfLessTrustedSource.java:19:26:19:61 | getHeader(...) : String | UseOfLessTrustedSource.java:25:16:25:25 | remoteAddr | X-Forwarded-For spoofing might include code from $@. | UseOfLessTrustedSource.java:19:26:19:61 | getHeader(...) | this user input |
| UseOfLessTrustedSource.java:32:60:32:61 | ip | UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) : String | UseOfLessTrustedSource.java:32:60:32:61 | ip | X-Forwarded-For spoofing might include code from $@. | UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) | this user input |
| UseOfLessTrustedSource.java:58:28:58:48 | ... + ... | UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) : String | UseOfLessTrustedSource.java:58:28:58:48 | ... + ... | X-Forwarded-For spoofing might include code from $@. | UseOfLessTrustedSource.java:30:21:30:56 | getHeader(...) | this user input |

View File

@@ -0,0 +1,74 @@
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UseOfLessTrustedSource {
private static final Logger log = LoggerFactory.getLogger(UseOfLessTrustedSource.class);
@GetMapping(value = "bad1")
@ResponseBody
public String bad1(HttpServletRequest request) {
String remoteAddr = "";
if (request != null) {
remoteAddr = request.getHeader("X-FORWARDED-FOR");
remoteAddr = remoteAddr.split(",")[0];
if (remoteAddr == null || "".equals(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
}
return remoteAddr;
}
@GetMapping(value = "bad2")
public void bad2(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
log.debug("getClientIP header X-Forwarded-For:{}", ip);
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("Proxy-Client-IP");
log.debug("getClientIP header Proxy-Client-IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
log.debug("getClientIP header WL-Proxy-Client-IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
log.debug("getClientIP header HTTP_CLIENT_IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
log.debug("getClientIP header HTTP_X_FORWARDED_FOR:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getHeader("X-Real-IP");
log.debug("getClientIP header X-Real-IP:{}", ip);
}
if (StringUtils.isBlank(ip) || StringUtils.equalsIgnoreCase("unknown", ip)) {
ip = request.getRemoteAddr();
log.debug("getRemoteAddr IP:{}", ip);
}
System.out.println("client ip is: " + ip);
}
@GetMapping(value = "good1")
@ResponseBody
public String good1(HttpServletRequest request) {
String remoteAddr = "";
if (request != null) {
remoteAddr = request.getHeader("X-FORWARDED-FOR");
remoteAddr = remoteAddr.split(",")[remoteAddr.split(",").length - 1]; // good
if (remoteAddr == null || "".equals(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
}
return remoteAddr;
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-348/UseOfLessTrustedSource.ql

View File

@@ -0,0 +1,2 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.2.3/:${tes
tdir}/../../../../stubs/slf4j-api-1.6.4/:${testdir}/../../../../stubs/apache-commons-lang3-3.7/

View File

@@ -0,0 +1,127 @@
package org.slf4j;
public interface Logger {
String ROOT_LOGGER_NAME = "ROOT";
String getName();
boolean isTraceEnabled();
void trace(String var1);
void trace(String var1, Object var2);
void trace(String var1, Object var2, Object var3);
void trace(String var1, Object[] var2);
void trace(String var1, Throwable var2);
boolean isTraceEnabled(Marker var1);
void trace(Marker var1, String var2);
void trace(Marker var1, String var2, Object var3);
void trace(Marker var1, String var2, Object var3, Object var4);
void trace(Marker var1, String var2, Object[] var3);
void trace(Marker var1, String var2, Throwable var3);
boolean isDebugEnabled();
void debug(String var1);
void debug(String var1, Object var2);
void debug(String var1, Object var2, Object var3);
void debug(String var1, Object[] var2);
void debug(String var1, Throwable var2);
boolean isDebugEnabled(Marker var1);
void debug(Marker var1, String var2);
void debug(Marker var1, String var2, Object var3);
void debug(Marker var1, String var2, Object var3, Object var4);
void debug(Marker var1, String var2, Object[] var3);
void debug(Marker var1, String var2, Throwable var3);
boolean isInfoEnabled();
void info(String var1);
void info(String var1, Object var2);
void info(String var1, Object var2, Object var3);
void info(String var1, Object[] var2);
void info(String var1, Throwable var2);
boolean isInfoEnabled(Marker var1);
void info(Marker var1, String var2);
void info(Marker var1, String var2, Object var3);
void info(Marker var1, String var2, Object var3, Object var4);
void info(Marker var1, String var2, Object[] var3);
void info(Marker var1, String var2, Throwable var3);
boolean isWarnEnabled();
void warn(String var1);
void warn(String var1, Object var2);
void warn(String var1, Object[] var2);
void warn(String var1, Object var2, Object var3);
void warn(String var1, Throwable var2);
boolean isWarnEnabled(Marker var1);
void warn(Marker var1, String var2);
void warn(Marker var1, String var2, Object var3);
void warn(Marker var1, String var2, Object var3, Object var4);
void warn(Marker var1, String var2, Object[] var3);
void warn(Marker var1, String var2, Throwable var3);
boolean isErrorEnabled();
void error(String var1);
void error(String var1, Object var2);
void error(String var1, Object var2, Object var3);
void error(String var1, Object[] var2);
void error(String var1, Throwable var2);
boolean isErrorEnabled(Marker var1);
void error(Marker var1, String var2);
void error(Marker var1, String var2, Object var3);
void error(Marker var1, String var2, Object var3, Object var4);
void error(Marker var1, String var2, Object[] var3);
void error(Marker var1, String var2, Throwable var3);
}

View File

@@ -0,0 +1,21 @@
package org.slf4j;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
public final class LoggerFactory {
public static Logger getLogger(String name) {
return null;
}
public static Logger getLogger(Class clazz) {
return null;
}
}

View File

@@ -0,0 +1,30 @@
package org.slf4j;
import java.io.Serializable;
import java.util.Iterator;
public interface Marker extends Serializable {
String ANY_MARKER = "*";
String ANY_NON_NULL_MARKER = "+";
String getName();
void add(Marker var1);
boolean remove(Marker var1);
/** @deprecated */
boolean hasChildren();
boolean hasReferences();
Iterator iterator();
boolean contains(Marker var1);
boolean contains(String var1);
boolean equals(Object var1);
int hashCode();
}

View File

@@ -0,0 +1,21 @@
package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AliasFor {
@AliasFor("attribute")
String value() default "";
@AliasFor("value")
String attribute() default "";
Class<? extends Annotation> annotation() default Annotation.class;
}

View File

@@ -1,9 +1,14 @@
package org.springframework.stereotype;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value=ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller { }
public @interface Controller {
String value() default "";
}

View File

@@ -0,0 +1,202 @@
package org.springframework.util;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import org.springframework.lang.Nullable;
public abstract class ObjectUtils {
private static final int INITIAL_HASH = 7;
private static final int MULTIPLIER = 31;
private static final String EMPTY_STRING = "";
private static final String NULL_STRING = "null";
private static final String ARRAY_START = "{";
private static final String ARRAY_END = "}";
private static final String EMPTY_ARRAY = "{}";
private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
public 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;
}
@Nullable
public static Object unwrapOptional(@Nullable Object obj) {
return null;
}
public static boolean containsElement(@Nullable Object[] array, Object element) {
return true;
}
public static boolean containsConstant(Enum<?>[] enumValues, String constant) {
return true;
}
public static boolean containsConstant(Enum<?>[] enumValues, String constant, boolean caseSensitive) {
return true;
}
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;
}
private static boolean arrayEquals(Object o1, Object o2) {
return false;
}
public static int nullSafeHashCode(@Nullable Object obj) {
return 1;
}
public static int nullSafeHashCode(@Nullable Object[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable boolean[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable byte[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable char[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable double[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable float[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable int[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable long[] array) {
return 1;
}
public static int nullSafeHashCode(@Nullable short[] array) {
return 1;
}
/** @deprecated */
@Deprecated
public static int hashCode(boolean bool) {
return 1;
}
/** @deprecated */
@Deprecated
public static int hashCode(double dbl) {
return 1;
}
/** @deprecated */
@Deprecated
public static int hashCode(float flt) {
return 1;
}
/** @deprecated */
@Deprecated
public static int hashCode(long lng) {
return 1;
}
public static String identityToString(@Nullable Object obj) {
return "";
}
public static String getIdentityHexString(Object obj) {
return "";
}
public static String getDisplayString(@Nullable Object obj) {
return "";
}
public static String nullSafeClassName(@Nullable Object obj) {
return "";
}
public static String nullSafeToString(@Nullable Object obj) {
return "";
}
public static String nullSafeToString(@Nullable Object[] array) {
return "";
}
public static String nullSafeToString(@Nullable boolean[] array) {
return "";
}
public static String nullSafeToString(@Nullable byte[] array) {
return "";
}
public static String nullSafeToString(@Nullable char[] array) {
return "";
}
public static String nullSafeToString(@Nullable double[] array) {
return "";
}
public static String nullSafeToString(@Nullable float[] array) {
return "";
}
public static String nullSafeToString(@Nullable int[] array) {
return "";
}
public static String nullSafeToString(@Nullable long[] array) {
return "";
}
public static String nullSafeToString(@Nullable short[] array) {
return "";
}
}

View File

@@ -0,0 +1,30 @@
package org.springframework.util;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;
import java.util.StringJoiner;
import java.util.StringTokenizer;
import java.util.TimeZone;
import org.springframework.lang.Nullable;
public abstract class StringUtils {
@Deprecated
public static boolean isEmpty(@Nullable Object str) {
return true;
}
}

View File

@@ -0,0 +1,51 @@
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
method = {RequestMethod.GET}
)
public @interface GetMapping {
@AliasFor(
annotation = RequestMapping.class
)
String name() default "";
@AliasFor(
annotation = RequestMapping.class
)
String[] value() default {};
@AliasFor(
annotation = RequestMapping.class
)
String[] path() default {};
@AliasFor(
annotation = RequestMapping.class
)
String[] params() default {};
@AliasFor(
annotation = RequestMapping.class
)
String[] headers() default {};
@AliasFor(
annotation = RequestMapping.class
)
String[] consumes() default {};
@AliasFor(
annotation = RequestMapping.class
)
String[] produces() default {};
}

View File

@@ -0,0 +1,4 @@
package org.springframework.web.bind.annotation;
public @interface Mapping {
}

View File

@@ -1,11 +1,32 @@
package org.springframework.web.bind.annotation;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(value=RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}

View File

@@ -1,8 +1,23 @@
package org.springframework.web.bind.annotation;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target(value=ElementType.PARAMETER)
@Retention(value=RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam { }
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}

View File

@@ -0,0 +1,13 @@
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}