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;
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;
*/
public class BootstrapSettings {
private Map<String, String> properties;
+ private final Encryption encryption;
public BootstrapSettings(BootstrapProperties bootstrapProperties) {
this(bootstrapProperties, null);
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) {
}
properties.putAll(System.getenv());
addProperties(System.getProperties());
+ encryption = new Encryption(properties.get(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
}
private void addProperties(Properties p) {
}
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);
}
}
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");
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
@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;
}
}
import com.google.common.collect.ImmutableMap;
+import javax.annotation.Nullable;
+
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
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);
}
/**
}
public boolean isEncrypted(String value) {
- return value.indexOf('{')==0 && value.indexOf('}') > 1;
+ return value.indexOf('{') == 0 && value.indexOf('}') > 1;
}
public String encrypt(String clearText) {
public Settings(PropertyDefinitions definitions) {
this.properties = Maps.newHashMap();
this.definitions = definitions;
- this.encryption = new Encryption(this);
+ this.encryption = new Encryption(null);
}
/**
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;
@Test
public void generateRandomSecretKey() {
- AesCipher cipher = new AesCipher(new Settings());
+ AesCipher cipher = new AesCipher(null);
String key = cipher.generateRandomSecretKey();
@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");
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=");
@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=");
@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
@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();
@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));
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);
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");
}
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();
@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));
@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"));
}
}
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
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
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
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
@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"});
}
}
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) {