template <typename ElementPtrType>
ElementPtrType
-redact(ElementPtrType const& element, list<string> json_path, string obscure) {
+ redact(ElementPtrType const& element, list<string> json_path,
+ string obscure, unsigned level) {
if (!element) {
isc_throw(BadValue, "redact() got a null pointer");
}
+ if (level == 0) {
+ isc_throw(BadValue, "redact() got too deep recursion");
+ }
string const next_key(json_path.empty() ? string() : json_path.front());
ElementPtr result;
// Then redact all children.
result = Element::createList();
for (ElementPtr const& child : element->listValue()) {
- result->add(redact(child, json_path, obscure));
+ result->add(redact(child, json_path, obscure, level - 1));
}
- return result;
+ return (result);
}
} else if (element->getType() == Element::map) {
// If we are looking for anything or if we have reached the end of a
result->set(key, value);
} else {
// We are looking for anything '*' so redact further.
- result->set(key, redact(value, json_path, obscure));
+ result->set(key, redact(value, json_path, obscure,
+ level - 1));
}
}
}
- return result;
+ 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, obscure));
- return result;
+ result->set(next_key,
+ redact(child, json_path, obscure, level - 1));
+ return (result);
}
}
}
- return element;
+ return (element);
}
} // namespace
ConstElementPtr
redactConfig(ConstElementPtr const& element, list<string> const& json_path,
- string obscure) {
- return redact(element, json_path, obscure);
+ string obscure, unsigned max_nesting_depth) {
+ return (redact(element, json_path, obscure, max_nesting_depth));
}
} // namespace process
/// configuration and smaller subtrees in recursive calls.
/// @param json_path JSON path to redact
/// @param obscure new value of secrets / passwords
+/// @param max_nesting_depth maximum nesting depth
///
/// @return a copy of the config where passwords and secrets were replaced by
/// 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::string obscure = "*****");
+ std::string obscure = "*****",
+ unsigned max_nesting_depth = isc::data::Element::MAX_NESTING_LEVEL);
} // namespace process
} // namespace isc
expected = "{ \"foo\": { \"password\": \"*****\" }, ";
expected += "\"next\": { \"secret\": \"bar\" } }";
EXPECT_EQ(expected, ret->str());
+
+ // Verify that it throws on cycles.
+ ElementPtr cycle = Element::createList();
+ cycle->add(cycle);
+ EXPECT_THROW(redactConfig(cycle), BadValue);
+ cycle = Element::createMap();
+ cycle->set("loop", cycle);
+ EXPECT_THROW(redactConfig(cycle), BadValue);
}
// Test that user context is not touched when configuration is redacted.