27

I have just been working on setting up Jenkins (latest - 2.5) behind a reverse proxy with Nginx so that I can access it over HTTPS.

It's working, however my Multibranch Pipeline jobs no longer have the "Trigger Builds Remotely" option in the main config. I don't think I changed any other configurations. Any ideas what happened and how to get it back?

Here's what I want back:

Screenshot of what I want back

MarkRoland
  • 915
  • 2
  • 9
  • 13

6 Answers6

35

After some time and searching around, I think I am able to answer my own question with some confidence.

I believe the answer lies within the security settings. The purpose of the Authentication Token is to allow unauthorized users (developers) to trigger a build without having login access to Jenkins (see https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients and https://wiki.jenkins-ci.org/display/JENKINS/Quick+and+Simple+Security).

So if you are using Matrix-based security (under "Configure Global Security" >> Authorization), then the "Trigger builds remotely" option will go away because it is presumed that you will be authenticating requests using a Jenkins user account.

In order to do that you can make an HTTP request with the username/password (or even better username/API Token):

curl -X POST "https://username:api-token@JENKINS_URL/job/Example/build"
MarkRoland
  • 915
  • 2
  • 9
  • 13
28

Disclaimer

Before reading this answer you have to know that I just accumulate all helpful information in this answer, which I've found across stackoverflow, all creds should be for guys who did actual researches.

I move the content of the link from this comment to stackoverflow just to preserve from deadlink.

Info

The name of my job is Football. I would also suggest you to create a dedicated jenkins user and password rather than using admin:admin as I'll use in this example. My jenkins GUI URL is http://192.168.99.20:8080 as I am on vagrant.

Create job

  1. Login to jenkins in http://192.168.99.20:8080 address.
  2. Create a "Free Style" project named as "Football".
  3. Open it's configuration.
  4. Go to "Build Triggers" section.
  5. Tick "Trigger builds remotely (e.g., from scripts)" option just to take a note of the text written in there and untick it again. Text reads Use the following URL to trigger build remotely: JENKINS_URL/job/Football/build?token=TOKEN_NAME or /buildWithParameters?token=TOKEN_NAME. Optionally append &cause=Cause+Text to provide text that will be included in the recorded build cause..
  6. Save and exit.

Get API user and token

  1. Login to jenkins in http://192.168.99.20:8080 address.
  2. Click your username (mine is admin) on right hand side of the page.
  3. Select "Configure" option which will take you to http://192.168.99.20:8080/user/admin/configure page.
  4. In "API Token" section click "Show API token" button.
  5. Note "User ID" and "API Token" to use in your curl command later on. e.g. admin:85703fb68927f04968630e192e4927cb

Obtain crumb

For more information, visit Remote access API page.

$ wget -q --auth-no-challenge --user admin --password admin --output-document - 'http://192.168.99.20:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)'

This will give you something like Jenkins-Crumb:44e7033af70da95a47403c3bed5c10f8. Without crumb information, running curl command will result in example errors such as HTTP/1.1 403 Forbidden or Error 403 No valid crumb was included in the request.

Test

$ curl -I -X POST http://admin:85703fb68927f04968630e192e4927cb@192.168.99.20:8080/job/Football/build -H "Jenkins-Crumb:44e7033af70da95a47403c3bed5c10f8"
HTTP/1.1 201 Created
Date: Fri, 02 Jun 2017 06:17:51 GMT
X-Content-Type-Options: nosniff
Location: http://192.168.99.20:8080/queue/item/17/
Content-Length: 0
Server: Jetty(9.2.z-SNAPSHOT)

Original link

In additional to the information above I've also found how to get Jenkins-Crumb with cli from this answer

CRUMB=$(curl -s 'http://USER:TOKEN@localhost:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
VaL
  • 776
  • 1
  • 10
  • 14
  • Thanks! Using API Token was really helpful. I changed to that to let me get through moving to a Google Login Plugin. Very helpful. – Josiah Nov 16 '18 at 20:39
  • Seems like the authorizationToken has been deprecated in DSL.. – Daniel Hajduk Mar 04 '20 at 14:53
  • @DanielHajduk, Thanks. I'm not using Jenkins anymore in my projects, so cannot update my post at this moment. But I'll try to do this in nearest time. – VaL Mar 05 '20 at 07:44
8

There’s a Jenkins plugin that works with 1.565.3 and newer which can bypass the matrix-based authentication for triggering the build job. I found this in a comment on JENKINS-17764 (which covers this particular issue) by Emil Dragu:

Install the Build Token Root Plugin, then change the upper part in the URL to the lower equivalent (rendered as list to make it more easily visible):

  • job/ProjectName/build?token=test
  • buildByToken/build?job=ProjectName&token=test

You can still pass an optional cause argument, too.

mirabilos
  • 5,123
  • 2
  • 46
  • 72
3

Agree. You can find the API token when you click on the user name which appears on right corner. Than go to configure and click on Show API Token.

Ankit
  • 88
  • 7
1

I wrote this python script to submit job. This also allow to upload file to a job.

import os
import json
import requests
from glob import glob
from getpass import getpass

AUTH = (
    os.environ.get('JENKIN_USER') or input('Jenkin username: '),
    os.environ.get('JENKIN_PASSWORD') or getpass('Jenkin password: ')
)
TOKEN = os.environ.get('JENKIN_TOKEN') or input('Jenkin job token: ')
JENKIN_DOMAIN = 'https://jenkins'
REASON = 'Batch jenkin job'
JOB_URL = f'{JENKIN_DOMAIN}/view/some-job-url'
CRUM_ISSUER = f'{JENKIN_DOMAIN}/crumbIssuer/api/json'


session = requests.Session()

def get_crumb(auth=AUTH):
    return session.get(CRUM_ISSUER, auth=auth).json()


def build_job(job_url, params=None, files=None, token=TOKEN, cause=REASON,
              auth=AUTH):
    crum = get_crumb()
    payload = {}
    if params:
        job_url = f'{job_url}/buildWithParameters'
        parameter = []
        if files:
            for key in files:
                parameter.append({"name": key, "file": key})
        for key, value in params.items():
            parameter.append({"name": key, "value": str(value)})
        payload.update(params)
        payload['json'] = json.dumps({
            'parameter': parameter,
            'statusCode': "303",
            'redirectTo': '.'
        })
    else:
        job_url = f'{job_url}/build'

    r = session.post(
        job_url,
        data=payload,
        files=files,
        params={"token": token, "cause": cause, crum['crumbRequestField']: crum['crumb']},
        auth=auth,
        headers={crum['crumbRequestField']: crum['crumb']}
    )
    return r


if __name__ == '__main__':
    # Build job
    build_job(JOB_URL, params={
        'DO_SOMETHING': 'true', "DO_SOMETHING_ELSE"
    })

    # Build job with file upload
    build_job(JOB_URL, params={'NO_HEADER': 'true'}, files={'UPLOAD_FILE_FIELD': f})

James
  • 13,571
  • 6
  • 61
  • 83
0

If you want the same programmatically, then you can have a look at Programmatically retrieve Jenkins REST API Token

You can then use this token to authenticate the other Jenkins API's.

footyapps27
  • 3,982
  • 2
  • 25
  • 42