Skip to content

Commit

Permalink
JENKINS-36760 - Added suport to use Jenkins Credentials. Deprecated o…
Browse files Browse the repository at this point in the history
…ld basic credentials
  • Loading branch information
janario committed Mar 31, 2017
1 parent 670eefc commit 5d0dad2
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 86 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Expand Up @@ -108,6 +108,11 @@ THE SOFTWARE.
<version>4.5.3</version>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials</artifactId>
<version>2.1.13</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>script-security</artifactId>
Expand Down
68 changes: 30 additions & 38 deletions src/main/java/jenkins/plugins/http_request/HttpRequest.java
Expand Up @@ -10,12 +10,17 @@
import java.util.Map;

import javax.annotation.Nonnull;
import javax.servlet.ServletException;

import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;

import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
import com.cloudbees.plugins.credentials.common.StandardCredentials;
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import com.google.common.base.Strings;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
Expand All @@ -29,14 +34,16 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Item;
import hudson.model.Items;
import hudson.model.TaskListener;
import hudson.security.ACL;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.ListBoxModel.Option;

import jenkins.plugins.http_request.auth.Authenticator;
import jenkins.plugins.http_request.auth.BasicDigestAuthentication;
import jenkins.plugins.http_request.auth.FormAuthentication;
import jenkins.plugins.http_request.util.HttpClientUtil;
Expand Down Expand Up @@ -342,48 +349,33 @@ public ListBoxModel doFillContentTypeItems() {
return MimeType.getContentTypeFillItems();
}

public ListBoxModel doFillAuthenticationItems() {
return fillAuthenticationItems();
public ListBoxModel doFillAuthenticationItems(@AncestorInPath Item project,
@QueryParameter String url) {
return fillAuthenticationItems(project, url);
}

public static ListBoxModel fillAuthenticationItems() {
ListBoxModel items = new ListBoxModel();
items.add("");
for (BasicDigestAuthentication basicDigestAuthentication : HttpRequestGlobalConfig.get().getBasicDigestAuthentications()) {
items.add(basicDigestAuthentication.getKeyName());
}
for (FormAuthentication formAuthentication : HttpRequestGlobalConfig.get().getFormAuthentications()) {
items.add(formAuthentication.getKeyName());
}

return items;
}

public FormValidation doCheckUrl(@QueryParameter String value)
throws IOException, ServletException {
return FormValidation.ok();
}

public FormValidation doValidateKeyName(@QueryParameter String value) {
return validateKeyName(value);
}

public static FormValidation validateKeyName(String value) {
List<Authenticator> list = HttpRequestGlobalConfig.get().getAuthentications();

int count = 0;
for (Authenticator basicAuthentication : list) {
if (basicAuthentication.getKeyName().equals(value)) {
count++;
}
}
public static ListBoxModel fillAuthenticationItems(Item project, String url) {
if (project == null || !project.hasPermission(Item.CONFIGURE)) {
return new StandardListBoxModel();
}

if (count > 1) {
return FormValidation.error("The Key Name must be unique");
List<Option> options = new ArrayList<>();
for (BasicDigestAuthentication basic : HttpRequestGlobalConfig.get().getBasicDigestAuthentications()) {
options.add(new Option("(deprecated - use Jenkins Credentials) " +
basic.getKeyName(), basic.getKeyName()));
}

return FormValidation.validateRequired(value);
for (FormAuthentication formAuthentication : HttpRequestGlobalConfig.get().getFormAuthentications()) {
options.add(new Option(formAuthentication.getKeyName()));
}

AbstractIdCredentialsListBoxModel<StandardListBoxModel, StandardCredentials> items = new StandardListBoxModel()
.includeEmptyValue()
.includeAs(ACL.SYSTEM,
project, StandardUsernamePasswordCredentials.class,
URIRequirementBuilder.fromUri(url).build());
items.addMissing(options);
return items;
}

public static List<Range<Integer>> parseToRange(String value) {
Expand Down
Expand Up @@ -29,6 +29,10 @@
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;

import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import com.google.common.collect.Range;
import com.google.common.io.ByteStreams;

Expand All @@ -37,13 +41,16 @@
import hudson.EnvVars;
import hudson.FilePath;
import hudson.model.AbstractBuild;
import hudson.model.Item;
import hudson.model.TaskListener;
import hudson.remoting.RemoteOutputStream;
import hudson.security.ACL;
import jenkins.security.MasterToSlaveCallable;

import jenkins.plugins.http_request.HttpRequest.DescriptorImpl;
import jenkins.plugins.http_request.HttpRequestStep.Execution;
import jenkins.plugins.http_request.auth.Authenticator;
import jenkins.plugins.http_request.auth.CredentialBasicAuthentication;
import jenkins.plugins.http_request.util.HttpClientUtil;
import jenkins.plugins.http_request.util.HttpRequestNameValuePair;
import jenkins.plugins.http_request.util.RequestAction;
Expand Down Expand Up @@ -81,6 +88,7 @@ static HttpRequestExecution from(HttpRequest http,
List<HttpRequestNameValuePair> headers = http.resolveHeaders(envVars);

FilePath outputFile = http.resolveOutputFile(envVars, build);
Item project = build.getProject();

return new HttpRequestExecution(
url, http.getHttpMode(), http.getIgnoreSslErrors(),
Expand All @@ -91,6 +99,7 @@ static HttpRequestExecution from(HttpRequest http,
http.getConsoleLogResponseBody(), outputFile,
ResponseHandle.NONE,

project,
taskListener.getLogger());
} catch (IOException e) {
throw new IllegalStateException(e);
Expand All @@ -100,7 +109,7 @@ static HttpRequestExecution from(HttpRequest http,
static HttpRequestExecution from(HttpRequestStep step, TaskListener taskListener, Execution execution) {
List<HttpRequestNameValuePair> headers = step.resolveHeaders();
FilePath outputFile = execution.resolveOutputFile();

Item project = execution.getProject();
return new HttpRequestExecution(
step.getUrl(), step.getHttpMode(), step.isIgnoreSslErrors(),
step.getRequestBody(), headers, step.getTimeout(),
Expand All @@ -109,7 +118,7 @@ static HttpRequestExecution from(HttpRequestStep step, TaskListener taskListener
step.getValidResponseCodes(), step.getValidResponseContent(),
step.getConsoleLogResponseBody(), outputFile,
step.getResponseHandle(),
taskListener.getLogger());
project, taskListener.getLogger());
}

private HttpRequestExecution(
Expand All @@ -120,7 +129,8 @@ private HttpRequestExecution(
String validResponseCodes, String validResponseContent,
Boolean consoleLogResponseBody, FilePath outputFile,
ResponseHandle responseHandle,
PrintStream logger

Item project, PrintStream logger
) {
this.url = url;
this.httpMode = httpMode;
Expand All @@ -130,10 +140,25 @@ private HttpRequestExecution(
this.headers = headers;
this.timeout = timeout != null ? timeout : -1;
if (authentication != null && !authentication.isEmpty()) {
authenticator = HttpRequestGlobalConfig.get().getAuthentication(authentication);
if (authenticator == null) {
Authenticator auth = HttpRequestGlobalConfig.get().getAuthentication(authentication);

if (auth == null) {
StandardUsernamePasswordCredentials credential = CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentials(
StandardUsernamePasswordCredentials.class,
project, ACL.SYSTEM,
URIRequirementBuilder.fromUri(url).build()),
CredentialsMatchers.withId(authentication));
if (credential != null) {
auth = new CredentialBasicAuthentication(credential);
}
}


if (auth == null) {
throw new IllegalStateException("Authentication '" + authentication + "' doesn't exist anymore");
}
authenticator = auth;
} else {
authenticator = null;
}
Expand Down
Expand Up @@ -12,6 +12,7 @@
import hudson.XmlFile;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.util.FormValidation;
import hudson.util.XStream2;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
Expand Down Expand Up @@ -60,6 +61,23 @@ public boolean configure(StaplerRequest req, JSONObject json)
return true;
}

public static FormValidation validateKeyName(String value) {
List<Authenticator> list = HttpRequestGlobalConfig.get().getAuthentications();

int count = 0;
for (Authenticator basicAuthentication : list) {
if (basicAuthentication.getKeyName().equals(value)) {
count++;
}
}

if (count > 1) {
return FormValidation.error("The Key Name must be unique");
}

return FormValidation.validateRequired(value);
}

public static HttpRequestGlobalConfig get() {
return GlobalConfiguration.all().get(HttpRequestGlobalConfig.class);
}
Expand Down
20 changes: 13 additions & 7 deletions src/main/java/jenkins/plugins/http_request/HttpRequestStep.java
Expand Up @@ -12,13 +12,16 @@
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution;
import org.jenkinsci.plugins.workflow.steps.StepContextParameter;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;

import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Item;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
Expand All @@ -43,7 +46,7 @@ public final class HttpRequestStep extends AbstractStepImpl {
private String requestBody = DescriptorImpl.requestBody;
private List<HttpRequestNameValuePair> customHeaders = DescriptorImpl.customHeaders;
private String outputFile = DescriptorImpl.outputFile;
private ResponseHandle responseHandle = ResponseHandle.STRING;
private ResponseHandle responseHandle = DescriptorImpl.responseHandle;

@DataBoundConstructor
public HttpRequestStep(String url) {
Expand Down Expand Up @@ -246,12 +249,9 @@ public ListBoxModel doFillResponseHandleItems() {
return items;
}

public ListBoxModel doFillAuthenticationItems() {
return HttpRequest.DescriptorImpl.fillAuthenticationItems();
}

public FormValidation doValidateKeyName(@QueryParameter String value) {
return HttpRequest.DescriptorImpl.validateKeyName(value);
public ListBoxModel doFillAuthenticationItems(@AncestorInPath Item project,
@QueryParameter String url) {
return HttpRequest.DescriptorImpl.fillAuthenticationItems(project, url);
}

public FormValidation doCheckValidResponseCodes(@QueryParameter String value) {
Expand All @@ -265,6 +265,8 @@ public static final class Execution extends AbstractSynchronousNonBlockingStepEx
@Inject
private transient HttpRequestStep step;

@StepContextParameter
private transient Run<?, ?> run;
@StepContextParameter
private transient TaskListener listener;

Expand Down Expand Up @@ -299,5 +301,9 @@ FilePath resolveOutputFile() {
throw new IllegalStateException(e);
}
}

public Item getProject() {
return run.getParent();
}
}
}
Expand Up @@ -2,16 +2,7 @@

import java.io.PrintStream;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIUtils;
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.HttpClientBuilder;
import org.apache.http.protocol.HttpContext;
Expand All @@ -23,11 +14,13 @@
import hudson.model.Descriptor;
import hudson.util.FormValidation;

import jenkins.plugins.http_request.HttpRequest;
import jenkins.plugins.http_request.HttpRequestGlobalConfig;

/**
* @author Janario Oliveira
* @deprecated use Jenkins credentials, marked to remove in 1.8.19
*/
@Deprecated
public class BasicDigestAuthentication extends AbstractDescribableImpl<BasicDigestAuthentication>
implements Authenticator {
private static final long serialVersionUID = 4818288270720177069L;
Expand Down Expand Up @@ -59,24 +52,14 @@ public String getPassword() {
@Override
public CloseableHttpClient authenticate(HttpClientBuilder clientBuilder, HttpContext context,
HttpRequestBase requestBase, PrintStream logger) {
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(
new AuthScope(requestBase.getURI().getHost(), requestBase.getURI().getPort()),
new UsernamePasswordCredentials(userName, password));
clientBuilder.setDefaultCredentialsProvider(provider);

AuthCache authCache = new BasicAuthCache();
authCache.put(URIUtils.extractHost(requestBase.getURI()), new BasicScheme());
context.setAttribute(HttpClientContext.AUTH_CACHE, authCache);

return clientBuilder.build();
return CredentialBasicAuthentication.auth(clientBuilder, context, requestBase, userName, password);
}

@Extension
public static class BasicDigestAuthenticationDescriptor extends Descriptor<BasicDigestAuthentication> {

public FormValidation doCheckKeyName(@QueryParameter String value) {
return HttpRequest.DescriptorImpl.validateKeyName(value);
return HttpRequestGlobalConfig.validateKeyName(value);
}

public FormValidation doCheckUserName(@QueryParameter String value) {
Expand Down

0 comments on commit 5d0dad2

Please sign in to comment.