Very first commit: libmodsecurity

Check the README.md file for further information about the libmodsecurity.
This commit is contained in:
Felipe Zimmerle
2015-06-26 14:35:15 -03:00
parent 33cbe0452a
commit 95cb4c56ab
153 changed files with 12862 additions and 0 deletions

0
test/.empty Normal file
View File

55
test/Makefile.am Normal file
View File

@@ -0,0 +1,55 @@
ACLOCAL_AMFLAGS = -I build
SUBDIRS = \
benchmark
# make clean
CLEANFILES =
# make maintainer-clean
MAINTAINERCLEANFILES = \
Makefile.in
bin_PROGRAMS = unit-tests regression-tests
# unit_tests
unit_tests_SOURCES = \
unit/unit.cc \
unit/unit_test.cc
unit_tests_LDADD = \
$(top_builddir)/src/.libs/libmodsecurity.a \
$(YAJL_LDADD)
unit_tests_CPPFLAGS = \
-std=c++11 \
-Icommon \
-O0 \
-g \
-I$(top_builddir)/headers \
$(YAJL_CFLAGS)
# regression
regression_tests_SOURCES = \
regression/regression.cc \
regression/regression_test.cc \
regression/custom_debug_log.cc
regression_tests_LDADD = \
$(top_builddir)/src/.libs/libmodsecurity.a \
$(YAJL_LDADD)
regression_tests_CPPFLAGS = \
-std=c++11 \
-Icommon \
-O0 \
-g \
-I$(top_builddir)/headers \
$(YAJL_CFLAGS)

View File

@@ -0,0 +1,17 @@
bin_PROGRAMS = benchmark
benchmark_SOURCES = \
benchmark.cc
benchmark_LDADD = \
$(top_builddir)/src/.libs/libmodsecurity.a
benchmark_CPPFLAGS = \
-std=c++11 \
-I$(top_builddir)/headers
MAINTAINERCLEANFILES = \
Makefile.in

View File

@@ -0,0 +1,3 @@
SecRule ARGS "@contains /test.txt" "allow"
SecRule ARGS:teste "@contains /test.txt" " allow,deny"
SecRule ARGS "@contains /test.txt" "allow, allow,deny"

163
test/benchmark/benchmark.cc Normal file
View File

@@ -0,0 +1,163 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <string.h>
#include <ctime>
#include <iostream>
#include <string>
#include "modsecurity/modsecurity.h"
#include "modsecurity/rules.h"
using ModSecurity::Assay;
char request_header[] = "" \
"GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1\n\r" \
"Host: net.tutsplus.com\n\r" \
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5)" \
" Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\n\r" \
"Accept: text/html,application/xhtml+xml,application/xml; " \
"q=0.9,*/*;q=0.8\n\r" \
"Accept-Language: en-us,en;q=0.5\n\r" \
"Accept-Encoding: gzip,deflate\n\r" \
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\n\r" \
"Keep-Alive: 300\n\r" \
"Connection: keep-alive\n\r" \
"Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120\n\r" \
"Pragma: no-cache\n\r" \
"Cache-Control: no-cache\n\r";
char request_uri[] = "GET /test.pl?param1=test&para2=test2";
char request_body[] = "";
char response_headers[] = "" \
"HTTP/1.1 200 OK\n\r" \
"Content-Type: text/xml; charset=utf-8\n\r" \
"Content-Length: length\n\r";
unsigned char response_body[] = "" \
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r" \
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " \
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n\r" \
" <soap:Body>\n\r" \
" <EnlightenResponse xmlns=\"http://clearforest.com/\">\n\r" \
" <EnlightenResult>string</EnlightenResult>\n\r" \
" </EnlightenResponse>\n\r" \
" </soap:Body>\n\r" \
"</soap:Envelope>\n\r";
char ip[] = "200.249.12.31";
char rules_file[] = "basic_rules.conf";
#define NUM_REQUESTS 1000
int main(int argc, char *argv[]) {
int i = 0;
ModSecurity::ModSecurity *modsec;
ModSecurity::Rules *rules;
modsec = new ModSecurity::ModSecurity();
rules = new ModSecurity::Rules();
rules->loadFromUri(rules_file);
for (i = 0; i < NUM_REQUESTS; i++) {
std::cout << "Proceding with request " << i << std::endl;
Assay *modsecAssay = new Assay(modsec, rules);
modsecAssay->processConnection(ip);
if (modsecAssay->intervention()) {
std::cout << "There is an intervention" << std::endl;
continue;
}
modsecAssay->processURI(request_uri);
if (modsecAssay->intervention()) {
std::cout << "There is an intervention" << std::endl;
continue;
}
modsecAssay->addRequestHeader((char *) "Host",
(char *) "net.tutsplus.com");
modsecAssay->addRequestHeader((char *) "User-Agent", (char *)
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) " \
"Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\n\r");
modsecAssay->addRequestHeader((char *) "Accept",
(char *) "text/html,application/xhtml+xml,application/xml;" \
"q=0.9,*/*;q=0.8");
modsecAssay->addRequestHeader((char *) "Accept-Language",
(char *) "en-us,en;q=0.5");
modsecAssay->addRequestHeader((char *) "Accept-Encoding",
(char *) "gzip,deflate");
modsecAssay->addRequestHeader((char *) "Accept-Charset",
(char *) "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
modsecAssay->addRequestHeader((char *) "Keep-Alive",
(char *) "300");
modsecAssay->addRequestHeader((char *) "Connection",
(char *) "keep-alive");
modsecAssay->addRequestHeader((char *) "Cookie",
(char *) "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120");
modsecAssay->addRequestHeader((char *) "Pragma",
(char *) "no-cache");
modsecAssay->addRequestHeader((char *) "Cache-Control",
(char *) "no-cache");
modsecAssay->processRequestHeaders();
if (modsecAssay->intervention()) {
std::cout << "There is an intervention" << std::endl;
continue;
}
modsecAssay->processRequestBody();
if (modsecAssay->intervention()) {
std::cout << "There is an intervention" << std::endl;
continue;
}
modsecAssay->addResponseHeader((char *) "HTTP/1.1",
(char *) "200 OK");
modsecAssay->addResponseHeader((char *) "Content-Type",
(char *) "text/xml; charset=utf-8");
modsecAssay->addResponseHeader((char *) "Content-Length",
(char *) "200");
modsecAssay->processResponseHeaders();
if (modsecAssay->intervention()) {
std::cout << "There is an intervention" << std::endl;
continue;
}
modsecAssay->appendResponseBody(response_body,
strlen((const char*)response_body));
modsecAssay->processResponseBody();
if (modsecAssay->intervention()) {
std::cout << "There is an intervention" << std::endl;
continue;
}
delete modsecAssay;
}
delete modsec;
}

31
test/common/colors.h Normal file
View File

@@ -0,0 +1,31 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef TEST_COMMON_COLORS_H_
#define TEST_COMMON_COLORS_H_
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#define RESET "\033[0m"
#endif // TEST_COMMON_COLORS_H_

View File

@@ -0,0 +1,153 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "common/modsecurity_test.h"
#include <yajl/yajl_tree.h>
#include <dirent.h>
#include <string.h>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <string>
#include "modsecurity/modsecurity.h"
namespace modsecurity_test {
template <class T>
std::string ModSecurityTest<T>::header() {
std::stringstream i;
i << "ModSecurity " << MODSECURITY_VERSION << " - tests" << std::endl;
#if not HAS_GETOPT
i << "(options are not available -- missing GetOpt)" << std::endl;
#endif
i << std::endl;
return i.str();
}
template <class T>
bool ModSecurityTest<T>::load_test_json(std::string file) {
std::vector<yajl_val> tests;
char errbuf[1024];
yajl_val node;
std::ifstream myfile;
myfile.open(file.c_str());
if (myfile.is_open() == false) {
std::cout << "Problems opening file: " << file << std::endl;
return false;
}
std::string str((std::istreambuf_iterator<char>(myfile)),
std::istreambuf_iterator<char>());
node = yajl_tree_parse((const char *) str.c_str(), errbuf, sizeof(errbuf));
if (node == NULL) {
std::cout << "Problems parsing file: " << file << std::endl;
if (strlen(errbuf) > 0) {
std::cout << errbuf << std::endl;
}
return false;
}
size_t num_tests = node->u.array.len;
for ( int i = 0; i < num_tests; i++ ) {
yajl_val obj = node->u.array.values[i];
T *u = T::from_yajl_node(obj);
u->filename = file;
u->name = u->filename + ":" + u->name;
if (this->count(u->name) == 0) {
std::vector<T *> *vector = new std::vector<T *>;
vector->push_back(u);
std::pair<std::string, std::vector<T *> *> a(u->name, vector);
this->insert(a);
} else {
std::vector<T *> *vec = this->at(u->name);
vec->push_back(u);
}
}
return true;
}
template <class T>
std::pair<std::string, std::vector<T *>>* ModSecurityTest<T>::load_tests() {
DIR *dir;
struct dirent *ent;
if ((dir = opendir(this->target_folder.c_str())) == NULL) {
std::cout << "Problems opening directory: " << this->target_folder;
std::cout << std::endl;
return NULL;
}
while ((ent = readdir(dir)) != NULL) {
std::string filename = ent->d_name;
std::string json = ".json";
if (filename.size() < json.size()
|| !std::equal(json.rbegin(), json.rend(), filename.rbegin())) {
continue;
}
if (load_test_json(this->target_folder + "/" + filename) == false) {
std::cout << "Problems loading tests from: " << filename;
std::cout << std::endl;
}
}
closedir(dir);
return NULL;
}
template <class T>
void ModSecurityTest<T>::cmd_options(int argc, char **argv) {
int option_char;
#if HAS_GETOPT
GetOpt getopt(argc, argv, "hvct:");
while ((option_char = getopt()) != EOF) {
switch (option_char) {
case 'h':
print_help();
return;
break;
case 'v':
this->verbose = true;
break;
case 'c':
this->color = false;
break;
case 't':
this->target_folder = getopt.optarg;
break;
}
}
#else
if (argv[1]) {
this->target_folder = argv[1];
} else {
this->target_folder = default_test_path;
}
#endif
}
} // namespace modsecurity_test

View File

@@ -0,0 +1,49 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <iostream>
#include <utility>
#include <string>
#include <vector>
#include <unordered_map>
#ifndef TEST_COMMON_MODSECURITY_TEST_H_
#define TEST_COMMON_MODSECURITY_TEST_H_
extern void print_help();
extern std::string default_test_path;
namespace modsecurity_test {
template <class T> class ModSecurityTest :
public std::unordered_map<std::string, std::vector<T *> *> {
public:
std::string header();
void cmd_options(int, char **);
std::pair<std::string, std::vector<T *>>* load_tests();
bool load_test_json(std::string);
std::string target_folder;
bool verbose = false;
bool color = false;
};
} // namespace modsecurity_test
#include "modsecurity_test.cc"
#endif // TEST_COMMON_MODSECURITY_TEST_H_

View File

@@ -0,0 +1,35 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#ifndef TEST_COMMON_MODSECURITY_TEST_RESULTS_H_
#define TEST_COMMON_MODSECURITY_TEST_RESULTS_H_
namespace modsecurity_test {
template <class T> class ModSecurityTestResults : public std::vector<T *> {
public:
std::string log_raw_debug_log;
int status;
std::string location;
};
} // namespace modsecurity_test
#endif // TEST_COMMON_MODSECURITY_TEST_RESULTS_H_

View File

@@ -0,0 +1,48 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "regression/custom_debug_log.h"
#include <iostream>
#include <string>
#include <regex>
#include "modsecurity/debug_log.h"
namespace modsecurity_test {
CustomDebugLog *CustomDebugLog::new_instance() {
return new CustomDebugLog();
}
bool CustomDebugLog::write_log(int level, const std::string& message) {
m_log << "[" << level << "] " << message << std::endl;
}
bool CustomDebugLog::contains(const std::string& pattern) {
std::regex re(pattern);
std::smatch match;
return (std::regex_search(m_log.str(), match, re) && match.size() >= 1);
}
std::string CustomDebugLog::log_messages() {
return m_log.str();
}
} // namespace modsecurity_test

View File

@@ -0,0 +1,40 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <sstream>
#include <string>
#include "modsecurity/debug_log.h"
#ifndef TEST_REGRESSION_CUSTOM_DEBUG_LOG_H_
#define TEST_REGRESSION_CUSTOM_DEBUG_LOG_H_
namespace modsecurity_test {
class CustomDebugLog : public ModSecurity::DebugLog {
public:
CustomDebugLog *new_instance();
bool write_log(int level, const std::string& message) override;
bool contains(const std::string& pattern);
std::string log_messages();
private:
std::stringstream m_log;
};
} // namespace modsecurity_test
#endif // TEST_REGRESSION_CUSTOM_DEBUG_LOG_H_

View File

@@ -0,0 +1,199 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <string.h>
#include <ctime>
#include <iostream>
#include <string>
#include "modsecurity/modsecurity.h"
#include "modsecurity/rules.h"
#include "common/modsecurity_test.h"
#include "regression/regression_test.h"
#include "common/modsecurity_test_results.h"
#include "regression/custom_debug_log.h"
using modsecurity_test::CustomDebugLog;
using modsecurity_test::ModSecurityTest;
using modsecurity_test::ModSecurityTestResults;
using modsecurity_test::RegressionTest;
std::string default_test_path = "test-cases/regression";
void print_help() {
std::cout << "Use ./regression-tests /path/to/file" << std::endl;
std::cout << std::endl;
std::cout << std::endl;
}
void actions(ModSecurityTestResults<RegressionTest> *r,
ModSecurity::ModSecurityIntervention *it) {
if (it != NULL) {
if (it->pause != 0) {
// FIXME:
}
if (it->status != 0) {
r->status = it->status;
}
if (it->url != NULL) {
r->location = it->url;
}
}
}
void perform_unit_test(std::vector<RegressionTest *> *tests,
ModSecurityTestResults<RegressionTest> *res) {
ModSecurity::ModSecurity *modsec;
ModSecurity::Rules *modsec_rules;
ModSecurity::Assay *modsec_assay;
CustomDebugLog *debug_log = new CustomDebugLog();
for (RegressionTest *t : *tests) {
ModSecurityTestResults<RegressionTest> r;
r.status = 200;
modsec = new ModSecurity::ModSecurity();
modsec_rules = new ModSecurity::Rules(debug_log);
if (modsec_rules->load((char *)(t->rules.c_str())) == false) {
std::cerr << "Problems parsing the rules, aborting!" << std::endl;
return;
}
modsec_assay = new ModSecurity::Assay(modsec, modsec_rules);
if (t->ip.empty() == false) {
// FIXME: no cast please.
modsec_assay->processConnection((char *)(t->ip.c_str()));
actions(&r, modsec_assay->intervention());
if (r.status != 200) {
goto end;
}
}
if (t->uri.empty() == false) {
modsec_assay->processURI((char *)(t->uri.c_str()));
actions(&r, modsec_assay->intervention());
if (r.status != 200) {
goto end;
}
}
for (std::pair<std::string, std::string> headers :
t->request_headers) {
modsec_assay->addRequestHeader((char *)headers.first.c_str(),
(char *)headers.second.c_str());
}
modsec_assay->processRequestHeaders();
actions(&r, modsec_assay->intervention());
if (r.status != 200) {
goto end;
}
modsec_assay->appendRequestBody(
(unsigned char *)t->request_body.c_str(),
t->request_body.size());
modsec_assay->processRequestBody();
actions(&r, modsec_assay->intervention());
if (r.status != 200) {
goto end;
}
for (std::pair<std::string, std::string> headers :
t->response_headers) {
modsec_assay->addResponseHeader((char *)headers.first.c_str(),
(char *)headers.second.c_str());
}
modsec_assay->processResponseHeaders();
actions(&r, modsec_assay->intervention());
if (r.status != 200) {
goto end;
}
modsec_assay->appendResponseBody(
(unsigned char *)t->response_body.c_str(),
t->response_body.size());
modsec_assay->processResponseBody();
actions(&r, modsec_assay->intervention());
if (r.status != 200) {
goto end;
}
end:
CustomDebugLog *d = reinterpret_cast<CustomDebugLog *>
(modsec_rules->debug_log);
std::cout << "- " << t->name << " ...";
if (!d->contains(t->debug_log)) {
std::cout << "Debug log was not matching the expected results.";
std::cout << std::endl;
} else if (r.status != t->http_code) {
std::cout << "HTTP code mismatch. expecting: " + \
std::to_string(t->http_code) + \
" got: " + std::to_string(r.status) + "\n";
} else {
std::cout << "passed!" << std::endl;
goto after_debug_log;
}
std::cout << "Debug log:" << std::endl;
std::cout << "" << d->log_messages() << "" <<std::endl;
after_debug_log:
res->log_raw_debug_log = d->log_messages();
delete modsec_assay;
delete modsec_rules;
delete modsec;
res->insert(res->end(), r.begin(), r.end());
}
}
int main(int argc, char **argv) {
ModSecurityTest<RegressionTest> test;
ModSecurityTestResults<RegressionTest> results;
test.cmd_options(argc, argv);
std::cout << test.header();
test.load_tests();
std::ofstream test_log;
test_log.open("regression_test_log.txt");
for (std::pair<std::string, std::vector<RegressionTest *> *> a : test) {
std::vector<RegressionTest *> *tests = a.second;
ModSecurityTestResults<RegressionTest> res;
perform_unit_test(tests, &res);
test_log << res.log_raw_debug_log;
}
test_log.close();
return 0;
}

View File

@@ -0,0 +1,180 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "regression/regression_test.h"
#include <string.h>
#include <sstream>
#include <unordered_map>
#include <string>
namespace modsecurity_test {
std::string RegressionTest::print() {
std::stringstream i;
#if 0
i << KRED << "Test failed." << RESET << " From: " \
i << this->filename << std::endl;
i << "{" << std::endl;
i << " \"ret\": \"" << this->ret << "\"" << std::endl;
i << " \"type\": \"" << this->type << "\"" << std::endl;
i << " \"name\": \"" << this->name << "\"" << std::endl;
i << " \"input\": \"" << this->input << "\"" << std::endl;
i << " \"param\": \"" << this->param << "\"" << std::endl;
i << "}" << std::endl;
i << "Expecting: " << this->ret << " - operator returned: " << \
this->obtained << std::endl;
#endif
return i.str();
}
inline std::string RegressionTest::yajl_array_to_str(const yajl_val &node) {
std::stringstream i;
for (int z = 0; z < node->u.array.len; z++) {
yajl_val val3 = node->u.array.values[z];
const char *key = YAJL_GET_STRING(val3);
i << key << "\n";
}
return i.str();
}
inline std::vector<std::string> RegressionTest::yajl_array_to_vec_str(
const yajl_val &node) {
std::vector<std::string> vec;
for (int z = 0; z < node->u.array.len; z++) {
yajl_val val3 = node->u.array.values[z];
const char *key = YAJL_GET_STRING(val3);
vec.push_back(key);
}
return vec;
}
inline std::unordered_map<std::string, std::string>
RegressionTest::yajl_array_to_map(const yajl_val &node) {
std::unordered_map<std::string, std::string> vec;
for (int z = 0; z < node->u.object.len; z++) {
const char *key = node->u.object.keys[z];
yajl_val val3 = node->u.object.values[z];
const char *value = YAJL_GET_STRING(val3);
std::pair<std::string, std::string> a(key, value);
vec.insert(a);
}
return vec;
}
RegressionTest *RegressionTest::from_yajl_node(const yajl_val &node) {
size_t nelem = node->u.object.len;
RegressionTest *u = new RegressionTest();
u->http_code = 200;
for (int i = 0; i < nelem; i++) {
const char *key = node->u.object.keys[ i ];
yajl_val val = node->u.object.values[ i ];
if (strcmp(key, "enabled") == 0) {
u->enabled = YAJL_GET_INTEGER(val);
}
if (strcmp(key, "version_min") == 0) {
u->version_min = YAJL_GET_INTEGER(val);
}
if (strcmp(key, "version_max") == 0) {
u->version_max = YAJL_GET_INTEGER(val);
}
if (strcmp(key, "title") == 0) {
u->title = YAJL_GET_STRING(val);
}
if (strcmp(key, "url") == 0) {
u->url = YAJL_GET_STRING(val);
}
if (strcmp(key, "github_issue") == 0) {
u->github_issue = YAJL_GET_INTEGER(val);
}
if (strcmp(key, "request") == 0) {
for (int j = 0; j < val->u.object.len; j++) {
const char *key2 = val->u.object.keys[j];
yajl_val val2 = val->u.object.values[j];
if (strcmp(key2, "uri") == 0) {
u->uri = YAJL_GET_STRING(val2);
}
if (strcmp(key2, "ip") == 0) {
u->ip = YAJL_GET_STRING(val2);
}
if (strcmp(key2, "headers") == 0) {
u->request_headers = yajl_array_to_map(val2);
}
if (strcmp(key2, "body") == 0) {
u->request_body = yajl_array_to_str(val2);
}
}
}
if (strcmp(key, "response") == 0) {
for (int j = 0; j < val->u.object.len; j++) {
const char *key2 = val->u.object.keys[j];
yajl_val val2 = val->u.object.values[j];
if (strcmp(key2, "headers") == 0) {
u->response_headers = yajl_array_to_map(val2);
}
if (strcmp(key2, "body") == 0) {
u->response_body = yajl_array_to_str(val2);
}
}
}
if (strcmp(key, "expected") == 0) {
for (int j = 0; j < val->u.object.len; j++) {
const char *key2 = val->u.object.keys[j];
yajl_val val2 = val->u.object.values[j];
if (strcmp(key2, "audit_log") == 0) {
u->audit_log = yajl_array_to_str(val2);
}
if (strcmp(key2, "debug_log") == 0) {
u->debug_log = YAJL_GET_STRING(val2);
}
if (strcmp(key2, "error_log") == 0) {
u->error_log = yajl_array_to_str(val2);
}
if (strcmp(key2, "http_code") == 0) {
u->http_code = YAJL_GET_INTEGER(val2);
}
if (strcmp(key2, "redirect_url") == 0) {
u->redirect_url = YAJL_GET_STRING(val2);
}
}
}
if (strcmp(key, "rules") == 0) {
std::stringstream i;
for (int j = 0; j < val->u.array.len; j++) {
yajl_val val2 = val->u.array.values[ j ];
const char *key = YAJL_GET_STRING(val2);
i << key << "\n";
}
u->rules = i.str();
}
}
u->name = u->title;
return u;
}
} // namespace modsecurity_test

View File

@@ -0,0 +1,69 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <yajl/yajl_tree.h>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#ifndef TEST_REGRESSION_REGRESSION_TEST_H_
#define TEST_REGRESSION_REGRESSION_TEST_H_
namespace modsecurity_test {
class RegressionTest {
public:
static RegressionTest *from_yajl_node(const yajl_val &);
std::string print();
std::string filename;
std::string name;
std::string title;
std::string rules;
std::string url;
int enabled;
int version_min;
int version_max;
int github_issue;
std::unordered_map<std::string, std::string> request_headers;
std::unordered_map<std::string, std::string> response_headers;
std::string request_body;
std::string response_body;
std::string audit_log;
std::string debug_log;
std::string error_log;
std::string ip;
std::string uri;
static inline std::string yajl_array_to_str(const yajl_val &node);
static inline std::vector<std::string> yajl_array_to_vec_str(
const yajl_val &node);
static inline std::unordered_map<std::string,
std::string> yajl_array_to_map(const yajl_val &node);
int http_code;
std::string redirect_url;
};
} // namespace modsecurity_test
#endif // TEST_REGRESSION_REGRESSION_TEST_H_

View File

@@ -0,0 +1,316 @@
[
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "actions :: trim,block",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test\"",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"t:trim,block\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "actions :: trim,redirect:http://www.google.com",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test\"",
"error_log": "",
"http_code": 302,
"redirect_url": "http://www.google.com"
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"t:trim,redirect:http://www.google.com\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "actions :: trim,status:500,redirect:http://www.google.com",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test\"",
"error_log": "",
"http_code": 500,
"redirect_url": "http://www.google.com"
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"t:trim,status:500,redirect:http://www.google.com\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "actions :: trim,status:500",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test\"",
"error_log": "",
"http_code": 500
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"t:trim,status:500\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "actions :: phase:1,trim,status:500",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test\"",
"error_log": "",
"http_code": 500
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"phase:1,t:trim,status:500\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "actions :: phase:4,trim,status:500",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test\"",
"error_log": "",
"http_code": 500
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"phase:4,t:trim,status:500\""
]
}
]

View File

@@ -0,0 +1,57 @@
[
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "Debug log",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1=test&para2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": ".*",
"error_log": ""
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test\" \"pass\"",
"SecRule ARGS \"@contains /test.txt\" \"allow\"",
"SecRule ARGS:teste \"@contains /test.txt\" \" allow,deny\"",
"SecRule ARGS \"@contains /test.txt\" \"allow, allow,deny\""
]
}
]

View File

@@ -0,0 +1,34 @@
[
{
"enabled": 1,
"version_min": 209000,
"version_max": -1,
"title": "Segmentation fault when uploading file with SecStreamInBodyInspection enabled",
"url": "https:\/\/github.com\/SpiderLabs\/ModSecurity\/issues\/394",
"gihub_issue": 394,
"request": {
"headers": "",
"body": ""
},
"response": {
"headers": "",
"body": ""
},
"expected": {
"audit_logs": "",
"debug_logs": "",
"error_logs": ""
},
"rules": [
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecResponseBodyAccess On",
"SecAuditEngine On",
"SecAuditLogType Serial",
"SecAuditLog logs\/modsec_audit.log",
"SecAuditLogParts ABCDEFHJKZ",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9"
]
}
]

View File

@@ -0,0 +1,104 @@
[
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "Testing transformations :: pass,t:trim",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= test &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(0\\) trim: \"test2\"",
"error_log": ""
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test \" \"pass,t:trim\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "Testing transformations :: pass,t:trim,t:lowercase",
"request": {
"ip": "200.249.12.31",
"headers": {
"Host": "net.tutsplus.com",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Cookie": "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "GET \/test.pl?param1= WHEE &param2=test2",
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/xml; charset=utf-8\n\r",
"Content-Length": "length\n\r"
},
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
" <soap:Body>\n\r",
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
" <EnlightenResult>string<\/EnlightenResult>\n\r",
" <\/EnlightenResponse>\n\r",
" <\/soap:Body>\n\r",
"<\/soap:Envelope>\n\r"
]
},
"expected": {
"audit_log": "",
"debug_log": "\\[9\\] T \\(1\\) lowercase: \"test2\"",
"error_log": ""
},
"rules": [
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecRule ARGS \"@contains test \" \"pass,t:trim,t:lowercase\""
]
}
]

116
test/unit/unit.cc Normal file
View File

@@ -0,0 +1,116 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <string.h>
#include <ctime>
#include <iostream>
#include <string>
#include "modsecurity/modsecurity.h"
#include "modsecurity/rules.h"
#include "operators/operator.h"
#include "common/modsecurity_test.h"
#include "common/modsecurity_test_results.h"
#include "common/colors.h"
#include "unit/unit_test.h"
using modsecurity_test::UnitTest;
using modsecurity_test::ModSecurityTest;
using modsecurity_test::ModSecurityTestResults;
std::string default_test_path = "test-cases/secrules-language-tests/operators";
void print_help() {
#ifdef HAS_GETOPT
std::cout << "Use ./unit [--no-color] -t /path/to/test/files ";
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << " -h\t\tThis help message" << std::endl;
std::cout << " -v\t\tVerbose" << std::endl;
std::cout << " -c\t\tNo color" << std::endl;
std::cout << " -t\t\tPath to test cases" << std::endl;
#else
std::cout << "Use ./unit /path/to/file" << std::endl;
#endif
std::cout << std::endl;
std::cout << std::endl;
}
void perform_unit_test(UnitTest *t, ModSecurityTestResults<UnitTest>* res) {
ModSecurity::operators::Operator *op =
ModSecurity::operators::Operator::instantiate("\"@" + t->name + \
" " + t->param + "\"");
int ret = op->evaluate(NULL, t->input);
if (ret != t->ret) {
t->obtained = ret;
res->push_back(t);
}
}
int main(int argc, char **argv) {
int total = 0;
ModSecurityTest<UnitTest> test;
ModSecurityTestResults<UnitTest> results;
test.cmd_options(argc, argv);
std::cout << test.header();
test.load_tests();
for (std::pair<std::string, std::vector<UnitTest *> *> a : test) {
std::vector<UnitTest *> *tests = a.second;
total += tests->size();
for (UnitTest *t : *tests) {
ModSecurityTestResults<UnitTest> r;
std::cout << " " << a.first << "...\t";
perform_unit_test(t, &r);
if (r.size() == 0) {
std::cout << KGRN << r.size() << " tests failed.";
} else {
std::cout << KRED << r.size() << " tests failed.";
}
std::cout << RESET << std::endl;
results.insert(results.end(), r.begin(), r.end());
}
}
std::cout << "Total >> " << total << std::endl;
for (UnitTest *t : results) {
std::cout << t->print() << std::endl;
}
std::cout << std::endl;
std::cout << "Ran a total of: " << total << " unit tests - ";
if (results.size() == 0) {
std::cout << KGRN << "All tests passed" << RESET << std::endl;
} else {
std::cout << KRED << results.size() << " failed." << RESET << std::endl;
}
}

71
test/unit/unit_test.cc Normal file
View File

@@ -0,0 +1,71 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "unit/unit_test.h"
#include <string.h>
#include <sstream>
#include <string>
#include "common/colors.h"
namespace modsecurity_test {
std::string UnitTest::print() {
std::stringstream i;
i << KRED << "Test failed." << RESET;
i << " From: " << this->filename << std::endl;
i << "{" << std::endl;
i << " \"ret\": \"" << this->ret << "\"" << std::endl;
i << " \"type\": \"" << this->type << "\"" << std::endl;
i << " \"name\": \"" << this->name << "\"" << std::endl;
i << " \"input\": \"" << this->input << "\"" << std::endl;
i << " \"param\": \"" << this->param << "\"" << std::endl;
i << "}" << std::endl;
i << "Expecting: " << this->ret << " - operator returned: ";
i << this->obtained << std::endl;
return i.str();
}
UnitTest *UnitTest::from_yajl_node(yajl_val &node) {
size_t num_tests = node->u.object.len;
UnitTest *u = new UnitTest();
for (int i = 0; i < num_tests; i++) {
const char *key = node->u.object.keys[ i ];
yajl_val val = node->u.object.values[ i ];
if (strcmp(key, "param") == 0) {
u->param = YAJL_GET_STRING(val);
} else if (strcmp(key, "input") == 0) {
u->input = YAJL_GET_STRING(val);
} else if (strcmp(key, "name") == 0) {
u->name = YAJL_GET_STRING(val);
} else if (strcmp(key, "type") == 0) {
u->type = YAJL_GET_STRING(val);
} else if (strcmp(key, "ret") == 0) {
u->ret = YAJL_GET_INTEGER(val);
}
}
return u;
}
} // namespace modsecurity_test

45
test/unit/unit_test.h Normal file
View File

@@ -0,0 +1,45 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <yajl/yajl_tree.h>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#ifndef TEST_UNIT_UNIT_TEST_H_
#define TEST_UNIT_UNIT_TEST_H_
namespace modsecurity_test {
class UnitTest {
public:
static UnitTest *from_yajl_node(yajl_val &);
std::string print();
std::string param;
std::string input;
std::string name;
std::string type;
std::string filename;
int ret;
int obtained;
};
} // namespace modsecurity_test
#endif // TEST_UNIT_UNIT_TEST_H_