From a5c87853e0bb8922986feab972dbc6b06eb0ce04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20M=C3=BCller?= Date: Wed, 15 Jun 2016 23:11:19 +0200 Subject: [PATCH] Add possibility to enable authentication for the /project end-point (Fixes #282) --- .../connection/GitLabConnectionConfig.java | 10 +++ .../gitlabjenkins/webhook/ActionResolver.java | 14 ++++ .../GitLabConnectionConfig/config.jelly | 3 + .../GitLabConnectionConfigTest.java | 69 +++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/src/main/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig.java b/src/main/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig.java index cd72a1992..b73052c6c 100644 --- a/src/main/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig.java +++ b/src/main/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig.java @@ -36,6 +36,7 @@ @Extension public class GitLabConnectionConfig extends GlobalConfiguration { + private boolean useAuthenticatedEndpoint; private List connections = new ArrayList<>(); private transient Map connectionMap = new HashMap<>(); private transient Map clients = new HashMap<>(); @@ -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 getConnections() { return connections; } diff --git a/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java b/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java index d93f28925..23e014abe 100644 --- a/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java +++ b/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java @@ -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; @@ -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; @@ -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); @@ -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) { } diff --git a/src/main/resources/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig/config.jelly b/src/main/resources/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig/config.jelly index 16db68322..13e18bb62 100644 --- a/src/main/resources/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig/config.jelly +++ b/src/main/resources/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfig/config.jelly @@ -1,6 +1,9 @@ + + + diff --git a/src/test/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfigTest.java b/src/test/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfigTest.java index 7e41f3601..8ba58a697 100644 --- a/src/test/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfigTest.java +++ b/src/test/java/com/dabsquared/gitlabjenkins/connection/GitLabConnectionConfigTest.java @@ -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; @@ -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; @@ -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)); + } }