I am working on a Jenkins plugin that uses an HTML form on a page that's generated using Jelly and Stapler requests. After upgrading to a newer version of Jenkins, POSTs from this form stopped working, giving me the following 403 error from Jenkins:
HTTP ERROR 403 No valid crumb was included in the request
URI: /job/Watchr_Sandbox/performanceReports/
STATUS: 403
MESSAGE: No valid crumb was included in the request
SERVLET: Stapler
I've done a lot of research on the recent CSRF security improvement to Jenkins that seems to be at the root of this problem, and I've read a lot of other Stack Overflow solutions to this problem (this one seems to be closest), but I haven't found any examples that are exactly like my situation.
Essentially, I would like the form's POST to include Jenkins crumb information. Right now, I'm trying to solve this by including the crumb information as hidden form values, but I don't know if I'm acquiring the Jenkins crumb the correct way, or if I'm even approaching this problem correctly.
.jelly file
<j:jelly xmlns:j="jelly:core" xmlns:g="glide" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:test="/lib/hudson/test" xmlns:f="/lib/form" xmlns:i="jelly:fmt" xmlns:RP="jelly:RP">
<l:layout title="Performance Reports">
<st:include page="sidepanel.jelly" it="${it.getOwner()}" />
<l:main-panel>
<j:out value="${it.createHtml()}"/>
</l:main-panel>
</l:layout>
</j:jelly>
Java code
import org.kohsuke.stapler.CrumbIssuer;
import org.kohsuke.stapler.Stapler;
import hudson.Functions;
public String createHtml() {
StringBuilder sb = new StringBuilder();
String crumb = Functions.getCrumb(Stapler.getCurrentRequest());
String crumbRequestField = Functions.getCrumbRequestField();
sb.append("<form method=\"post\" autocomplete=\"off\"");
// ...
sb.append("<input type=\"hidden\"");
sb.append(" id=\"crumb\"");
sb.append(" name=\"crumb\"");
sb.append(" value=\"").append(crumb).append("\"");
sb.append("/>");
sb.append("<input type=\"hidden\"");
sb.append(" id=\"crumbRequestField\"");
sb.append(" name=\"crumbRequestField\"");
sb.append(" value=\"").append(crumbRequestField).append("\"");
sb.append("/>");
// ...
sb.append("</form>");
return sb.toString();
}