]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4061 The property 'sonar.password' is not encryptable
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 26 Jun 2013 14:44:16 +0000 (16:44 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Wed, 26 Jun 2013 14:44:38 +0000 (16:44 +0200)
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java
sonar-plugin-api/src/main/java/org/sonar/api/config/AesCipher.java
sonar-plugin-api/src/main/java/org/sonar/api/config/Encryption.java
sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java
sonar-plugin-api/src/test/java/org/sonar/api/config/AesCipherTest.java
sonar-plugin-api/src/test/java/org/sonar/api/config/EncryptionTest.java
sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java
sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java

index 17a95e7cfc3e5f9b3ad6b456df96c512155e3d03..fc2faf0a3436e8b856ec2f4a219191afba1b07e2 100644 (file)
@@ -50,6 +50,7 @@ public class BatchSettings extends Settings {
   public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions,
       ServerClient client, Configuration deprecatedConfiguration) {
     super(propertyDefinitions);
+    getEncryption().setPathToSecretKey(bootstrapSettings.property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
     this.bootstrapSettings = bootstrapSettings;
     this.client = client;
     this.deprecatedConfiguration = deprecatedConfiguration;
index 588ef9c1cb10a5599b236c2cafd812232f3cb8cb..4e005a82c7d9cd1246c0aea72e939dcb01a1488b 100644 (file)
@@ -21,7 +21,9 @@ package org.sonar.batch.bootstrap;
 
 import com.google.common.collect.Maps;
 import org.codehaus.plexus.util.StringUtils;
+import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.config.Encryption;
 
 import javax.annotation.Nullable;
 
@@ -33,6 +35,7 @@ import java.util.Properties;
  */
 public class BootstrapSettings {
   private Map<String, String> properties;
+  private final Encryption encryption;
 
   public BootstrapSettings(BootstrapProperties bootstrapProperties) {
     this(bootstrapProperties, null);
@@ -40,7 +43,6 @@ public class BootstrapSettings {
 
   public BootstrapSettings(BootstrapProperties bootstrapProperties, @Nullable ProjectReactor projectReactor) {
     properties = Maps.newHashMap();
-
     // order is important -> bottom-up. The last one overrides all the others.
     properties.putAll(bootstrapProperties.properties());
     if (projectReactor != null) {
@@ -48,6 +50,7 @@ public class BootstrapSettings {
     }
     properties.putAll(System.getenv());
     addProperties(System.getProperties());
+    encryption = new Encryption(properties.get(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
   }
 
   private void addProperties(Properties p) {
@@ -63,10 +66,18 @@ public class BootstrapSettings {
   }
 
   public String property(String key) {
-    return properties.get(key);
+    String value = properties.get(key);
+    if (value != null && encryption.isEncrypted(value)) {
+      try {
+        value = encryption.decrypt(value);
+      } catch (Exception e) {
+        throw new IllegalStateException("Fail to decrypt the property " + key + ". Please check your secret key.", e);
+      }
+    }
+    return value;
   }
 
   public String property(String key, String defaultValue) {
-    return StringUtils.defaultString(properties.get(key), defaultValue);
+    return StringUtils.defaultString(property(key), defaultValue);
   }
 }
index 91eb139310090c685795f954b0b4cea5ca700127..bae7e8e69ff472bc01e66007ef882aa585868370 100644 (file)
@@ -44,6 +44,7 @@ public class ModuleSettings extends Settings {
 
   public ModuleSettings(BatchSettings batchSettings, ProjectDefinition project, Configuration deprecatedCommonsConf) {
     super(batchSettings.getDefinitions());
+    getEncryption().setPathToSecretKey(batchSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
     this.dryRun = "true".equals(batchSettings.getString(CoreProperties.DRY_RUN));
 
     LoggerFactory.getLogger(ModuleSettings.class).info("Load module settings");
index 35a36401b386f0acaaa184b64e7391d421d25138..96b12a0000b9bd70ab6a9ef38bf862d28bec2efb 100644 (file)
@@ -45,10 +45,10 @@ final class AesCipher extends Cipher {
 
   private static final String CRYPTO_KEY = "AES";
 
-  private final Settings settings;
+  private String pathToSecretKey;
 
-  AesCipher(Settings settings) {
-    this.settings = settings;
+  AesCipher(@Nullable String pathToSecretKey) {
+    this.pathToSecretKey = pathToSecretKey;
   }
 
   @Override
@@ -121,10 +121,13 @@ final class AesCipher extends Cipher {
 
   @VisibleForTesting
   String getPathToSecretKey() {
-    String path = settings.getClearString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH);
-    if (StringUtils.isBlank(path)) {
-      path = new File(FileUtils.getUserDirectoryPath(), ".sonar/sonar-secret.txt").getPath();
+    if (StringUtils.isBlank(pathToSecretKey)) {
+      pathToSecretKey = new File(FileUtils.getUserDirectoryPath(), ".sonar/sonar-secret.txt").getPath();
     }
-    return path;
+    return pathToSecretKey;
+  }
+
+  public void setPathToSecretKey(String pathToSecretKey) {
+    this.pathToSecretKey = pathToSecretKey;
   }
 }
index 293b6754f5b3bd343f407331d3c78b70296021e2..879e405f6b7860e9fa938f02f08941d1e31c42f4 100644 (file)
@@ -21,6 +21,8 @@ package org.sonar.api.config;
 
 import com.google.common.collect.ImmutableMap;
 
+import javax.annotation.Nullable;
+
 import java.util.Locale;
 import java.util.Map;
 import java.util.regex.Matcher;
@@ -39,12 +41,16 @@ public final class Encryption {
   private final Map<String, Cipher> ciphers;
   private static final Pattern ENCRYPTED_PATTERN = Pattern.compile("\\{(.*?)\\}(.*)");
 
-  Encryption(Settings settings) {
-    aesCipher = new AesCipher(settings);
+  public Encryption(@Nullable String pathToSecretKey) {
+    aesCipher = new AesCipher(pathToSecretKey);
     ciphers = ImmutableMap.of(
         BASE64_ALGORITHM, new Base64Cipher(),
         AES_ALGORITHM, aesCipher
-    );
+        );
+  }
+
+  public void setPathToSecretKey(@Nullable String pathToSecretKey) {
+    aesCipher.setPathToSecretKey(pathToSecretKey);
   }
 
   /**
@@ -55,7 +61,7 @@ public final class Encryption {
   }
 
   public boolean isEncrypted(String value) {
-    return value.indexOf('{')==0 && value.indexOf('}') > 1;
+    return value.indexOf('{') == 0 && value.indexOf('}') > 1;
   }
 
   public String encrypt(String clearText) {
index d23873e8bfccf269cddaaec60f8278896d4712fc..4c427ebe68419d3c642d1295b8ab4dd8f9ea130e 100644 (file)
@@ -61,7 +61,7 @@ public class Settings implements BatchComponent, ServerComponent {
   public Settings(PropertyDefinitions definitions) {
     this.properties = Maps.newHashMap();
     this.definitions = definitions;
-    this.encryption = new Encryption(this);
+    this.encryption = new Encryption(null);
   }
 
   /**
index 43b33074c3420473a0745ff346dc9988deaf5c5b..902e89974438c33a3b322d7fe880493545618500 100644 (file)
@@ -25,9 +25,9 @@ import org.hamcrest.Matchers;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.CoreProperties;
 
 import javax.crypto.BadPaddingException;
+
 import java.io.File;
 import java.net.URL;
 import java.security.InvalidKeyException;
@@ -45,7 +45,7 @@ public class AesCipherTest {
 
   @Test
   public void generateRandomSecretKey() {
-    AesCipher cipher = new AesCipher(new Settings());
+    AesCipher cipher = new AesCipher(null);
 
     String key = cipher.generateRandomSecretKey();
 
@@ -55,9 +55,7 @@ public class AesCipherTest {
 
   @Test
   public void encrypt() throws Exception {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, pathToSecretKey());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(pathToSecretKey());
 
     String encryptedText = cipher.encrypt("this is a secret");
 
@@ -71,18 +69,14 @@ public class AesCipherTest {
     thrown.expectMessage("Invalid AES key");
 
     URL resource = getClass().getResource("/org/sonar/api/config/AesCipherTest/bad_secret_key.txt");
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, new File(resource.toURI()).getCanonicalPath());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(new File(resource.toURI()).getCanonicalPath());
 
     cipher.encrypt("this is a secret");
   }
 
   @Test
   public void decrypt() throws Exception {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, pathToSecretKey());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(pathToSecretKey());
 
     // the following value has been encrypted with the key /org/sonar/api/config/AesCipherTest/aes_secret_key.txt
     String clearText = cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
@@ -93,9 +87,7 @@ public class AesCipherTest {
   @Test
   public void decrypt_bad_key() throws Exception {
     URL resource = getClass().getResource("/org/sonar/api/config/AesCipherTest/bad_secret_key.txt");
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, new File(resource.toURI()).getCanonicalPath());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(new File(resource.toURI()).getCanonicalPath());
 
     try {
       cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
@@ -109,9 +101,7 @@ public class AesCipherTest {
   @Test
   public void decrypt_other_key() throws Exception {
     URL resource = getClass().getResource("/org/sonar/api/config/AesCipherTest/other_secret_key.txt");
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, new File(resource.toURI()).getCanonicalPath());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(new File(resource.toURI()).getCanonicalPath());
 
     try {
       // text encrypted with another key
@@ -125,16 +115,14 @@ public class AesCipherTest {
 
   @Test
   public void encryptThenDecrypt() throws Exception {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, pathToSecretKey());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(pathToSecretKey());
 
     assertThat(cipher.decrypt(cipher.encrypt("foo")), is("foo"));
   }
 
   @Test
   public void testDefaultPathToSecretKey() {
-    AesCipher cipher = new AesCipher(new Settings());
+    AesCipher cipher = new AesCipher(null);
 
     String path = cipher.getPathToSecretKey();
 
@@ -144,7 +132,7 @@ public class AesCipherTest {
 
   @Test
   public void loadSecretKeyFromFile() throws Exception {
-    AesCipher cipher = new AesCipher(new Settings());
+    AesCipher cipher = new AesCipher(null);
     Key secretKey = cipher.loadSecretFileFromFile(pathToSecretKey());
     assertThat(secretKey.getAlgorithm(), is("AES"));
     assertThat(secretKey.getEncoded().length, greaterThan(10));
@@ -154,7 +142,7 @@ public class AesCipherTest {
   public void loadSecretKeyFromFile_trim_content() throws Exception {
     URL resource = getClass().getResource("/org/sonar/api/config/AesCipherTest/non_trimmed_secret_key.txt");
     String path = new File(resource.toURI()).getCanonicalPath();
-    AesCipher cipher = new AesCipher(new Settings());
+    AesCipher cipher = new AesCipher(null);
 
     Key secretKey = cipher.loadSecretFileFromFile(path);
 
@@ -166,7 +154,7 @@ public class AesCipherTest {
   public void loadSecretKeyFromFile_file_does_not_exist() throws Exception {
     thrown.expect(IllegalStateException.class);
 
-    AesCipher cipher = new AesCipher(new Settings());
+    AesCipher cipher = new AesCipher(null);
     cipher.loadSecretFileFromFile("/file/does/not/exist");
   }
 
@@ -174,29 +162,24 @@ public class AesCipherTest {
   public void loadSecretKeyFromFile_no_property() throws Exception {
     thrown.expect(IllegalStateException.class);
 
-    AesCipher cipher = new AesCipher(new Settings());
+    AesCipher cipher = new AesCipher(null);
     cipher.loadSecretFileFromFile(null);
   }
 
   @Test
   public void hasSecretKey() throws Exception {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, pathToSecretKey());
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher(pathToSecretKey());
 
     assertThat(cipher.hasSecretKey(), Matchers.is(true));
   }
 
   @Test
   public void doesNotHaveSecretKey() throws Exception {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCRYPTION_SECRET_KEY_PATH, "/my/twitter/id/is/SimonBrandhof");
-    AesCipher cipher = new AesCipher(settings);
+    AesCipher cipher = new AesCipher("/my/twitter/id/is/SimonBrandhof");
 
     assertThat(cipher.hasSecretKey(), Matchers.is(false));
   }
 
-
   private String pathToSecretKey() throws Exception {
     URL resource = getClass().getResource("/org/sonar/api/config/AesCipherTest/aes_secret_key.txt");
     return new File(resource.toURI()).getCanonicalPath();
index eaf9053c526993ebc619a8e824cc72689b6373e6..37bbf2adee0f641de7261890efe776cd055809ea 100644 (file)
@@ -28,7 +28,7 @@ public class EncryptionTest {
 
   @Test
   public void isEncrypted() {
-    Encryption encryption = new Encryption(new Settings());
+    Encryption encryption = new Encryption(null);
     assertThat(encryption.isEncrypted("{aes}ADASDASAD"), is(true));
     assertThat(encryption.isEncrypted("{b64}ADASDASAD"), is(true));
     assertThat(encryption.isEncrypted("{abc}ADASDASAD"), is(true));
@@ -40,25 +40,25 @@ public class EncryptionTest {
 
   @Test
   public void scramble() {
-    Encryption encryption = new Encryption(new Settings());
+    Encryption encryption = new Encryption(null);
     assertThat(encryption.scramble("foo"), is("{b64}Zm9v"));
   }
 
   @Test
   public void decrypt() {
-    Encryption encryption = new Encryption(new Settings());
+    Encryption encryption = new Encryption(null);
     assertThat(encryption.decrypt("{b64}Zm9v"), is("foo"));
   }
 
   @Test
   public void decrypt_unknown_algorithm() {
-    Encryption encryption = new Encryption(new Settings());
+    Encryption encryption = new Encryption(null);
     assertThat(encryption.decrypt("{xxx}Zm9v"), is("{xxx}Zm9v"));
   }
 
   @Test
   public void decrypt_uncrypted_text() {
-    Encryption encryption = new Encryption(new Settings());
+    Encryption encryption = new Encryption(null);
     assertThat(encryption.decrypt("foo"), is("foo"));
   }
 }
index 228e0ee6e121bc5c5826b641381a234c7d4d0436..ee5bc28bcab4febf766b0be79026477ad500f778 100644 (file)
@@ -211,53 +211,53 @@ public class SettingsTest {
   public void getStringArray() {
     Settings settings = new Settings(definitions);
     String[] array = settings.getStringArray("array");
-    assertThat(array).isEqualTo(new String[]{"one", "two", "three"});
+    assertThat(array).isEqualTo(new String[] {"one", "two", "three"});
   }
 
   @Test
   public void setStringArray() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("multi_values", new String[]{"A", "B"});
+    settings.setProperty("multi_values", new String[] {"A", "B"});
     String[] array = settings.getStringArray("multi_values");
-    assertThat(array).isEqualTo(new String[]{"A", "B"});
+    assertThat(array).isEqualTo(new String[] {"A", "B"});
   }
 
   @Test
   public void setStringArrayTrimValues() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("multi_values", new String[]{" A ", " B "});
+    settings.setProperty("multi_values", new String[] {" A ", " B "});
     String[] array = settings.getStringArray("multi_values");
-    assertThat(array).isEqualTo(new String[]{"A", "B"});
+    assertThat(array).isEqualTo(new String[] {"A", "B"});
   }
 
   @Test
   public void setStringArrayEscapeCommas() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("multi_values", new String[]{"A,B", "C,D"});
+    settings.setProperty("multi_values", new String[] {"A,B", "C,D"});
     String[] array = settings.getStringArray("multi_values");
-    assertThat(array).isEqualTo(new String[]{"A,B", "C,D"});
+    assertThat(array).isEqualTo(new String[] {"A,B", "C,D"});
   }
 
   @Test
   public void setStringArrayWithEmptyValues() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("multi_values", new String[]{"A,B", "", "C,D"});
+    settings.setProperty("multi_values", new String[] {"A,B", "", "C,D"});
     String[] array = settings.getStringArray("multi_values");
-    assertThat(array).isEqualTo(new String[]{"A,B", "", "C,D"});
+    assertThat(array).isEqualTo(new String[] {"A,B", "", "C,D"});
   }
 
   @Test
   public void setStringArrayWithNullValues() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("multi_values", new String[]{"A,B", null, "C,D"});
+    settings.setProperty("multi_values", new String[] {"A,B", null, "C,D"});
     String[] array = settings.getStringArray("multi_values");
-    assertThat(array).isEqualTo(new String[]{"A,B", "", "C,D"});
+    assertThat(array).isEqualTo(new String[] {"A,B", "", "C,D"});
   }
 
   @Test(expected = IllegalStateException.class)
   public void shouldFailToSetArrayValueOnSingleValueProperty() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("array", new String[]{"A", "B", "C"});
+    settings.setProperty("array", new String[] {"A", "B", "C"});
   }
 
   @Test
@@ -272,7 +272,7 @@ public class SettingsTest {
     Settings settings = new Settings();
     settings.setProperty("foo", "  one,  two, three  ");
     String[] array = settings.getStringArray("foo");
-    assertThat(array).isEqualTo(new String[]{"one", "two", "three"});
+    assertThat(array).isEqualTo(new String[] {"one", "two", "three"});
   }
 
   @Test
@@ -280,7 +280,7 @@ public class SettingsTest {
     Settings settings = new Settings();
     settings.setProperty("foo", "  one,  , two");
     String[] array = settings.getStringArray("foo");
-    assertThat(array).isEqualTo(new String[]{"one", "", "two"});
+    assertThat(array).isEqualTo(new String[] {"one", "", "two"});
   }
 
   @Test
@@ -338,34 +338,34 @@ public class SettingsTest {
   public void getStringLines_single_line() {
     Settings settings = new Settings();
     settings.setProperty("foo", "the line");
-    assertThat(settings.getStringLines("foo")).isEqualTo(new String[]{"the line"});
+    assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"the line"});
   }
 
   @Test
   public void getStringLines_linux() {
     Settings settings = new Settings();
     settings.setProperty("foo", "one\ntwo");
-    assertThat(settings.getStringLines("foo")).isEqualTo(new String[]{"one", "two"});
+    assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
 
     settings.setProperty("foo", "one\ntwo\n");
-    assertThat(settings.getStringLines("foo")).isEqualTo(new String[]{"one", "two"});
+    assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
   }
 
   @Test
   public void getStringLines_windows() {
     Settings settings = new Settings();
     settings.setProperty("foo", "one\r\ntwo");
-    assertThat(settings.getStringLines("foo")).isEqualTo(new String[]{"one", "two"});
+    assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
 
     settings.setProperty("foo", "one\r\ntwo\r\n");
-    assertThat(settings.getStringLines("foo")).isEqualTo(new String[]{"one", "two"});
+    assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
   }
 
   @Test
   public void getStringLines_mix() {
     Settings settings = new Settings();
     settings.setProperty("foo", "one\r\ntwo\nthree");
-    assertThat(settings.getStringLines("foo")).isEqualTo(new String[]{"one", "two", "three"});
+    assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two", "three"});
   }
 
   @Test
@@ -419,8 +419,8 @@ public class SettingsTest {
   @Test
   public void should_support_deprecated_props_with_multi_values() {
     Settings settings = new Settings(definitions);
-    settings.setProperty("new_multi_values", new String[]{" A ", " B "});
-    assertThat(settings.getStringArray("new_multi_values")).isEqualTo(new String[]{"A", "B"});
-    assertThat(settings.getStringArray("old_multi_values")).isEqualTo(new String[]{"A", "B"});
+    settings.setProperty("new_multi_values", new String[] {" A ", " B "});
+    assertThat(settings.getStringArray("new_multi_values")).isEqualTo(new String[] {"A", "B"});
+    assertThat(settings.getStringArray("old_multi_values")).isEqualTo(new String[] {"A", "B"});
   }
 }
index a357d077fe86779065ca23eb55deb62780063989..9397fc8305df2bffd3cbac8800187c57f2c97fa0 100644 (file)
@@ -63,7 +63,9 @@ public class ServerSettings extends Settings {
     this.deprecatedConfiguration = deprecatedConfiguration;
     this.deployDir = deployDir;
     this.sonarHome = sonarHome;
-    load(Collections.<String, String>emptyMap());
+    load(Collections.<String, String> emptyMap());
+    // Secret key is loaded from conf/sonar.properties
+    getEncryption().setPathToSecretKey(getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
   }
 
   public ServerSettings activateDatabaseSettings(Map<String, String> databaseProperties) {