|
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.
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. Ie. 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".) 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, // ie. 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()
Perl LWP example for a scripted clientThe 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.2This 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.xThis 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()); } } |
Authenticating scripted clients
Skip to end of metadata
Go to start of metadata
Comments (8)
Jan 21, 2013
Timmy johnson says:
Will this still work with the active directory plugin enabled? I tried aut...Will this still work with the active directory plugin enabled? I tried authenticating from powershell using http basic authentication (passing in the api token for the password) with no luck.
Jan 24, 2013
John Dean says:
I have the same question. When using active directory plugin, I have to pr...I have the same question. When using active directory plugin, I have to provide my active directory password, which is definitely not what I want to do.
Feb 22, 2013
Timmy johnson says:
Hi, I'm not sure if it was the ps code I was using at the time or something wron...Hi, I'm not sure if it was the ps code I was using at the time or something wrong with that version of jenkins but I am now able to get this to work in version 1.501
Feb 07, 2013
Sergej Kleva says:
Hi there! I've successfully managed to run build with Java code e...Hi there!
I've successfully managed to run build with Java code example above.
But i tried similar to directly download an artifact file from the Jenkins and didn't succeed :(
I want to download a file with a similar Java code from above.
This is the actual file i want to download.
http://myJenkins:8080/job/staff-service/lastSuccessfulBuild/staff.rest.tomcat/artifact/1.3.0-SNAPSHOT/staff.rest.tomcat-1.3.0-SNAPSHOT.war
I've also tried with wget but with No success :( Always getting 403 Forbiden or 404 Not found.
If i put this link in web browser and enable Anonymous Read access in Jenkins i can download the file without problem!
But I don't want to grant Anonymous access within Jenkins 'cause of security issues.
Anyone willing to help? :)
Thanks in advance!
Feb 07, 2013
Sergej Kleva says:
I actually find the solution: Here it is: import java.io.FileOutputStream; i...I actually find the solution:
Here it is:
May 28, 2013
Grégory Joseph says:
Is it me or is this relatively unsafe ? If a malicious user got hold of my API t...Is it me or is this relatively unsafe ? If a malicious user got hold of my API token, they'd have access to anything I have access to, right ? And this probably includes changing my password remotely ? Or does this token only allow read access anyway ?
Sep 05, 2014
Jonathan Langevin says:
It does seem unsafe. Two-step auth seems more in order. Another option is to pro...It does seem unsafe. Two-step auth seems more in order. Another option is to proxy your Jenkins set up, and add additional auth requirements (or limit the /api/ path to only specific IPs, etc).
Oct 30, 2014
Leo Leung says:
Since Jenkins ver. 1.586, the method to trigger builds remotely using TOKEN auth...Since Jenkins ver. 1.586, the method to trigger builds remotely using TOKEN authentication URLs with wget described no longer work due to SSLv1 and SSLv2 is now disabled because of the POODLE vulnerability fix.
The following error will appear:
Add Comment