From: Andrei Pavel Date: Wed, 21 Apr 2021 21:39:33 +0000 (+0300) Subject: [#1721] proper JSON path algorithm redaction X-Git-Tag: Kea-1.9.8~23 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=70b36a14f18a3bcb4b96ab19abd03e72a3f6de60;p=thirdparty%2Fkea.git [#1721] proper JSON path algorithm redaction --- diff --git a/src/bin/agent/ca_cfg_mgr.cc b/src/bin/agent/ca_cfg_mgr.cc index 5e873fd19f..854fa233de 100644 --- a/src/bin/agent/ca_cfg_mgr.cc +++ b/src/bin/agent/ca_cfg_mgr.cc @@ -143,7 +143,7 @@ std::list> CtrlAgentCfgMgr::jsonPathsToRedact() const { static std::list> const list({ {"authentication", "clients"}, - {"hooks-libraries", "parameters"}, + {"hooks-libraries", "[]", "parameters", "*"}, }); return list; } diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 462b5958a5..6c943ead56 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -4071,10 +4071,10 @@ void Dhcpv4Srv::discardPackets() { std::list> Dhcpv4Srv::jsonPathsToRedact() const { static std::list> 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; diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 919a8d4234..3f017122d8 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -4340,10 +4340,10 @@ Dhcpv6Srv::checkDynamicSubnetChange(const Pkt6Ptr& question, Pkt6Ptr& answer, std::list> Dhcpv6Srv::jsonPathsToRedact() const{ static std::list> 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; diff --git a/src/bin/netconf/netconf_cfg_mgr.cc b/src/bin/netconf/netconf_cfg_mgr.cc index 2e54b196b2..3ad6dbbc46 100644 --- a/src/bin/netconf/netconf_cfg_mgr.cc +++ b/src/bin/netconf/netconf_cfg_mgr.cc @@ -167,7 +167,7 @@ NetconfConfig::toElement() const { std::list> NetconfCfgMgr::jsonPathsToRedact() const { static std::list> const list({ - {"hooks-libraries", "parameters", "*"}, + {"hooks-libraries", "[]", "parameters", "*"}, }); return list; } diff --git a/src/lib/process/redact_config.cc b/src/lib/process/redact_config.cc index 8a8cf53aba..16bba0f3ce 100644 --- a/src/lib/process/redact_config.cc +++ b/src/lib/process/redact_config.cc @@ -8,65 +8,90 @@ #include +#include + +using namespace isc; using namespace isc::data; using namespace std; -namespace isc { -namespace process { +namespace { -ConstElementPtr -redactConfig(ConstElementPtr const& element, - list const& json_path) { +template +ElementPtrType +redact(ElementPtrType const& element, list 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 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 const& json_path) { + return redact(element, json_path); } -} // namespace process -} // namespace isc +} // namespace process +} // namespace isc diff --git a/src/lib/process/redact_config.h b/src/lib/process/redact_config.h index 61dae0e077..a0d1d0a33e 100644 --- a/src/lib/process/redact_config.h +++ b/src/lib/process/redact_config.h @@ -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 const& json_path = {}); + std::list const& json_path = {"*"}); } // namespace process } // namespace isc