]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1721] proper JSON path algorithm redaction
authorAndrei Pavel <andrei@isc.org>
Wed, 21 Apr 2021 21:39:33 +0000 (00:39 +0300)
committerAndrei Pavel <andrei@isc.org>
Fri, 21 May 2021 13:22:00 +0000 (13:22 +0000)
src/bin/agent/ca_cfg_mgr.cc
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
src/bin/netconf/netconf_cfg_mgr.cc
src/lib/process/redact_config.cc
src/lib/process/redact_config.h

index 5e873fd19fa99b7eadc19d82e6f337b7dfaf3e23..854fa233dece4311a89f648d3f7d4152432b01db 100644 (file)
@@ -143,7 +143,7 @@ std::list<std::list<std::string>>
 CtrlAgentCfgMgr::jsonPathsToRedact() const {
     static std::list<std::list<std::string>> const list({
         {"authentication", "clients"},
-        {"hooks-libraries", "parameters"},
+        {"hooks-libraries", "[]", "parameters", "*"},
     });
     return list;
 }
index 462b5958a5119c1ff6068113c4ea01f3032c1562..6c943ead563a6e34764ad0343dcf92a47729cc47 100644 (file)
@@ -4071,10 +4071,10 @@ void Dhcpv4Srv::discardPackets() {
 
 std::list<std::list<std::string>> Dhcpv4Srv::jsonPathsToRedact() const {
     static std::list<std::list<std::string>> const list({
-        {"config-control", "config-databases"},
-        {"hooks-libraries", "parameters"},
+        {"config-control", "config-databases", "[]"},
+        {"hooks-libraries", "[]", "parameters", "*"},
         {"hosts-database"},
-        {"hosts-databases"},
+        {"hosts-databases", "[]"},
         {"lease-database"},
     });
     return list;
index 919a8d4234ae9b67ba1d1d18dcf4340e7db6a5e3..3f017122d81924dabb834d7bc22b10821907acde 100644 (file)
@@ -4340,10 +4340,10 @@ Dhcpv6Srv::checkDynamicSubnetChange(const Pkt6Ptr& question, Pkt6Ptr& answer,
 
 std::list<std::list<std::string>> Dhcpv6Srv::jsonPathsToRedact()  const{
     static std::list<std::list<std::string>> const list({
-        {"config-control", "config-databases"},
-        {"hooks-libraries", "parameters"},
+        {"config-control", "config-databases", "[]"},
+        {"hooks-libraries", "[]", "parameters", "*"},
         {"hosts-database"},
-        {"hosts-databases"},
+        {"hosts-databases", "[]"},
         {"lease-database"},
     });
     return list;
index 2e54b196b2e7c2f31966203214ed4f58e6a36325..3ad6dbbc463ac4e8c24da06aa890191033d736e9 100644 (file)
@@ -167,7 +167,7 @@ NetconfConfig::toElement() const {
 std::list<std::list<std::string>>
 NetconfCfgMgr::jsonPathsToRedact() const {
     static std::list<std::list<std::string>> const list({
-        {"hooks-libraries", "parameters", "*"},
+        {"hooks-libraries", "[]", "parameters", "*"},
     });
     return list;
 }
index 8a8cf53aba7523b592559eff510d80644f81a3e7..16bba0f3ceb80105096080bce5f1c975825b3311 100644 (file)
@@ -8,65 +8,90 @@
 
 #include <process/redact_config.h>
 
+#include <boost/algorithm/string.hpp>
+
+using namespace isc;
 using namespace isc::data;
 using namespace std;
 
-namespace isc {
-namespace process {
+namespace {
 
-ConstElementPtr
-redactConfig(ConstElementPtr const& element,
-             list<string> const& json_path) {
+template <typename ElementPtrType>
+ElementPtrType
+redact(ElementPtrType const& element, list<string> json_path) {
     if (!element) {
-        isc_throw(BadValue, "redactConfig got a null pointer");
+        isc_throw(BadValue, "redact() got a null pointer");
     }
 
+    string const next_key(json_path.empty() ? string() : json_path.front());
     ElementPtr result;
     if (element->getType() == Element::list) {
-        // Redact lists.
-        result = Element::createList();
-        for (ConstElementPtr const& item : element->listValue()) {
-            // add wants an ElementPtr so use a shallow copy.
-            // We could hypothetically filter lists through JSON paths, but we
-            // would have to dig inside the list's children to see if we have a
-            // match. So we always copy because it's faster.
-            result->add(data::copy(redactConfig(item, json_path), 0));
+        // If we are looking for a list...
+        if (next_key == "*" || next_key == "[]") {
+            // But if we are looking specifically for a list...
+            if (next_key == "[]") {
+                // Then advance in the path.
+                json_path.pop_front();
+            }
+            // Then redact all children.
+            result = Element::createList();
+            for (ElementPtr const& child : element->listValue()) {
+                result->add(redact(child, json_path));
+            }
+            return result;
         }
     } else if (element->getType() == Element::map) {
-        // Redact maps.
-        result = Element::createMap();
-        for (auto kv : element->mapValue()) {
-            std::string const& key(kv.first);
-            ConstElementPtr const& value(kv.second);
+        // If we are looking for anything or if we have reached the end of a
+        /// path...
+        if (next_key == "*" || json_path.empty()) {
+            // Then iterate through all the children.
+            result = Element::createMap();
+            for (auto kv : element->mapValue()) {
+                std::string const& key(kv.first);
+                ConstElementPtr const& value(kv.second);
 
-            if ((key == "password") || (key == "secret")) {
-                // Handle passwords.
-                result->set(key, Element::create(string("*****")));
-            } else if (key == "user-context") {
-                // Skip user contexts.
-                result->set(key, value);
-            } else if (json_path.empty()) {
-                // Passwords or secrets expected in this subtree.
-                result->set(key, isc::data::copy(
-                                     redactConfig(value, json_path)));
-            } else if (key == json_path.front()) {
-                // Passwords or secrets expected in this subtree.
-                auto it(json_path.begin());
-                std::advance(it, 1);
-                list<string> new_json_path(it, json_path.end());
-                result->set(key, isc::data::copy(
-                                     redactConfig(value, new_json_path)));
-            } else {
-                // No passwords or secrets expected in this subtree.
-                result->set(key, value);
+                if (boost::algorithm::ends_with(key, "password") ||
+                    boost::algorithm::ends_with(key, "secret")) {
+                    // Sensitive data
+                    result->set(key, Element::create(string("*****")));
+                } else if (key == "user-context") {
+                    // Skip user contexts.
+                    result->set(key, value);
+                } else {
+                    if (json_path.empty()) {
+                        // End of path means no sensitive data expected in this
+                        // subtree, so we stop here.
+                        result->set(key, value);
+                    } else {
+                        // We are looking for anything '*' so redact further.
+                        result->set(key, redact(value, json_path));
+                    }
+                }
+            }
+            return result;
+        } else {
+            ConstElementPtr child(element->get(next_key));
+            if (child) {
+                result = isc::data::copy(element, 1);
+                json_path.pop_front();
+                result->set(next_key, redact(child, json_path));
+                return result;
             }
         }
-    } else {
-        return element;
     }
 
-    return result;
+    return element;
+}
+
+}  // namespace
+
+namespace isc {
+namespace process {
+
+ConstElementPtr
+redactConfig(ConstElementPtr const& element, list<string> const& json_path) {
+    return redact(element, json_path);
 }
 
-} // namespace process
-} // namespace isc
+}  // namespace process
+}  // namespace isc
index 61dae0e07799f336dab1ed134e669f20dfb4fc97..a0d1d0a33e673e9925841d2e462678567d577dbb 100644 (file)
@@ -29,7 +29,7 @@ namespace process {
 /// asterisks so it can be safely logged to an unprivileged place.
 isc::data::ConstElementPtr
 redactConfig(isc::data::ConstElementPtr const& element,
-             std::list<std::string> const& json_path = {});
+             std::list<std::string> const& json_path = {"*"});
 
 } // namespace process
 } // namespace isc