Skip to content

Commit

Permalink
Add possibility to enable authentication for the /project end-point (F…
Browse files Browse the repository at this point in the history
…ixes #282)
  • Loading branch information
coder-hugo committed Jun 16, 2016
1 parent 6f43a5e commit a5c8785
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
@Extension
public class GitLabConnectionConfig extends GlobalConfiguration {

private boolean useAuthenticatedEndpoint;
private List<GitLabConnection> connections = new ArrayList<>();
private transient Map<String, GitLabConnection> connectionMap = new HashMap<>();
private transient Map<String, GitLabApi> clients = new HashMap<>();
Expand All @@ -48,12 +49,21 @@ public GitLabConnectionConfig() {
@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
connections = req.bindJSONToList(GitLabConnection.class, json.get("connections"));
useAuthenticatedEndpoint = json.getBoolean("useAuthenticatedEndpoint");
refreshConnectionMap();
clients.clear();
save();
return super.configure(req, json);
}

public boolean isUseAuthenticatedEndpoint() {
return useAuthenticatedEndpoint;
}

void setUseAuthenticatedEndpoint(boolean useAuthenticatedEndpoint) {
this.useAuthenticatedEndpoint = useAuthenticatedEndpoint;
}

public List<GitLabConnection> getConnections() {
return connections;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dabsquared.gitlabjenkins.webhook;

import com.dabsquared.gitlabjenkins.connection.GitLabConnectionConfig;
import com.dabsquared.gitlabjenkins.util.ACLUtil;
import com.dabsquared.gitlabjenkins.webhook.build.MergeRequestBuildAction;
import com.dabsquared.gitlabjenkins.webhook.build.PushBuildAction;
Expand All @@ -14,6 +15,8 @@
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.security.ACL;
import hudson.security.AccessDeniedException2;
import hudson.security.Permission;
import hudson.util.HttpResponses;
import jenkins.model.Jenkins;
import org.apache.commons.io.IOUtils;
Expand Down Expand Up @@ -52,6 +55,7 @@ public WebHookAction resolve(final String projectName, StaplerRequest request) {
private WebHookAction resolveAction(Job<?, ?> project, String restOfPath, StaplerRequest request) {
String method = request.getMethod();
if (method.equals("POST")) {
checkPermission(Item.BUILD);
return onPost(project, request);
} else if (method.equals("GET")) {
return onGet(project, restOfPath, request);
Expand Down Expand Up @@ -137,6 +141,16 @@ private String getRequestBody(StaplerRequest request) {
});
}

private void checkPermission(Permission permission) {
if (((GitLabConnectionConfig) Jenkins.getInstance().getDescriptor(GitLabConnectionConfig.class)).isUseAuthenticatedEndpoint()) {
try {
Jenkins.getInstance().checkPermission(permission);
} catch (AccessDeniedException2 e) {
throw HttpResponses.error(403, e.getMessage());
}
}
}

static class NoopAction implements WebHookAction {
public void execute(StaplerResponse response) {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:c="/lib/credentials" xmlns:st="jelly:stapler">
<f:section title="Gitlab">
<f:entry title="${%Enable authentication for '/project' end-point}" field="useAuthenticatedEndpoint">
<f:checkbox/>
</f:entry>
<f:entry title="${%GitLab connections}">
<f:repeatable var="connection" items="${descriptor.connections}" name="connections">
<table width="100%">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@
import com.cloudbees.plugins.credentials.CredentialsStore;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import com.cloudbees.plugins.credentials.domains.Domain;
import hudson.model.Item;
import hudson.security.GlobalMatrixAuthorizationStrategy;
import hudson.util.FormValidation;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl;
import org.junit.Before;
import org.junit.Rule;
Expand All @@ -19,6 +28,9 @@

import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
Expand Down Expand Up @@ -76,4 +88,61 @@ public void doCheckConnection_forbidden() throws IOException {
assertThat(formValidation.getMessage(), is(Messages.connection_error("HTTP 403 Forbidden")));
mockServerClient.verify(request);
}

@Test
public void authenticationEnabled_anonymous_forbidden() throws IOException, URISyntaxException {
jenkins.get(GitLabConnectionConfig.class).setUseAuthenticatedEndpoint(true);
jenkins.getInstance().setAuthorizationStrategy(new GlobalMatrixAuthorizationStrategy());
URL jenkinsURL = jenkins.getURL();
jenkins.createFreeStyleProject("test");

CloseableHttpClient client = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(jenkinsURL.toExternalForm() + "project/test");
request.addHeader("X-Gitlab-Event", "Push Hook");
request.setEntity(new StringEntity("{}"));

CloseableHttpResponse response = client.execute(request);

assertThat(response.getStatusLine().getStatusCode(), is(403));
}

@Test
public void authenticationEnabled_registered_success() throws Exception {
String username = "test-user";
jenkins.get(GitLabConnectionConfig.class).setUseAuthenticatedEndpoint(true);
jenkins.getInstance().setSecurityRealm(jenkins.createDummySecurityRealm());
GlobalMatrixAuthorizationStrategy authorizationStrategy = new GlobalMatrixAuthorizationStrategy();
authorizationStrategy.add(Item.BUILD, username);
jenkins.getInstance().setAuthorizationStrategy(authorizationStrategy);
URL jenkinsURL = jenkins.getURL();
jenkins.createFreeStyleProject("test");

CloseableHttpClient client = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(jenkinsURL.toExternalForm() + "project/test");
request.addHeader("X-Gitlab-Event", "Push Hook");
String auth = username + ":" + username;
request.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + new String(Base64.encodeBase64(auth.getBytes(Charset.forName("ISO-8859-1")))));
request.setEntity(new StringEntity("{}"));

CloseableHttpResponse response = client.execute(request);

assertThat(response.getStatusLine().getStatusCode(), is(200));
}

@Test
public void authenticationDisabled_anonymous_success() throws IOException, URISyntaxException {
jenkins.get(GitLabConnectionConfig.class).setUseAuthenticatedEndpoint(false);
jenkins.getInstance().setAuthorizationStrategy(new GlobalMatrixAuthorizationStrategy());
URL jenkinsURL = jenkins.getURL();
jenkins.createFreeStyleProject("test");

CloseableHttpClient client = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(jenkinsURL.toExternalForm() + "project/test");
request.addHeader("X-Gitlab-Event", "Push Hook");
request.setEntity(new StringEntity("{}"));

CloseableHttpResponse response = client.execute(request);

assertThat(response.getStatusLine().getStatusCode(), is(200));
}
}

0 comments on commit a5c8785

Please sign in to comment.