Skip to content

Commit a1547ea

Browse files
martinhsvzimmerle
authored andcommitted
Regression tests: audit log compare support and test cases
1 parent 7a48245 commit a1547ea

File tree

6 files changed

+136
-1
lines changed

6 files changed

+136
-1
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
v3.x.y - YYYY-MMM-DD (to be released)
22
-------------------------------------
33

4+
- Add support to test framework for audit log content verification
5+
and add regression tests for issues #2000, #2196
46
- Multipart Content-Dispostion should allow field: filename*=
57
[@martinhsv]
68
- Fix rule-update-target for non-regex

Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ TESTS+=test/test-cases/regression/issue-1943.json
155155
TESTS+=test/test-cases/regression/issue-1956.json
156156
TESTS+=test/test-cases/regression/issue-1960.json
157157
TESTS+=test/test-cases/regression/issue-2099.json
158+
TESTS+=test/test-cases/regression/issue-2000.json
158159
TESTS+=test/test-cases/regression/issue-2111.json
160+
TESTS+=test/test-cases/regression/issue-2196.json
159161
TESTS+=test/test-cases/regression/issue-394.json
160162
TESTS+=test/test-cases/regression/issue-849.json
161163
TESTS+=test/test-cases/regression/issue-960.json

test/regression/regression.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,30 @@ bool contains(const std::string &s, const std::string &pattern) {
5858
return ret;
5959
}
6060

61+
void clearAuditLog(const std::string &filename) {
62+
if (!filename.empty()) {
63+
std::ifstream file;
64+
file.open(filename.c_str(), std::ifstream::out | std::ifstream::trunc);
65+
if (!file.is_open() || file.fail()) {
66+
std::cout << std::endl << "Failed to clear previous contents of audit log: " \
67+
<< filename << std::endl;
68+
}
69+
file.close();
70+
}
71+
}
72+
std::string getAuditLogContent(const std::string &filename) {
73+
std::stringstream buffer;
74+
if (!filename.empty()) {
75+
try {
76+
std::ifstream t(filename);
77+
buffer << t.rdbuf();
78+
} catch (...) {
79+
std::cout << "Failed to read file:" << filename << std::endl;
80+
}
81+
}
82+
return buffer.str();
83+
}
84+
6185

6286
void actions(ModSecurityTestResults<RegressionTest> *r,
6387
modsecurity::Transaction *a, std::stringstream *serverLog) {
@@ -278,6 +302,8 @@ void perform_unit_test(ModSecurityTest<RegressionTest> *test,
278302
modsec_transaction = new modsecurity::Transaction(modsec, modsec_rules,
279303
&serverLog);
280304

305+
clearAuditLog(modsec_transaction->m_rules->m_auditLog->m_path1);
306+
281307
modsec_transaction->processConnection(t->clientIp.c_str(),
282308
t->clientPort, t->serverIp.c_str(), t->serverPort);
283309

@@ -393,6 +419,19 @@ void perform_unit_test(ModSecurityTest<RegressionTest> *test,
393419
testRes->reason << KWHT << "Expecting: " << RESET \
394420
<< t->error_log + "";
395421
testRes->passed = false;
422+
} else if (!t->audit_log.empty()
423+
&& !contains(getAuditLogContent(modsec_transaction->m_rules->m_auditLog->m_path1), t->audit_log)) {
424+
if (test->m_automake_output) {
425+
std::cout << ":test-result: FAIL " << filename \
426+
<< ":" << t->name << std::endl;
427+
} else {
428+
std::cout << KRED << "failed!" << RESET << std::endl;
429+
}
430+
testRes->reason << "Audit log was not matching the " \
431+
<< "expected results." << std::endl;
432+
testRes->reason << KWHT << "Expecting: " << RESET \
433+
<< t->audit_log + "";
434+
testRes->passed = false;
396435
} else {
397436
if (test->m_automake_output) {
398437
std::cout << ":test-result: PASS " << filename \
@@ -410,6 +449,8 @@ void perform_unit_test(ModSecurityTest<RegressionTest> *test,
410449
testRes->reason << d->log_messages() << std::endl;
411450
testRes->reason << KWHT << "Error log:" << RESET << std::endl;
412451
testRes->reason << serverLog.str() << std::endl;
452+
testRes->reason << KWHT << "Audit log:" << RESET << std::endl;
453+
testRes->reason << getAuditLogContent(modsec_transaction->m_rules->m_auditLog->m_path1) << std::endl;
413454
}
414455
}
415456

test/regression/regression_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ RegressionTest *RegressionTest::from_yajl_node(const yajl_val &node) {
180180
yajl_val val2 = val->u.object.values[j];
181181

182182
if (strcmp(key2, "audit_log") == 0) {
183-
u->audit_log = yajl_array_to_str(val2);
183+
u->audit_log = YAJL_GET_STRING(val2);
184184
}
185185
if (strcmp(key2, "debug_log") == 0) {
186186
u->debug_log = YAJL_GET_STRING(val2);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[
2+
{
3+
"enabled":1,
4+
"version_min":300000,
5+
"title":"Testing audit log part H should output when deny - issue-2000",
6+
"expected":{
7+
"http_code":200
8+
},
9+
"client":{
10+
"ip":"127.0.0.1",
11+
"port":123
12+
},
13+
"request":{
14+
"headers":{
15+
"Host":"localhost",
16+
"User-Agent":"curl/7.38.0",
17+
"Accept":"*/*"
18+
},
19+
"uri":"index.php?foo=bar&a=xxx",
20+
"method":"GET",
21+
"body": ""
22+
},
23+
"expected": {
24+
"http_code": 403,
25+
"audit_log": "id \"1234"
26+
},
27+
28+
"server":{
29+
"ip":"127.0.0.1",
30+
"port":80
31+
},
32+
"rules":[
33+
"SecRuleEngine On",
34+
"SecAuditLogParts ABIJDEFHZ",
35+
"SecAuditEngine RelevantOnly",
36+
"SecAuditLogParts ABCFHZ",
37+
"SecAuditLog /tmp/test/modsec_audit.log",
38+
"SecAuditLogDirMode 0766",
39+
"SecAuditLogFileMode 0666",
40+
"SecAuditLogType Serial",
41+
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\"",
42+
"SecRule ARGS:foo \"@rx ^bar$\" \"id:1234,phase:1,deny,status:403\""
43+
]
44+
}
45+
]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[
2+
{
3+
"enabled":1,
4+
"version_min":300000,
5+
"title":"Testing audit log not written when nolog - issue-2196",
6+
"expected":{
7+
"http_code":200
8+
},
9+
"client":{
10+
"ip":"127.0.0.1",
11+
"port":123
12+
},
13+
"request":{
14+
"headers":{
15+
"Host":"localhost",
16+
"User-Agent":"curl/7.38.0",
17+
"Accept":"*/*"
18+
},
19+
"uri":"index.php?foo=bar&a=xxx",
20+
"method":"GET",
21+
"body": ""
22+
},
23+
"expected": {
24+
"http_code": 200,
25+
"audit_log": "\\A[\\s\\S]{0}\\z"
26+
},
27+
28+
"server":{
29+
"ip":"127.0.0.1",
30+
"port":80
31+
},
32+
"rules":[
33+
"SecRuleEngine On",
34+
"SecAuditLogParts ABIJDEFHZ",
35+
"SecAuditEngine RelevantOnly",
36+
"SecAuditLogParts ABCFHZ",
37+
"SecAuditLog /tmp/test/modsec_audit.log",
38+
"SecAuditLogDirMode 0766",
39+
"SecAuditLogFileMode 0666",
40+
"SecAuditLogType Serial",
41+
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\"",
42+
"SecRule ARGS:foo \"@rx ^bar$\" \"id:1234,phase:1,nolog,pass\""
43+
]
44+
}
45+
]

0 commit comments

Comments
 (0)