You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ge...@apache.org on 2022/10/11 16:54:49 UTC

[solr-sandbox] branch crossdc-wip updated: Redact properties before string-ifying or logging (#49)

This is an automated email from the ASF dual-hosted git repository.

gerlowskija pushed a commit to branch crossdc-wip
in repository https://gitbox.apache.org/repos/asf/solr-sandbox.git


The following commit(s) were added to refs/heads/crossdc-wip by this push:
     new e246a24  Redact properties before string-ifying or logging (#49)
e246a24 is described below

commit e246a24e968593ff3d0aab746685dfce8c40388c
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Tue Oct 11 12:54:44 2022 -0400

    Redact properties before string-ifying or logging (#49)
    
    Prior to this commit, certain log messages during Producer/Consumer
    startup contained potentially sensitive information, such as SSL
    passwords, etc.
    
    This commit amends the string-ification of KafkaCrossDcConf and other
    Map/Properties types to "redact" properties whose key/name contains a
    block-list of values.  This list currently consists of "password" and
    "credentials": any property name containing these substrings (ignoring
    case) will be redacted before logging.
---
 .../solr/crossdc/common/KafkaCrossDcConf.java      |  8 ++-
 .../common/SensitivePropRedactionUtils.java        | 66 ++++++++++++++++++++++
 .../org/apache/solr/crossdc/consumer/Consumer.java |  4 +-
 3 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/KafkaCrossDcConf.java b/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/KafkaCrossDcConf.java
index 44c4e04..0b45bbb 100644
--- a/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/KafkaCrossDcConf.java
+++ b/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/KafkaCrossDcConf.java
@@ -23,6 +23,9 @@ import org.apache.kafka.common.config.internals.BrokerSecurityConfigs;
 
 import java.util.*;
 
+import static org.apache.solr.crossdc.common.SensitivePropRedactionUtils.propertyRequiresRedaction;
+import static org.apache.solr.crossdc.common.SensitivePropRedactionUtils.redactPropertyIfNecessary;
+
 public class KafkaCrossDcConf extends CrossDcConf {
 
   public static final String DEFAULT_BATCH_SIZE_BYTES = "2097152";
@@ -245,7 +248,9 @@ public class KafkaCrossDcConf extends CrossDcConf {
     StringBuilder sb = new StringBuilder(128);
     for (ConfigProperty configProperty : CONFIG_PROPERTIES) {
       if (properties.get(configProperty.getKey()) != null) {
-        sb.append(configProperty.getKey()).append("=").append(properties.get(configProperty.getKey())).append(",");
+        final String printablePropertyValue = redactPropertyIfNecessary(configProperty.getKey(),
+                String.valueOf(properties.get(configProperty.getKey())));
+        sb.append(configProperty.getKey()).append("=").append(printablePropertyValue).append(",");
       }
     }
     if (sb.length() > 0) {
@@ -254,5 +259,4 @@ public class KafkaCrossDcConf extends CrossDcConf {
 
     return "KafkaCrossDcConf{" + sb + "}";
   }
-
 }
diff --git a/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/SensitivePropRedactionUtils.java b/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/SensitivePropRedactionUtils.java
new file mode 100644
index 0000000..58675a0
--- /dev/null
+++ b/crossdc-commons/src/main/java/org/apache/solr/crossdc/common/SensitivePropRedactionUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.crossdc.common;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Helper functionality related to redacting arbitrary properties which may contain sensitive password information.
+ *
+ * Used primarily as a safeguard before logging out configuration properties.  Redaction logic heavily depends on string
+ * matching against elements of the {@link #PATTERNS_REQUIRING_REDACTION_LOWERCASE} block-list.
+ */
+public class SensitivePropRedactionUtils {
+    private static final String[] PATTERNS_REQUIRING_REDACTION_LOWERCASE = new String[] {"password", "credentials"};
+    private static final String REDACTED_STRING = "<REDACTED>";
+
+    public static boolean propertyRequiresRedaction(String propName) {
+        final String propNameLowercase = propName.toLowerCase(Locale.ROOT);
+        for (String pattern : PATTERNS_REQUIRING_REDACTION_LOWERCASE) {
+            if (propNameLowercase.contains(pattern)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Redacts a property value if necessary, and returns the result.
+     *
+     * Redaction only occurs when the property name matches a pattern on the
+     * {@link #PATTERNS_REQUIRING_REDACTION_LOWERCASE} block-list.
+     *
+     * @param propName the name or key of the property being considered for redaction
+     * @param propValue the value of the property under consideration; returned verbatim if redaction is not necessary.
+     */
+    public static String redactPropertyIfNecessary(String propName, String propValue) {
+        return propertyRequiresRedaction(propName) ? REDACTED_STRING : propValue;
+    }
+
+    public static String flattenAndRedactForLogging(Map<String, Object> properties) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        for (Map.Entry<String, Object> entry : properties.entrySet()) {
+            final Object printablePropValue = redactPropertyIfNecessary(entry.getKey(), String.valueOf(entry.getValue()));
+            sb.append(entry.getKey()).append("=").append(printablePropValue).append(", ");
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+}
diff --git a/crossdc-consumer/src/main/java/org/apache/solr/crossdc/consumer/Consumer.java b/crossdc-consumer/src/main/java/org/apache/solr/crossdc/consumer/Consumer.java
index 7a061f9..08749b0 100644
--- a/crossdc-consumer/src/main/java/org/apache/solr/crossdc/consumer/Consumer.java
+++ b/crossdc-consumer/src/main/java/org/apache/solr/crossdc/consumer/Consumer.java
@@ -21,6 +21,7 @@ import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.crossdc.common.ConfigProperty;
 import org.apache.solr.crossdc.common.CrossDcConf;
 import org.apache.solr.crossdc.common.KafkaCrossDcConf;
+import org.apache.solr.crossdc.common.SensitivePropRedactionUtils;
 import org.apache.solr.crossdc.messageprocessor.SolrMessageProcessor;
 import org.eclipse.jetty.server.Server;
 import org.slf4j.Logger;
@@ -60,7 +61,8 @@ public class Consumer {
             }
         }
 
-        log.info("Consumer startup config properties before adding additional properties from Zookeeper={}", properties);
+        log.info("Consumer startup config properties before adding additional properties from Zookeeper={}",
+                SensitivePropRedactionUtils.flattenAndRedactForLogging(properties));
 
         String zkConnectString = (String) properties.get("zkConnectString");
         if (zkConnectString == null) {