To make scripted clients (such as wget) invoke operations that require authorization (such as scheduling a build), use HTTP BASIC authentication to specify the user name and the API token. This is often more convenient than emulating the form-based authentication.
API token is new since 1.426
Earlier versions of Jenkins require you to specify your real password, and it is only available when your security realm is password-based (for example, OpenID, Crowd and CAS plugins authenticate you without a password, so you simply don't have any password!) Specifying the real password is still supported after 1.426, but it is not recommended because the risk of revealing password, and the human tendency to reuse the same password in different places.
The API token is available in your personal configuration page. Click your name on the top right corner on every page, then click "Configure" to see your API token. (The URL $root/me/configure
is a good shortcut.) You can also change your API token from here.
Note that Jenkins does not do any authorization negotiation. i.e. it immediately returns a 403 (Forbidden) response instead of a 401 (Unauthorized) response, so make sure to send the authentication information from the first request (aka "preemptive authentication").
Groovy script using cdancy/jenkins-rest
The cdancy/jenkins-rest client greatly simplifies REST API access. The following Groovy code shows how to authenticate to Jenkins and get some system info:
@Grab(group='com.cdancy', module='jenkins-rest', version='0.0.18') import com.cdancy.jenkins.rest.JenkinsClient JenkinsClient client = JenkinsClient.builder() .endPoint("http://127.0.0.1:8080") // Optional. Defaults to http://127.0.0.1:8080 .credentials("user:apiToken") // Optional. .build() println(client.api().systemApi().systemInfo())
For additional information, see the cdancy/jenkins-rest wiki.
Groovy script using commons-httpclient
In a groovy script, this could look something like this (using commons-httpclient):
import org.apache.commons.httpclient.* import org.apache.commons.httpclient.auth.* import org.apache.commons.httpclient.methods.* @Grab(group='commons-httpclient', module='commons-httpclient', version='3.1') void createNewJenkinsProject() { def server = "server" def jenkinsHost = "https://${server}/jenkins/" def projectName = "TEST" def configurationFile = "config.xml" def username = "username" def apiToken = "apiToken" def client = new HttpClient() client.state.setCredentials( new AuthScope( server, 443, "realm"), new UsernamePasswordCredentials( username, apiToken ) ) // Jenkins does not do any authentication negotiation, // i.e. it does not return a 401 (Unauthorized) // but immediately a 403 (Forbidden) client.params.authenticationPreemptive = true def post = new PostMethod( "${jenkinsHost}/createItem?name=${projectName}" ) post.doAuthentication = true File input = new File(configurationFile); RequestEntity entity = new FileRequestEntity(input, "text/xml; charset=UTF-8"); post.setRequestEntity(entity); try { int result = client.executeMethod(post) println "Return code: ${result}" post.responseHeaders.each{ println it.toString().trim() } println post.getResponseBodyAsString() } finally { post.releaseConnection() } } createNewJenkinsProject()
wget note
Note: If you are using wget 1.11 against Jenkins version 1.586 and above with the JENKINS-25169 fix, you might need to use the following options:
wget --auth-no-challenge --http-user=user --http-password=apiToken --secure-protocol=TLSv1 http://jenkins.yourcompany.com/job/your_job/build?token=TOKEN
Note: If you are using wget 1.11, you might need to use the following options:
wget --auth-no-challenge --http-user=user --http-password=apiToken http://jenkins.yourcompany.com/job/your_job/build?token=TOKEN
With wget 1.10.x the following is enough (but will not work with 1.11.x) :
wget http://user:apiToken@jenkins.yourcompany.com/job/your_job/build?token=TOKEN
See this RedHat bug report for more detailled explanations: https://bugzilla.redhat.com/show_bug.cgi?id=446949 (this also affect other distributions)
(Report indicates that wget 1.0 and 1.1 don't appear to have a --auth-no-challenge option.)
Perl LWP example for a scripted client
The following Perl example uses the LWP module to start a Job via a "Trigger builds remotely" token:
# # Use LWP to run a Jenkins job # set authorization_basic on the request object # to make use of BASIC HTTP authorization, apparently # already handling the preemptive part correctly this # way. # use strict; use warnings; use LWP; my $server = 'srvname'; my $srvurl = "http://$server/jenkins"; my $uagent = LWP::UserAgent->new; my $req = HTTP::Request->new( GET => "$srvurl/job/test/build?token=theTokenConfiguredForThisJob&cause=LWP+Test" ); $req->authorization_basic('username@mydomain.com', 'apiToken'); my $res = $uagent->request($req); # Check the outcome of the response print "Result: " . $res->status_line . "\n"; print $res->headers->as_string; print "\n"; if (!$res->is_success) { print "Failed\n"; } else { print "Success!\n"; # print $res->content, "\n"; }
Java example with httpclient 4.1.2
This will authenticate you on your jenkins and launch the defined build. Be careful on security issues since this sample is based on username/password authentication.
import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthState; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.ClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; /** * Simple class to launch a jenkins build on run@Cloud platform, should also work on every jenkins instance (not tested) * */ public class TestPreemptive { public static void main(String[] args) { // Credentials String username = "YOUR_USERNAME"; String password = "YOUR_PASSWORD"; // Jenkins url String jenkinsUrl = "JENKINS_URL"; // Build name String jobName = "JOB"; // Build token String buildToken = "BUILD_TOKEN"; // Create your httpclient DefaultHttpClient client = new DefaultHttpClient(); // Then provide the right credentials client.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), new UsernamePasswordCredentials(username, password)); // Generate BASIC scheme object and stick it to the execution context BasicScheme basicAuth = new BasicScheme(); BasicHttpContext context = new BasicHttpContext(); context.setAttribute("preemptive-auth", basicAuth); // Add as the first (because of the zero) request interceptor // It will first intercept the request and preemptively initialize the authentication scheme if there is not client.addRequestInterceptor(new PreemptiveAuth(), 0); // You get request that will start the build String getUrl = jenkinsUrl + "/job/" + jobName + "/build?token=" + buildToken; HttpGet get = new HttpGet(getUrl); try { // Execute your request with the given context HttpResponse response = client.execute(get, context); HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Preemptive authentication interceptor * */ static class PreemptiveAuth implements HttpRequestInterceptor { /* * (non-Javadoc) * * @see org.apache.http.HttpRequestInterceptor#process(org.apache.http.HttpRequest, * org.apache.http.protocol.HttpContext) */ public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { // Get the AuthState AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); // If no auth scheme available yet, try to initialize it preemptively if (authState.getAuthScheme() == null) { AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth"); CredentialsProvider credsProvider = (CredentialsProvider) context .getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authScheme != null) { Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost .getPort())); if (creds == null) { throw new HttpException("No credentials for preemptive authentication"); } authState.setAuthScheme(authScheme); authState.setCredentials(creds); } } } } }
Java example with httpclient 4.3.x
This will cause httpclient 4.3 to issue authentication preemptively:
import java.io.IOException; import java.net.URI; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; public class JenkinsScraper { public String scrape(String urlString, String username, String password) throws ClientProtocolException, IOException { URI uri = URI.create(urlString); HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(new AuthScope(uri.getHost(), uri.getPort()), new UsernamePasswordCredentials(username, password)); // Create AuthCache instance AuthCache authCache = new BasicAuthCache(); // Generate BASIC scheme object and add it to the local auth cache BasicScheme basicAuth = new BasicScheme(); authCache.put(host, basicAuth); CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build(); HttpGet httpGet = new HttpGet(uri); // Add AuthCache to the execution context HttpClientContext localContext = HttpClientContext.create(); localContext.setAuthCache(authCache); HttpResponse response = httpClient.execute(host, httpGet, localContext); return EntityUtils.toString(response.getEntity()); } }