Skip to content

Commit 5a6eed4

Browse files
BenHuddlestondaverigby
authored andcommitted
MB-30041: Migrate audit and event descriptor to nlohmann::json
Migrate the auditd eventdescriptor file to nlohmann::json and make the necessary changes to audit parsing to do so. Change-Id: I5847553adfd24abddbe65d0562fb2c2127bd059a Reviewed-on: http://review.couchbase.org/99887 Reviewed-by: Dave Rigby <[email protected]> Tested-by: Build Bot <[email protected]>
1 parent 851d6b1 commit 5a6eed4

File tree

8 files changed

+187
-270
lines changed

8 files changed

+187
-270
lines changed

auditd/src/audit.cc

Lines changed: 53 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222
#include "event.h"
2323
#include "eventdescriptor.h"
2424

25-
#include <cJSON.h>
2625
#include <logger/logger.h>
2726
#include <memcached/isotime.h>
2827
#include <memcached/server_cookie_iface.h>
2928
#include <nlohmann/json.hpp>
3029
#include <platform/dirutils.h>
30+
#include <utilities/json_utilities.h>
3131
#include <utilities/logtags.h>
32+
3233
#include <algorithm>
3334
#include <chrono>
3435
#include <cstring>
@@ -113,88 +114,66 @@ void AuditImpl::create_audit_event(uint32_t event_id, nlohmann::json& payload) {
113114
"Audit::create_audit_event: Invalid event identifier specified");
114115
}
115116

116-
bool AuditImpl::add_event_descriptor(cJSON* event_ptr) {
117-
if (event_ptr == nullptr) {
118-
LOG_WARNING(
119-
"Audit::add_event_descriptor: No JSON data "
120-
"provided");
121-
return false;
122-
}
123-
117+
bool AuditImpl::add_event_descriptor(const nlohmann::json& json) {
124118
try {
125-
auto entry = std::make_unique<EventDescriptor>(event_ptr);
119+
auto entry = std::make_unique<EventDescriptor>(json);
126120
events.insert(std::pair<uint32_t, std::unique_ptr<EventDescriptor>>(
127121
entry->getId(), std::move(entry)));
128122
return true;
129123
} catch (const std::bad_alloc&) {
130124
LOG_WARNING(
131125
"Audit::add_event_descriptor: Failed to allocate "
132126
"memory");
133-
} catch (const std::logic_error& le) {
134-
LOG_WARNING(R"(Audit::add_event_descriptor: JSON key "{}" error)",
135-
le.what());
127+
} catch (const nlohmann::json::exception& e) {
128+
LOG_WARNING(
129+
"Audit::add_event_descriptor: JSON parsing exception {}"
130+
" for event {}",
131+
cb::UserDataView(e.what()),
132+
cb::UserDataView(json.dump()));
133+
} catch (const std::invalid_argument& e) {
134+
LOG_WARNING(
135+
"Audit::add_event_descriptor: parsing exception {}"
136+
" for event {}",
137+
cb::UserDataView(e.what()),
138+
cb::UserDataView(json.dump()));
136139
}
137140

138141
return false;
139142
}
140143

141-
bool AuditImpl::process_module_data_structures(cJSON* module) {
142-
if (module == NULL) {
143-
LOG_WARNING(
144-
"Audit::process_module_data_structures: No JSON data provided "
145-
"for module");
146-
return false;
147-
}
148-
while (module != NULL) {
149-
cJSON *mod_ptr = module->child;
150-
if (mod_ptr == NULL) {
151-
LOG_WARNING(
152-
"Audit::process_module_data_structures: No JSON data "
153-
"provided for child node");
144+
bool AuditImpl::process_module_data_structures(const nlohmann::json& json) {
145+
for (const auto& event : json) {
146+
if (!add_event_descriptor(event)) {
154147
return false;
155148
}
156-
while (mod_ptr != NULL) {
157-
cJSON *event_ptr;
158-
switch (mod_ptr->type) {
159-
case cJSON_Number:
160-
case cJSON_String:
161-
break;
162-
case cJSON_Array:
163-
event_ptr = mod_ptr->child;
164-
while (event_ptr != NULL) {
165-
if (!add_event_descriptor(event_ptr)) {
166-
return false;
167-
}
168-
event_ptr = event_ptr->next;
169-
}
170-
break;
171-
default:
172-
LOG_WARNING("Audit: JSON unknown field error");
173-
return false;
174-
}
175-
mod_ptr = mod_ptr->next;
176-
}
177-
module = module->next;
178149
}
179150
return true;
180151
}
181152

182-
bool AuditImpl::process_module_descriptor(cJSON* module_descriptor) {
153+
bool AuditImpl::process_module_descriptor(const nlohmann::json& json) {
183154
events.clear();
184-
while(module_descriptor != NULL) {
185-
switch (module_descriptor->type) {
186-
case cJSON_Number:
187-
break;
188-
case cJSON_Array:
189-
if (!process_module_data_structures(module_descriptor->child)) {
190-
return false;
191-
}
192-
break;
193-
default:
194-
LOG_WARNING("Audit: JSON unknown field error");
155+
for (const auto& module_descriptor : json) {
156+
auto events = cb::getOptionalJsonObject(module_descriptor, "events");
157+
if (!events.is_initialized()) {
158+
LOG_WARNING(
159+
"Audit::process_module_descriptor: \"events\""
160+
" field missing");
161+
return false;
162+
}
163+
switch (events->type()) {
164+
case nlohmann::json::value_t::number_integer:
165+
break;
166+
case nlohmann::json::value_t::array:
167+
if (!process_module_data_structures(*events)) {
195168
return false;
169+
}
170+
break;
171+
default:
172+
LOG_WARNING(
173+
"Audit:process_module_descriptor \"events\" field is not"
174+
" integer or array");
175+
return false;
196176
}
197-
module_descriptor = module_descriptor->next;
198177
}
199178
return true;
200179
}
@@ -253,20 +232,25 @@ bool AuditImpl::configure() {
253232
if (str.empty()) {
254233
return false;
255234
}
256-
cJSON *json_ptr = cJSON_Parse(str.c_str());
257-
if (json_ptr == NULL) {
235+
236+
nlohmann::json events_json;
237+
try {
238+
events_json = nlohmann::json::parse(str);
239+
} catch (const nlohmann::json::exception& e) {
258240
LOG_WARNING(
259-
R"(Audit::configure: JSON parsing error of "{}" with the content: "{}")",
241+
R"(Audit::configure: JSON parsing error of "{}" with the
242+
content: "{}", e.what(): {})",
260243
audit_events_file,
261-
cb::UserDataView(str));
244+
cb::UserDataView(str),
245+
cb::UserDataView(e.what()));
262246
return false;
263247
}
264-
if (!process_module_descriptor(json_ptr->child)) {
265-
cJSON_Delete(json_ptr);
248+
249+
auto modules = cb::getOptionalJsonObject(
250+
events_json, "modules", nlohmann::json::value_t::array);
251+
if (!modules.is_initialized() || !process_module_descriptor(*modules)) {
266252
return false;
267253
}
268-
cJSON_Delete(json_ptr);
269-
270254
auditfile.reconfigure(config);
271255

272256
// iterate through the events map and update the sync and enabled flags

auditd/src/audit.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ class AuditImpl : public cb::audit::Audit {
9090
* @param event_ptr the definition of the descriptor in JSON
9191
* @return true if the descriptor was successfully added
9292
*/
93-
bool add_event_descriptor(cJSON* event_ptr);
93+
bool add_event_descriptor(const nlohmann::json& json);
9494

95-
bool process_module_data_structures(cJSON* module);
96-
bool process_module_descriptor(cJSON* module_descriptor);
95+
bool process_module_data_structures(const nlohmann::json& json);
96+
bool process_module_descriptor(const nlohmann::json& json);
9797

9898
/**
9999
* Create an internal audit event structure

auditd/src/auditfile.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "auditfile.h"
1818
#include "audit.h"
1919
#include <JSON_checker.h>
20-
#include <cJSON.h>
20+
#include <cJSON_utils.h>
2121
#include <logger/logger.h>
2222
#include <memcached/isotime.h>
2323
#include <nlohmann/json.hpp>

auditd/src/eventdescriptor.cc

Lines changed: 38 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,75 +15,54 @@
1515
* limitations under the License.
1616
*/
1717
#include "eventdescriptor.h"
18+
19+
#include <utilities/json_utilities.h>
20+
21+
#include <boost/optional.hpp>
1822
#include <stdexcept>
1923

20-
EventDescriptor::EventDescriptor(const cJSON* root)
21-
: id(uint32_t(locate(root, "id", cJSON_Number)->valueint)),
22-
name(locate(root, "name", cJSON_String)->valuestring),
23-
description(locate(root, "description", cJSON_String)->valuestring),
24-
sync(locate(root, "sync", cJSON_True)->type == cJSON_True),
25-
enabled(locate(root, "enabled", cJSON_True)->type == cJSON_True),
24+
EventDescriptor::EventDescriptor(const nlohmann::json& root)
25+
: id(root.at("id").get<uint32_t>()),
26+
name(root.at("name").get<std::string>()),
27+
description(root.at("description").get<std::string>()),
28+
sync(root.at("sync").get<bool>()),
29+
enabled(root.at("enabled").get<bool>()),
2630
filteringPermitted(false) {
31+
size_t expected = 5;
2732

28-
int expected = 5;
2933
// Look for the optional parameter filtering_permitted
30-
cJSON* obj = cJSON_GetObjectItem(const_cast<cJSON*>(root), "filtering_permitted");
31-
// If filter_permitted parameter is defined then set to appropriate value.
32-
if (obj != nullptr) {
33-
filteringPermitted = (obj->type == cJSON_True);
34-
expected++;
35-
}
34+
filteringPermitted = root.value("filtering_permitted", false);
35+
expected += root.count("filtering_permitted");
3636

37-
if ((obj = cJSON_GetObjectItem(const_cast<cJSON*>(root),
38-
"mandatory_fields")) != nullptr) {
39-
if (obj->type != cJSON_Array && obj->type != cJSON_Object) {
40-
throw std::logic_error(
41-
"EventDescriptor::EventDescriptor: Invalid type for mandatory_fields");
37+
auto obj = cb::getOptionalJsonObject(root, "mandatory_fields");
38+
if (obj.is_initialized()) {
39+
if ((*obj).type() != nlohmann::json::value_t::array &&
40+
(*obj).type() != nlohmann::json::value_t::object) {
41+
throw std::invalid_argument(
42+
"EventDescriptor::EventDescriptor: "
43+
"Invalid type for mandatory_fields");
44+
} else {
45+
expected++;
4246
}
43-
++expected;
4447
}
45-
if ((obj = cJSON_GetObjectItem(const_cast<cJSON*>(root),
46-
"optional_fields")) != nullptr) {
47-
if (obj->type != cJSON_Array && obj->type != cJSON_Object) {
48-
throw std::logic_error(
49-
"EventDescriptor::EventDescriptor: Invalid type for optional_fields");
50-
}
51-
++expected;
52-
}
53-
54-
if (expected != cJSON_GetArraySize(const_cast<cJSON*>(root))) {
55-
throw std::logic_error(
56-
"EventDescriptor::EventDescriptor: Unknown elements specified");
5748

58-
}
59-
}
60-
61-
const cJSON* EventDescriptor::locate(const cJSON* root,
62-
const char* field,
63-
int type) {
64-
const cJSON* ret = cJSON_GetObjectItem(const_cast<cJSON*>(root), field);
65-
if (ret == nullptr) {
66-
std::string msg("EventDescriptor::locate: Element \"");
67-
msg.append(field);
68-
msg.append("\" not found");
69-
throw std::logic_error(msg);
70-
}
71-
72-
if (type == cJSON_True) {
73-
if (ret->type != cJSON_True && ret->type != cJSON_False) {
74-
std::string msg("EventDescriptor::locate: Element \"");
75-
msg.append(field);
76-
msg.append("\" is not of the expected type");
77-
throw std::logic_error(msg);
78-
}
79-
} else {
80-
if (ret->type != type) {
81-
std::string msg("EventDescriptor::locate: Element \"");
82-
msg.append(field);
83-
msg.append("\" is not of the expected type");
84-
throw std::logic_error(msg);
49+
obj = cb::getOptionalJsonObject(root, "optional_fields");
50+
if (obj.is_initialized()) {
51+
if ((*obj).type() != nlohmann::json::value_t::array &&
52+
(*obj).type() != nlohmann::json::value_t::object) {
53+
throw std::invalid_argument(
54+
"EventDescriptor::EventDescriptor: "
55+
"Invalid type for optional_fields");
56+
} else {
57+
expected++;
8558
}
8659
}
8760

88-
return ret;
61+
if (expected != root.size()) {
62+
throw std::invalid_argument(
63+
"EventDescriptor::EventDescriptor: "
64+
"Unknown elements specified. Number expected:" +
65+
std::to_string(expected) +
66+
" actual:" + std::to_string(root.size()));
67+
}
8968
}

auditd/src/eventdescriptor.h

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
*/
1717
#pragma once
1818

19+
#include <nlohmann/json_fwd.hpp>
1920
#include <string>
20-
#include <cJSON_utils.h>
2121

2222
/**
2323
* The EventDescriptor class represents a single event descriptor and
@@ -32,10 +32,10 @@ class EventDescriptor {
3232
* descriptor.
3333
*
3434
* @param root pointer to the json represenatation
35-
* @throws std::logic_error if called with a JSON representation which
35+
* @throws std::invalid_argument if called with a JSON representation which
3636
* isn't what we expect
3737
*/
38-
EventDescriptor(const cJSON* root);
38+
EventDescriptor(const nlohmann::json& root);
3939

4040
const uint32_t getId() const {
4141
return id;
@@ -70,20 +70,6 @@ class EventDescriptor {
7070
}
7171

7272
protected:
73-
/**
74-
* Locate the given field in the JSON
75-
*
76-
* @param root pointer to the first entry
77-
* @param field the name of the field to locate
78-
* @param type the expected type of the object (Note: there is no
79-
* cJSON_Bool #define, so you have to pass in cJSON_True
80-
* for that).
81-
* @return the cJSON element for the object
82-
* @throws std::logic_error if the field is missing or is of an
83-
* incorrect type
84-
*/
85-
const cJSON* locate(const cJSON* root, const char* field, int type);
86-
8773
const uint32_t id;
8874
const std::string name;
8975
const std::string description;

auditd/tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ ADD_TEST(NAME memcached-auditd-test
4343
ADD_EXECUTABLE(memcached_audit_evdescr_test eventdescriptor_test.cc
4444
${Memcached_SOURCE_DIR}/auditd/src/eventdescriptor.cc
4545
${Memcached_SOURCE_DIR}/auditd/src/eventdescriptor.h)
46-
TARGET_LINK_LIBRARIES(memcached_audit_evdescr_test cJSON gtest gtest_main)
46+
TARGET_LINK_LIBRARIES(memcached_audit_evdescr_test cJSON gtest gtest_main
47+
mcd_util)
4748
ADD_TEST(NAME memcached-audit-evdescr-test
4849
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
4950
COMMAND memcached_audit_evdescr_test)

0 commit comments

Comments
 (0)