From: Belen Pruvost Date: Wed, 25 Aug 2021 11:37:19 +0000 (+0200) Subject: SONAR-15323 - Allow encryption of Global DevOps Platform Settings X-Git-Tag: 9.1.0.47736~78 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f44c423b8d51ca59461bd630ddfd19a64c1894cf;p=sonarqube.git SONAR-15323 - Allow encryption of Global DevOps Platform Settings --- diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java index 94a74ff68ed..a6fa5aca298 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/setting/AlmSettingDto.java @@ -21,6 +21,9 @@ package org.sonar.db.alm.setting; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.sonar.api.config.internal.Encryption; + +import static com.google.common.base.Strings.isNullOrEmpty; public class AlmSettingDto { @@ -142,7 +145,10 @@ public class AlmSettingDto { } @CheckForNull - public String getPrivateKey() { + public String getDecryptedPrivateKey(Encryption encryption) { + if (!isNullOrEmpty(privateKey) && encryption.isEncrypted(privateKey)) { + return encryption.decrypt(privateKey); + } return privateKey; } @@ -152,7 +158,10 @@ public class AlmSettingDto { } @CheckForNull - public String getPersonalAccessToken() { + public String getDecryptedPersonalAccessToken(Encryption encryption) { + if (!isNullOrEmpty(personalAccessToken) && encryption.isEncrypted(personalAccessToken)) { + return encryption.decrypt(personalAccessToken); + } return personalAccessToken; } @@ -172,7 +181,10 @@ public class AlmSettingDto { } @CheckForNull - public String getClientSecret() { + public String getDecryptedClientSecret(Encryption encryption) { + if (!isNullOrEmpty(clientSecret) && encryption.isEncrypted(clientSecret)) { + return encryption.decrypt(clientSecret); + } return clientSecret; } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java index acebd2bc6c5..2ff6c75f8a2 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/setting/AlmSettingDaoTest.java @@ -22,6 +22,7 @@ package org.sonar.db.alm.setting; import java.util.List; import org.junit.Rule; import org.junit.Test; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.impl.utils.TestSystem2; import org.sonar.core.util.UuidFactory; import org.sonar.db.DbSession; @@ -30,6 +31,7 @@ import org.sonar.db.almsettings.AlmSettingsTesting; import org.sonar.db.audit.NoOpAuditPersister; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubAlmSettingDto; @@ -42,6 +44,8 @@ public class AlmSettingDaoTest { @Rule public DbTester db = DbTester.create(system2); + private final Encryption encryption = mock(Encryption.class); + private DbSession dbSession = db.getSession(); private UuidFactory uuidFactory = mock(UuidFactory.class); @@ -50,17 +54,22 @@ public class AlmSettingDaoTest { @Test public void selectByUuid() { when(uuidFactory.create()).thenReturn(A_UUID); + when(encryption.isEncrypted(any())).thenReturn(false); AlmSettingDto almSettingDto = newGithubAlmSettingDto(); underTest.insert(dbSession, almSettingDto); assertThat(underTest.selectByUuid(dbSession, A_UUID).get()) .extracting(AlmSettingDto::getUuid, AlmSettingDto::getKey, AlmSettingDto::getRawAlm, AlmSettingDto::getUrl, - AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getPersonalAccessToken, - AlmSettingDto::getCreatedAt, AlmSettingDto::getUpdatedAt) + AlmSettingDto::getAppId, AlmSettingDto::getCreatedAt, AlmSettingDto::getUpdatedAt, + s -> almSettingDto.getDecryptedPrivateKey(encryption), + s -> almSettingDto.getDecryptedPersonalAccessToken(encryption), + s -> almSettingDto.getDecryptedClientSecret(encryption)) .containsExactly(A_UUID, almSettingDto.getKey(), ALM.GITHUB.getId(), almSettingDto.getUrl(), - almSettingDto.getAppId(), almSettingDto.getPrivateKey(), - almSettingDto.getPersonalAccessToken(), NOW, NOW); + almSettingDto.getAppId(), NOW, NOW, + almSettingDto.getDecryptedPrivateKey(encryption), + almSettingDto.getDecryptedPersonalAccessToken(encryption), + almSettingDto.getDecryptedClientSecret(encryption)); assertThat(underTest.selectByUuid(dbSession, "foo")).isNotPresent(); } @@ -68,17 +77,46 @@ public class AlmSettingDaoTest { @Test public void selectByKey() { when(uuidFactory.create()).thenReturn(A_UUID); + String decrypted = "decrypted"; + when(encryption.isEncrypted(any())).thenReturn(true); + when(encryption.decrypt(any())).thenReturn(decrypted); AlmSettingDto almSettingDto = AlmSettingsTesting.newGithubAlmSettingDto(); underTest.insert(dbSession, almSettingDto); assertThat(underTest.selectByKey(dbSession, almSettingDto.getKey()).get()) .extracting(AlmSettingDto::getUuid, AlmSettingDto::getKey, AlmSettingDto::getRawAlm, AlmSettingDto::getUrl, - AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getPersonalAccessToken, - AlmSettingDto::getCreatedAt, AlmSettingDto::getUpdatedAt) + AlmSettingDto::getAppId, AlmSettingDto::getCreatedAt, AlmSettingDto::getUpdatedAt, + s -> almSettingDto.getDecryptedPrivateKey(encryption), + s -> almSettingDto.getDecryptedPersonalAccessToken(encryption), + s -> almSettingDto.getDecryptedClientSecret(encryption)) + .containsExactly(A_UUID, almSettingDto.getKey(), ALM.GITHUB.getId(), almSettingDto.getUrl(), + almSettingDto.getAppId(), NOW, NOW, + almSettingDto.getDecryptedPrivateKey(encryption), + null, + almSettingDto.getDecryptedClientSecret(encryption)); + + assertThat(underTest.selectByKey(dbSession, "foo")).isNotPresent(); + } + + @Test + public void selectByKey_withEmptySecrets() { + when(uuidFactory.create()).thenReturn(A_UUID); + String decrypted = "decrypted"; + when(encryption.isEncrypted(any())).thenReturn(true); + when(encryption.decrypt(any())).thenReturn(decrypted); + + AlmSettingDto almSettingDto = AlmSettingsTesting.newAlmSettingDtoWithEmptySecrets(); + underTest.insert(dbSession, almSettingDto); + + assertThat(underTest.selectByKey(dbSession, almSettingDto.getKey()).get()) + .extracting(AlmSettingDto::getUuid, AlmSettingDto::getKey, AlmSettingDto::getRawAlm, AlmSettingDto::getUrl, + AlmSettingDto::getAppId, AlmSettingDto::getCreatedAt, AlmSettingDto::getUpdatedAt, + s -> almSettingDto.getDecryptedPrivateKey(encryption), + s -> almSettingDto.getDecryptedPersonalAccessToken(encryption), + s -> almSettingDto.getDecryptedClientSecret(encryption)) .containsExactly(A_UUID, almSettingDto.getKey(), ALM.GITHUB.getId(), almSettingDto.getUrl(), - almSettingDto.getAppId(), almSettingDto.getPrivateKey(), - almSettingDto.getPersonalAccessToken(), NOW, NOW); + almSettingDto.getAppId(), NOW, NOW, null, null, null); assertThat(underTest.selectByKey(dbSession, "foo")).isNotPresent(); } @@ -127,11 +165,13 @@ public class AlmSettingDaoTest { AlmSettingDto result = underTest.selectByUuid(dbSession, A_UUID).get(); assertThat(result) .extracting(AlmSettingDto::getUuid, AlmSettingDto::getKey, AlmSettingDto::getRawAlm, AlmSettingDto::getUrl, - AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getPersonalAccessToken, + AlmSettingDto::getAppId, + s -> almSettingDto.getDecryptedPrivateKey(encryption), + s -> almSettingDto.getDecryptedPersonalAccessToken(encryption), AlmSettingDto::getCreatedAt, AlmSettingDto::getUpdatedAt) .containsExactly(A_UUID, almSettingDto.getKey(), ALM.GITHUB.getId(), almSettingDto.getUrl(), - almSettingDto.getAppId(), almSettingDto.getPrivateKey(), - almSettingDto.getPersonalAccessToken(), NOW, NOW + 1); + almSettingDto.getAppId(), almSettingDto.getDecryptedPrivateKey(encryption), + almSettingDto.getDecryptedPersonalAccessToken(encryption), NOW, NOW + 1); } @Test diff --git a/server/sonar-db-dao/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/server/sonar-db-dao/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 00000000000..1f0955d450f --- /dev/null +++ b/server/sonar-db-dao/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java index 788caa61d2c..cd7fed0f18b 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/almsettings/AlmSettingsTesting.java @@ -40,6 +40,15 @@ public class AlmSettingsTesting { .setAlm(ALM.GITHUB); } + public static AlmSettingDto newAlmSettingDtoWithEmptySecrets() { + return new AlmSettingDto() + .setKey(randomAlphanumeric(200)) + .setUrl(randomAlphanumeric(2000)) + .setAppId(randomNumeric(8)) + .setClientId(randomNumeric(8)) + .setAlm(ALM.GITHUB); + } + public static AlmSettingDto newAzureAlmSettingDto() { return new AlmSettingDto() .setKey(randomAlphanumeric(200)) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidator.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidator.java index 334dde8d206..b0e6e63c558 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidator.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidator.java @@ -20,20 +20,24 @@ package org.sonar.server.almintegration.validator; import org.sonar.alm.client.bitbucketserver.BitbucketServerRestClient; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.server.ServerSide; import org.sonar.db.alm.setting.AlmSettingDto; @ServerSide public class BitbucketServerSettingsValidator { private final BitbucketServerRestClient bitbucketServerRestClient; + private final Encryption encryption; - public BitbucketServerSettingsValidator(BitbucketServerRestClient bitbucketServerRestClient) { + public BitbucketServerSettingsValidator(BitbucketServerRestClient bitbucketServerRestClient, Settings settings) { this.bitbucketServerRestClient = bitbucketServerRestClient; + this.encryption = settings.getEncryption(); } public void validate(AlmSettingDto almSettingDto) { String bitbucketUrl = almSettingDto.getUrl(); - String bitbucketToken = almSettingDto.getPersonalAccessToken(); + String bitbucketToken = almSettingDto.getDecryptedPersonalAccessToken(encryption); if (bitbucketUrl == null || bitbucketToken == null) { throw new IllegalArgumentException("Your global Bitbucket Server configuration is incomplete."); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidator.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidator.java index 6dd4c540d27..56298ced863 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidator.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidator.java @@ -23,6 +23,8 @@ import java.util.Optional; import org.sonar.alm.client.github.GithubApplicationClient; import org.sonar.alm.client.github.GithubApplicationClientImpl; import org.sonar.alm.client.github.config.GithubAppConfiguration; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.server.ServerSide; import org.sonar.db.alm.setting.AlmSettingDto; @@ -31,9 +33,11 @@ import static org.apache.commons.lang.StringUtils.isBlank; @ServerSide public class GithubGlobalSettingsValidator { + private final Encryption encryption; private final GithubApplicationClient githubApplicationClient; - public GithubGlobalSettingsValidator(GithubApplicationClientImpl githubApplicationClient) { + public GithubGlobalSettingsValidator(GithubApplicationClientImpl githubApplicationClient, Settings settings) { + this.encryption = settings.getEncryption(); this.githubApplicationClient = githubApplicationClient; } @@ -47,10 +51,11 @@ public class GithubGlobalSettingsValidator { if (isBlank(settings.getClientId())) { throw new IllegalArgumentException("Missing Client Id"); } - if (isBlank(settings.getClientSecret())) { + if (isBlank(settings.getDecryptedClientSecret(encryption))) { throw new IllegalArgumentException("Missing Client Secret"); } - GithubAppConfiguration configuration = new GithubAppConfiguration(appId, settings.getPrivateKey(), settings.getUrl()); + GithubAppConfiguration configuration = new GithubAppConfiguration(appId, settings.getDecryptedPrivateKey(encryption), + settings.getUrl()); githubApplicationClient.checkApiEndpoint(configuration); githubApplicationClient.checkAppPermissions(configuration); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidator.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidator.java index 40c4195e81b..d6758b48201 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidator.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidator.java @@ -20,21 +20,25 @@ package org.sonar.server.almintegration.validator; import org.sonar.alm.client.gitlab.GitlabHttpClient; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.server.ServerSide; import org.sonar.db.alm.setting.AlmSettingDto; @ServerSide public class GitlabGlobalSettingsValidator { + private final Encryption encryption; private final GitlabHttpClient gitlabHttpClient; - public GitlabGlobalSettingsValidator(GitlabHttpClient gitlabHttpClient) { + public GitlabGlobalSettingsValidator(GitlabHttpClient gitlabHttpClient, Settings settings) { + this.encryption = settings.getEncryption(); this.gitlabHttpClient = gitlabHttpClient; } public void validate(AlmSettingDto almSettingDto) { String gitlabUrl = almSettingDto.getUrl(); - String accessToken = almSettingDto.getPersonalAccessToken(); + String accessToken = almSettingDto.getDecryptedPersonalAccessToken(encryption); if (gitlabUrl == null || accessToken == null) { throw new IllegalArgumentException("Your Gitlab global configuration is incomplete."); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsAction.java index ec378fed138..64664859dfc 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsAction.java @@ -26,6 +26,8 @@ import org.sonar.alm.client.github.GithubApplicationClient.Organization; import org.sonar.alm.client.github.GithubApplicationClientImpl; import org.sonar.alm.client.github.security.AccessToken; import org.sonar.alm.client.github.security.UserAccessToken; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -53,11 +55,14 @@ public class ListGithubOrganizationsAction implements AlmIntegrationsWsAction { public static final String PARAM_TOKEN = "token"; private final DbClient dbClient; + private final Encryption encryption; private final UserSession userSession; private final GithubApplicationClient githubApplicationClient; - public ListGithubOrganizationsAction(DbClient dbClient, UserSession userSession, GithubApplicationClientImpl githubApplicationClient) { + public ListGithubOrganizationsAction(DbClient dbClient, Settings settings, UserSession userSession, + GithubApplicationClientImpl githubApplicationClient) { this.dbClient = dbClient; + this.encryption = settings.getEncryption(); this.userSession = userSession; this.githubApplicationClient = githubApplicationClient; } @@ -109,7 +114,8 @@ public class ListGithubOrganizationsAction implements AlmIntegrationsWsAction { if (request.hasParam(PARAM_TOKEN)) { String code = request.mandatoryParam(PARAM_TOKEN); String clientId = requireNonNull(almSettingDto.getClientId(), String.format("No clientId set for GitHub ALM '%s'", almSettingKey)); - String clientSecret = requireNonNull(almSettingDto.getClientSecret(), String.format("No clientSecret set for GitHub ALM '%s'", almSettingKey)); + String clientSecret = requireNonNull(almSettingDto.getDecryptedClientSecret(encryption), String.format("No clientSecret set for GitHub ALM '%s'", + almSettingKey)); try { accessToken = githubApplicationClient.createUserAccessToken(url, clientId, clientSecret, code); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateAzureAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateAzureAction.java index 111f6306daf..700bc9eefa2 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateAzureAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateAzureAction.java @@ -94,9 +94,13 @@ public class UpdateAzureAction implements AlmSettingsWsAction { if (isNotBlank(newKey) && !newKey.equals(key)) { almSettingsSupport.checkAlmSettingDoesNotAlreadyExist(dbSession, newKey); } + + if (isNotBlank(pat)) { + almSettingDto.setPersonalAccessToken(pat); + } + dbClient.almSettingDao().update(dbSession, almSettingDto .setKey(isNotBlank(newKey) ? newKey : key) - .setPersonalAccessToken(isNotBlank(pat) ? pat : almSettingDto.getPersonalAccessToken()) .setUrl(url), pat != null); dbSession.commit(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketAction.java index 811621fb64c..2fb0ad70a3f 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketAction.java @@ -93,10 +93,14 @@ public class UpdateBitbucketAction implements AlmSettingsWsAction { if (isNotBlank(newKey) && !newKey.equals(key)) { almSettingsSupport.checkAlmSettingDoesNotAlreadyExist(dbSession, newKey); } + + if (isNotBlank(pat)) { + almSettingDto.setPersonalAccessToken(pat); + } + dbClient.almSettingDao().update(dbSession, almSettingDto .setKey(isNotBlank(newKey) ? newKey : key) - .setUrl(url) - .setPersonalAccessToken(isNotBlank(pat) ? pat : almSettingDto.getPersonalAccessToken()), + .setUrl(url), pat != null); dbSession.commit(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudAction.java index 1f00edcec0f..1141bc58b2a 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudAction.java @@ -96,11 +96,15 @@ public class UpdateBitbucketCloudAction implements AlmSettingsWsAction { if (isNotBlank(newKey) && !newKey.equals(key)) { almSettingsSupport.checkAlmSettingDoesNotAlreadyExist(dbSession, newKey); } + + if (isNotBlank(clientSecret)) { + almSettingDto.setClientSecret(clientSecret); + } + dbClient.almSettingDao().update(dbSession, almSettingDto .setKey(isNotBlank(newKey) ? newKey : key) .setClientId(clientId) - .setAppId(workspace) - .setClientSecret(isNotBlank(clientSecret) ? clientSecret : almSettingDto.getClientSecret()), + .setAppId(workspace), clientSecret != null); dbSession.commit(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGithubAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGithubAction.java index 275b4f26f9f..9525bc70a1e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGithubAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGithubAction.java @@ -116,13 +116,20 @@ public class UpdateGithubAction implements AlmSettingsWsAction { if (isNotBlank(newKey) && !newKey.equals(key)) { almSettingsSupport.checkAlmSettingDoesNotAlreadyExist(dbSession, newKey); } + + if (isNotBlank(privateKey)) { + almSettingDto.setPrivateKey(privateKey); + } + + if (isNotBlank(clientSecret)) { + almSettingDto.setClientSecret(clientSecret); + } + dbClient.almSettingDao().update(dbSession, almSettingDto - .setKey(isNotBlank(newKey) ? newKey : key) - .setUrl(url) - .setAppId(appId) - .setPrivateKey(isNotBlank(privateKey) ? privateKey : almSettingDto.getPrivateKey()) - .setClientId(clientId) - .setClientSecret(isNotBlank(clientSecret) ? clientSecret : almSettingDto.getClientSecret()), + .setKey(isNotBlank(newKey) ? newKey : key) + .setUrl(url) + .setAppId(appId) + .setClientId(clientId), clientSecret != null || privateKey != null); dbSession.commit(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGitlabAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGitlabAction.java index 2ef16921f00..4766e6794c7 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGitlabAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/UpdateGitlabAction.java @@ -95,10 +95,14 @@ public class UpdateGitlabAction implements AlmSettingsWsAction { if (isNotBlank(newKey) && !newKey.equals(key)) { almSettingsSupport.checkAlmSettingDoesNotAlreadyExist(dbSession, newKey); } + + if (isNotBlank(pat)) { + almSettingDto.setPersonalAccessToken(pat); + } + dbClient.almSettingDao().update(dbSession, almSettingDto .setKey(isNotBlank(newKey) ? newKey : key) - .setUrl(url) - .setPersonalAccessToken(isNotBlank(pat) ? pat : almSettingDto.getPersonalAccessToken()), + .setUrl(url), pat != null); dbSession.commit(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/ValidateAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/ValidateAction.java index 24ce864f687..4e98da5649a 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/ValidateAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/ValidateAction.java @@ -21,6 +21,8 @@ package org.sonar.server.almsettings.ws; import org.sonar.alm.client.azure.AzureDevOpsHttpClient; import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudRestClient; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -37,6 +39,7 @@ public class ValidateAction implements AlmSettingsWsAction { private static final String PARAM_KEY = "key"; private final DbClient dbClient; + private final Encryption encryption; private final UserSession userSession; private final AlmSettingsSupport almSettingsSupport; private final AzureDevOpsHttpClient azureDevOpsHttpClient; @@ -46,6 +49,7 @@ public class ValidateAction implements AlmSettingsWsAction { private final BitbucketCloudRestClient bitbucketCloudRestClient; public ValidateAction(DbClient dbClient, + Settings settings, UserSession userSession, AlmSettingsSupport almSettingsSupport, AzureDevOpsHttpClient azureDevOpsHttpClient, @@ -54,6 +58,7 @@ public class ValidateAction implements AlmSettingsWsAction { BitbucketServerSettingsValidator bitbucketServerSettingsValidator, BitbucketCloudRestClient bitbucketCloudRestClient) { this.dbClient = dbClient; + this.encryption = settings.getEncryption(); this.userSession = userSession; this.almSettingsSupport = almSettingsSupport; this.azureDevOpsHttpClient = azureDevOpsHttpClient; @@ -111,13 +116,13 @@ public class ValidateAction implements AlmSettingsWsAction { private void validateAzure(AlmSettingDto almSettingDto) { try { - azureDevOpsHttpClient.checkPAT(almSettingDto.getUrl(), almSettingDto.getPersonalAccessToken()); + azureDevOpsHttpClient.checkPAT(almSettingDto.getUrl(), almSettingDto.getDecryptedPersonalAccessToken(encryption)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Invalid Azure URL or Personal Access Token", e); } } private void validateBitbucketCloud(AlmSettingDto almSettingDto) { - bitbucketCloudRestClient.validate(almSettingDto.getClientId(), almSettingDto.getClientSecret(), almSettingDto.getAppId()); + bitbucketCloudRestClient.validate(almSettingDto.getClientId(), almSettingDto.getDecryptedClientSecret(encryption), almSettingDto.getAppId()); } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidatorTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidatorTest.java index 9122af01a08..e8644877c1c 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidatorTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/BitbucketServerSettingsValidatorTest.java @@ -19,28 +19,41 @@ */ package org.sonar.server.almintegration.validator; +import org.junit.BeforeClass; import org.junit.Test; import org.sonar.alm.client.bitbucketserver.BitbucketServerRestClient; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.db.alm.setting.AlmSettingDto; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.sonar.db.almsettings.AlmSettingsTesting.newBitbucketAlmSettingDto; public class BitbucketServerSettingsValidatorTest { + private static final Encryption encryption = mock(Encryption.class); + private static final Settings settings = mock(Settings.class); private final BitbucketServerRestClient bitbucketServerRestClient = mock(BitbucketServerRestClient.class); - private final BitbucketServerSettingsValidator underTest = new BitbucketServerSettingsValidator(bitbucketServerRestClient); + private final BitbucketServerSettingsValidator underTest = new BitbucketServerSettingsValidator(bitbucketServerRestClient, settings); + + @BeforeClass + public static void setUp() { + when(settings.getEncryption()).thenReturn(encryption); + } @Test public void validate_success() { AlmSettingDto almSettingDto = newBitbucketAlmSettingDto() .setUrl("http://abc.com") .setPersonalAccessToken("abc"); + when(encryption.isEncrypted(any())).thenReturn(false); underTest.validate(almSettingDto); @@ -49,6 +62,23 @@ public class BitbucketServerSettingsValidatorTest { verify(bitbucketServerRestClient, times(1)).validateReadPermission("http://abc.com", "abc"); } + @Test + public void validate_success_with_encrypted_token() { + String encryptedToken = "abc"; + String decryptedToken = "decrypted-token"; + AlmSettingDto almSettingDto = newBitbucketAlmSettingDto() + .setUrl("http://abc.com") + .setPersonalAccessToken(encryptedToken); + when(encryption.isEncrypted(encryptedToken)).thenReturn(true); + when(encryption.decrypt(encryptedToken)).thenReturn(decryptedToken); + + underTest.validate(almSettingDto); + + verify(bitbucketServerRestClient, times(1)).validateUrl("http://abc.com"); + verify(bitbucketServerRestClient, times(1)).validateToken("http://abc.com", decryptedToken); + verify(bitbucketServerRestClient, times(1)).validateReadPermission("http://abc.com", decryptedToken); + } + @Test public void validate_failure_on_incomplete_configuration() { AlmSettingDto almSettingDto = newBitbucketAlmSettingDto() diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidatorTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidatorTest.java index efc2679fe28..5c3d274a65b 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidatorTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GithubGlobalSettingsValidatorTest.java @@ -19,27 +19,61 @@ */ package org.sonar.server.almintegration.validator; +import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.alm.client.github.GithubApplicationClientImpl; import org.sonar.alm.client.github.config.GithubAppConfiguration; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.db.alm.setting.AlmSettingDto; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubAlmSettingDto; public class GithubGlobalSettingsValidatorTest { + private static final Encryption encryption = mock(Encryption.class); + private static final Settings settings = mock(Settings.class); + private final GithubApplicationClientImpl appClient = mock(GithubApplicationClientImpl.class); - private final GithubGlobalSettingsValidator underTest = new GithubGlobalSettingsValidator(appClient); + private final GithubGlobalSettingsValidator underTest = new GithubGlobalSettingsValidator(appClient, settings); + + @BeforeClass + public static void setUp() { + when(settings.getEncryption()).thenReturn(encryption); + } @Test public void github_global_settings_validation() { AlmSettingDto almSettingDto = newGithubAlmSettingDto() .setClientId("clientId") .setClientSecret("clientSecret"); + when(encryption.isEncrypted(any())).thenReturn(false); + + GithubAppConfiguration configuration = underTest.validate(almSettingDto); + + ArgumentCaptor configurationArgumentCaptor = ArgumentCaptor.forClass(GithubAppConfiguration.class); + verify(appClient).checkApiEndpoint(configurationArgumentCaptor.capture()); + verify(appClient).checkAppPermissions(configurationArgumentCaptor.capture()); + assertThat(configuration.getId()).isEqualTo(configurationArgumentCaptor.getAllValues().get(0).getId()); + assertThat(configuration.getId()).isEqualTo(configurationArgumentCaptor.getAllValues().get(1).getId()); + } + + @Test + public void github_global_settings_validation_with_encrypted_key() { + String encryptedKey = "encrypted-key"; + String decryptedKey = "decrypted-key"; + AlmSettingDto almSettingDto = newGithubAlmSettingDto() + .setClientId("clientId") + .setPrivateKey(encryptedKey) + .setClientSecret("clientSecret"); + when(encryption.isEncrypted(encryptedKey)).thenReturn(true); + when(encryption.decrypt(encryptedKey)).thenReturn(decryptedKey); GithubAppConfiguration configuration = underTest.validate(almSettingDto); @@ -47,7 +81,9 @@ public class GithubGlobalSettingsValidatorTest { verify(appClient).checkApiEndpoint(configurationArgumentCaptor.capture()); verify(appClient).checkAppPermissions(configurationArgumentCaptor.capture()); assertThat(configuration.getId()).isEqualTo(configurationArgumentCaptor.getAllValues().get(0).getId()); + assertThat(decryptedKey).isEqualTo(configurationArgumentCaptor.getAllValues().get(0).getPrivateKey()); assertThat(configuration.getId()).isEqualTo(configurationArgumentCaptor.getAllValues().get(1).getId()); + assertThat(decryptedKey).isEqualTo(configurationArgumentCaptor.getAllValues().get(1).getPrivateKey()); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidatorTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidatorTest.java index 1e16fef29fa..186b671ed2f 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidatorTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/validator/GitlabGlobalSettingsValidatorTest.java @@ -19,26 +19,63 @@ */ package org.sonar.server.almintegration.validator; +import org.junit.BeforeClass; import org.junit.Test; import org.sonar.alm.client.gitlab.GitlabHttpClient; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.db.alm.setting.AlmSettingDto; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class GitlabGlobalSettingsValidatorTest { + private static final Encryption encryption = mock(Encryption.class); + private static final Settings settings = mock(Settings.class); private final GitlabHttpClient gitlabHttpClient = mock(GitlabHttpClient.class); - private final GitlabGlobalSettingsValidator underTest = new GitlabGlobalSettingsValidator(gitlabHttpClient); + private final GitlabGlobalSettingsValidator underTest = new GitlabGlobalSettingsValidator(gitlabHttpClient, settings); + + @BeforeClass + public static void setUp() { + when(settings.getEncryption()).thenReturn(encryption); + } @Test public void validate_success() { + String token = "personal-access-token"; AlmSettingDto almSettingDto = new AlmSettingDto() .setUrl("https://gitlab.com/api") .setPersonalAccessToken("personal-access-token"); + when(encryption.isEncrypted(token)).thenReturn(false); + + underTest.validate(almSettingDto); + verify(gitlabHttpClient, times(1)).checkUrl(almSettingDto.getUrl()); + verify(gitlabHttpClient, times(1)).checkToken(almSettingDto.getUrl(), almSettingDto.getDecryptedPersonalAccessToken(encryption)); + verify(gitlabHttpClient, times(1)).checkReadPermission(almSettingDto.getUrl(), almSettingDto.getDecryptedPersonalAccessToken(encryption)); + verify(gitlabHttpClient, times(1)).checkWritePermission(almSettingDto.getUrl(), almSettingDto.getDecryptedPersonalAccessToken(encryption)); + } + + @Test + public void validate_success_with_encrypted_token() { + String encryptedToken = "personal-access-token"; + String decryptedToken = "decrypted-token"; + AlmSettingDto almSettingDto = new AlmSettingDto() + .setUrl("https://gitlab.com/api") + .setPersonalAccessToken(encryptedToken); + when(encryption.isEncrypted(encryptedToken)).thenReturn(true); + when(encryption.decrypt(encryptedToken)).thenReturn(decryptedToken); underTest.validate(almSettingDto); + + verify(gitlabHttpClient, times(1)).checkUrl(almSettingDto.getUrl()); + verify(gitlabHttpClient, times(1)).checkToken(almSettingDto.getUrl(), decryptedToken); + verify(gitlabHttpClient, times(1)).checkReadPermission(almSettingDto.getUrl(), decryptedToken); + verify(gitlabHttpClient, times(1)).checkWritePermission(almSettingDto.getUrl(), decryptedToken); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java index 8d7610b206b..bd3b5926298 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java @@ -28,6 +28,7 @@ import org.junit.Test; import org.sonar.alm.client.azure.AzureDevOpsHttpClient; import org.sonar.alm.client.azure.GsonAzureProject; import org.sonar.alm.client.azure.GsonAzureRepo; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.core.i18n.I18n; @@ -78,6 +79,7 @@ public class ImportAzureProjectActionTest { private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE, mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); + private final Encryption encryption = mock(Encryption.class); private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); private final ImportAzureProjectAction importAzureProjectAction = new ImportAzureProjectAction(db.getDbClient(), userSession, @@ -96,11 +98,12 @@ public class ImportAzureProjectActionTest { AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting(); db.almPats().insert(dto -> { dto.setAlmSettingUuid(almSetting.getUuid()); - dto.setPersonalAccessToken(almSetting.getPersonalAccessToken()); + dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption)); dto.setUserUuid(user.getUuid()); }); GsonAzureRepo repo = getGsonAzureRepo(); - when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getPersonalAccessToken(), "project-name", "repo-name")) + when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption), + "project-name", "repo-name")) .thenReturn(repo); Projects.CreateWsResponse response = ws.newRequest() @@ -138,11 +141,12 @@ public class ImportAzureProjectActionTest { AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting(); db.almPats().insert(dto -> { dto.setAlmSettingUuid(almSetting.getUuid()); - dto.setPersonalAccessToken(almSetting.getPersonalAccessToken()); + dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption)); dto.setUserUuid(user.getUuid()); }); GsonAzureRepo repo = getEmptyGsonAzureRepo(); - when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getPersonalAccessToken(), "project-name", "repo-name")) + when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption), + "project-name", "repo-name")) .thenReturn(repo); Projects.CreateWsResponse response = ws.newRequest() @@ -228,14 +232,15 @@ public class ImportAzureProjectActionTest { AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting(); db.almPats().insert(dto -> { dto.setAlmSettingUuid(almSetting.getUuid()); - dto.setPersonalAccessToken(almSetting.getPersonalAccessToken()); + dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption)); dto.setUserUuid(user.getUuid()); }); GsonAzureRepo repo = getGsonAzureRepo(); String projectKey = repo.getProject().getName() + "_" + repo.getName(); db.components().insertPublicProject(p -> p.setDbKey(projectKey)); - when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getPersonalAccessToken(), "project-name", "repo-name")).thenReturn(repo); + when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption), + "project-name", "repo-name")).thenReturn(repo); TestRequest request = ws.newRequest() .setParam("almSetting", almSetting.getKey()) .setParam("projectName", "project-name") diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java index 7918962abd5..792d279205b 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java @@ -28,6 +28,7 @@ import org.sonar.alm.client.azure.AzureDevOpsHttpClient; import org.sonar.alm.client.azure.GsonAzureProject; import org.sonar.alm.client.azure.GsonAzureRepo; import org.sonar.alm.client.azure.GsonAzureRepoList; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.pat.AlmPatDto; @@ -60,8 +61,9 @@ public class SearchAzureReposActionTest { @Rule public DbTester db = DbTester.create(); - private AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class); - private WsActionTester ws = new WsActionTester(new SearchAzureReposAction(db.getDbClient(), userSession, azureDevOpsHttpClient)); + private final AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class); + private final Encryption encryption = mock(Encryption.class); + private final WsActionTester ws = new WsActionTester(new SearchAzureReposAction(db.getDbClient(), userSession, azureDevOpsHttpClient)); @Before public void before() { @@ -347,7 +349,7 @@ public class SearchAzureReposActionTest { db.almPats().insert(dto -> { dto.setAlmSettingUuid(almSetting.getUuid()); dto.setUserUuid(user.getUuid()); - dto.setPersonalAccessToken(almSetting.getPersonalAccessToken()); + dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption)); }); return almSetting; } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsActionTest.java index 7bca0e3af5e..32945d45ce8 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubOrganizationsActionTest.java @@ -21,12 +21,15 @@ package org.sonar.server.almintegration.ws.github; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.mockito.Mockito; import org.sonar.alm.client.github.GithubApplicationClient; import org.sonar.alm.client.github.GithubApplicationClientImpl; import org.sonar.alm.client.github.security.UserAccessToken; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; import org.sonar.db.alm.pat.AlmPatDto; @@ -58,6 +61,8 @@ import static org.sonar.server.almintegration.ws.github.ListGithubOrganizationsA import static org.sonar.server.tester.UserSessionRule.standalone; public class ListGithubOrganizationsActionTest { + private static final Encryption encryption = mock(Encryption.class); + private static final Settings settings = mock(Settings.class); @Rule public UserSessionRule userSession = standalone(); @@ -68,7 +73,12 @@ public class ListGithubOrganizationsActionTest { @Rule public DbTester db = DbTester.create(system2); - private final WsActionTester ws = new WsActionTester(new ListGithubOrganizationsAction(db.getDbClient(), userSession, appClient)); + private final WsActionTester ws = new WsActionTester(new ListGithubOrganizationsAction(db.getDbClient(), settings, userSession, appClient)); + + @BeforeClass + public static void setUp() { + when(settings.getEncryption()).thenReturn(encryption); + } @Test public void fail_when_missing_create_project_permission() { @@ -91,7 +101,8 @@ public class ListGithubOrganizationsActionTest { @Test public void fail_when_unable_to_create_personal_access_token() { AlmSettingDto githubAlmSetting = setupAlm(); - when(appClient.createUserAccessToken(githubAlmSetting.getUrl(), githubAlmSetting.getClientId(), githubAlmSetting.getClientSecret(), "abc")) + when(appClient.createUserAccessToken(githubAlmSetting.getUrl(), githubAlmSetting.getClientId(), + githubAlmSetting.getDecryptedClientSecret(encryption), "abc")) .thenThrow(IllegalStateException.class); TestRequest request = ws.newRequest() .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) @@ -105,7 +116,8 @@ public class ListGithubOrganizationsActionTest { @Test public void fail_create_personal_access_token_because_of_invalid_settings() { AlmSettingDto githubAlmSetting = setupAlm(); - when(appClient.createUserAccessToken(githubAlmSetting.getUrl(), githubAlmSetting.getClientId(), githubAlmSetting.getClientSecret(), "abc")) + when(appClient.createUserAccessToken(githubAlmSetting.getUrl(), githubAlmSetting.getClientId(), + githubAlmSetting.getDecryptedClientSecret(encryption), "abc")) .thenThrow(IllegalArgumentException.class); TestRequest request = ws.newRequest() .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) @@ -130,8 +142,42 @@ public class ListGithubOrganizationsActionTest { public void return_organizations_and_store_personal_access_token() { UserAccessToken accessToken = new UserAccessToken("token_for_abc"); AlmSettingDto githubAlmSettings = setupAlm(); + when(encryption.isEncrypted(any())).thenReturn(false); + + when(appClient.createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), + githubAlmSettings.getDecryptedClientSecret(encryption), "abc")) + .thenReturn(accessToken); + setupGhOrganizations(githubAlmSettings, accessToken.getValue()); + + ListGithubOrganizationsWsResponse response = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSettings.getKey()) + .setParam(PARAM_TOKEN, "abc") + .executeProtobuf(ListGithubOrganizationsWsResponse.class); + + assertThat(response.getPaging()) + .extracting(Common.Paging::getPageIndex, Common.Paging::getPageSize, Common.Paging::getTotal) + .containsOnly(1, 100, 2); + assertThat(response.getOrganizationsList()) + .extracting(GithubOrganization::getKey, GithubOrganization::getName) + .containsOnly(tuple("github", "github"), tuple("octacat", "octacat")); + + verify(appClient).createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), + githubAlmSettings.getDecryptedClientSecret(encryption), "abc"); + verify(appClient).listOrganizations(githubAlmSettings.getUrl(), accessToken, 1, 100); + Mockito.verifyNoMoreInteractions(appClient); + assertThat(db.getDbClient().almPatDao().selectByUserAndAlmSetting(db.getSession(), userSession.getUuid(), githubAlmSettings).get().getPersonalAccessToken()) + .isEqualTo(accessToken.getValue()); + } + + @Test + public void return_organizations_and_store_personal_access_token_with_encrypted_client_secret() { + String decryptedSecret = "decrypted-secret"; + UserAccessToken accessToken = new UserAccessToken("token_for_abc"); + AlmSettingDto githubAlmSettings = setupAlm(); + when(encryption.isEncrypted(any())).thenReturn(true); + when(encryption.decrypt(any())).thenReturn(decryptedSecret); - when(appClient.createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), githubAlmSettings.getClientSecret(), "abc")) + when(appClient.createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), decryptedSecret, "abc")) .thenReturn(accessToken); setupGhOrganizations(githubAlmSettings, accessToken.getValue()); @@ -147,7 +193,7 @@ public class ListGithubOrganizationsActionTest { .extracting(GithubOrganization::getKey, GithubOrganization::getName) .containsOnly(tuple("github", "github"), tuple("octacat", "octacat")); - verify(appClient).createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), githubAlmSettings.getClientSecret(), "abc"); + verify(appClient).createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), decryptedSecret, "abc"); verify(appClient).listOrganizations(githubAlmSettings.getUrl(), accessToken, 1, 100); Mockito.verifyNoMoreInteractions(appClient); assertThat(db.getDbClient().almPatDao().selectByUserAndAlmSetting(db.getSession(), userSession.getUuid(), githubAlmSettings).get().getPersonalAccessToken()) @@ -163,7 +209,8 @@ public class ListGithubOrganizationsActionTest { // new pat UserAccessToken accessToken = new UserAccessToken("token_for_abc"); - when(appClient.createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), githubAlmSettings.getClientSecret(), "abc")) + when(appClient.createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), + githubAlmSettings.getDecryptedClientSecret(encryption), "abc")) .thenReturn(accessToken); setupGhOrganizations(githubAlmSettings, accessToken.getValue()); @@ -179,7 +226,8 @@ public class ListGithubOrganizationsActionTest { .extracting(GithubOrganization::getKey, GithubOrganization::getName) .containsOnly(tuple("github", "github"), tuple("octacat", "octacat")); - verify(appClient).createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), githubAlmSettings.getClientSecret(), "abc"); + verify(appClient).createUserAccessToken(githubAlmSettings.getUrl(), githubAlmSettings.getClientId(), + githubAlmSettings.getDecryptedClientSecret(encryption), "abc"); verify(appClient).listOrganizations(eq(githubAlmSettings.getUrl()), argThat(token -> token.getValue().equals(accessToken.getValue())), eq(1), eq(100)); Mockito.verifyNoMoreInteractions(appClient); assertThat(db.getDbClient().almPatDao().selectByUserAndAlmSetting(db.getSession(), userSession.getUuid(), githubAlmSettings).get().getPersonalAccessToken()) diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateAzureActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateAzureActionTest.java index ad9fb29acc9..da14c3f8473 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateAzureActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateAzureActionTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -48,7 +49,8 @@ public class CreateAzureActionTest { @Rule public DbTester db = DbTester.create(); - private MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); + private final Encryption encryption = mock(Encryption.class); + private final MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); private WsActionTester ws = new WsActionTester(new CreateAzureAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), @@ -71,7 +73,9 @@ public class CreateAzureActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getPersonalAccessToken, AlmSettingDto::getUrl) + .extracting(AlmSettingDto::getKey, + s -> s.getDecryptedPersonalAccessToken(encryption), + AlmSettingDto::getUrl) .containsOnly(tuple("Azure Server - Dev Team", "98765432100", "https://ado.sonarqube.com/")); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketActionTest.java index ae8fe639867..d899ddadd27 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketActionTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -48,7 +49,8 @@ public class CreateBitbucketActionTest { @Rule public DbTester db = DbTester.create(); - private MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); + private final Encryption encryption = mock(Encryption.class); + private final MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); private WsActionTester ws = new WsActionTester(new CreateBitBucketAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), @@ -71,7 +73,7 @@ public class CreateBitbucketActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple("Bitbucket Server - Dev Team", "https://bitbucket.enterprise.com", "98765432100")); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketCloudActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketCloudActionTest.java index 769a4db66b0..cb7f30be4be 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketCloudActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateBitbucketCloudActionTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -48,7 +49,8 @@ public class CreateBitbucketCloudActionTest { @Rule public DbTester db = DbTester.create(); - private MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); + private final Encryption encryption = mock(Encryption.class); + private final MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); private WsActionTester ws = new WsActionTester(new CreateBitbucketCloudAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), @@ -72,7 +74,7 @@ public class CreateBitbucketCloudActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret, AlmSettingDto::getAppId) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption), AlmSettingDto::getAppId) .containsOnly(tuple("Bitbucket Server - Dev Team", "id", "secret", "workspace1")); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGithubActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGithubActionTest.java index d5f93eeae70..6ab9d86a433 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGithubActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGithubActionTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -48,7 +49,8 @@ public class CreateGithubActionTest { @Rule public DbTester db = DbTester.create(); - private MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); + private final Encryption encryption = mock(Encryption.class); + private final MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); private WsActionTester ws = new WsActionTester(new CreateGithubAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), @@ -74,7 +76,8 @@ public class CreateGithubActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, + s -> s.getDecryptedPrivateKey(encryption), AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption)) .containsOnly(tuple("GitHub Server - Dev Team", "https://github.enterprise.com", "12345", "678910", "client_1234", "client_so_secret")); } @@ -93,7 +96,8 @@ public class CreateGithubActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, + s -> s.getDecryptedPrivateKey(encryption), AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption)) .containsOnly(tuple("GitHub Server - Dev Team", "https://github.enterprise.com", "12345", "678910", "client_1234", "client_so_secret")); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGitlabActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGitlabActionTest.java index 7323ec7f2f1..e1cf4fd2e06 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGitlabActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/CreateGitlabActionTest.java @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -52,7 +53,8 @@ public class CreateGitlabActionTest { private static String GITLAB_URL = "gitlab.com/api/v4"; - private MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); + private final Encryption encryption = mock(Encryption.class); + private final MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); private WsActionTester ws = new WsActionTester(new CreateGitlabAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), multipleAlmFeatureProvider))); @@ -88,7 +90,7 @@ public class CreateGitlabActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple("Gitlab - Dev Team", GITLAB_URL, "98765432100")); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateAzureActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateAzureActionTest.java index 9d4908802ed..d26e59986e5 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateAzureActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateAzureActionTest.java @@ -22,6 +22,7 @@ package org.sonar.server.almsettings.ws; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -49,6 +50,8 @@ public class UpdateAzureActionTest { private static String AZURE_URL = "https://ado.sonarqube.com/"; + private final Encryption encryption = mock(Encryption.class); + private WsActionTester ws = new WsActionTester(new UpdateAzureAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), mock(MultipleAlmFeatureProvider.class)))); @@ -66,7 +69,7 @@ public class UpdateAzureActionTest { .setParam("url", AZURE_URL) .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple(almSettingDto.getKey(), AZURE_URL, "10987654321")); } @@ -84,7 +87,7 @@ public class UpdateAzureActionTest { .setParam("url", AZURE_URL) .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple("Azure Server - Infra Team", AZURE_URL, "0123456789")); } @@ -100,8 +103,8 @@ public class UpdateAzureActionTest { .setParam("url", AZURE_URL) .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) - .containsOnly(tuple(almSettingDto.getKey(), AZURE_URL, almSettingDto.getPersonalAccessToken())); + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) + .containsOnly(tuple(almSettingDto.getKey(), AZURE_URL, almSettingDto.getDecryptedPersonalAccessToken(encryption))); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketActionTest.java index f05b53c083f..19927eb0fa6 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketActionTest.java @@ -22,6 +22,7 @@ package org.sonar.server.almsettings.ws; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -47,6 +48,8 @@ public class UpdateBitbucketActionTest { @Rule public DbTester db = DbTester.create(); + private final Encryption encryption = mock(Encryption.class); + private WsActionTester ws = new WsActionTester(new UpdateBitbucketAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), mock(MultipleAlmFeatureProvider.class)))); @@ -64,7 +67,7 @@ public class UpdateBitbucketActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple(almSettingDto.getKey(), "https://bitbucket.enterprise-unicorn.com", "10987654321")); } @@ -82,7 +85,7 @@ public class UpdateBitbucketActionTest { .setParam("personalAccessToken", "0123456789") .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple("Bitbucket Server - Infra Team", "https://bitbucket.enterprise-unicorn.com", "0123456789")); } @@ -98,8 +101,8 @@ public class UpdateBitbucketActionTest { .setParam("url", "https://bitbucket.enterprise-unicorn.com") .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) - .containsOnly(tuple(almSettingDto.getKey(), "https://bitbucket.enterprise-unicorn.com", almSettingDto.getPersonalAccessToken())); + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) + .containsOnly(tuple(almSettingDto.getKey(), "https://bitbucket.enterprise-unicorn.com", almSettingDto.getDecryptedPersonalAccessToken(encryption))); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudActionTest.java index 47d2868bdbd..0a4639ce137 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateBitbucketCloudActionTest.java @@ -21,6 +21,7 @@ package org.sonar.server.almsettings.ws; import org.junit.Rule; import org.junit.Test; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.resources.ResourceTypes; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; @@ -38,7 +39,9 @@ import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.groups.Tuple.tuple; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class UpdateBitbucketCloudActionTest { @Rule @@ -46,12 +49,15 @@ public class UpdateBitbucketCloudActionTest { @Rule public DbTester db = DbTester.create(); + private final Encryption encryption = mock(Encryption.class); + private final WsActionTester ws = new WsActionTester(new UpdateBitbucketCloudAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), mock(ResourceTypes.class)), mock(MultipleAlmFeatureProvider.class)))); @Test public void update() { + when(encryption.isEncrypted(any())).thenReturn(false); UserDto user = db.users().insertUser(); userSession.logIn(user).setSystemAdministrator(); AlmSettingDto almSettingDto = db.almSettings().insertBitbucketAlmSetting(); @@ -64,12 +70,15 @@ public class UpdateBitbucketCloudActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret, AlmSettingDto::getAppId) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, + s -> s.getDecryptedClientSecret(encryption), AlmSettingDto::getAppId) .containsOnly(tuple(almSettingDto.getKey(), "id", "secret", "workspace")); } @Test public void update_with_new_key() { + when(encryption.isEncrypted(any())).thenReturn(false); + UserDto user = db.users().insertUser(); userSession.logIn(user).setSystemAdministrator(); @@ -83,12 +92,15 @@ public class UpdateBitbucketCloudActionTest { .setParam("clientSecret", "secret") .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret, AlmSettingDto::getAppId) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, + s -> s.getDecryptedClientSecret(encryption), AlmSettingDto::getAppId) .containsOnly(tuple("Bitbucket Server - Infra Team", "id", "secret", "workspace")); } @Test public void update_binding_without_changing_the_key() { + when(encryption.isEncrypted(any())).thenReturn(false); + UserDto user = db.users().insertUser(); userSession.logIn(user).setSystemAdministrator(); AlmSettingDto almSetting = db.almSettings().insertBitbucketAlmSetting(); @@ -102,12 +114,15 @@ public class UpdateBitbucketCloudActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret, AlmSettingDto::getAppId) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, + s -> s.getDecryptedClientSecret(encryption), AlmSettingDto::getAppId) .containsOnly(tuple(almSetting.getKey(), "id", "secret", "workspace")); } @Test public void update_without_secret() { + when(encryption.isEncrypted(any())).thenReturn(false); + UserDto user = db.users().insertUser(); userSession.logIn(user).setSystemAdministrator(); @@ -119,8 +134,9 @@ public class UpdateBitbucketCloudActionTest { .setParam("clientId", "id") .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret, AlmSettingDto::getAppId) - .containsOnly(tuple(almSettingDto.getKey(), "id", almSettingDto.getClientSecret(), "workspace")); + .extracting(AlmSettingDto::getKey, AlmSettingDto::getClientId, + s -> s.getDecryptedClientSecret(encryption), AlmSettingDto::getAppId) + .containsOnly(tuple(almSettingDto.getKey(), "id", almSettingDto.getDecryptedPrivateKey(encryption), "workspace")); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGithubActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGithubActionTest.java index 93265c354fb..d100ba0674e 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGithubActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGithubActionTest.java @@ -22,6 +22,7 @@ package org.sonar.server.almsettings.ws; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -47,6 +48,8 @@ public class UpdateGithubActionTest { @Rule public DbTester db = DbTester.create(); + private final Encryption encryption = mock(Encryption.class); + private WsActionTester ws = new WsActionTester(new UpdateGithubAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), mock(MultipleAlmFeatureProvider.class)))); @@ -67,7 +70,8 @@ public class UpdateGithubActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, + s -> s.getDecryptedPrivateKey(encryption), AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption)) .containsOnly(tuple(almSettingDto.getKey(), "https://github.enterprise-unicorn.com", "54321", "10987654321", "client_1234", "client_so_secret")); } @@ -87,7 +91,8 @@ public class UpdateGithubActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, + s -> s.getDecryptedPrivateKey(encryption), AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption)) .containsOnly(tuple(almSettingDto.getKey(), "https://github.enterprise-unicorn.com", "54321", "10987654321", "client_1234", "client_so_secret")); } @@ -108,7 +113,8 @@ public class UpdateGithubActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, + s -> s.getDecryptedPrivateKey(encryption), AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption)) .containsOnly(tuple("GitHub Server - Infra Team", "https://github.enterprise-unicorn.com", "54321", "10987654321", "client_1234", "client_so_secret")); } @@ -126,8 +132,10 @@ public class UpdateGithubActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, AlmSettingDto::getPrivateKey, AlmSettingDto::getClientId, AlmSettingDto::getClientSecret) - .containsOnly(tuple(almSettingDto.getKey(), "https://github.enterprise-unicorn.com", "54321", almSettingDto.getPrivateKey(), "client_1234", almSettingDto.getClientSecret())); + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getAppId, + s -> s.getDecryptedPrivateKey(encryption), AlmSettingDto::getClientId, s -> s.getDecryptedClientSecret(encryption)) + .containsOnly(tuple(almSettingDto.getKey(), "https://github.enterprise-unicorn.com", "54321", + almSettingDto.getDecryptedPrivateKey(encryption), "client_1234", almSettingDto.getDecryptedClientSecret(encryption))); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGitlabActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGitlabActionTest.java index 132d8d2dde6..073e64f89ac 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGitlabActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/UpdateGitlabActionTest.java @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.alm.setting.AlmSettingDto; @@ -53,7 +54,8 @@ public class UpdateGitlabActionTest { private static String GITLAB_URL = "gitlab.com/api/v4"; - private MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); + private final Encryption encryption = mock(Encryption.class); + private final MultipleAlmFeatureProvider multipleAlmFeatureProvider = mock(MultipleAlmFeatureProvider.class); private WsActionTester ws = new WsActionTester(new UpdateGitlabAction(db.getDbClient(), userSession, new AlmSettingsSupport(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), null), multipleAlmFeatureProvider))); @@ -90,7 +92,7 @@ public class UpdateGitlabActionTest { .setParam("personalAccessToken", "10987654321") .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) .containsOnly(tuple(almSettingDto.getKey(), GITLAB_URL, "10987654321")); } @@ -109,7 +111,7 @@ public class UpdateGitlabActionTest { .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getPersonalAccessToken, AlmSettingDto::getUrl) + .extracting(AlmSettingDto::getKey, s -> s.getDecryptedPersonalAccessToken(encryption), AlmSettingDto::getUrl) .containsOnly(tuple("Gitlab - Infra Team", "0123456789", GITLAB_URL)); } @@ -125,8 +127,8 @@ public class UpdateGitlabActionTest { .setParam("url", GITLAB_URL) .execute(); assertThat(db.getDbClient().almSettingDao().selectAll(db.getSession())) - .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, AlmSettingDto::getPersonalAccessToken) - .containsOnly(tuple(almSettingDto.getKey(), GITLAB_URL, almSettingDto.getPersonalAccessToken())); + .extracting(AlmSettingDto::getKey, AlmSettingDto::getUrl, s -> s.getDecryptedPersonalAccessToken(encryption)) + .containsOnly(tuple(almSettingDto.getKey(), GITLAB_URL, almSettingDto.getDecryptedPersonalAccessToken(encryption))); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/ValidateActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/ValidateActionTest.java index 545922e664b..97da7ad21fb 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/ValidateActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/ValidateActionTest.java @@ -19,11 +19,14 @@ */ package org.sonar.server.almsettings.ws; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.alm.client.azure.AzureDevOpsHttpClient; import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudRestClient; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.config.internal.Settings; import org.sonar.api.resources.ResourceTypes; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; @@ -48,8 +51,11 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class ValidateActionTest { + private static final Encryption encryption = mock(Encryption.class); + private static final Settings settings = mock(Settings.class); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @@ -65,8 +71,13 @@ public class ValidateActionTest { private final BitbucketServerSettingsValidator bitbucketServerSettingsValidator = mock(BitbucketServerSettingsValidator.class); private final BitbucketCloudRestClient bitbucketCloudRestClient = mock(BitbucketCloudRestClient.class); private final WsActionTester ws = new WsActionTester( - new ValidateAction(db.getDbClient(), userSession, almSettingsSupport, azureDevOpsHttpClient, githubGlobalSettingsValidator, gitlabSettingsValidator, - bitbucketServerSettingsValidator, bitbucketCloudRestClient)); + new ValidateAction(db.getDbClient(), settings, userSession, almSettingsSupport, azureDevOpsHttpClient, githubGlobalSettingsValidator, + gitlabSettingsValidator, bitbucketServerSettingsValidator, bitbucketCloudRestClient)); + + @BeforeClass + public static void setUp() { + when(settings.getEncryption()).thenReturn(encryption); + } @Test public void fail_when_key_does_not_match_existing_alm_setting() { @@ -93,6 +104,7 @@ public class ValidateActionTest { @Test public void gitlab_validation_checks() { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertGitlabAlmSetting()); + when(encryption.isEncrypted(any())).thenReturn(false); ws.newRequest() .setParam("key", almSetting.getKey()) @@ -105,6 +117,29 @@ public class ValidateActionTest { public void github_validation_checks() { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertGitHubAlmSetting(settings -> settings.setClientId("clientId") .setClientSecret("clientSecret"))); + when(encryption.isEncrypted(any())).thenReturn(false); + + ws.newRequest() + .setParam("key", almSetting.getKey()) + .execute(); + + ArgumentCaptor almSettingDtoArgumentCaptor = ArgumentCaptor.forClass(AlmSettingDto.class); + verify(githubGlobalSettingsValidator).validate(almSettingDtoArgumentCaptor.capture()); + assertThat(almSettingDtoArgumentCaptor.getAllValues()).hasSize(1); + assertThat(almSettingDtoArgumentCaptor.getValue().getClientId()).isEqualTo(almSetting.getClientId()); + assertThat(almSettingDtoArgumentCaptor.getValue().getDecryptedClientSecret(encryption)).isEqualTo(almSetting.getDecryptedClientSecret(encryption)); + assertThat(almSettingDtoArgumentCaptor.getValue().getAlm()).isEqualTo(almSetting.getAlm()); + assertThat(almSettingDtoArgumentCaptor.getValue().getAppId()).isEqualTo(almSetting.getAppId()); + } + + @Test + public void github_validation_checks_with_encrypted_secret() { + String secret = "encrypted-secret"; + String decryptedSecret = "decrypted-secret"; + AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertGitHubAlmSetting(settings -> settings.setClientId("clientId") + .setClientSecret(secret))); + when(encryption.isEncrypted(secret)).thenReturn(true); + when(encryption.decrypt(secret)).thenReturn(decryptedSecret); ws.newRequest() .setParam("key", almSetting.getKey()) @@ -114,7 +149,7 @@ public class ValidateActionTest { verify(githubGlobalSettingsValidator).validate(almSettingDtoArgumentCaptor.capture()); assertThat(almSettingDtoArgumentCaptor.getAllValues()).hasSize(1); assertThat(almSettingDtoArgumentCaptor.getValue().getClientId()).isEqualTo(almSetting.getClientId()); - assertThat(almSettingDtoArgumentCaptor.getValue().getClientSecret()).isEqualTo(almSetting.getClientSecret()); + assertThat(almSettingDtoArgumentCaptor.getValue().getDecryptedClientSecret(encryption)).isEqualTo(decryptedSecret); assertThat(almSettingDtoArgumentCaptor.getValue().getAlm()).isEqualTo(almSetting.getAlm()); assertThat(almSettingDtoArgumentCaptor.getValue().getAppId()).isEqualTo(almSetting.getAppId()); } @@ -122,6 +157,7 @@ public class ValidateActionTest { @Test public void bitbucketServer_validation_checks() { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertBitbucketAlmSetting()); + when(encryption.isEncrypted(any())).thenReturn(false); ws.newRequest() .setParam("key", almSetting.getKey()) @@ -137,12 +173,27 @@ public class ValidateActionTest { @Test public void azure_devops_validation_checks() { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertAzureAlmSetting()); + when(encryption.isEncrypted(any())).thenReturn(false); ws.newRequest() .setParam("key", almSetting.getKey()) .execute(); - verify(azureDevOpsHttpClient).checkPAT(almSetting.getUrl(), almSetting.getPersonalAccessToken()); + verify(azureDevOpsHttpClient).checkPAT(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption)); + } + + @Test + public void azure_devops_validation_checks_with_encrypted_token() { + AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertAzureAlmSetting()); + String decryptedToken = "decrypted-token"; + when(encryption.isEncrypted(any())).thenReturn(true); + when(encryption.decrypt(any())).thenReturn(decryptedToken); + + ws.newRequest() + .setParam("key", almSetting.getKey()) + .execute(); + + verify(azureDevOpsHttpClient).checkPAT(almSetting.getUrl(), decryptedToken); } @Test @@ -150,7 +201,7 @@ public class ValidateActionTest { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertAzureAlmSetting()); doThrow(IllegalArgumentException.class) - .when(azureDevOpsHttpClient).checkPAT(almSetting.getUrl(), almSetting.getPersonalAccessToken()); + .when(azureDevOpsHttpClient).checkPAT(any(), any()); assertThatThrownBy(() -> ws.newRequest() .setParam("key", almSetting.getKey()) @@ -160,20 +211,36 @@ public class ValidateActionTest { @Test public void bitbucketcloud_validation_checks() { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertBitbucketCloudAlmSetting()); + when(encryption.isEncrypted(any())).thenReturn(false); + + ws.newRequest() + .setParam("key", almSetting.getKey()) + .execute(); + + verify(bitbucketCloudRestClient).validate(almSetting.getClientId(), almSetting.getDecryptedClientSecret(encryption), almSetting.getAppId()); + } + + @Test + public void bitbucketcloud_validation_checks_with_encrypted_secret() { + String decryptedSecret = "decrypted-secret"; + AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertBitbucketCloudAlmSetting()); + when(encryption.isEncrypted(any())).thenReturn(true); + when(encryption.decrypt(any())).thenReturn(decryptedSecret); ws.newRequest() .setParam("key", almSetting.getKey()) .execute(); - verify(bitbucketCloudRestClient).validate(almSetting.getClientId(), almSetting.getClientSecret(), almSetting.getAppId()); + verify(bitbucketCloudRestClient).validate(almSetting.getClientId(), decryptedSecret, almSetting.getAppId()); } @Test public void bitbucketcloud_validation_check_fails() { AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertBitbucketCloudAlmSetting()); + when(encryption.isEncrypted(any())).thenReturn(false); doThrow(IllegalArgumentException.class) - .when(bitbucketCloudRestClient).validate(almSetting.getClientId(), almSetting.getClientSecret(), almSetting.getAppId()); + .when(bitbucketCloudRestClient).validate(any(), any(), any()); TestRequest request = ws.newRequest() .setParam("key", almSetting.getKey());