aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-09-06 17:00:25 +0200
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-09-07 17:06:10 +0200
commit7ef29c10d2efaaa9e092c90b1ac64e37f8dd056c (patch)
treeffbe9356501cd38b3a5c630cff41af7c298d9d6e
parent037cba432e43e3c92259e51b53b9149029e40865 (diff)
downloadsonarqube-7ef29c10d2efaaa9e092c90b1ac64e37f8dd056c.tar.gz
sonarqube-7ef29c10d2efaaa9e092c90b1ac64e37f8dd056c.zip
SONAR-7984 WS api/server_id/generate
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdGenerator.java45
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdLoader.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/serverid/ws/GenerateAction.java110
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWs.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWsModule.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ShowAction.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java6
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/generate-example.json3
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/show-example.json2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdGeneratorTest.java51
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdLoaderTest.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/serverid/ws/GenerateActionTest.java182
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsModuleTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsTest.java44
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ShowActionTest.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java2
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/GenerateRequest.java70
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/package-info.java27
-rw-r--r--sonar-ws/src/main/protobuf/ws-serverid.proto7
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/serverid/GenerateRequestTest.java65
20 files changed, 609 insertions, 53 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdGenerator.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdGenerator.java
index 86d03a72efe..7439b6dd60d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdGenerator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdGenerator.java
@@ -28,12 +28,16 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
+import java.util.Objects;
import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.log.Loggers;
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+
public class ServerIdGenerator {
private static final Pattern ORGANIZATION_PATTERN = Pattern.compile("[a-zA-Z0-9]+[a-zA-Z0-9 ]*");
@@ -56,21 +60,33 @@ public class ServerIdGenerator {
this.acceptPrivateAddress = acceptPrivateAddress;
}
- @CheckForNull
- public String generate(String organisationName, String ipAddress) {
- String id = null;
- String organisation = organisationName.trim();
+ public boolean validate(String organisationName, String ipAddress, String expectedServerId) {
+ String organization = organisationName.trim();
String ip = ipAddress.trim();
- if (StringUtils.isNotBlank(organisation) && StringUtils.isNotBlank(ip) && isValidOrganizationName(organisation)) {
- InetAddress inetAddress = toValidAddress(ip);
- if (inetAddress != null) {
- id = toId(organisation, inetAddress);
- }
+ if (isBlank(ip) || isBlank(organization) || !isValidOrganizationName(organization)) {
+ return false;
}
- return id;
+
+ InetAddress inetAddress = toValidAddress(ip);
+
+ return inetAddress != null
+ && Objects.equals(expectedServerId, toId(organization, inetAddress));
}
- boolean isValidOrganizationName(String organisation) {
+ public String generate(String organizationName, String ipAddress) {
+ String organization = organizationName.trim();
+ String ip = ipAddress.trim();
+ checkArgument(isNotBlank(organization), "Organization name must not be null or empty");
+ checkArgument(isValidOrganizationName(organization), "Organization name is invalid. Alpha numeric characters and space only are allowed. '%s' was provided.", organization);
+ checkArgument(isNotBlank(ip), "IP must not be null or empty");
+
+ InetAddress inetAddress = toValidAddress(ip);
+ checkArgument(inetAddress != null, "Invalid IP '%s'", ip);
+
+ return toId(organization, inetAddress);
+ }
+
+ static boolean isValidOrganizationName(String organisation) {
return ORGANIZATION_PATTERN.matcher(organisation).matches();
}
@@ -81,13 +97,14 @@ public class ServerIdGenerator {
return acceptPrivateAddress || (!address.isLoopbackAddress() && !address.isLinkLocalAddress());
}
- String toId(String organisation, InetAddress address) {
+ static String toId(String organisation, InetAddress address) {
String id = new StringBuilder().append(organisation).append("-").append(address.getHostAddress()).toString();
return VERSION + DigestUtils.sha1Hex(id.getBytes(StandardCharsets.UTF_8)).substring(0, CHECKSUM_SIZE);
}
+ @CheckForNull
private InetAddress toValidAddress(String ipAddress) {
- if (StringUtils.isNotBlank(ipAddress)) {
+ if (isNotBlank(ipAddress)) {
List<InetAddress> validAddresses = getAvailableAddresses();
try {
InetAddress address = InetAddress.getByName(ipAddress);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdLoader.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdLoader.java
index 37f9fd59728..6ca91d6e2c8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdLoader.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerIdLoader.java
@@ -47,13 +47,10 @@ public class ServerIdLoader {
String organisation = settings.getString(CoreProperties.ORGANISATION);
String ipAddress = settings.getString(CoreProperties.SERVER_ID_IP_ADDRESS);
- boolean validated;
- if (organisation == null || ipAddress == null) {
- validated = false;
- } else {
- String generatedId = idGenerator.generate(organisation, ipAddress);
- validated = generatedId != null && generatedId.equals(rawId.get());
- }
+ boolean validated = organisation != null
+ && ipAddress != null
+ && idGenerator.validate(organisation, ipAddress, rawId.get());
+
return Optional.of(new ServerId(rawId.get(), validated));
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/GenerateAction.java b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/GenerateAction.java
new file mode 100644
index 00000000000..bfe0690f728
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/GenerateAction.java
@@ -0,0 +1,110 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.serverid.ws;
+
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.platform.ServerIdGenerator;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.ServerId.GenerateWsResponse;
+import org.sonarqube.ws.client.serverid.GenerateRequest;
+
+import static org.sonar.api.CoreProperties.ORGANISATION;
+import static org.sonar.api.CoreProperties.PERMANENT_SERVER_ID;
+import static org.sonar.api.CoreProperties.SERVER_ID_IP_ADDRESS;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class GenerateAction implements ServerIdWsAction {
+ public static final String PARAM_ORGANIZATION = "organization";
+ public static final String PARAM_IP = "ip";
+
+ private static final Logger LOG = Loggers.get(GenerateAction.class);
+
+ private final UserSession userSession;
+ private final ServerIdGenerator generator;
+ private final DbClient dbClient;
+
+ public GenerateAction(UserSession userSession, ServerIdGenerator generator, DbClient dbClient) {
+ this.userSession = userSession;
+ this.generator = generator;
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ WebService.NewAction action = controller.createAction("generate")
+ .setDescription("Generate a server id.<br/>" +
+ "Requires 'System Administer' permissions")
+ .setSince("6.1")
+ .setInternal(true)
+ .setPost(true)
+ .setResponseExample(getClass().getResource("generate-example.json"))
+ .setHandler(this);
+
+ action.createParam(PARAM_ORGANIZATION)
+ .setDescription("Organization name")
+ .setExampleValue("SonarSource")
+ .setRequired(true);
+
+ action.createParam(PARAM_IP)
+ .setDescription("IP address")
+ .setExampleValue("10.142.20.56")
+ .setRequired(true);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ userSession.checkPermission(SYSTEM_ADMIN);
+
+ DbSession dbSession = dbClient.openSession(true);
+ try {
+ writeProtobuf(doHandle(dbSession, toGenerateRequest(request)), request, response);
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+ private GenerateWsResponse doHandle(DbSession dbSession, GenerateRequest request) {
+ String serverId = generator.generate(request.getOrganization(), request.getIp());
+ dbClient.propertiesDao().insertProperty(dbSession, new PropertyDto().setKey(PERMANENT_SERVER_ID).setValue(serverId));
+ dbClient.propertiesDao().insertProperty(dbSession, new PropertyDto().setKey(ORGANISATION).setValue(request.getOrganization()));
+ dbClient.propertiesDao().insertProperty(dbSession, new PropertyDto().setKey(SERVER_ID_IP_ADDRESS).setValue(request.getIp()));
+ dbSession.commit();
+ LOG.info("Generated new server ID={}", serverId);
+
+ return GenerateWsResponse.newBuilder().setServerId(serverId).build();
+ }
+
+ private static GenerateRequest toGenerateRequest(Request request) {
+ return GenerateRequest.builder()
+ .setOrganization(request.mandatoryParam(PARAM_ORGANIZATION))
+ .setIp(request.mandatoryParam(PARAM_IP))
+ .build();
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWs.java b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWs.java
index 0825f9f9dac..37aaef58342 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWs.java
@@ -32,7 +32,8 @@ public class ServerIdWs implements WebService {
@Override
public void define(Context context) {
NewController controller = context.createController("api/server_id")
- .setDescription("Get server id information and generate server id.");
+ .setDescription("Get server id information and generate server id.")
+ .setSince("6.1");
for (ServerIdWsAction action : actions) {
action.define(controller);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWsModule.java
index 2f30d5cbbb6..d8ab4dd59aa 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWsModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ServerIdWsModule.java
@@ -26,6 +26,7 @@ public class ServerIdWsModule extends Module {
protected void configureModule() {
add(
ServerIdWs.class,
- ShowAction.class);
+ ShowAction.class,
+ GenerateAction.class);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ShowAction.java
index 183f00eacca..e65bbcc22e1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ShowAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/serverid/ws/ShowAction.java
@@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableSet;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
@@ -115,11 +114,9 @@ public class ShowAction implements ServerIdWsAction {
return propertyDto != null ? Optional.of(propertyDto.getValue()) : Optional.empty();
}
- private boolean isValidServerId(String serverId, Optional<String> organisation, Optional<String> ip) {
- if (organisation.isPresent() && ip.isPresent()) {
- String generatedServerId = serverIdGenerator.generate(organisation.get(), ip.get());
- return Objects.equals(generatedServerId, serverId);
- }
- return false;
+ private boolean isValidServerId(String serverId, Optional<String> organization, Optional<String> ip) {
+ return organization.isPresent()
+ && ip.isPresent()
+ && serverIdGenerator.validate(organization.get(), ip.get(), serverId);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
index 0789b460c1f..105d05c116a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
@@ -55,12 +55,12 @@ import org.sonar.server.authentication.IdentityProviderRepository;
import org.sonar.server.component.ComponentCleanerService;
import org.sonar.server.measure.MeasureFilterEngine;
import org.sonar.server.measure.MeasureFilterResult;
+import org.sonar.server.platform.PersistentSettings;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.ServerIdGenerator;
import org.sonar.server.platform.db.migrations.DatabaseMigrator;
import org.sonar.server.platform.ws.UpgradesAction;
import org.sonar.server.rule.RuleRepositories;
-import org.sonar.server.platform.PersistentSettings;
import org.sonar.server.user.NewUserNotifier;
import static com.google.common.collect.Lists.newArrayList;
@@ -274,7 +274,7 @@ public final class JRubyFacade {
}
public String generateRandomSecretKey() {
- return get(Settings.class).getEncryption().generateRandomSecretKey();
+ return get(Settings.class).getEncryption().generateRandomSecretKey();
}
public License parseLicense(String base64) {
@@ -361,7 +361,7 @@ public final class JRubyFacade {
}
}
- public List<IdentityProvider> getIdentityProviders(){
+ public List<IdentityProvider> getIdentityProviders() {
return get(IdentityProviderRepository.class).getAllEnabledAndSorted();
}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/generate-example.json b/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/generate-example.json
new file mode 100644
index 00000000000..3ebe88f1542
--- /dev/null
+++ b/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/generate-example.json
@@ -0,0 +1,3 @@
+{
+ "serverId": "1818a1eefb26f9g"
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/show-example.json b/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/show-example.json
index 1f322a4cc57..bd00b32b768 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/show-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/serverid/ws/show-example.json
@@ -1,5 +1,5 @@
{
- "serverId": "server_id",
+ "serverId": "1818a1eefb26f9g",
"organization": "home",
"ip": "127.0.1",
"validIpAdresses": [
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdGeneratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdGeneratorTest.java
index 72052685400..62f5105c54d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdGeneratorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdGeneratorTest.java
@@ -23,14 +23,20 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.commons.lang.StringUtils;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.assertj.core.api.Assertions.assertThat;
public class ServerIdGeneratorTest {
+ static InetAddress localhost;
- private static InetAddress localhost;
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ ServerIdGenerator underTest = new ServerIdGenerator(true);
@BeforeClass
public static void init() throws UnknownHostException {
@@ -40,15 +46,50 @@ public class ServerIdGeneratorTest {
@Test
public void shouldNotGenerateIdIfBlankParams() {
ServerIdGenerator generator = new ServerIdGenerator(true);
- assertThat(generator.generate(" ", "127.0.0.1")).isNull();
- assertThat(generator.generate("SonarSource", " ")).isNull();
+ assertThat(generator.validate(" ", "127.0.0.1", "191e806623bb0c2")).isFalse();
+ assertThat(generator.validate("SonarSource", " ", "191e806623bb0c2")).isFalse();
}
@Test
public void organizationShouldRespectPattern() {
ServerIdGenerator generator = new ServerIdGenerator(true);
- assertThat(generator.generate("SonarSource", "127.0.0.1")).isNotNull();
- assertThat(generator.generate("SonarSource$", "127.0.0.1")).isNull();
+ assertThat(generator.generate("SonarSource", "127.0.0.1")).isEqualTo("191e806623bb0c2");
+ assertThat(generator.validate("SonarSource", "127.0.0.1", "191e806623bb0c2")).isTrue();
+ assertThat(generator.validate("SonarSource$", "127.0.0.1", "191e806623bb0c2")).isFalse();
+ }
+
+ @Test
+ public void fail_if_organization_does_not_respect_pattern() {
+ assertThat(underTest.generate("SonarSource", "127.0.0.1")).isNotEmpty();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Organization name is invalid. Alpha numeric characters and space only are allowed. 'SonarSource$' was provided.");
+
+ underTest.generate("SonarSource$", "127.0.0.1");
+ }
+
+ @Test
+ public void fail_if_organization_is_blank() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Organization name must not be null or empty");
+
+ underTest.generate(" ", "127.0.0.1");
+ }
+
+ @Test
+ public void fail_if_ip_blank() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("IP must not be null or empty");
+
+ underTest.generate("SonarSource", " ");
+ }
+
+ @Test
+ public void fail_if_ip_is_unknown() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Invalid IP '50.154.42.42'");
+
+ underTest.generate("SonarSource", "50.154.42.42");
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdLoaderTest.java
index c056a1c502f..89b87c8367d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdLoaderTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerIdLoaderTest.java
@@ -56,11 +56,11 @@ public class ServerIdLoaderTest {
settings.setProperty(CoreProperties.PERMANENT_SERVER_ID, AN_ID);
settings.setProperty(CoreProperties.ORGANISATION, AN_ORGANISATION);
settings.setProperty(CoreProperties.SERVER_ID_IP_ADDRESS, AN_IP);
- when(idGenerator.generate(AN_ORGANISATION, AN_IP)).thenReturn(AN_ID);
+ when(idGenerator.validate(AN_ORGANISATION, AN_IP, AN_ID)).thenReturn(true);
Optional<ServerId> serverIdOpt = underTest.get();
verifyServerId(serverIdOpt.get(), AN_ID, true);
- verify(idGenerator).generate(AN_ORGANISATION, AN_IP);
+ verify(idGenerator).validate(AN_ORGANISATION, AN_IP, AN_ID);
}
@Test
@@ -104,7 +104,7 @@ public class ServerIdLoaderTest {
Optional<ServerId> serverIdOpt = underTest.get();
verifyServerId(serverIdOpt.get(), AN_ID, false);
- verify(idGenerator).generate(AN_ORGANISATION, AN_IP);
+ verify(idGenerator).validate(AN_ORGANISATION, AN_IP, AN_ID);
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/GenerateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/GenerateActionTest.java
new file mode 100644
index 00000000000..ceb7fa4bd70
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/GenerateActionTest.java
@@ -0,0 +1,182 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.serverid.ws;
+
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.platform.ServerIdGenerator;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.ServerId.GenerateWsResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.CoreProperties.ORGANISATION;
+import static org.sonar.api.CoreProperties.PERMANENT_SERVER_ID;
+import static org.sonar.api.CoreProperties.SERVER_ID_IP_ADDRESS;
+import static org.sonar.server.serverid.ws.GenerateAction.PARAM_IP;
+import static org.sonar.server.serverid.ws.GenerateAction.PARAM_ORGANIZATION;
+import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.MediaTypes.PROTOBUF;
+
+public class GenerateActionTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ @Rule
+ public LogTester log = new LogTester();
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+ DbClient dbClient = db.getDbClient();
+
+ ServerIdGenerator generator = mock(ServerIdGenerator.class);
+
+ GenerateAction underTest = new GenerateAction(userSession, generator, dbClient);
+
+ WsActionTester ws = new WsActionTester(underTest);
+
+ @Test
+ public void persist_settings() {
+ when(generator.generate("SonarSource", "10.51.42.255")).thenReturn("server_id");
+
+ GenerateWsResponse result = call("SonarSource", "10.51.42.255");
+
+ assertThat(result.getServerId()).isEqualTo("server_id");
+ assertGlobalSetting(ORGANISATION, "SonarSource");
+ assertGlobalSetting(SERVER_ID_IP_ADDRESS, "10.51.42.255");
+ assertGlobalSetting(PERMANENT_SERVER_ID, "server_id");
+ }
+
+ @Test
+ public void json_example() {
+ when(generator.generate("SonarSource", "127.0.0.1")).thenReturn("1818a1eefb26f9g");
+
+ String result = ws.newRequest()
+ .setParam(PARAM_ORGANIZATION, "SonarSource")
+ .setParam(PARAM_IP, "127.0.0.1")
+ .execute().getInput();
+
+ assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString());
+ }
+
+ @Test
+ public void log_message_when_id_generated() {
+ when(generator.generate("SonarSource", "127.0.0.1")).thenReturn("server_id");
+
+ call("SonarSource", "127.0.0.1");
+
+ assertThat(log.logs(LoggerLevel.INFO)).contains("Generated new server ID=" + "server_id");
+ }
+
+ @Test
+ public void definition() {
+ WebService.Action definition = ws.getDef();
+
+ assertThat(definition.key()).isEqualTo("generate");
+ assertThat(definition.since()).isEqualTo("6.1");
+ assertThat(definition.isInternal()).isTrue();
+ assertThat(definition.isPost()).isTrue();
+ assertThat(definition.responseExampleAsString()).isNotEmpty();
+ assertThat(definition.params()).hasSize(2);
+ }
+
+ @Test
+ public void fail_if_insufficient_permission() {
+ userSession.setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+ expectedException.expect(ForbiddenException.class);
+
+ call("SonarSource", "127.0.0.1");
+ }
+
+ @Test
+ public void fail_if_no_organization() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ call(null, "127.0.0.1");
+ }
+
+ @Test
+ public void fail_if_empty_organization() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ call("", "127.0.0.1");
+ }
+
+ @Test
+ public void fail_if_no_ip() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ call("SonarSource", null);
+ }
+
+ @Test
+ public void fail_if_empty_ip() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ call("SonarSource", "");
+ }
+
+ private void assertGlobalSetting(String key, String value) {
+ PropertyDto result = dbClient.propertiesDao().selectGlobalProperty(key);
+
+ assertThat(result)
+ .extracting(PropertyDto::getKey, PropertyDto::getValue, PropertyDto::getResourceId)
+ .containsExactly(key, value, null);
+ }
+
+ private GenerateWsResponse call(@Nullable String organization, @Nullable String ip) {
+ TestRequest request = ws.newRequest()
+ .setMethod("POST")
+ .setMediaType(PROTOBUF);
+
+ if (organization != null) {
+ request.setParam(PARAM_ORGANIZATION, organization);
+ }
+
+ if (ip != null) {
+ request.setParam(PARAM_IP, ip);
+ }
+
+ try {
+ return GenerateWsResponse.parseFrom(request.execute().getInputStream());
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsModuleTest.java
index 7c0bf9c26dd..e989bbd45f7 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsModuleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsModuleTest.java
@@ -30,6 +30,6 @@ public class ServerIdWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new ServerIdWsModule().configure(container);
- assertThat(container.size()).isEqualTo(2 + 2);
+ assertThat(container.size()).isEqualTo(3 + 2);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsTest.java
new file mode 100644
index 00000000000..8bcd99a484a
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ServerIdWsTest.java
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.serverid.ws;
+
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.server.platform.ServerIdGenerator;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ServerIdWsTest {
+
+ WsTester ws = new WsTester(new ServerIdWs(new ShowAction(mock(UserSession.class), mock(ServerIdGenerator.class), mock(DbClient.class))));
+ WebService.Controller underTest = ws.controller("api/server_id");
+
+ @Test
+ public void definition() {
+ assertThat(underTest.path()).isEqualTo("api/server_id");
+ assertThat(underTest.since()).isEqualTo("6.1");
+ assertThat(underTest.description()).isNotEmpty();
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ShowActionTest.java
index 2a7dd64321b..fdbc861ae02 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ShowActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/serverid/ws/ShowActionTest.java
@@ -70,13 +70,13 @@ public class ShowActionTest {
@Test
public void return_server_id_info() throws Exception {
setUserAsSystemAdmin();
- when(generator.generate("home", "127.0.1")).thenReturn("server_id");
+ when(generator.validate("home", "127.0.1", "1818a1eefb26f9g")).thenReturn(true);
setAvailableIpAdresses("192.168.1.1", "127.0.1");
- insertConfiguration("server_id", "home", "127.0.1");
+ insertConfiguration("1818a1eefb26f9g", "home", "127.0.1");
ShowWsResponse response = executeRequest();
- assertThat(response.getServerId()).isEqualTo("server_id");
+ assertThat(response.getServerId()).isEqualTo("1818a1eefb26f9g");
assertThat(response.getOrganization()).isEqualTo("home");
assertThat(response.getIp()).isEqualTo("127.0.1");
assertThat(response.getValidIpAdressesList()).containsOnly("192.168.1.1", "127.0.1");
@@ -86,7 +86,7 @@ public class ShowActionTest {
@Test
public void return_invalid_server_id() throws Exception {
setUserAsSystemAdmin();
- when(generator.generate("home", "127.0.1")).thenReturn("server_id");
+ when(generator.validate("home", "127.0.1", "1818a1eefb26f9g")).thenReturn(true);
insertConfiguration("invalid", null, null);
ShowWsResponse response = executeRequest();
@@ -161,9 +161,9 @@ public class ShowActionTest {
@Test
public void test_example_json_response() {
setUserAsSystemAdmin();
- when(generator.generate("home", "127.0.1")).thenReturn("server_id");
+ when(generator.validate("home", "127.0.1", "1818a1eefb26f9g")).thenReturn(true);
setAvailableIpAdresses("192.168.1.1", "127.0.1");
- insertConfiguration("server_id", "home", "127.0.1");
+ insertConfiguration("1818a1eefb26f9g", "home", "127.0.1");
String result = ws.newRequest()
.setMediaType(JSON)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java b/server/sonar-server/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java
index 4fdd4840b0c..269e6913613 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java
@@ -117,7 +117,7 @@ public class ThreadLocalSettingsTest {
@Test
public void encryption_secret_key_is_undefined_by_default() {
- underTest = create(ImmutableMap.of("foo", "bar"));
+ underTest = create(ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", "unknown/path/to/sonar-secret.txt"));
assertThat(underTest.getEncryption().hasSecretKey()).isFalse();
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/GenerateRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/GenerateRequest.java
new file mode 100644
index 00000000000..57b29d62b15
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/GenerateRequest.java
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.serverid;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class GenerateRequest {
+ private final String organization;
+ private final String ip;
+
+ public GenerateRequest(Builder builder) {
+ this.organization = builder.organization;
+ this.ip = builder.ip;
+ }
+
+ public String getOrganization() {
+ return organization;
+ }
+
+ public String getIp() {
+ return ip;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String organization;
+ private String ip;
+
+ private Builder() {
+ // enforce static constructor
+ }
+
+ public Builder setOrganization(String organization) {
+ this.organization = organization;
+ return this;
+ }
+
+ public Builder setIp(String ip) {
+ this.ip = ip;
+ return this;
+ }
+
+ public GenerateRequest build() {
+ checkArgument(organization != null && !organization.isEmpty(), "Organization must not be null or empty");
+ checkArgument(ip != null && !ip.isEmpty(), "IP must not be null or empty");
+ return new GenerateRequest(this);
+ }
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/package-info.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/package-info.java
new file mode 100644
index 00000000000..2ea55636428
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/serverid/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+
+
+
+@ParametersAreNonnullByDefault
+package org.sonarqube.ws.client.serverid;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-ws/src/main/protobuf/ws-serverid.proto b/sonar-ws/src/main/protobuf/ws-serverid.proto
index 18a2a813ef6..af02b223d86 100644
--- a/sonar-ws/src/main/protobuf/ws-serverid.proto
+++ b/sonar-ws/src/main/protobuf/ws-serverid.proto
@@ -33,6 +33,7 @@ message ShowWsResponse {
optional bool invalidServerId = 5;
}
-
-
-
+// Response of POST api/server_id/generate
+message GenerateWsResponse {
+ optional string serverId = 1;
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/serverid/GenerateRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/serverid/GenerateRequestTest.java
new file mode 100644
index 00000000000..ecbf2588ae3
--- /dev/null
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/serverid/GenerateRequestTest.java
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.serverid;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class GenerateRequestTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ GenerateRequest.Builder underTest = GenerateRequest.builder();
+
+ @Test
+ public void fail_if_null_organization() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Organization must not be null or empty");
+
+ underTest.setIp("127.0.0.1").setOrganization(null).build();
+ }
+
+ @Test
+ public void fail_if_empty_organization() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Organization must not be null or empty");
+
+ underTest.setIp("127.0.0.1").setOrganization("").build();
+ }
+
+ @Test
+ public void fail_if_null_ip() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("IP must not be null or empty");
+
+ underTest.setOrganization("SonarSource").setIp(null).build();
+ }
+
+ @Test
+ public void fail_if_empty_ip() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("IP must not be null or empty");
+
+ underTest.setOrganization("SonarSource").setIp("").build();
+ }
+}