aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorPawel Kupinski <pawel.kupinski@sonarsource.com>2025-02-20 09:57:54 +0100
committerLukasz Jarocki <lukasz.jarocki@sonarsource.com>2025-02-28 09:57:47 +0100
commit20d7a52648033668ee648b3e7f875e3ea831bde1 (patch)
tree8f7c588fdc4ea69ff0cbdb733223f7f06d584dae /server
parentfa85e9d726a9b42464f3c4f3383b43fc964d9e46 (diff)
downloadsonarqube-20d7a52648033668ee648b3e7f875e3ea831bde1.tar.gz
sonarqube-20d7a52648033668ee648b3e7f875e3ea831bde1.zip
SONAR-24350 Decrypt encrypted properties from SMTP configuration
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/email/EmailSmtpConfiguration.java22
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/email/EmailSmtpConfigurationTest.java82
-rw-r--r--server/sonar-server-common/src/test/resources/org/sonar/encryption/aes_secret_key.txt1
3 files changed, 103 insertions, 2 deletions
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/email/EmailSmtpConfiguration.java b/server/sonar-server-common/src/main/java/org/sonar/server/email/EmailSmtpConfiguration.java
index fdb82e52af1..b69faf6ea80 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/email/EmailSmtpConfiguration.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/email/EmailSmtpConfiguration.java
@@ -20,10 +20,14 @@
package org.sonar.server.email;
import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.config.internal.Encryption;
+import org.sonar.api.config.internal.Settings;
import org.sonar.api.server.ServerSide;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import static org.sonar.api.CoreProperties.ENCRYPTION_SECRET_KEY_PATH;
+
@ServerSide
@ComputeEngineSide
public class EmailSmtpConfiguration {
@@ -62,9 +66,11 @@ public class EmailSmtpConfiguration {
public static final String EMAIL_CONFIG_SMTP_OAUTH_GRANT_DEFAULT = "client_credentials";
private final DbClient dbClient;
+ private final Encryption encryption;
- public EmailSmtpConfiguration(DbClient dbClient) {
+ public EmailSmtpConfiguration(DbClient dbClient, Settings settings) {
this.dbClient = dbClient;
+ this.encryption = new Encryption(settings.getRawString(ENCRYPTION_SECRET_KEY_PATH).orElse(null));
}
public String getSmtpHost() {
@@ -129,8 +135,20 @@ public class EmailSmtpConfiguration {
private String get(String key, String defaultValue) {
try (DbSession dbSession = dbClient.openSession(false)) {
- return dbClient.internalPropertiesDao().selectByKey(dbSession, key).orElse(defaultValue);
+ return dbClient.internalPropertiesDao().selectByKey(dbSession, key)
+ .map(value -> decryptIfNeeded(key, value))
+ .orElse(defaultValue);
}
}
+ private String decryptIfNeeded(String key, String value) {
+ if (!encryption.isEncrypted(value)) {
+ return value;
+ }
+ try {
+ return encryption.decrypt(value);
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to decrypt the property %s. Please check your secret key.".formatted(key), e);
+ }
+ }
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/email/EmailSmtpConfigurationTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/email/EmailSmtpConfigurationTest.java
new file mode 100644
index 00000000000..94a47b844b7
--- /dev/null
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/email/EmailSmtpConfigurationTest.java
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.email;
+
+
+import java.io.File;
+import java.util.Optional;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.sonar.api.config.internal.Encryption;
+import org.sonar.api.config.internal.Settings;
+import org.sonar.db.DbClient;
+import org.sonar.db.property.InternalPropertiesDao;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.CoreProperties.ENCRYPTION_SECRET_KEY_PATH;
+import static org.sonar.server.email.EmailSmtpConfiguration.EMAIL_CONFIG_FROM;
+import static org.sonar.server.email.EmailSmtpConfiguration.EMAIL_CONFIG_SMTP_PASSWORD;
+
+class EmailSmtpConfigurationTest {
+
+ DbClient dbClientMock = mock(DbClient.class);
+ InternalPropertiesDao internalPropertiesDaoMock = mock(InternalPropertiesDao.class);
+ Settings settings = mock(Settings.class);
+ EmailSmtpConfiguration smtpConfiguration;
+
+ @BeforeEach
+ void beforeEach() {
+ when(dbClientMock.internalPropertiesDao()).thenReturn(internalPropertiesDaoMock);
+ when(settings.getRawString(ENCRYPTION_SECRET_KEY_PATH)).thenReturn(Optional.of(pathToSecretKey()));
+ smtpConfiguration = new EmailSmtpConfiguration(dbClientMock, settings);
+ }
+
+ @Test
+ void getValue_whenNoEncryption_shouldReturnOriginalValue() {
+ when(internalPropertiesDaoMock.selectByKey(any(), eq(EMAIL_CONFIG_FROM))).thenReturn(Optional.of("email-from-value"));
+ var value = smtpConfiguration.getFrom();
+
+ assertThat(value).isEqualTo("email-from-value");
+ }
+
+ @Test
+ void getValue_whenStoredInEncryptedFormat_shouldReturnDecryptedValue() {
+ var encryptedValue = new Encryption(pathToSecretKey()).encrypt("password123");
+
+ when(internalPropertiesDaoMock.selectByKey(any(), eq(EMAIL_CONFIG_SMTP_PASSWORD))).thenReturn(Optional.of(encryptedValue));
+ var value = smtpConfiguration.getSmtpPassword();
+
+ assertThat(encryptedValue).startsWith("{aes-gcm}");
+ assertThat(value).isEqualTo("password123");
+ }
+
+ String pathToSecretKey() {
+ try {
+ var resource = getClass().getResource("/org/sonar/encryption/aes_secret_key.txt");
+ return new File(resource.toURI()).getCanonicalPath();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/server/sonar-server-common/src/test/resources/org/sonar/encryption/aes_secret_key.txt b/server/sonar-server-common/src/test/resources/org/sonar/encryption/aes_secret_key.txt
new file mode 100644
index 00000000000..65b98c522da
--- /dev/null
+++ b/server/sonar-server-common/src/test/resources/org/sonar/encryption/aes_secret_key.txt
@@ -0,0 +1 @@
+0PZz+G+f8mjr3sPn4+AhHg== \ No newline at end of file