所有
我需要能够使用Jenkins REST API将作业发布到Jenkins,但无法通过身份验证。我一直试图这样做几天,并在本网站和Jenkins网站上研究了答案。我一直试图使用Apache HttpClient没有成功(即使有抢占式验证)。我一直收到错误代码403 - 禁止。有没有人能够成功地做到这一点?这是我正在使用的代码:
package stackoverflow.question;
import gsafame.sample;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
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.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class PreEmptiveAuth {
final Logger log = Logger.getLogger(sample.class.getCanonicalName());
private JobData jd;
private CredentialsProvider credpro;
private AuthScope as;
private UsernamePasswordCredentials upc;
private String url;
public PreEmptiveAuth(JobData jd) {
this.jd = jd;
credpro = new BasicCredentialsProvider();
as = new AuthScope(jd.getServer(), 443);
upc = new UsernamePasswordCredentials(jd.getUsername(), jd.getPassword());
credpro.setCredentials(as, upc);
url = String.format("%s:8080/jenkins/job/%s/buildWithParameters", jd.getServer(), jd.getJob());
}
public void runTagJob() throws ClientProtocolException, IOException {
log.entering(this.getClass().getCanonicalName(), "runTagJob");
log.info("Entering runTagJob");
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credpro).build();
HttpPost httpPost = new HttpPost(url);
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", jd.getUsername()));
nvps.add(new BasicNameValuePair("password", jd.getPassword()));
nvps.add(new BasicNameValuePair("apiToken", jd.getToken()));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println(response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity2);
} finally {
response2.close();
}
log.info("Exiting runTagJob");
log.exiting(this.getClass().getCanonicalName(), "runTagJob");
}
public void runPreTagJob() throws ClientProtocolException, IOException {
log.entering(this.getClass().getCanonicalName(), "runPreTagJob");
log.info("Entering runPreTagJob");
HttpHost targetHost = new HttpHost(jd.getServer(), 8080, "http");
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credpro).build();
try {
// 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(targetHost, basicAuth);
// Add AuthCache to the execution context
HttpClientContext localContext = HttpClientContext.create();
localContext.setAuthCache(authCache);
HttpPost httpPost = new HttpPost(url);
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", jd.getUsername()));
nvps.add(new BasicNameValuePair("password", jd.getPassword()));
nvps.add(new BasicNameValuePair("apiToken", jd.getToken()));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(targetHost, httpPost, localContext);
try {
System.out.println(response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity2);
} finally {
response2.close();
}
} finally {
httpclient.close();
}
log.info("Exiting runPreTagJob");
log.exiting(this.getClass().getCanonicalName(), "runPreTagJob");
}
}
传递给此类的JobData对象包含用户名,密码,服务器和作业信息等信息。我希望这有帮助!
答案 0 :(得分:8)
在对几个网站进行研究之后,我设法将足够的信息拼凑起来以提出解决方案。我正在使用旧的HTTP身份验证代码,在某些情况下不推荐使用它 - 但它没有其他任何东西可以使用。如果有人有更好的解决方案,我会有兴趣看到它。无论如何,这是:
主类:
package stackoverflow.answer;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
public class sample {
public static void main(String[] args) throws Exception {
final Logger log = Logger.getLogger(sample.class.getCanonicalName());
JobData jd = new JobData();
Scanner input = new Scanner(System.in);
try {
System.out.print("What is your user name? ");
jd.setUsername(input.next());
System.out.print("What is your password? ");
jd.setPassword(input.next());
} catch (Exception e) {
log.log(Level.SEVERE, "The system encountered an exception while attempting to login");
} finally {
input.close();
}
jd.setJob("TestREST");
jd.setServer("http://YOUR-SERVER");
jd.setPort("YOUR-PORT");
// set the parameters
List<NameValuePair> parameters = jd.getParameters();
parameters.add(new BasicNameValuePair("SONAR-TARGET", "true"));
parameters.add(new BasicNameValuePair("RELEASE", "1311.1.1"));
parameters.add(new BasicNameValuePair("REVISION", "HEAD"));
// run the job
JenkinsPoster jp = new JenkinsPoster(jd);
log.info("executing postJenkinsJob");
jp.postJenkinsJob();
log.info("executed postJenkinsJob");
}
}
JobData类(包含有关您需要运行的作业的信息)
package stackoverflow.answer;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
public class JobData {
private String username;
private String password;
private String token;
private String server;
private String port;
private String job;
private List<NameValuePair> parameters;
public JobData() {
parameters = new ArrayList<NameValuePair>();
}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public String getToken() {return token;}
public void setToken(String token) {this.token = token;}
public String getServer() {return server;}
public void setServer(String server) {this.server = server;}
public String getPort() {return port;}
public void setPort(String port) {this.port = port;}
public String getJob() {return job;}
public void setJob(String job) {this.job = job;}
public List<NameValuePair> getParameters() {return parameters;}
}
JenkinsPoster类(包含连接到Jenkins和POST作业的业务逻辑)
package stackoverflow.answer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
public class JenkinsPoster {
final Logger log = Logger.getLogger(getClass().getCanonicalName());
private JobData jd;
public JenkinsPoster(JobData jobData) {
this.jd = jobData;
}
@SuppressWarnings("deprecation")
public void postJenkinsJob() throws UnsupportedEncodingException {
log.entering(getClass().getCanonicalName(), "JenkinsPoster");
// Jenkins url
String jenkinsUrl = String.format("%s:%s/jenkins", jd.getServer(), jd.getPort());
log.info("url = " + jenkinsUrl);
// 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(jd.getUsername(), jd.getPassword()));
// 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);
// Post the request to start the build
List<NameValuePair> parameters = jd.getParameters();
UrlEncodedFormEntity uefe = null;
String buildUrl = "";
if (parameters.isEmpty()) {
buildUrl = jenkinsUrl + "/job/" + jd.getJob() + "/build";
}
else {
buildUrl = jenkinsUrl + "/job/" + jd.getJob() + "/buildWithParameters";
uefe = new UrlEncodedFormEntity(parameters);
}
HttpPost post = new HttpPost(buildUrl);
post.setHeader("User-Agent", "Mozilla/5.0");
if (uefe != null) {
post.setEntity(uefe);
}
try {
// Execute your request with the given context
HttpResponse response = client.execute(post, context);
HttpEntity entity = response.getEntity();
log.info(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
client.close();
}
log.exiting(getClass().getCanonicalName(), "JenkinsPoster");
}
}
...最后,前一个类用于抢先登录Jenkins的PreemptiveAuth类。
package stackoverflow.answer;
import java.io.IOException;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
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.client.CredentialsProvider;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
public class PreemptiveAuth implements HttpRequestInterceptor {
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);
}
}
}
}
答案 1 :(得分:0)
有关处理Jenkins REST API身份验证的文档,请访问:
https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients