summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2017-08-23 17:22:12 +0200
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2017-09-13 15:50:49 +0200
commit564c915cec585008f1f16951e42a20a30c72c929 (patch)
tree77bf8527eb58868f026c9467d5c74ccf99923670 /server
parent9d5fc95ed97f0dc0e1a797065b5a3870449a9ded (diff)
downloadsonarqube-564c915cec585008f1f16951e42a20a30c72c929.tar.gz
sonarqube-564c915cec585008f1f16951e42a20a30c72c929.zip
SONAR-9740 support system passcode in WS
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscode.java43
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java81
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookCallerImplTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/SystemPasscodeImplTest.java123
5 files changed, 250 insertions, 1 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
index 6de6ea8288a..4f67d5f0bb3 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
@@ -53,6 +53,7 @@ import org.sonar.server.platform.db.EmbeddedDatabaseFactory;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.search.EsSearchModule;
import org.sonar.server.setting.ThreadLocalSettings;
+import org.sonar.server.user.SystemPasscodeImpl;
import org.sonar.server.user.ThreadLocalUserSession;
import org.sonar.server.util.OkHttpClientProvider;
@@ -101,6 +102,7 @@ public class PlatformLevel1 extends PlatformLevel {
// user session
ThreadLocalUserSession.class,
+ SystemPasscodeImpl.class,
// DB
DBSessionsImpl.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscode.java b/server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscode.java
new file mode 100644
index 00000000000..4174446eb69
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscode.java
@@ -0,0 +1,43 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.user;
+
+import org.sonar.api.server.ws.Request;
+
+/**
+ * Passcode for accessing some web services, usually for connecting
+ * monitoring tools without using the credentials
+ * of a system administrator.
+ */
+public interface SystemPasscode {
+
+ /**
+ * Whether the system passcode is configured in sonar.properties or not.
+ * By default passcode is not defined and {@code false} is returned.
+ */
+ boolean isConfigured();
+
+ /**
+ * Whether the configured system passcode is provided by the HTTP request or not.
+ * Returns {@code false} if {@link #isConfigured()} is {@code false}.
+ */
+ boolean isValid(Request request);
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java b/server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java
new file mode 100644
index 00000000000..5a04178479b
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java
@@ -0,0 +1,81 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.user;
+
+import java.util.Optional;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.Startable;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.utils.log.Loggers;
+
+@ServerSide
+public class SystemPasscodeImpl implements SystemPasscode, Startable {
+
+ public static final String PASSCODE_HTTP_HEADER = "X-Sonar-Passcode";
+ public static final String PASSCODE_CONF_PROPERTY = "sonar.web.systemPasscode";
+
+ private final Configuration configuration;
+ private String configuredPasscode;
+
+ public SystemPasscodeImpl(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public boolean isConfigured() {
+ return configuredPasscode != null;
+ }
+
+ @Override
+ public boolean isValid(Request request) {
+ if (configuredPasscode == null) {
+ return false;
+ }
+ return request.header(PASSCODE_HTTP_HEADER)
+ .map(s -> configuredPasscode.equals(s))
+ .orElse(false);
+ }
+
+ @Override
+ public void start() {
+ Optional<String> passcodeOpt = configuration.get(PASSCODE_CONF_PROPERTY)
+ // if present, result is never empty string
+ .map(StringUtils::trimToNull);
+
+ if (passcodeOpt.isPresent()) {
+ logState("enabled");
+ configuredPasscode = passcodeOpt.get();
+ } else {
+ logState("disabled");
+ configuredPasscode = null;
+ }
+ }
+
+ private void logState(String state) {
+ Loggers.get(getClass()).info("System authentication by passcode is {}", state);
+ }
+
+ @Override
+ public void stop() {
+ // nothing to do
+ }
+}
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 5685f9fd064..aff151adb48 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
@@ -62,7 +62,7 @@ public class WebhookCallerImplTest {
server.enqueue(new MockResponse().setBody("pong").setResponseCode(201));
WebhookDelivery delivery = newSender().call(webhook, PAYLOAD);
- assertThat(delivery.getHttpStatus().get()).isEqualTo(201);
+ assertThat(delivery.getHttpStatus()).hasValue(201);
assertThat(delivery.getDurationInMs().get()).isGreaterThanOrEqualTo(0);
assertThat(delivery.getError()).isEmpty();
assertThat(delivery.getAt()).isEqualTo(NOW);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/SystemPasscodeImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/SystemPasscodeImplTest.java
new file mode 100644
index 00000000000..9c37c5467cc
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/SystemPasscodeImplTest.java
@@ -0,0 +1,123 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.user;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.server.ws.TestRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SystemPasscodeImplTest {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ private MapSettings settings = new MapSettings();
+ private SystemPasscodeImpl underTest = new SystemPasscodeImpl(settings.asConfig());
+
+ @After
+ public void tearDown() {
+ underTest.stop();
+ }
+
+ @Test
+ public void isConfigured_is_true_if_property_is_not_blank() {
+ verifyIsConfigured("foo", true);
+ }
+
+ @Test
+ public void isConfigured_is_false_if_property_value_is_blank() {
+ verifyIsConfigured(" ", false);
+ }
+
+ @Test
+ public void isConfigured_is_false_if_property_value_is_empty() {
+ verifyIsConfigured("", false);
+ }
+
+ @Test
+ public void isConfigured_is_false_if_property_is_not_defined() {
+ assertThat(underTest.isConfigured()).isFalse();
+ }
+
+ @Test
+ public void startup_logs_show_that_feature_is_enabled() {
+ configurePasscode("foo");
+ underTest.start();
+
+ assertThat(logTester.logs(LoggerLevel.INFO)).contains("System authentication by passcode is enabled");
+ }
+
+ @Test
+ public void startup_logs_show_that_feature_is_disabled() {
+ underTest.start();
+
+ assertThat(logTester.logs(LoggerLevel.INFO)).contains("System authentication by passcode is disabled");
+ }
+
+ @Test
+ public void isValid_is_true_if_request_header_matches_configured_passcode() {
+ verifyIsValid(true, "foo", "foo");
+ }
+
+ @Test
+ public void isValid_is_false_if_request_header_matches_configured_passcode_with_different_case() {
+ verifyIsValid(false, "foo", "FOO");
+ }
+
+ @Test
+ public void isValid_is_false_if_request_header_does_not_match_configured_passcode() {
+ verifyIsValid(false, "foo", "bar");
+ }
+
+ @Test
+ public void isValid_is_false_if_request_header_is_defined_but_passcode_is_not_configured() {
+ verifyIsValid(false, null, "foo");
+ }
+
+ @Test
+ public void isValid_is_false_if_request_header_is_empty() {
+ verifyIsValid(false, "foo", "");
+ }
+
+ private void verifyIsValid(boolean expectedResult, String configuredPasscode, String header) {
+ configurePasscode(configuredPasscode);
+
+ TestRequest request = new TestRequest();
+ request.setHeader("X-Sonar-Passcode", header);
+
+ assertThat(underTest.isValid(request)).isEqualTo(expectedResult);
+ }
+
+ private void verifyIsConfigured(String propertyValue, boolean expectedResult) {
+ configurePasscode(propertyValue);
+ assertThat(underTest.isConfigured()).isEqualTo(expectedResult);
+ }
+
+ private void configurePasscode(String propertyValue) {
+ settings.setProperty("sonar.web.systemPasscode", propertyValue);
+ underTest.start();
+ }
+}