diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-10-02 14:48:30 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-10-02 18:04:42 +0200 |
commit | 3601435b31bfdeaee7a7e2251d275e4b1a9e254e (patch) | |
tree | 6ff7f0df01d1351f37325e930cce037c03f57cb3 /server | |
parent | cf6b9cb7a653e875f693a8364642411b46d38d95 (diff) | |
download | sonarqube-3601435b31bfdeaee7a7e2251d275e4b1a9e254e.tar.gz sonarqube-3601435b31bfdeaee7a7e2251d275e4b1a9e254e.zip |
SONAR-9896 Webhook must support basic authentication
Diffstat (limited to 'server')
2 files changed, 55 insertions, 6 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImpl.java index 40cb2b128d8..3c14782e586 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImpl.java @@ -20,6 +20,7 @@ package org.sonar.server.computation.task.projectanalysis.webhook; import java.io.IOException; +import okhttp3.Credentials; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -32,8 +33,10 @@ import org.sonar.api.utils.System2; import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_MOVED_PERM; import static java.net.HttpURLConnection.HTTP_MOVED_TEMP; +import static java.nio.charset.StandardCharsets.UTF_8; import static okhttp3.internal.http.StatusLine.HTTP_PERM_REDIRECT; import static okhttp3.internal.http.StatusLine.HTTP_TEMP_REDIRECT; +import static org.apache.commons.lang.StringUtils.isNotEmpty; @ComputeEngineSide public class WebhookCallerImpl implements WebhookCaller { @@ -71,9 +74,17 @@ public class WebhookCallerImpl implements WebhookCaller { } private static Request buildHttpRequest(Webhook webhook, WebhookPayload payload) { + HttpUrl url = HttpUrl.parse(webhook.getUrl()); + if (url == null) { + throw new IllegalArgumentException("Webhook URL is not valid: " + webhook.getUrl()); + } Request.Builder request = new Request.Builder(); - request.url(webhook.getUrl()); + request.url(url); request.header(PROJECT_KEY_HEADER, payload.getProjectKey()); + if (isNotEmpty(url.username())) { + request.header("Authorization", Credentials.basic(url.username(), url.password(), UTF_8)); + } + RequestBody body = RequestBody.create(JSON, payload.getJson()); request.post(body); return request.build(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImplTest.java index aff151adb48..155ec647963 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImplTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.computation.task.projectanalysis.webhook; +import okhttp3.Credentials; import okhttp3.HttpUrl; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -103,7 +104,7 @@ public class WebhookCallerImplTest { assertThat(delivery.getHttpStatus()).isEmpty(); assertThat(delivery.getDurationInMs()).isEmpty(); assertThat(delivery.getError().get()).isInstanceOf(IllegalArgumentException.class); - assertThat(delivery.getErrorMessage().get()).isEqualTo("unexpected url: this_is_not_an_url"); + assertThat(delivery.getErrorMessage().get()).isEqualTo("Webhook URL is not valid: this_is_not_an_url"); assertThat(delivery.getAt()).isEqualTo(NOW); assertThat(delivery.getWebhook()).isSameAs(webhook); assertThat(delivery.getPayload()).isSameAs(PAYLOAD); @@ -134,6 +135,26 @@ public class WebhookCallerImplTest { } @Test + public void credentials_are_propagated_to_POST_redirects() throws Exception { + HttpUrl url = server.url("/redirect").newBuilder().username("theLogin").password("thePassword").build(); + Webhook webhook = new Webhook(PROJECT_UUID, CE_TASK_UUID, "my-webhook", url.toString()); + + // /redirect redirects to /target + server.enqueue(new MockResponse().setResponseCode(307).setHeader("Location", server.url("target"))); + server.enqueue(new MockResponse().setResponseCode(200)); + + WebhookDelivery delivery = newSender().call(webhook, PAYLOAD); + + assertThat(delivery.getHttpStatus().get()).isEqualTo(200); + + RecordedRequest redirectedRequest = takeAndVerifyPostRequest("/redirect"); + assertThat(redirectedRequest.getHeader("Authorization")).isEqualTo(Credentials.basic(url.username(), url.password())); + + RecordedRequest targetRequest = takeAndVerifyPostRequest("/target"); + assertThat(targetRequest.getHeader("Authorization")).isEqualTo(Credentials.basic(url.username(), url.password())); + } + + @Test public void redirects_throws_ISE_if_header_Location_is_missing() throws Exception { HttpUrl url = server.url("/redirect"); Webhook webhook = new Webhook(PROJECT_UUID, CE_TASK_UUID, "my-webhook", url.toString()); @@ -163,11 +184,28 @@ public class WebhookCallerImplTest { .hasMessage("Unsupported protocol in redirect of " + url + " to ftp://foo"); } - private void takeAndVerifyPostRequest(String expectedPath) throws Exception { - RecordedRequest redirectedRequest = server.takeRequest(); + @Test + public void send_basic_authentication_header_if_url_contains_credentials() throws Exception { + HttpUrl url = server.url("/ping").newBuilder().username("theLogin").password("thePassword").build(); + Webhook webhook = new Webhook(PROJECT_UUID, CE_TASK_UUID, "my-webhook", url.toString()); + server.enqueue(new MockResponse().setBody("pong")); + + WebhookDelivery delivery = newSender().call(webhook, PAYLOAD); + + assertThat(delivery.getWebhook().getUrl()) + .isEqualTo(url.toString()) + .contains("://theLogin:thePassword@"); + RecordedRequest recordedRequest = takeAndVerifyPostRequest("/ping"); + assertThat(recordedRequest.getHeader("Authorization")).isEqualTo(Credentials.basic(url.username(), url.password())); + } + + private RecordedRequest takeAndVerifyPostRequest(String expectedPath) throws Exception { + RecordedRequest request = server.takeRequest(); - assertThat(redirectedRequest.getMethod()).isEqualTo("POST"); - assertThat(redirectedRequest.getPath()).isEqualTo(expectedPath); + assertThat(request.getMethod()).isEqualTo("POST"); + assertThat(request.getPath()).isEqualTo(expectedPath); + assertThat(request.getHeader("User-Agent")).isEqualTo("SonarQube/6.2"); + return request; } private WebhookCaller newSender() { |