]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8153 Do not export sensitive settings in System Info
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Thu, 21 Sep 2017 15:21:08 +0000 (17:21 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 26 Sep 2017 21:49:38 +0000 (23:49 +0200)
server/sonar-main/src/main/java/org/sonar/application/config/ClusterSettings.java
server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
server/sonar-server/src/main/java/org/sonar/server/authentication/JwtSerializer.java
server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java
server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SettingsSectionTest.java

index e3cf57f2526c2e5d5e3915fa8969d680fb8d2598..d0cb1b54ad37a489551b9af68bec77f287f5af82 100644 (file)
@@ -38,6 +38,7 @@ import static java.util.Arrays.stream;
 import static java.util.Collections.singletonList;
 import static java.util.stream.Collectors.joining;
 import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.sonar.process.ProcessProperties.AUTH_JWT_SECRET;
 import static org.sonar.process.ProcessProperties.CLUSTER_ENABLED;
 import static org.sonar.process.ProcessProperties.CLUSTER_HOSTS;
 import static org.sonar.process.ProcessProperties.CLUSTER_NODE_HOST;
@@ -72,7 +73,7 @@ public class ClusterSettings implements Consumer<Props> {
     switch (nodeType) {
       case APPLICATION:
         ensureNotH2(props);
-        requireValue(props, "sonar.auth.jwtBase64Hs256Secret");
+        requireValue(props, AUTH_JWT_SECRET);
         break;
       case SEARCH:
         requireValue(props, SEARCH_HOST);
index 012474d50d72db14cfade333380ea4dcd4b4ca89..a8f2f0b3a94f61bcdef6de0062647dc67a8cfc7d 100644 (file)
@@ -59,6 +59,7 @@ public class ProcessProperties {
   public static final String WEB_JAVA_OPTS = "sonar.web.javaOpts";
   public static final String WEB_JAVA_ADDITIONAL_OPTS = "sonar.web.javaAdditionalOpts";
   public static final String WEB_PORT = "sonar.web.port";
+  public static final String AUTH_JWT_SECRET = "sonar.auth.jwtBase64Hs256Secret";
 
   public static final String CE_JAVA_OPTS = "sonar.ce.javaOpts";
   public static final String CE_JAVA_ADDITIONAL_OPTS = "sonar.ce.javaAdditionalOpts";
index 477f4f59e89e4965afbd9fcc756123be176f6fed..0f3d55b06fc873a11f55b8aa60e789042a3b7263 100644 (file)
@@ -45,6 +45,7 @@ import org.sonar.server.authentication.event.AuthenticationException;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static io.jsonwebtoken.impl.crypto.MacProvider.generateKey;
 import static java.util.Objects.requireNonNull;
+import static org.sonar.process.ProcessProperties.AUTH_JWT_SECRET;
 
 /**
  * This class can be used to encode or decode a JWT token
@@ -52,8 +53,6 @@ import static java.util.Objects.requireNonNull;
 @ServerSide
 public class JwtSerializer implements Startable {
 
-  private static final String SECRET_KEY_PROPERTY = "sonar.auth.jwtBase64Hs256Secret";
-
   private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
 
   private final Configuration config;
@@ -75,7 +74,7 @@ public class JwtSerializer implements Startable {
 
   @Override
   public void start() {
-    Optional<String> encodedKey = config.get(SECRET_KEY_PROPERTY);
+    Optional<String> encodedKey = config.get(AUTH_JWT_SECRET);
     if (encodedKey.isPresent()) {
       this.secretKey = decodeSecretKeyProperty(encodedKey.get());
     } else {
index e6e3a473635c2e3c08d996ed384c52e65a5e521d..961938a46d26d9eaef4164b5465f6a8e59ec5a37 100644 (file)
@@ -30,12 +30,16 @@ import org.sonar.process.systeminfo.SystemInfoSection;
 import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
 
 import static org.apache.commons.lang.StringUtils.abbreviate;
+import static org.apache.commons.lang.StringUtils.containsIgnoreCase;
+import static org.apache.commons.lang.StringUtils.endsWithIgnoreCase;
+import static org.sonar.process.ProcessProperties.AUTH_JWT_SECRET;
 import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
 
 @ServerSide
 public class SettingsSection implements SystemInfoSection, Global {
 
-  static final int MAX_VALUE_LENGTH = 500;
+  private static final int MAX_VALUE_LENGTH = 500;
+  private static final String PASSWORD_VALUE = "xxxxxxxx";
   private final Settings settings;
 
   public SettingsSection(Settings settings) {
@@ -50,11 +54,23 @@ public class SettingsSection implements SystemInfoSection, Global {
     PropertyDefinitions definitions = settings.getDefinitions();
     for (Map.Entry<String, String> prop : settings.getProperties().entrySet()) {
       String key = prop.getKey();
-      PropertyDefinition def = definitions.get(key);
-      if (def == null || def.type() != PropertyType.PASSWORD) {
-        setAttribute(protobuf, key, abbreviate(prop.getValue(), MAX_VALUE_LENGTH));
-      }
+      String value = obfuscateValue(definitions, key, prop.getValue());
+      setAttribute(protobuf, key, value);
     }
     return protobuf.build();
   }
+
+  private static String obfuscateValue(PropertyDefinitions definitions, String key, String value) {
+    PropertyDefinition def = definitions.get(key);
+    if (def != null && def.type() == PropertyType.PASSWORD) {
+      return PASSWORD_VALUE;
+    }
+    if (endsWithIgnoreCase(key, ".secured") ||
+      containsIgnoreCase(key, "password") ||
+      containsIgnoreCase(key, "passcode") ||
+      AUTH_JWT_SECRET.equals(key)) {
+      return PASSWORD_VALUE;
+    }
+    return abbreviate(value, MAX_VALUE_LENGTH);
+  }
 }
index b5f5c14dadc5441ff4ca3d0910a9405f4eedef94..dc6c9c1b16c666a055bae2d14d88017ee4cd9c54 100644 (file)
@@ -56,20 +56,40 @@ public class SettingsSectionTest {
 
     ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
     String value = attribute(protobuf, "foo").getStringValue();
-    assertThat(value).hasSize(SettingsSection.MAX_VALUE_LENGTH).startsWith("abcde");
+    assertThat(value).hasSize(500).startsWith("abcde");
   }
 
   @Test
-  public void exclude_password_properties() {
-    settings.setProperty(PASSWORD_PROPERTY, "abcde");
+  public void value_is_obfuscated_if_key_matches_patterns() {
+    verifyObfuscated(PASSWORD_PROPERTY);
+    verifyObfuscated("foo.password.something");
+    // case insensitive search of "password" term
+    verifyObfuscated("bar.CheckPassword");
+    verifyObfuscated("foo.passcode.something");
+    // case insensitive search of "passcode" term
+    verifyObfuscated("bar.CheckPassCode");
+    verifyObfuscated("foo.something.secured");
+    verifyObfuscated("bar.something.Secured");
+    verifyObfuscated("sonar.auth.jwtBase64Hs256Secret");
 
+    verifyNotObfuscated("securedStuff");
+    verifyNotObfuscated("foo");
+  }
+
+  private void verifyObfuscated(String key) {
+    settings.setProperty(key, "foo");
+    ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+    assertThatAttributeIs(protobuf, key, "xxxxxxxx");
+  }
+
+  private void verifyNotObfuscated(String key) {
+    settings.setProperty(key, "foo");
     ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
-    assertThat(attribute(protobuf, PASSWORD_PROPERTY)).isNull();
+    assertThatAttributeIs(protobuf, key, "foo");
   }
 
   @Test
   public void test_monitor_name() {
     assertThat(underTest.toProtobuf().getName()).isEqualTo("Settings");
-
   }
 }