0

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();
}

1 Answers1

0

Finally found the answer, thanks to this other question: Jenkins stapler requests fail with no valid crumb

The problem was that for some reason, the name of the crumb header appended to the requests by default is actually wrong. It's Crumb as shown in the screenshot in my question, but it actually should be Jenkins-Crumb or .crumb for older versions of Jenkins.

So in my case, I simply needed to change the code to use "Jenkins-Crumb" instead of "crumb", and it worked perfectly:

    sb.append("<input type=\"hidden\"");
    sb.append(" id=\"Jenkins-Crumb\"");
    sb.append(" name=\"Jenkins-Crumb\"");
    sb.append(" value=\"").append(crumb).append("\"");
    sb.append("/>");