Java: Stapler tests and stubs

This commit is contained in:
Jami Cogswell
2024-12-18 10:52:33 -05:00
parent 26b7c1a572
commit 3bf6dc24c1
12 changed files with 259 additions and 1 deletions

View File

@@ -13,6 +13,15 @@ import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.kohsuke.stapler.WebMethod;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.kohsuke.stapler.verb.POST;
import org.kohsuke.stapler.verb.GET;
import org.kohsuke.stapler.verb.PUT;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.HttpRedirect;
import org.kohsuke.stapler.HttpResponses;
@Controller
public class CsrfUnprotectedRequestTypeTest {
@@ -212,9 +221,71 @@ public class CsrfUnprotectedRequestTypeTest {
myBatisService.bad10(user);
}
// Test name-based heuristic
// BAD: method name implies a state-change
@GetMapping(value = "delete")
public String delete(@RequestParam String user) { // $ hasCsrfUnprotectedRequestType
return "delete";
}
// Test Stapler web methods with name-based heuristic
// BAD: Stapler web method annotated with `@WebMethod` and method name that implies a state-change
@WebMethod(name = "post")
public String doPost(String user) { // $ hasCsrfUnprotectedRequestType
return "post";
}
// GOOD: nothing to indicate that this is a Stapler web method
public String postNotAWebMethod(String user) {
return "post";
}
// GOOD: Stapler web method annotated with `@RequirePOST` and method name that implies a state-change
@RequirePOST
public String doPost1(String user) {
return "post";
}
// GOOD: Stapler web method annotated with `@POST` and method name that implies a state-change
@POST
public String doPost2(String user) {
return "post";
}
// BAD: Stapler web method annotated with `@GET` and method name that implies a state-change
@GET
public String doPost3(String user) { // $ hasCsrfUnprotectedRequestType
return "post";
}
// BAD: Stapler web method annotated with `@PUT` and method name that implies a state-change
// We treat this case as bad for Stapler since the Jenkins docs only say that @POST/@RequirePOST
// provide default protection against CSRF.
@PUT
public String doPut(String user) { // $ hasCsrfUnprotectedRequestType
return "put";
}
// BAD: Stapler web method parameter of type `StaplerRequest` and method name that implies a state-change
public String doPost4(StaplerRequest request) { // $ hasCsrfUnprotectedRequestType
return "post";
}
// BAD: Stapler web method parameter annotated with `@QueryParameter` and method name that implies a state-change
public String doPost5(@QueryParameter(value="user", fixEmpty=false, required=false) String user) { // $ hasCsrfUnprotectedRequestType
return "post";
}
// BAD: Stapler web method with declared exception type implementing HttpResponse and method name that implies a state-change
public String doPost6(String user) throws HttpResponses.HttpResponseException { // $ hasCsrfUnprotectedRequestType
return "post";
}
// BAD: Stapler web method with return type implementing HttpResponse and method name that implies a state-change
public HttpRedirect doPost7(String url) { // $ hasCsrfUnprotectedRequestType
HttpRedirect redirect = new HttpRedirect(url);
return redirect;
}
}

View File

@@ -1 +1 @@
semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/org.mybatis-3.5.4/
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/org.mybatis-3.5.4/:${testdir}/../../../stubs/stapler-1.263/:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/jaxen-1.2.0

View File

@@ -0,0 +1,13 @@
// Generated automatically from org.kohsuke.stapler.AnnotationHandler for testing purposes
package org.kohsuke.stapler;
import java.lang.annotation.Annotation;
import org.kohsuke.stapler.StaplerRequest;
abstract public class AnnotationHandler<T extends Annotation>
{
protected final Object convert(Class p0, String p1){ return null; }
public AnnotationHandler(){}
public abstract Object parse(StaplerRequest p0, T p1, Class p2, String p3);
}

View File

@@ -0,0 +1,28 @@
// Generated automatically from org.kohsuke.stapler.QueryParameter for testing purposes
package org.kohsuke.stapler;
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;
import org.kohsuke.stapler.AnnotationHandler;
import org.kohsuke.stapler.InjectedParameter;
import org.kohsuke.stapler.StaplerRequest;
@Documented
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.PARAMETER})
public @interface QueryParameter
{
String value();
boolean fixEmpty();
boolean required();
static public class HandlerImpl extends AnnotationHandler<QueryParameter>
{
public HandlerImpl(){}
public Object parse(StaplerRequest p0, QueryParameter p1, Class p2, String p3){ return null; }
}
}

View File

@@ -0,0 +1,18 @@
// Generated automatically from org.kohsuke.stapler.WebMethod for testing purposes
package org.kohsuke.stapler;
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;
@Documented
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.METHOD})
public @interface WebMethod
{
String[] name();
}

View File

@@ -0,0 +1,15 @@
// Generated automatically from org.kohsuke.stapler.interceptor.Interceptor for testing purposes
package org.kohsuke.stapler.interceptor;
import org.kohsuke.stapler.Function;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
abstract public class Interceptor
{
protected Function target = null;
public Interceptor(){}
public abstract Object invoke(StaplerRequest p0, StaplerResponse p1, Object p2, Object[] p3);
public void setTarget(Function p0){}
}

View File

@@ -0,0 +1,21 @@
// Generated automatically from org.kohsuke.stapler.interceptor.InterceptorAnnotation for testing purposes
package org.kohsuke.stapler.interceptor;
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;
import org.kohsuke.stapler.interceptor.Interceptor;
import org.kohsuke.stapler.interceptor.Stage;
@Documented
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.ANNOTATION_TYPE})
public @interface InterceptorAnnotation
{
Class<? extends Interceptor> value();
Stage stage();
}

View File

@@ -0,0 +1,25 @@
// Generated automatically from org.kohsuke.stapler.interceptor.RequirePOST for testing purposes
package org.kohsuke.stapler.interceptor;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.interceptor.Interceptor;
import org.kohsuke.stapler.interceptor.InterceptorAnnotation;
import org.kohsuke.stapler.interceptor.Stage;
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD})
public @interface RequirePOST
{
static public class Processor extends Interceptor
{
public Object invoke(StaplerRequest p0, StaplerResponse p1, Object p2, Object[] p3){ return null; }
public Processor(){}
}
}

View File

@@ -0,0 +1,10 @@
// Generated automatically from org.kohsuke.stapler.interceptor.Stage for testing purposes
package org.kohsuke.stapler.interceptor;
public enum Stage
{
PREINVOKE, SELECTION;
private Stage() {}
}

View File

@@ -0,0 +1,19 @@
// Generated automatically from org.kohsuke.stapler.verb.GET for testing purposes
package org.kohsuke.stapler.verb;
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;
import org.kohsuke.stapler.interceptor.InterceptorAnnotation;
import org.kohsuke.stapler.interceptor.Stage;
@Documented
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.METHOD})
public @interface GET
{
}

View File

@@ -0,0 +1,19 @@
// Generated automatically from org.kohsuke.stapler.verb.POST for testing purposes
package org.kohsuke.stapler.verb;
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;
import org.kohsuke.stapler.interceptor.InterceptorAnnotation;
import org.kohsuke.stapler.interceptor.Stage;
@Documented
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.METHOD})
public @interface POST
{
}

View File

@@ -0,0 +1,19 @@
// Generated automatically from org.kohsuke.stapler.verb.PUT for testing purposes
package org.kohsuke.stapler.verb;
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;
import org.kohsuke.stapler.interceptor.InterceptorAnnotation;
import org.kohsuke.stapler.interceptor.Stage;
@Documented
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.METHOD})
public @interface PUT
{
}