Jenkins Docker container - 403 no valid crumb was included in the request

1/3/2018

I'm setting up my Jenkins server, and on simple requests in the web interface, like creating a folder, a pipeline, a job, etc., I periodically get the following error:

HTTP ERROR 403
Problem accessing /job/Mgmt/createItem. Reason:

    No valid crumb was included in the request

The server is using the Jenkins/Jenkins container, orchestrated by Kubernetes on a cluster on AWS created with kops. It sits behind a class ELB.

Why might I be experiencing this? I thought the crumb was to combat certain CSRF requests, but all I'm doing is using the Jenkins web interface.

-- djt
jenkins
kubernetes

3 Answers

11/1/2019

After a couple of hours of struggling, I was able to make it work with curl:

export JENKINS_URL=http://localhost
export JENKINS_USER=user
export JENKINS_TOKEN=mytoken
export COOKIE_JAR=/tmp/cookies

JENKINS_CRUMB=$(curl --silent --cookie-jar $COOKIE_JAR $JENKINS_URL'/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' -u $JENKINS_USER:$JENKINS_TOKEN)

echo $JENKINS_CRUMB

curl --cookie $COOKIE_JAR $JENKINS_URL/createItem?name=yourJob --data-binary @jenkins/config.xml -H $JENKINS_CRUMB -H "Content-Type:text/xml" -u $JENKINS_USER:$JENKINS_TOKEN -v
-- ThiagoAlves
Source: StackOverflow

3/7/2018

Enabling proxy compatibility may help to solve this issue. Go to Settings -> Security -> Enable proxy compatibility in CSRF Protection section

Some HTTP proxies filter out information that the default crumb issuer uses to calculate the nonce value. If an HTTP proxy sits between your browser client and your Jenkins server and you receive a 403 response when submitting a form to Jenkins, checking this option may help. Using this option makes the nonce value easier to forge.

-- Alik Khilazhev
Source: StackOverflow

11/27/2019

when calling the http://JENKINS_SERVER:JENKINS_PORT/JENKINS_PREFIX/crumbIssuer/api/json you receive a header ("Set-Cookie") to set a JSESSIONID, so you must supply it in the upcoming requests you issue,

the reason is that jenkins test for valid crumb in this manner: comparing the crumb you send in the request with a crumb it generates on the server side (using your session id),

you can see it in jenkins code: scroll down to method:

public boolean validateCrumb(ServletRequest request, String salt, String crumb)

it means you HAVE to include a session in the next requests (after fetching the crumb)!

so the curl --cookie must be used as ThiagoAlves stated in his solution

i use java so i used this next tester (HTTPClient would be prefered, but i wanted a simple java only example):

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;


public class JobRunner
{
    String jenkinsUser = "tester";
    String jenkinsPassword = "1234"; // password or API token
    String jenkinsServer = "localhost";
    String jenkinsPort = "8080";
    String jenkinsPrefix = "/jenkins";

    String jSession = null;
    String crumb = null;
    HttpURLConnection connection = null;
    String responseBody = "";

    public void openConnection(String requestMethod, String relativeURL) throws Exception
    {       
        // prepare the authentication string
        String authenticationString = jenkinsUser + ":" + jenkinsPassword;
        String encodedAuthenticationString = Base64.getEncoder().encodeToString(authenticationString.getBytes("utf-8"));

        // construct the url and open a connection to it
        URL url = new URL("http://" + jenkinsServer + ":" + jenkinsPort + jenkinsPrefix + relativeURL);
        connection = (HttpURLConnection) url.openConnection();

        // set the login info as a http header
        connection.setRequestProperty("Authorization", "Basic " + encodedAuthenticationString);

        // set the request method
        connection.setRequestMethod(requestMethod);
    }

    public void readResponse() throws Exception
    {
        // get response body and set it in the body member
        int responseCode = connection.getResponseCode();
        switch (responseCode)
        {
        case 401:
                System.out.println("server returned 401 response code - make sure your user/password are correct");
            break;

        case 404:
            System.out.println("server returned 404 response code - make sure your url is correct");
        break;

        case 201:
        case 200:
            System.out.println("server returned " + responseCode + " response code");
            InputStream responseBodyContent = connection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseBodyContent));
            String currentLine;
            while ((currentLine = bufferedReader.readLine()) != null)
            {
                responseBody = responseBody + currentLine + "\n";
            }
        break;

        default:
            System.out.println("server returned error response code: " + responseCode);
            break;
        }
    }

    public void setSessionCookie() throws Exception
    {
        jSession = connection.getHeaderField("Set-Cookie"); 
        System.out.println("jSession: " + jSession);
    }

    public void disconnect() throws Exception
    {
        if(connection!=null)
        {
            connection.disconnect();
            connection = null;
            responseBody = "";
        }
    }

    public void getCrumb() throws Exception
    {
        try
        {
            openConnection("GET", "/crumbIssuer/api/json");
            readResponse();
            setSessionCookie();

            int crumbIndex = responseBody.indexOf("crumb\":\"");
            if(crumbIndex!=-1)
            {
                int crumbIndexEnd = responseBody.indexOf("\",\"", crumbIndex);

                crumb = responseBody.substring(crumbIndex + "crumb\":\"".length(), crumbIndexEnd);
                System.out.println(crumb);
            }
        }
        finally
        {
            disconnect();
        }
    }

    public void runJob() throws Exception
    {
        try
        {
            openConnection("POST", "/job/test/build");

            connection.setDoOutput(true);
            connection.setRequestProperty("Cookie", jSession);
            connection.setRequestProperty("Jenkins-Crumb", crumb);

            readResponse();
            System.out.println("Post response: " + responseBody);
        }
        finally
        {
            disconnect();
        }
    }

    public static void main(String[] args)
    {
        JobRunner jobRunner = new JobRunner();

        try
        {
            jobRunner.getCrumb();

            jobRunner.runJob();
        }
        catch (Exception err)
        {
            err.printStackTrace();
        }
    }
}
-- Shaybc
Source: StackOverflow