mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-06 09:35:20 +00:00
Replace ptree with JSON on serialization code (#4128)
This commit is contained in:
parent
99c8debe4f
commit
1bbdff8c7a
@ -13,8 +13,7 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/core/json.h>
|
||||
#include <osquery/flags.h>
|
||||
#include <osquery/registry.h>
|
||||
|
||||
@ -63,15 +62,15 @@ class EnrollPlugin : public Plugin {
|
||||
virtual std::string enroll() = 0;
|
||||
|
||||
/**
|
||||
* @brief Populate a property tree with host details.
|
||||
* @brief Populate a JSON object with host details.
|
||||
*
|
||||
* This will use kEnrollHostDetails to select from each table and
|
||||
* construct a property tree from the results of the first row of each.
|
||||
* The input property tree will have a key set for each table.
|
||||
* construct a JSON object from the results of the first row of each.
|
||||
* The input JSON object will have a key set for each table.
|
||||
*
|
||||
* @param host_details An output property tree containing each table.
|
||||
* @param host_details An output JSON object containing each table.
|
||||
*/
|
||||
void genHostDetails(boost::property_tree::ptree& host_details);
|
||||
void genHostDetails(JSON& host_details);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,6 @@
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/database.h>
|
||||
#include <osquery/distributed.h>
|
||||
@ -85,20 +84,22 @@ void updateCarveValue(const std::string& guid,
|
||||
return;
|
||||
}
|
||||
|
||||
pt::ptree tree;
|
||||
try {
|
||||
std::stringstream ss(carve);
|
||||
pt::read_json(ss, tree);
|
||||
} catch (const pt::ptree_error& e) {
|
||||
VLOG(1) << "Failed to parse carve entries: " << e.what();
|
||||
JSON tree;
|
||||
s = tree.fromString(carve);
|
||||
if (!s.ok()) {
|
||||
VLOG(1) << "Failed to parse carve entries: " << s.what();
|
||||
return;
|
||||
}
|
||||
|
||||
tree.put(key, value);
|
||||
tree.add(key, value);
|
||||
|
||||
std::ostringstream os;
|
||||
pt::write_json(os, tree, false);
|
||||
s = setDatabaseValue(kCarveDbDomain, kCarverDBPrefix + guid, os.str());
|
||||
std::string out;
|
||||
s = tree.toString(out);
|
||||
if (!s.ok()) {
|
||||
VLOG(1) << "Failed to serialize carve entries: " << s.what();
|
||||
}
|
||||
|
||||
s = setDatabaseValue(kCarveDbDomain, kCarverDBPrefix + guid, out);
|
||||
if (!s.ok()) {
|
||||
VLOG(1) << "Failed to update status of carve in database " << guid;
|
||||
}
|
||||
@ -237,7 +238,7 @@ Status Carver::carve(const boost::filesystem::path& path) {
|
||||
};
|
||||
|
||||
Status Carver::postCarve(const boost::filesystem::path& path) {
|
||||
auto startRequest = Request<TLSTransport, JSONSerializer>(startUri_);
|
||||
Request<TLSTransport, JSONSerializer> startRequest(startUri_);
|
||||
startRequest.setOption("hostname", FLAGS_tls_hostname);
|
||||
|
||||
// Perform the start request to get the session id
|
||||
@ -245,14 +246,14 @@ Status Carver::postCarve(const boost::filesystem::path& path) {
|
||||
auto blkCount =
|
||||
static_cast<size_t>(ceil(static_cast<double>(pFile.size()) /
|
||||
static_cast<double>(FLAGS_carver_block_size)));
|
||||
pt::ptree startParams;
|
||||
JSON startParams;
|
||||
|
||||
startParams.put<size_t>("block_count", blkCount);
|
||||
startParams.put<size_t>("block_size", FLAGS_carver_block_size);
|
||||
startParams.put<size_t>("carve_size", pFile.size());
|
||||
startParams.put<std::string>("carve_id", carveGuid_);
|
||||
startParams.put<std::string>("request_id", requestId_);
|
||||
startParams.put<std::string>("node_key", getNodeKey("tls"));
|
||||
startParams.add("block_count", blkCount);
|
||||
startParams.add("block_size", size_t(FLAGS_carver_block_size));
|
||||
startParams.add("carve_size", pFile.size());
|
||||
startParams.add("carve_id", carveGuid_);
|
||||
startParams.add("request_id", requestId_);
|
||||
startParams.add("node_key", getNodeKey("tls"));
|
||||
|
||||
auto status = startRequest.call(startParams);
|
||||
if (!status.ok()) {
|
||||
@ -260,18 +261,26 @@ Status Carver::postCarve(const boost::filesystem::path& path) {
|
||||
}
|
||||
|
||||
// The call succeeded, store the session id for future posts
|
||||
boost::property_tree::ptree startRecv;
|
||||
JSON startRecv;
|
||||
status = startRequest.getResponse(startRecv);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
auto session_id = startRecv.get("session_id", "");
|
||||
if (session_id.empty()) {
|
||||
auto it = startRecv.doc().FindMember("session_id");
|
||||
if (it == startRecv.doc().MemberEnd()) {
|
||||
return Status(1, "No session_id received from remote endpoint");
|
||||
}
|
||||
if (!it->value.IsString()) {
|
||||
return Status(1, "Invalid session_id received from remote endpoint");
|
||||
}
|
||||
|
||||
auto contRequest = Request<TLSTransport, JSONSerializer>(contUri_);
|
||||
std::string session_id = it->value.GetString();
|
||||
if (session_id.empty()) {
|
||||
return Status(1, "Empty session_id received from remote endpoint");
|
||||
}
|
||||
|
||||
Request<TLSTransport, JSONSerializer> contRequest(contUri_);
|
||||
contRequest.setOption("hostname", FLAGS_tls_hostname);
|
||||
for (size_t i = 0; i < blkCount; i++) {
|
||||
std::vector<char> block(FLAGS_carver_block_size, 0);
|
||||
@ -282,12 +291,11 @@ Status Carver::postCarve(const boost::filesystem::path& path) {
|
||||
block.resize(r);
|
||||
}
|
||||
|
||||
pt::ptree params;
|
||||
params.put<size_t>("block_id", i);
|
||||
params.put<std::string>("session_id", session_id);
|
||||
params.put<std::string>("request_id", requestId_);
|
||||
params.put<std::string>(
|
||||
"data", base64Encode(std::string(block.begin(), block.end())));
|
||||
JSON params;
|
||||
params.add("block_id", i);
|
||||
params.add("session_id", session_id);
|
||||
params.add("request_id", requestId_);
|
||||
params.add("data", base64Encode(std::string(block.begin(), block.end())));
|
||||
|
||||
// TODO: Error sending files.
|
||||
status = contRequest.call(params);
|
||||
@ -303,24 +311,30 @@ Status Carver::postCarve(const boost::filesystem::path& path) {
|
||||
};
|
||||
|
||||
Status carvePaths(const std::set<std::string>& paths) {
|
||||
Status s;
|
||||
auto guid = generateNewUUID();
|
||||
|
||||
pt::ptree tree;
|
||||
tree.put("carve_guid", guid);
|
||||
tree.put("time", getUnixTime());
|
||||
tree.put("status", "STARTING");
|
||||
tree.put("sha256", "");
|
||||
tree.put("size", -1);
|
||||
JSON tree;
|
||||
tree.add("carve_guid", guid);
|
||||
tree.add("time", getUnixTime());
|
||||
tree.add("status", "STARTING");
|
||||
tree.add("sha256", "");
|
||||
tree.add("size", -1);
|
||||
|
||||
if (paths.size() > 1) {
|
||||
tree.put("path", boost::algorithm::join(paths, ","));
|
||||
tree.add("path", boost::algorithm::join(paths, ","));
|
||||
} else {
|
||||
tree.put("path", *(paths.begin()));
|
||||
tree.add("path", *(paths.begin()));
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
pt::write_json(os, tree, false);
|
||||
auto s = setDatabaseValue(kCarveDbDomain, kCarverDBPrefix + guid, os.str());
|
||||
std::string out;
|
||||
s = tree.toString(out);
|
||||
if (!s.ok()) {
|
||||
VLOG(1) << "Failed to serialize carve paths: " << s.what();
|
||||
return s;
|
||||
}
|
||||
|
||||
s = setDatabaseValue(kCarveDbDomain, kCarverDBPrefix + guid, out);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
} else {
|
||||
|
@ -87,7 +87,7 @@ TEST_F(TLSConfigTests, test_retrieve_config) {
|
||||
Config c;
|
||||
c.load();
|
||||
|
||||
EXPECT_EQ("d9b4a05d914c81a1ed4ce129928e2d9a0309c753",
|
||||
EXPECT_EQ("6f1980704cb3fd0c902a8a1107f65c59016c5dd2",
|
||||
c.getHash("tls_plugin"));
|
||||
|
||||
// Configure the plugin to use the node API.
|
||||
@ -141,14 +141,14 @@ TEST_F(TLSConfigTests, test_setup) {
|
||||
ASSERT_TRUE(status.ok());
|
||||
|
||||
// Verify that the setup call resulted in no remote requests.
|
||||
pt::ptree response_tree;
|
||||
JSON response_tree;
|
||||
std::string test_read_uri =
|
||||
"https://" + Flag::getValue("tls_hostname") + "/test_read_requests";
|
||||
|
||||
auto request = Request<TLSTransport, JSONSerializer>(test_read_uri);
|
||||
Request<TLSTransport, JSONSerializer> request(test_read_uri);
|
||||
request.setOption("hostname", Flag::getValue("tls_hostname"));
|
||||
|
||||
status = request.call(pt::ptree());
|
||||
status = request.call(JSON());
|
||||
ASSERT_TRUE(status.ok());
|
||||
|
||||
status = request.getResponse(response_tree);
|
||||
@ -156,7 +156,7 @@ TEST_F(TLSConfigTests, test_setup) {
|
||||
|
||||
// TLSConfigPlugin should *not* have sent an enroll or any other TLS request
|
||||
// It should have used the cached-key
|
||||
EXPECT_EQ(response_tree.size(), 0UL);
|
||||
EXPECT_EQ(response_tree.doc().Size(), 0UL);
|
||||
|
||||
status = getDatabaseValue(kPersistentSettings, "nodeKey", db_value);
|
||||
ASSERT_TRUE(status.ok());
|
||||
@ -177,17 +177,23 @@ TEST_F(TLSConfigTests, test_setup) {
|
||||
EXPECT_STRNE(db_value.c_str(), "CachedKey");
|
||||
|
||||
// Make sure TLSConfigPlugin called enroll
|
||||
status = request.call(pt::ptree());
|
||||
status = request.call(JSON());
|
||||
ASSERT_TRUE(status.ok());
|
||||
|
||||
status = request.getResponse(response_tree);
|
||||
ASSERT_TRUE(status.ok());
|
||||
|
||||
// There should only be one command that should have been posted - an enroll
|
||||
EXPECT_EQ(response_tree.size(), 1UL);
|
||||
EXPECT_EQ(response_tree.doc().Size(), 1UL);
|
||||
|
||||
auto const& obj = response_tree.doc()[0];
|
||||
ASSERT_TRUE(obj.IsObject());
|
||||
|
||||
ASSERT_TRUE(obj.HasMember("command"));
|
||||
ASSERT_TRUE(obj["command"].IsString());
|
||||
|
||||
// Verify that it is indeed Enroll
|
||||
db_value = response_tree.get<std::string>(".command");
|
||||
db_value = obj["command"].GetString();
|
||||
EXPECT_STREQ(db_value.c_str(), "enroll");
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,6 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/config.h>
|
||||
#include <osquery/dispatcher.h>
|
||||
#include <osquery/enroll.h>
|
||||
@ -66,10 +64,10 @@ Status TLSConfigPlugin::setUp() {
|
||||
|
||||
Status TLSConfigPlugin::genConfig(std::map<std::string, std::string>& config) {
|
||||
std::string json;
|
||||
pt::ptree params;
|
||||
JSON params;
|
||||
if (FLAGS_tls_node_api) {
|
||||
// The TLS node API morphs some verbs and variables.
|
||||
params.put("_get", true);
|
||||
params.add("_get", true);
|
||||
}
|
||||
|
||||
auto s = TLSRequestHelper::go<JSONSerializer>(
|
||||
@ -77,17 +75,19 @@ Status TLSConfigPlugin::genConfig(std::map<std::string, std::string>& config) {
|
||||
if (s.ok()) {
|
||||
if (FLAGS_tls_node_api) {
|
||||
// The node API embeds configuration data (JSON escaped).
|
||||
pt::ptree tree;
|
||||
try {
|
||||
std::stringstream input;
|
||||
input << json;
|
||||
pt::read_json(input, tree);
|
||||
} catch (const pt::json_parser::json_parser_error& /* e */) {
|
||||
|
||||
JSON tree;
|
||||
Status parse_status = tree.fromString(json);
|
||||
if (!parse_status.ok()) {
|
||||
VLOG(1) << "Could not parse JSON from TLS node API";
|
||||
}
|
||||
|
||||
// Re-encode the config key into JSON.
|
||||
config["tls_plugin"] = unescapeUnicode(tree.get("config", ""));
|
||||
auto it = tree.doc().FindMember("config");
|
||||
config["tls_plugin"] =
|
||||
unescapeUnicode(it != tree.doc().MemberEnd() && it->value.IsString()
|
||||
? it->value.GetString()
|
||||
: "");
|
||||
} else {
|
||||
config["tls_plugin"] = json;
|
||||
}
|
||||
|
@ -95,11 +95,11 @@ void JSON::pushCopy(const std::string& value, rj::Value& arr) {
|
||||
arr.PushBack(sc.Move(), doc_.GetAllocator());
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, rj::Value& value) {
|
||||
void JSON::add(const std::string& key, const rj::Value& value) {
|
||||
add(key, value, doc());
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, rj::Value& value, rj::Value& obj) {
|
||||
void JSON::add(const std::string& key, const rj::Value& value, rj::Value& obj) {
|
||||
assert(obj.IsObject());
|
||||
auto itr = obj.FindMember(key);
|
||||
if (itr != obj.MemberEnd()) {
|
||||
@ -149,6 +149,31 @@ void JSON::addRef(const std::string& key, const std::string& value) {
|
||||
addRef(key, value, doc());
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, const std::string& value) {
|
||||
addCopy(key, value);
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key,
|
||||
const std::string& value,
|
||||
rj::Value& obj) {
|
||||
addCopy(key, value, obj);
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, const char* value, rj::Value& obj) {
|
||||
assert(obj.IsObject());
|
||||
auto itr = obj.FindMember(key);
|
||||
if (itr != obj.MemberEnd()) {
|
||||
obj.RemoveMember(itr);
|
||||
}
|
||||
|
||||
obj.AddMember(rj::Value(rj::StringRef(key), doc_.GetAllocator()).Move(),
|
||||
rj::Value(value, strlen(value)).Move(),
|
||||
doc_.GetAllocator());
|
||||
}
|
||||
void JSON::add(const std::string& key, const char* value) {
|
||||
add(key, value, doc());
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, size_t value, rj::Value& obj) {
|
||||
assert(obj.IsObject());
|
||||
auto itr = obj.FindMember(key);
|
||||
@ -181,6 +206,22 @@ void JSON::add(const std::string& key, int value) {
|
||||
add(key, value, doc());
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, bool value, rj::Value& obj) {
|
||||
assert(obj.IsObject());
|
||||
auto itr = obj.FindMember(key);
|
||||
if (itr != obj.MemberEnd()) {
|
||||
obj.RemoveMember(itr);
|
||||
}
|
||||
|
||||
obj.AddMember(rj::Value(rj::StringRef(key), doc_.GetAllocator()).Move(),
|
||||
rj::Value(value).Move(),
|
||||
doc_.GetAllocator());
|
||||
}
|
||||
|
||||
void JSON::add(const std::string& key, bool value) {
|
||||
add(key, value, doc());
|
||||
}
|
||||
|
||||
Status JSON::toString(std::string& str) const {
|
||||
rj::StringBuffer sb;
|
||||
rj::Writer<rj::StringBuffer> writer(sb);
|
||||
@ -218,7 +259,7 @@ void JSON::mergeArray(rj::Value& target_arr, rj::Value& source_arr) {
|
||||
}
|
||||
}
|
||||
|
||||
JSON JSON::newFromValue(const rapidjson::Value& value) {
|
||||
JSON JSON::newFromValue(const rj::Value& value) {
|
||||
assert(value.IsObject() || value.IsArray());
|
||||
|
||||
JSON doc;
|
||||
@ -231,6 +272,10 @@ void JSON::copyFrom(const rapidjson::Value& value, rj::Value& target) {
|
||||
target.CopyFrom(value, doc().GetAllocator());
|
||||
}
|
||||
|
||||
void JSON::copyFrom(const rj::Value& value) {
|
||||
copyFrom(value, doc());
|
||||
}
|
||||
|
||||
rj::Document& JSON::doc() {
|
||||
return doc_;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <osquery/core.h>
|
||||
// Make sure system is included to work around the GetObject problem on Windows
|
||||
#include <osquery/system.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(push, 3)
|
||||
@ -92,7 +94,8 @@ class JSON : private only_movable {
|
||||
/**
|
||||
* @brief Add a string value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to an input document.
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void addCopy(const std::string& key,
|
||||
@ -102,7 +105,8 @@ class JSON : private only_movable {
|
||||
/**
|
||||
* @brief Add a string value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to the JSON document.
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The document must be an object type.
|
||||
*/
|
||||
void addCopy(const std::string& key, const std::string& value);
|
||||
@ -112,7 +116,8 @@ class JSON : private only_movable {
|
||||
*
|
||||
* The string value must live longer than the document's use.
|
||||
*
|
||||
* This will add the key and value to an input document.
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void addRef(const std::string& key,
|
||||
@ -124,15 +129,59 @@ class JSON : private only_movable {
|
||||
*
|
||||
* The string value must live longer than the document's use.
|
||||
*
|
||||
* This will add the key and value to the JSON document.
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void addRef(const std::string& key, const std::string& value);
|
||||
|
||||
/**
|
||||
* @brief Add a string value to a JSON object by copying the contents.
|
||||
*
|
||||
* This is basically and alias for addCopy()
|
||||
*
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key,
|
||||
const std::string& value,
|
||||
rapidjson::Value& obj);
|
||||
|
||||
/**
|
||||
* @brief Add a string value to a JSON object by copying the contents.
|
||||
*
|
||||
* This is basically and alias for addCopy().
|
||||
*
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, const std::string& value);
|
||||
|
||||
/**
|
||||
* @brief Add a char* value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, const char* value, rapidjson::Value& obj);
|
||||
|
||||
/**
|
||||
* @brief Add a char* value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, const char* value);
|
||||
|
||||
/**
|
||||
* @brief Add a size_t value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to an input document.
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, size_t value, rapidjson::Value& obj);
|
||||
@ -140,7 +189,8 @@ class JSON : private only_movable {
|
||||
/**
|
||||
* @brief Add a size_t value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to the JSON document.
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, size_t value);
|
||||
@ -148,7 +198,8 @@ class JSON : private only_movable {
|
||||
/**
|
||||
* @brief Add an int value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to an input document.
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, int value, rapidjson::Value& obj);
|
||||
@ -156,17 +207,36 @@ class JSON : private only_movable {
|
||||
/**
|
||||
* @brief Add an int value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to the JSON document.
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, int value);
|
||||
|
||||
/**
|
||||
* @brief Add a bool value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to an input document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The input document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, bool value, rapidjson::Value& obj);
|
||||
|
||||
/**
|
||||
* @brief Add a bool value to a JSON object by copying the contents.
|
||||
*
|
||||
* This will add the key and value to the JSON document. If the key exists
|
||||
* the value will be replaced.
|
||||
* The document must be an object type.
|
||||
*/
|
||||
void add(const std::string& key, bool value);
|
||||
|
||||
/// Add a JSON document as a member.
|
||||
void add(const std::string& key, rapidjson::Value& value);
|
||||
void add(const std::string& key, const rapidjson::Value& value);
|
||||
|
||||
/// Add a JSON document as a member of another document.
|
||||
void add(const std::string& key,
|
||||
rapidjson::Value& value,
|
||||
const rapidjson::Value& value,
|
||||
rapidjson::Value& obj);
|
||||
|
||||
/**
|
||||
@ -176,6 +246,13 @@ class JSON : private only_movable {
|
||||
*/
|
||||
void copyFrom(const rapidjson::Value& value, rapidjson::Value& target);
|
||||
|
||||
/**
|
||||
* @brief Copy a JSON object/array into the document.
|
||||
*
|
||||
* The type of the base document may change, be careful.
|
||||
*/
|
||||
void copyFrom(const rapidjson::Value& value);
|
||||
|
||||
/// Convert this document to a JSON string.
|
||||
Status toString(std::string& str) const;
|
||||
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/distributed.h>
|
||||
#include <osquery/enroll.h>
|
||||
#include <osquery/flags.h>
|
||||
@ -70,19 +68,18 @@ Status TLSDistributedPlugin::setUp() {
|
||||
}
|
||||
|
||||
Status TLSDistributedPlugin::getQueries(std::string& json) {
|
||||
pt::ptree params;
|
||||
params.put("_verb", "POST");
|
||||
JSON params;
|
||||
params.add("_verb", "POST");
|
||||
return TLSRequestHelper::go<JSONSerializer>(
|
||||
read_uri_, params, json, FLAGS_distributed_tls_max_attempts);
|
||||
}
|
||||
|
||||
Status TLSDistributedPlugin::writeResults(const std::string& json) {
|
||||
pt::ptree params;
|
||||
try {
|
||||
std::stringstream ss(json);
|
||||
pt::read_json(ss, params);
|
||||
} catch (const pt::ptree_error& e) {
|
||||
return Status(1, "Error parsing JSON: " + std::string(e.what()));
|
||||
JSON params;
|
||||
Status s = params.fromString(json);
|
||||
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// The response is ignored.
|
||||
|
@ -24,11 +24,6 @@
|
||||
#include "osquery/tests/test_additional_util.h"
|
||||
#include "osquery/tests/test_util.h"
|
||||
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
||||
// distributed.cpp for why this is undefed
|
||||
#undef GetObject
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
DECLARE_string(distributed_tls_read_endpoint);
|
||||
|
@ -8,8 +8,6 @@
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/enroll.h>
|
||||
#include <osquery/flags.h>
|
||||
#include <osquery/registry.h>
|
||||
@ -86,41 +84,38 @@ void TLSLoggerPlugin::init(const std::string& name,
|
||||
|
||||
Status TLSLogForwarder::send(std::vector<std::string>& log_data,
|
||||
const std::string& log_type) {
|
||||
pt::ptree params;
|
||||
params.put<std::string>("node_key", getNodeKey("tls"));
|
||||
params.put<std::string>("log_type", log_type);
|
||||
JSON params;
|
||||
params.add("node_key", getNodeKey("tls"));
|
||||
params.add("log_type", log_type);
|
||||
|
||||
{
|
||||
// Read each logged line into JSON and populate a list of lines.
|
||||
// The result list will use the 'data' key.
|
||||
pt::ptree children;
|
||||
iterate(log_data, ([&children](std::string& item) {
|
||||
auto children = params.newArray();
|
||||
iterate(log_data, ([¶ms, &children](std::string& item) {
|
||||
// Enforce a max log line size for TLS logging.
|
||||
if (item.size() > FLAGS_logger_tls_max) {
|
||||
LOG(WARNING) << "Line exceeds TLS logger max: " << item.size();
|
||||
return;
|
||||
}
|
||||
|
||||
pt::ptree child;
|
||||
try {
|
||||
std::stringstream input;
|
||||
input << item;
|
||||
std::string().swap(item);
|
||||
pt::read_json(input, child);
|
||||
} catch (const pt::json_parser::json_parser_error& /* e */) {
|
||||
JSON child;
|
||||
Status s = child.fromString(item);
|
||||
if (!s.ok()) {
|
||||
// The log line entered was not valid JSON, skip it.
|
||||
return;
|
||||
}
|
||||
children.push_back(std::make_pair("", std::move(child)));
|
||||
std::string().swap(item);
|
||||
params.push(child.doc(), children.doc());
|
||||
}));
|
||||
params.add_child("data", std::move(children));
|
||||
params.add("data", children.doc());
|
||||
}
|
||||
|
||||
// The response body is ignored (status is set appropriately by
|
||||
// TLSRequestHelper::go())
|
||||
std::string response;
|
||||
if (FLAGS_logger_tls_compress) {
|
||||
params.put("_compress", true);
|
||||
params.add("_compress", true);
|
||||
}
|
||||
return TLSRequestHelper::go<JSONSerializer>(uri_, params, response);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/core.h>
|
||||
#include <osquery/database.h>
|
||||
@ -111,16 +110,16 @@ const std::string getEnrollSecret() {
|
||||
return enrollment_secret;
|
||||
}
|
||||
|
||||
void EnrollPlugin::genHostDetails(pt::ptree& host_details) {
|
||||
void EnrollPlugin::genHostDetails(JSON& host_details) {
|
||||
// Select from each table describing host details.
|
||||
for (const auto& table : kEnrollHostDetails) {
|
||||
auto results = SQL::selectAllFrom(table);
|
||||
if (!results.empty()) {
|
||||
pt::ptree details;
|
||||
JSON details;
|
||||
for (const auto& detail : results[0]) {
|
||||
details.put<std::string>(detail.first, detail.second);
|
||||
details.add(detail.first, detail.second);
|
||||
}
|
||||
host_details.put_child(table, details);
|
||||
host_details.add(table, details.doc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/config.h>
|
||||
#include <osquery/database.h>
|
||||
#include <osquery/flags.h>
|
||||
@ -38,7 +36,7 @@ class TLSEnrollTests : public testing::Test {
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
Status testReadRequests(pt::ptree& response_tree);
|
||||
Status testReadRequests(JSON& response_tree);
|
||||
|
||||
private:
|
||||
std::string test_read_uri_;
|
||||
@ -60,10 +58,10 @@ void TLSEnrollTests::TearDown() {
|
||||
TLSServerRunner::stop();
|
||||
}
|
||||
|
||||
Status TLSEnrollTests::testReadRequests(pt::ptree& response_tree) {
|
||||
auto request_ = Request<TLSTransport, JSONSerializer>(test_read_uri_);
|
||||
Status TLSEnrollTests::testReadRequests(JSON& response_tree) {
|
||||
Request<TLSTransport, JSONSerializer> request_(test_read_uri_);
|
||||
request_.setOption("hostname", Flag::getValue("tls_hostname"));
|
||||
auto status = request_.call(pt::ptree());
|
||||
auto status = request_.call(JSON());
|
||||
if (status.ok()) {
|
||||
status = request_.getResponse(response_tree);
|
||||
}
|
||||
@ -73,15 +71,23 @@ Status TLSEnrollTests::testReadRequests(pt::ptree& response_tree) {
|
||||
TEST_F(TLSEnrollTests, test_tls_enroll) {
|
||||
auto node_key = getNodeKey("tls");
|
||||
|
||||
pt::ptree response;
|
||||
JSON response;
|
||||
std::string value;
|
||||
|
||||
auto status = testReadRequests(response);
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ(response.size(), 1U);
|
||||
EXPECT_EQ(response.doc().Size(), 1U);
|
||||
|
||||
auto value = response.get<std::string>(".command");
|
||||
auto const& obj = response.doc()[0];
|
||||
EXPECT_TRUE(obj.IsObject());
|
||||
EXPECT_TRUE(obj.HasMember("command"));
|
||||
EXPECT_TRUE(obj["command"].IsString());
|
||||
value = obj["command"].GetString();
|
||||
EXPECT_EQ(value, "enroll");
|
||||
|
||||
value = response.get<std::string>(".host_identifier");
|
||||
EXPECT_TRUE(obj.HasMember("host_identifier"));
|
||||
EXPECT_TRUE(obj["host_identifier"].IsString());
|
||||
value = obj["host_identifier"].GetString();
|
||||
EXPECT_EQ(value, getHostIdentifier());
|
||||
|
||||
// Check that osquery_info exists in the host_details.
|
||||
@ -90,7 +96,12 @@ TEST_F(TLSEnrollTests, test_tls_enroll) {
|
||||
ASSERT_EQ(osquery_info.size(), 1U);
|
||||
ASSERT_EQ(osquery_info[0].count("uuid"), 1U);
|
||||
|
||||
value = response.get<std::string>(".host_details.osquery_info.uuid");
|
||||
EXPECT_TRUE(obj.HasMember("host_details"));
|
||||
EXPECT_TRUE(obj["host_details"].HasMember("osquery_info"));
|
||||
EXPECT_TRUE(obj["host_details"]["osquery_info"].HasMember("uuid"));
|
||||
|
||||
EXPECT_TRUE(obj["host_details"]["osquery_info"]["uuid"].IsString());
|
||||
value = obj["host_details"]["osquery_info"]["uuid"].GetString();
|
||||
EXPECT_EQ(osquery_info[0]["uuid"], value);
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,6 @@
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/enroll.h>
|
||||
#include <osquery/flags.h>
|
||||
#include <osquery/logger.h>
|
||||
@ -23,8 +21,6 @@
|
||||
|
||||
#include "osquery/remote/enroll/plugins/tls_enroll.h"
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace osquery {
|
||||
|
||||
DECLARE_string(enroll_secret_path);
|
||||
@ -78,18 +74,19 @@ std::string TLSEnrollPlugin::enroll() {
|
||||
Status TLSEnrollPlugin::requestKey(const std::string& uri,
|
||||
std::string& node_key) {
|
||||
// Read the optional enrollment secret data (sent with an enrollment request).
|
||||
pt::ptree params;
|
||||
params.put<std::string>(FLAGS_tls_enroll_override, getEnrollSecret());
|
||||
params.put<std::string>("host_identifier", getHostIdentifier());
|
||||
params.put<std::string>("platform_type",
|
||||
JSON params;
|
||||
params.add(FLAGS_tls_enroll_override, getEnrollSecret());
|
||||
params.add("host_identifier", getHostIdentifier());
|
||||
params.add(
|
||||
"platform_type",
|
||||
boost::lexical_cast<std::string>(static_cast<uint64_t>(kPlatformType)));
|
||||
|
||||
// Select from each table describing host details.
|
||||
pt::ptree host_details;
|
||||
JSON host_details;
|
||||
genHostDetails(host_details);
|
||||
params.put_child("host_details", host_details);
|
||||
params.add("host_details", host_details.doc());
|
||||
|
||||
auto request = Request<TLSTransport, JSONSerializer>(uri);
|
||||
Request<TLSTransport, JSONSerializer> request(uri);
|
||||
request.setOption("hostname", FLAGS_tls_hostname);
|
||||
auto status = request.call(params);
|
||||
if (!status.ok()) {
|
||||
@ -97,17 +94,20 @@ Status TLSEnrollPlugin::requestKey(const std::string& uri,
|
||||
}
|
||||
|
||||
// The call succeeded, store the node secret key (the enrollment response).
|
||||
boost::property_tree::ptree recv;
|
||||
JSON recv;
|
||||
status = request.getResponse(recv);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Support multiple response keys as a node key (identifier).
|
||||
if (recv.count("node_key") > 0) {
|
||||
node_key = recv.get("node_key", "");
|
||||
} else if (recv.count("id") > 0) {
|
||||
node_key = recv.get("id", "");
|
||||
auto it = recv.doc().FindMember("node_key");
|
||||
if (it == recv.doc().MemberEnd()) {
|
||||
it = recv.doc().FindMember("id");
|
||||
}
|
||||
|
||||
if (it != recv.doc().MemberEnd()) {
|
||||
node_key = it->value.IsString() ? it->value.GetString() : "";
|
||||
}
|
||||
|
||||
if (node_key.empty()) {
|
||||
|
@ -14,8 +14,6 @@
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/status.h>
|
||||
|
||||
@ -94,13 +92,13 @@ class Transport {
|
||||
*
|
||||
* @return The parameters
|
||||
*/
|
||||
const boost::property_tree::ptree& getResponseParams() const {
|
||||
const JSON& getResponseParams() const {
|
||||
return response_params_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setOption(const std::string& name, const T& value) {
|
||||
options_.put(name, value);
|
||||
options_.add(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,10 +117,10 @@ class Transport {
|
||||
Status response_status_;
|
||||
|
||||
/// storage for response parameters
|
||||
boost::property_tree::ptree response_params_;
|
||||
JSON response_params_;
|
||||
|
||||
/// options from request call (use defined by specific transport)
|
||||
boost::property_tree::ptree options_;
|
||||
JSON options_;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -147,24 +145,22 @@ class Serializer {
|
||||
virtual std::string getContentType() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Serialize a property tree into a string
|
||||
* @brief Serialize a JSON object into a string
|
||||
*
|
||||
* @param params A property tree of parameters
|
||||
* @param serialized the output serialized params
|
||||
* @param params a JSON object to be serialized
|
||||
* @param serialized the output serialized string
|
||||
* @return success or failure of the operation
|
||||
*/
|
||||
virtual Status serialize(const boost::property_tree::ptree& params,
|
||||
std::string& serialized) = 0;
|
||||
virtual Status serialize(const JSON& json, std::string& serialized) = 0;
|
||||
|
||||
/**
|
||||
* @brief Deserialize a property tree into a property tree
|
||||
* @brief Deserialize a JSON string into a JSON object
|
||||
*
|
||||
* @param params A string of serialized parameters
|
||||
* @param serialized the output deserialized parameters
|
||||
* @param params a string of JSON
|
||||
* @param serialized the deserialized JSON object
|
||||
* @return success or failure of the operation
|
||||
*/
|
||||
virtual Status deserialize(const std::string& serialized,
|
||||
boost::property_tree::ptree& params) = 0;
|
||||
virtual Status deserialize(const std::string& serialized, JSON& params) = 0;
|
||||
|
||||
/**
|
||||
* @brief Virtual destructor
|
||||
@ -222,33 +218,39 @@ class Request {
|
||||
/**
|
||||
* @brief Send a simple request to the destination with parameters
|
||||
*
|
||||
* @param params A property tree representing the parameters
|
||||
* @param params a JSON object representing the parameters
|
||||
*
|
||||
* @return success or failure of the operation
|
||||
*/
|
||||
Status call(const boost::property_tree::ptree& params) {
|
||||
Status call(const JSON& params) {
|
||||
std::string serialized;
|
||||
auto s = serializer_->serialize(params, serialized);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
return transport_->sendRequest(serialized, options_.get("compress", false));
|
||||
bool compress = false;
|
||||
auto it = options_.doc().FindMember("compress");
|
||||
if (it != options_.doc().MemberEnd() && it->value.IsBool()) {
|
||||
compress = it->value.GetBool();
|
||||
}
|
||||
|
||||
return transport_->sendRequest(serialized, compress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the request response
|
||||
*
|
||||
* @return A pair of a Status and a property tree of response params
|
||||
* @return A pair of a Status and a JSON object of response params
|
||||
*/
|
||||
Status getResponse(boost::property_tree::ptree& params) {
|
||||
params = transport_->getResponseParams();
|
||||
Status getResponse(JSON& params) {
|
||||
params.copyFrom(transport_->getResponseParams().doc());
|
||||
return transport_->getResponseStatus();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setOption(const std::string& name, const T& value) {
|
||||
options_.put(name, value);
|
||||
options_.add(name, value);
|
||||
transport_->setOption(name, value);
|
||||
}
|
||||
|
||||
@ -263,7 +265,7 @@ class Request {
|
||||
std::shared_ptr<TTransport> transport_{nullptr};
|
||||
|
||||
/// options from request call (duplicated in transport)
|
||||
boost::property_tree::ptree options_;
|
||||
JSON options_;
|
||||
|
||||
private:
|
||||
FRIEND_TEST(TLSTransportsTests, test_call);
|
||||
|
@ -11,38 +11,21 @@
|
||||
#include "osquery/core/json.h"
|
||||
#include "osquery/remote/serializers/json.h"
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace osquery {
|
||||
|
||||
Status JSONSerializer::serialize(const pt::ptree& params,
|
||||
std::string& serialized) {
|
||||
std::ostringstream output;
|
||||
try {
|
||||
pt::write_json(output, params, false);
|
||||
} catch (const pt::json_parser::json_parser_error& e) {
|
||||
return Status(1, std::string("JSON serialize error: ") + e.what());
|
||||
}
|
||||
serialized = output.str();
|
||||
return Status(0, "OK");
|
||||
Status JSONSerializer::serialize(const JSON& json, std::string& serialized) {
|
||||
return json.toString(serialized);
|
||||
}
|
||||
|
||||
Status JSONSerializer::deserialize(const std::string& serialized,
|
||||
pt::ptree& params) {
|
||||
Status JSONSerializer::deserialize(const std::string& serialized, JSON& json) {
|
||||
if (serialized.empty()) {
|
||||
// Prevent errors from being thrown when a TLS endpoint accepts the JSON
|
||||
// payload, but doesn't respond with anything. This has been seen in the
|
||||
// wild, for example with Sumo Logic.
|
||||
params = pt::ptree();
|
||||
json = JSON();
|
||||
return Status(0, "OK");
|
||||
}
|
||||
try {
|
||||
std::stringstream input;
|
||||
input << serialized;
|
||||
pt::read_json(input, params);
|
||||
} catch (const pt::json_parser::json_parser_error& e) {
|
||||
return Status(1, std::string("JSON deserialize error: ") + e.what());
|
||||
}
|
||||
return Status(0, "OK");
|
||||
|
||||
return json.fromString(serialized);
|
||||
}
|
||||
}
|
||||
|
@ -20,34 +20,17 @@ namespace osquery {
|
||||
class JSONSerializer : public Serializer {
|
||||
public:
|
||||
/**
|
||||
* @brief Serialize a property tree into a string
|
||||
*
|
||||
* @param params A property tree of parameters
|
||||
*
|
||||
* @param serialized The string to populate the final serialized params into
|
||||
*
|
||||
* @return An instance of osquery::Status indicating the success or failure
|
||||
* of the operation
|
||||
* @brief See Serializer::serialize
|
||||
*/
|
||||
Status serialize(const boost::property_tree::ptree& params,
|
||||
std::string& serialized);
|
||||
Status serialize(const JSON& json, std::string& serialized);
|
||||
|
||||
/**
|
||||
* @brief Deerialize a property tree into a property tree
|
||||
*
|
||||
* @param params A string of serialized parameters
|
||||
*
|
||||
* @param serialized The property tree to populate the final serialized
|
||||
* params into
|
||||
*
|
||||
* @return An instance of osquery::Status indicating the success or failure
|
||||
* of the operation
|
||||
* @brief See Serializer::desiralize
|
||||
*/
|
||||
Status deserialize(const std::string& serialized,
|
||||
boost::property_tree::ptree& params);
|
||||
Status deserialize(const std::string& serialized, JSON& json);
|
||||
|
||||
/**
|
||||
* @brief Returns the HTTP content type, for HTTP/TLS transport
|
||||
* @brief See Serializer::getContentType
|
||||
*
|
||||
* @return The content type
|
||||
*/
|
||||
|
@ -18,25 +18,25 @@ class JSONSerializersTests : public testing::Test {};
|
||||
|
||||
TEST_F(JSONSerializersTests, test_serialize) {
|
||||
auto json = JSONSerializer();
|
||||
boost::property_tree::ptree params;
|
||||
params.put<std::string>("foo", "bar");
|
||||
JSON params;
|
||||
params.add("foo", "bar");
|
||||
|
||||
std::string serialized;
|
||||
auto s = json.serialize(params, serialized);
|
||||
EXPECT_TRUE(s.ok());
|
||||
EXPECT_EQ(serialized, "{\"foo\":\"bar\"}\n");
|
||||
EXPECT_EQ(serialized, "{\"foo\":\"bar\"}");
|
||||
}
|
||||
|
||||
TEST_F(JSONSerializersTests, test_deserialize) {
|
||||
auto json = JSONSerializer();
|
||||
boost::property_tree::ptree params;
|
||||
std::string serialized = "{\"foo\":\"bar\"}\n";
|
||||
JSON params;
|
||||
std::string serialized = "{\"foo\":\"bar\"}";
|
||||
auto s = json.deserialize(serialized, params);
|
||||
|
||||
boost::property_tree::ptree expected;
|
||||
expected.put<std::string>("foo", "bar");
|
||||
JSON expected;
|
||||
expected.add("foo", "bar");
|
||||
|
||||
EXPECT_TRUE(s.ok());
|
||||
EXPECT_EQ(params, expected);
|
||||
EXPECT_EQ(params.doc(), expected.doc());
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class MockTransport : public Transport {
|
||||
}
|
||||
|
||||
Status sendRequest(const std::string& params, bool compress) override {
|
||||
response_params_.put<std::string>("foo", "baz");
|
||||
response_params_.add("foo", "baz");
|
||||
response_status_ = Status(0, "OK");
|
||||
return response_status_;
|
||||
}
|
||||
@ -42,13 +42,11 @@ class MockSerializer : public Serializer {
|
||||
return "mock";
|
||||
}
|
||||
|
||||
Status serialize(const boost::property_tree::ptree& params,
|
||||
std::string& serialized) {
|
||||
Status serialize(const JSON& params, std::string& serialized) {
|
||||
return Status(0, "OK");
|
||||
}
|
||||
|
||||
Status deserialize(const std::string& serialized,
|
||||
boost::property_tree::ptree& params) {
|
||||
Status deserialize(const std::string& serialized, JSON& params) {
|
||||
return Status(0, "OK");
|
||||
}
|
||||
};
|
||||
@ -75,31 +73,31 @@ TEST_F(RequestsTests, test_url) {
|
||||
}
|
||||
|
||||
TEST_F(RequestsTests, test_call) {
|
||||
auto req = Request<MockTransport, MockSerializer>("foobar");
|
||||
Request<MockTransport, MockSerializer> req("foobar");
|
||||
auto s1 = req.call();
|
||||
EXPECT_TRUE(s1.ok());
|
||||
|
||||
boost::property_tree::ptree params;
|
||||
JSON params;
|
||||
auto s2 = req.getResponse(params);
|
||||
EXPECT_TRUE(s2.ok());
|
||||
boost::property_tree::ptree empty_ptree;
|
||||
EXPECT_EQ(params, empty_ptree);
|
||||
JSON empty;
|
||||
EXPECT_EQ(params.doc(), empty.doc());
|
||||
}
|
||||
|
||||
TEST_F(RequestsTests, test_call_with_params) {
|
||||
auto req = Request<MockTransport, MockSerializer>("foobar");
|
||||
boost::property_tree::ptree params;
|
||||
params.put<std::string>("foo", "bar");
|
||||
Request<MockTransport, MockSerializer> req("foobar");
|
||||
JSON params;
|
||||
params.add("foo", "bar");
|
||||
auto s1 = req.call(params);
|
||||
EXPECT_TRUE(s1.ok());
|
||||
|
||||
boost::property_tree::ptree recv;
|
||||
JSON recv;
|
||||
auto s2 = req.getResponse(recv);
|
||||
EXPECT_TRUE(s2.ok());
|
||||
|
||||
boost::property_tree::ptree expected;
|
||||
expected.put<std::string>("foo", "baz");
|
||||
EXPECT_EQ(recv, expected);
|
||||
JSON expected;
|
||||
expected.add("foo", "baz");
|
||||
EXPECT_EQ(recv.doc(), expected.doc());
|
||||
}
|
||||
|
||||
class CopyTransport : public Transport {
|
||||
@ -122,20 +120,22 @@ class CopySerializer : public Serializer {
|
||||
return "copy";
|
||||
}
|
||||
|
||||
Status serialize(const boost::property_tree::ptree& params,
|
||||
std::string& serialized) {
|
||||
serialized = params.get("copy", "");
|
||||
Status serialize(const JSON& params, std::string& serialized) {
|
||||
auto it = params.doc().FindMember("copy");
|
||||
serialized = (it != params.doc().MemberEnd() && it->value.IsString()
|
||||
? it->value.GetString()
|
||||
: "");
|
||||
|
||||
return Status(0, "OK");
|
||||
}
|
||||
|
||||
Status deserialize(const std::string& serialized,
|
||||
boost::property_tree::ptree& params) {
|
||||
Status deserialize(const std::string& serialized, JSON& params) {
|
||||
return Status(0, "OK");
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RequestsTests, test_compression) {
|
||||
auto req = Request<CopyTransport, CopySerializer>("foobar");
|
||||
Request<CopyTransport, CopySerializer> req("foobar");
|
||||
|
||||
// Ask the request to compress the output from serialization.
|
||||
req.setOption("compress", true);
|
||||
@ -146,8 +146,8 @@ TEST_F(RequestsTests, test_compression) {
|
||||
}
|
||||
|
||||
// Our special 'copy' serializer copies input from the 'copy' key in params.
|
||||
boost::property_tree::ptree params;
|
||||
params.put<std::string>("copy", uncompressed);
|
||||
JSON params;
|
||||
params.add("copy", uncompressed);
|
||||
|
||||
// Similarly, the 'copy' transport copies the request params into the
|
||||
// response status.
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include "osquery/tests/test_additional_util.h"
|
||||
#include "osquery/tests/test_util.h"
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace osquery {
|
||||
|
||||
DECLARE_string(tls_server_certs);
|
||||
@ -81,14 +79,14 @@ TEST_F(TLSTransportsTests, test_call) {
|
||||
|
||||
// Create a request using a TLSTransport and JSONSerializer.
|
||||
auto url = "https://localhost:" + port_;
|
||||
auto r = Request<TLSTransport, JSONSerializer>(url, t);
|
||||
Request<TLSTransport, JSONSerializer> r(url, t);
|
||||
|
||||
// Use the 'call' method on the request without any input parameters.
|
||||
// This will use a GET for the URI given in the Request constructor.
|
||||
Status status;
|
||||
ASSERT_NO_THROW(status = r.call());
|
||||
if (verify(status)) {
|
||||
pt::ptree recv;
|
||||
JSON recv;
|
||||
status = r.getResponse(recv);
|
||||
EXPECT_TRUE(status.ok());
|
||||
}
|
||||
@ -100,28 +98,28 @@ TEST_F(TLSTransportsTests, test_call_with_params) {
|
||||
t->disableVerifyPeer();
|
||||
|
||||
auto url = "https://localhost:" + port_;
|
||||
auto r = Request<TLSTransport, JSONSerializer>(url, t);
|
||||
Request<TLSTransport, JSONSerializer> r(url, t);
|
||||
|
||||
// This time we'll construct a request parameter.
|
||||
pt::ptree params;
|
||||
params.put<std::string>("foo", "bar");
|
||||
JSON params;
|
||||
params.add("foo", "bar");
|
||||
|
||||
// The call with a set of a params will push this "JSONSerializer"-serialized
|
||||
// data into the body of the request and issue a POST to the URI.
|
||||
Status status;
|
||||
ASSERT_NO_THROW(status = r.call(params));
|
||||
if (verify(status)) {
|
||||
pt::ptree recv;
|
||||
JSON recv;
|
||||
status = r.getResponse(recv);
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ(params, recv);
|
||||
EXPECT_EQ(params.doc(), recv.doc());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TLSTransportsTests, test_call_verify_peer) {
|
||||
// Create a default request without a transport that accepts invalid peers.
|
||||
auto url = "https://localhost:" + port_;
|
||||
auto r = Request<TLSTransport, JSONSerializer>(url);
|
||||
Request<TLSTransport, JSONSerializer> r(url);
|
||||
|
||||
// The status/call will fail TLS negotiation because our client is trying
|
||||
// to verify the fake server, CA, commonName.
|
||||
@ -146,10 +144,10 @@ TEST_F(TLSTransportsTests, test_call_server_cert_pinning) {
|
||||
t->setPeerCertificate(kTestDataPath + "test_server_ca.pem");
|
||||
|
||||
auto url = "https://localhost:" + port_;
|
||||
auto r = Request<TLSTransport, JSONSerializer>(url, t);
|
||||
Request<TLSTransport, JSONSerializer> r1(url, t);
|
||||
|
||||
Status status;
|
||||
ASSERT_NO_THROW(status = r.call());
|
||||
ASSERT_NO_THROW(status = r1.call());
|
||||
if (verify(status)) {
|
||||
EXPECT_TRUE(status.ok());
|
||||
}
|
||||
@ -157,9 +155,9 @@ TEST_F(TLSTransportsTests, test_call_server_cert_pinning) {
|
||||
// Now try with a path that is not a filename.
|
||||
t = std::make_shared<TLSTransport>();
|
||||
t->setPeerCertificate(kTestDataPath);
|
||||
r = Request<TLSTransport, JSONSerializer>(url, t);
|
||||
Request<TLSTransport, JSONSerializer> r2(url, t);
|
||||
|
||||
ASSERT_NO_THROW(status = r.call());
|
||||
ASSERT_NO_THROW(status = r2.call());
|
||||
if (verify(status)) {
|
||||
EXPECT_FALSE(status.ok());
|
||||
}
|
||||
@ -172,7 +170,7 @@ TEST_F(TLSTransportsTests, test_call_client_auth) {
|
||||
kTestDataPath + "test_client.key");
|
||||
|
||||
auto url = "https://localhost:" + port_;
|
||||
auto r = Request<TLSTransport, JSONSerializer>(url, t);
|
||||
Request<TLSTransport, JSONSerializer> r(url, t);
|
||||
|
||||
Status status;
|
||||
ASSERT_NO_THROW(status = r.call());
|
||||
|
@ -149,8 +149,9 @@ http::Client::Options TLSTransport::getOptions() {
|
||||
|
||||
// 'Optionally', though all TLS plugins should set a hostname, supply an SNI
|
||||
// hostname. This will reveal the requested domain.
|
||||
if (options_.count("hostname")) {
|
||||
options.openssl_sni_hostname(options_.get<std::string>("hostname"));
|
||||
auto it = options_.doc().FindMember("hostname");
|
||||
if (it != options_.doc().MemberEnd() && it->value.IsString()) {
|
||||
options.openssl_sni_hostname(it->value.GetString());
|
||||
}
|
||||
|
||||
return options;
|
||||
@ -230,10 +231,12 @@ Status TLSTransport::sendRequest(const std::string& params, bool compress) {
|
||||
}
|
||||
|
||||
// Allow request calls to override the default HTTP POST verb.
|
||||
HTTPVerb verb = HTTP_POST;
|
||||
if (options_.count("_verb") > 0) {
|
||||
verb = (HTTPVerb)options_.get<int>("_verb", HTTP_POST);
|
||||
}
|
||||
HTTPVerb verb;
|
||||
auto it = options_.doc().FindMember("_verb");
|
||||
|
||||
verb = (HTTPVerb)(it != options_.doc().MemberEnd() && it->value.IsInt()
|
||||
? it->value.GetInt()
|
||||
: HTTP_POST);
|
||||
|
||||
VLOG(1) << "TLS/HTTPS " << ((verb == HTTP_POST) ? "POST" : "PUT")
|
||||
<< " request to URI: " << destination_;
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <osquery/enroll.h>
|
||||
#include <osquery/flags.h>
|
||||
#include <osquery/system.h>
|
||||
|
||||
#include "osquery/remote/requests.h"
|
||||
#include "osquery/remote/transports/tls.h"
|
||||
@ -32,7 +33,7 @@ DECLARE_bool(disable_reenrollment);
|
||||
* There are many static functions in this class that have very similar
|
||||
* behavior, which allow them to be used in many context. Some methods accept
|
||||
* parameters, some don't require them. Some have built-in retry logic, some
|
||||
* don't. Some return results in a ptree, some return results in JSON, etc.
|
||||
* don't.
|
||||
*/
|
||||
class TLSRequestHelper : private boost::noncopyable {
|
||||
public:
|
||||
@ -66,17 +67,18 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
* @brief Send a TLS request
|
||||
*
|
||||
* @param uri is the URI to send the request to
|
||||
* @param params is a ptree of the params to send to the server. This isn't
|
||||
* const because it will be modified to include node_key.
|
||||
* @param output is the ptree which will be populated with the deserialized
|
||||
* @param params is a JSON object containing the params to send to the server.
|
||||
* This isn't const because it will be modified to include node_key.
|
||||
* @param output is the JSON which will be populated with the deserialized
|
||||
* results
|
||||
*
|
||||
* @return a Status object indicating the success or failure of the operation
|
||||
*/
|
||||
template <class TSerializer>
|
||||
static Status go(const std::string& uri,
|
||||
boost::property_tree::ptree& params,
|
||||
boost::property_tree::ptree& output) {
|
||||
static Status go(const std::string& uri, JSON& params, JSON& output) {
|
||||
auto& params_doc = params.doc();
|
||||
auto& output_doc = output.doc();
|
||||
|
||||
auto node_key = getNodeKey("tls");
|
||||
|
||||
// If using a GET request, append the node_key to the URI variables.
|
||||
@ -84,42 +86,47 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
if (FLAGS_tls_node_api) {
|
||||
uri_suffix = "&node_key=" + node_key;
|
||||
} else {
|
||||
params.put<std::string>("node_key", node_key);
|
||||
params.add("node_key", node_key);
|
||||
}
|
||||
|
||||
// Again check for GET to call with/without parameters.
|
||||
auto request = Request<TLSTransport, TSerializer>(uri + uri_suffix);
|
||||
Request<TLSTransport, TSerializer> request(uri + uri_suffix);
|
||||
request.setOption("hostname", FLAGS_tls_hostname);
|
||||
|
||||
bool compress = false;
|
||||
if (params.count("_compress")) {
|
||||
auto it = params_doc.FindMember("_compress");
|
||||
if (it != params_doc.MemberEnd()) {
|
||||
compress = true;
|
||||
request.setOption("compress", true);
|
||||
params.erase("_compress");
|
||||
request.setOption("compress", compress);
|
||||
params_doc.RemoveMember("_compress");
|
||||
}
|
||||
|
||||
// The caller-supplied parameters may force a POST request.
|
||||
bool force_post = false;
|
||||
if (params.count("_verb")) {
|
||||
force_post = (params.get<std::string>("_verb") == "POST");
|
||||
params.erase("_verb");
|
||||
it = params_doc.FindMember("_verb");
|
||||
if (it != params_doc.MemberEnd()) {
|
||||
assert(it->value.IsString());
|
||||
|
||||
force_post = std::string(it->value.GetString()) == "POST";
|
||||
params_doc.RemoveMember("_verb");
|
||||
}
|
||||
|
||||
bool use_post = true;
|
||||
if (params.count("_get")) {
|
||||
it = params_doc.FindMember("_get");
|
||||
if (it != params_doc.MemberEnd()) {
|
||||
use_post = false;
|
||||
params.erase("_get");
|
||||
params_doc.RemoveMember("_get");
|
||||
}
|
||||
bool should_post = (use_post || force_post);
|
||||
auto status = (should_post) ? request.call(params) : request.call();
|
||||
|
||||
// Restore caller-supplied parameters.
|
||||
if (force_post) {
|
||||
params.put("_verb", "POST");
|
||||
params.add("_verb", "POST");
|
||||
}
|
||||
|
||||
if (compress) {
|
||||
params.put("_compress", true);
|
||||
params.add("_compress", true);
|
||||
}
|
||||
|
||||
if (!status.ok()) {
|
||||
@ -133,23 +140,36 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
}
|
||||
|
||||
// Receive config or key rejection
|
||||
if (output.count("node_invalid") > 0) {
|
||||
auto invalid = output.get("node_invalid", "");
|
||||
if (invalid == "1" || invalid == "true" || invalid == "True") {
|
||||
it = output_doc.FindMember("node_invalid");
|
||||
if (it != output_doc.MemberEnd()) {
|
||||
assert(it->value.IsBool());
|
||||
|
||||
if (it->value.GetBool()) {
|
||||
if (!FLAGS_disable_reenrollment) {
|
||||
clearNodeKey();
|
||||
}
|
||||
|
||||
std::string message = "Request failed: Invalid node key";
|
||||
if (output.count("error") > 0) {
|
||||
message += ": " + output.get("error", "<unknown>");
|
||||
|
||||
it = output_doc.FindMember("error");
|
||||
if (it != output_doc.MemberEnd()) {
|
||||
message +=
|
||||
": " + std::string(it->value.IsString() ? it->value.GetString()
|
||||
: "<unknown>");
|
||||
}
|
||||
|
||||
return Status(1, message);
|
||||
}
|
||||
}
|
||||
|
||||
if (output.count("error") > 0) {
|
||||
return Status(1, "Request failed: " + output.get("error", "<unknown>"));
|
||||
it = output_doc.FindMember("error");
|
||||
if (it != output_doc.MemberEnd()) {
|
||||
std::string message =
|
||||
"Request failed: " + std::string(it->value.IsString()
|
||||
? it->value.GetString()
|
||||
: "<unknown>");
|
||||
|
||||
return Status(1, message);
|
||||
}
|
||||
|
||||
return Status(0, "OK");
|
||||
@ -159,15 +179,14 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
* @brief Send a TLS request
|
||||
*
|
||||
* @param uri is the URI to send the request to
|
||||
* @param output is a ptree of the output from the server
|
||||
* @param output is a JSON object containing the output from the server
|
||||
*
|
||||
* @return a Status object indicating the success or failure of the operation
|
||||
*/
|
||||
template <class TSerializer>
|
||||
static Status go(const std::string& uri,
|
||||
boost::property_tree::ptree& output) {
|
||||
boost::property_tree::ptree params;
|
||||
params.put("_get", true);
|
||||
static Status go(const std::string& uri, JSON& output) {
|
||||
JSON params;
|
||||
params.add("_get", true);
|
||||
return TLSRequestHelper::go<TSerializer>(uri, params, output);
|
||||
}
|
||||
|
||||
@ -175,18 +194,16 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
* @brief Send a TLS request
|
||||
*
|
||||
* @param uri is the URI to send the request to
|
||||
* @param params is a ptree of the params to send to the server. This isn't
|
||||
* const because it will be modified to include node_key.
|
||||
* @param params is a JSON object containing the params to send to the server.
|
||||
* This isn't const because it will be modified to include node_key.
|
||||
* @param output is the string which will be populated with the deserialized
|
||||
* results
|
||||
*
|
||||
* @return a Status object indicating the success or failure of the operation
|
||||
*/
|
||||
template <class TSerializer>
|
||||
static Status go(const std::string& uri,
|
||||
boost::property_tree::ptree& params,
|
||||
std::string& output) {
|
||||
boost::property_tree::ptree recv;
|
||||
static Status go(const std::string& uri, JSON& params, std::string& output) {
|
||||
JSON recv;
|
||||
auto s = TLSRequestHelper::go<TSerializer>(uri, params, recv);
|
||||
if (s.ok()) {
|
||||
auto serializer = TSerializer();
|
||||
@ -206,8 +223,8 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
*/
|
||||
template <class TSerializer>
|
||||
static Status go(const std::string& uri, std::string& output) {
|
||||
boost::property_tree::ptree params;
|
||||
params.put("_get", true);
|
||||
JSON params;
|
||||
params.add("_get", true);
|
||||
return TLSRequestHelper::go<TSerializer>(uri, params, output);
|
||||
}
|
||||
|
||||
@ -215,8 +232,8 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
* @brief Send a TLS request
|
||||
*
|
||||
* @param uri is the URI to send the request to
|
||||
* @param params is a ptree of the params to send to the server. This isn't
|
||||
* const because it will be modified to include node_key.
|
||||
* @param params is a JSON object containing the params to send to the server.
|
||||
* This isn't const because it will be modified to include node_key.
|
||||
* @param output is the string which will be populated with the deserialized
|
||||
* results
|
||||
* @param attempts is the number of attempts to make if the request fails
|
||||
@ -225,15 +242,18 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
*/
|
||||
template <class TSerializer>
|
||||
static Status go(const std::string& uri,
|
||||
boost::property_tree::ptree& params,
|
||||
JSON& params,
|
||||
std::string& output,
|
||||
const size_t attempts) {
|
||||
Status s;
|
||||
JSON override_params;
|
||||
const auto& params_doc = params.doc();
|
||||
const auto& override_params_doc = override_params.doc();
|
||||
|
||||
boost::property_tree::ptree override_params;
|
||||
for (const auto& param : params) {
|
||||
if (param.first.find('_') == 0) {
|
||||
override_params.put(param.first, param.second.data());
|
||||
for (auto& m : params_doc.GetObject()) {
|
||||
std::string name = m.name.GetString();
|
||||
if (name.find('_') == 0) {
|
||||
override_params.add(name, m.value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,8 +265,8 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
if (i == attempts) {
|
||||
break;
|
||||
}
|
||||
for (const auto& param : override_params) {
|
||||
params.put(param.first, param.second.data());
|
||||
for (auto& m : override_params_doc.GetObject()) {
|
||||
params.add(m.name.GetString(), m.value);
|
||||
}
|
||||
sleepFor(i * i * 1000);
|
||||
}
|
||||
@ -267,8 +287,8 @@ class TLSRequestHelper : private boost::noncopyable {
|
||||
static Status go(const std::string& uri,
|
||||
std::string& output,
|
||||
const size_t attempts) {
|
||||
boost::property_tree::ptree params;
|
||||
params.put("_get", true);
|
||||
JSON params;
|
||||
params.add("_get", true);
|
||||
return TLSRequestHelper::go<TSerializer>(uri, params, output, attempts);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user