diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-08-23 17:22:12 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-09-13 15:50:49 +0200 |
commit | 564c915cec585008f1f16951e42a20a30c72c929 (patch) | |
tree | 77bf8527eb58868f026c9467d5c74ccf99923670 /server | |
parent | 9d5fc95ed97f0dc0e1a797065b5a3870449a9ded (diff) | |
download | sonarqube-564c915cec585008f1f16951e42a20a30c72c929.tar.gz sonarqube-564c915cec585008f1f16951e42a20a30c72c929.zip |
SONAR-9740 support system passcode in WS
Diffstat (limited to 'server')
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(); + } +} |