mirror of
https://github.com/openappsec/openappsec.git
synced 2025-06-28 16:41:02 +03:00
Feb 15th 2023 update
This commit is contained in:
parent
f7934cd09d
commit
6a9b33ff93
@ -78,12 +78,13 @@ Before compiling the services, you'll need to ensure the latest development vers
|
||||
* GTest
|
||||
* GMock
|
||||
* cURL
|
||||
* Python2
|
||||
|
||||
An example of installing the packages on Alpine:
|
||||
|
||||
```bash
|
||||
$ apk update
|
||||
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev
|
||||
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev python2
|
||||
```
|
||||
|
||||
## Compiling and packaging the agent code
|
||||
|
@ -1,6 +1,5 @@
|
||||
add_subdirectory(report_messaging)
|
||||
add_subdirectory(http_manager)
|
||||
add_subdirectory(http_transaction_data)
|
||||
add_subdirectory(generic_rulebase)
|
||||
add_subdirectory(signal_handler)
|
||||
add_subdirectory(gradual_deployment)
|
||||
|
@ -149,6 +149,7 @@ public:
|
||||
{
|
||||
dbgFlow(D_NGINX_ATTACHMENT) << "Initializing NGINX attachment";
|
||||
|
||||
i_env = Singleton::Consume<I_Environment>::by<NginxAttachment>();
|
||||
timer = Singleton::Consume<I_TimeGet>::by<NginxAttachment>();
|
||||
i_socket = Singleton::Consume<I_Socket>::by<NginxAttachment>();
|
||||
mainloop = Singleton::Consume<I_MainLoop>::by<NginxAttachment>();
|
||||
@ -156,6 +157,30 @@ public:
|
||||
i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
|
||||
inst_awareness = Singleton::Consume<I_InstanceAwareness>::by<NginxAttachment>();
|
||||
|
||||
auto agent_type = getSetting<string>("agentType");
|
||||
bool is_nsaas_env = false;
|
||||
if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) {
|
||||
is_nsaas_env = true;
|
||||
}
|
||||
|
||||
if (is_nsaas_env && inst_awareness->getFamilyID().ok()) {
|
||||
mainloop->addOneTimeRoutine(
|
||||
I_MainLoop::RoutineType::Offline,
|
||||
[this] ()
|
||||
{
|
||||
while (true) {
|
||||
if (!setActiveTenantAndProfile()) {
|
||||
mainloop->yield(std::chrono::seconds(2));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"Setting active tenant and profile for an NGINX based security app",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
metric_report_interval = chrono::seconds(
|
||||
getConfigurationWithDefault<uint>(
|
||||
METRIC_PERIODIC_TIMEOUT,
|
||||
@ -237,6 +262,73 @@ public:
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Successfully initialized NGINX Attachment";
|
||||
}
|
||||
|
||||
bool
|
||||
setActiveTenantAndProfile()
|
||||
{
|
||||
string container_id = inst_awareness->getFamilyID().unpack();
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Found a family ID: " << container_id;
|
||||
|
||||
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<NginxAttachment>();
|
||||
|
||||
string cmd =
|
||||
"docker inspect --format='{{.Name}}' " + container_id +
|
||||
" | awk -F'cp_nginx_gaia' '{print substr($2, index($2, \" \"))}'";
|
||||
auto maybe_tenant_id = shell_cmd->getExecOutput(cmd, 1000, false);
|
||||
|
||||
if (maybe_tenant_id.ok()) {
|
||||
|
||||
string tenant_id = *maybe_tenant_id;
|
||||
tenant_id.erase(remove(tenant_id.begin(), tenant_id.end(), '\n'), tenant_id.end());
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "The tenant ID found is :" << tenant_id;
|
||||
|
||||
static string region;
|
||||
if (region.empty()) {
|
||||
const char *env_region = getenv("CP_NSAAS_REGION");
|
||||
if (env_region) {
|
||||
region = env_region;
|
||||
} else {
|
||||
region = getProfileAgentSettingWithDefault<string>("eu-west-1", "accessControl.region");
|
||||
}
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Resolved region is " << region;
|
||||
}
|
||||
|
||||
string profile_id = Singleton::Consume<I_TenantManager>::by<NginxAttachment>()->getProfileId(
|
||||
tenant_id,
|
||||
region
|
||||
);
|
||||
|
||||
if (!profile_id.empty()) {
|
||||
i_env->setActiveTenantAndProfile(tenant_id, profile_id);
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "NGINX attachment setting active context. Tenant ID: "
|
||||
<< tenant_id
|
||||
<< ", Profile ID: "
|
||||
<< profile_id
|
||||
<< ", Region: "
|
||||
<< region;
|
||||
return true;
|
||||
} else {
|
||||
dbgWarning(D_NGINX_ATTACHMENT)
|
||||
<< "Received an empty profile ID. Tenant ID: "
|
||||
<< tenant_id
|
||||
<< ", Region: "
|
||||
<< region;
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
dbgWarning(D_NGINX_ATTACHMENT)
|
||||
<< "Failed getting the tenant ID: "
|
||||
<< cmd
|
||||
<< ". Error :"
|
||||
<< maybe_tenant_id.getErr();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
fini()
|
||||
{
|
||||
@ -1714,6 +1806,7 @@ private:
|
||||
I_Socket *i_socket = nullptr;
|
||||
I_TimeGet *timer = nullptr;
|
||||
I_MainLoop *mainloop = nullptr;
|
||||
I_Environment *i_env = nullptr;
|
||||
I_HttpManager *http_manager = nullptr;
|
||||
I_InstanceAwareness *inst_awareness = nullptr;
|
||||
I_TableSpecific<SessionID> *i_transaction_table = nullptr;
|
||||
@ -1750,6 +1843,7 @@ void
|
||||
NginxAttachment::preload()
|
||||
{
|
||||
pimpl->preload();
|
||||
registerExpectedSetting<string>("agentType");
|
||||
registerExpectedConfiguration<bool>("HTTP manager", "Container mode");
|
||||
registerExpectedConfiguration<uint>("HTTP manager", "Shared memory segment size in KB");
|
||||
registerExpectedConfiguration<string>("HTTP manager", "Nginx permission");
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
string AssetMatcher::ctx_key = "asset_id";
|
||||
|
||||
AssetMatcher::AssetMatcher(const vector<string> ¶ms)
|
||||
@ -36,5 +38,15 @@ AssetMatcher::evalVariable() const
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>();
|
||||
auto bc_asset_id_ctx = env->get<GenericConfigId>(AssetMatcher::ctx_key);
|
||||
|
||||
if (bc_asset_id_ctx.ok()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Asset ID: "
|
||||
<< asset_id
|
||||
<< "; Current set assetId context: "
|
||||
<< *bc_asset_id_ctx;
|
||||
} else {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Asset ID: " << asset_id << ". Empty context";
|
||||
}
|
||||
|
||||
return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id;
|
||||
}
|
||||
|
@ -95,6 +95,8 @@ MatchQuery::load(cereal::JSONInputArchive &archive_in)
|
||||
is_specific_label = false;
|
||||
}
|
||||
}
|
||||
is_ignore_keyword = (key == "indicator");
|
||||
|
||||
if (condition_type != Conditions::Exist) {
|
||||
archive_in(cereal::make_nvp("value", value));
|
||||
for(const auto &val: value) {
|
||||
@ -221,23 +223,34 @@ MatchQuery::getAllKeys() const
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
MatchQuery::matchAttributes(
|
||||
const unordered_map<string, set<string>> &key_value_pairs,
|
||||
set<string> &matched_override_keywords ) const
|
||||
{
|
||||
|
||||
if (type == MatchType::Condition) {
|
||||
auto key_value_pair = key_value_pairs.find(key);
|
||||
if (key_value_pair == key_value_pairs.end()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key;
|
||||
return false;
|
||||
}
|
||||
return matchAttributes(key_value_pair->second);
|
||||
return matchAttributes(key_value_pair->second, matched_override_keywords);
|
||||
} else if (type == MatchType::Operator && operator_type == Operators::And) {
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
if (!inner_match.matchAttributes(key_value_pairs)) return false;
|
||||
if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (type == MatchType::Operator && operator_type == Operators::Or) {
|
||||
// With 'or' condition, evaluate matched override keywords first and add the ones that were fully matched
|
||||
set<string> inner_override_keywords;
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
if (inner_match.matchAttributes(key_value_pairs)) return true;
|
||||
inner_override_keywords.clear();
|
||||
if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords)) {
|
||||
matched_override_keywords.insert(inner_override_keywords.begin(), inner_override_keywords.end());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
@ -246,18 +259,39 @@ MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_
|
||||
return false;
|
||||
}
|
||||
|
||||
MatchQuery::MatchResult
|
||||
MatchQuery::getMatch( const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
{
|
||||
MatchQuery::MatchResult matches;
|
||||
matches.matched_keywords = make_shared<set<string>>();
|
||||
matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords);
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(const set<string> &values) const
|
||||
MatchQuery::matchAttributes(
|
||||
const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
{
|
||||
return getMatch(key_value_pairs).is_match;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(
|
||||
const set<string> &values,
|
||||
set<string> &matched_override_keywords) const
|
||||
{
|
||||
auto &type = condition_type;
|
||||
bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn;
|
||||
bool match = isRegEx() ? matchAttributesRegEx(values) : matchAttributesString(values);
|
||||
bool match = isRegEx() ? matchAttributesRegEx(values, matched_override_keywords) : matchAttributesString(values);
|
||||
return negate ? !match : match;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributesRegEx(const set<string> &values) const
|
||||
MatchQuery::matchAttributesRegEx(
|
||||
const set<string> &values,
|
||||
set<string> &matched_override_keywords) const
|
||||
{
|
||||
bool res = false;
|
||||
boost::cmatch value_matcher;
|
||||
for (const boost::regex &val_regex : regex_values) {
|
||||
for (const string &requested_match_value : values) {
|
||||
@ -268,11 +302,16 @@ MatchQuery::matchAttributesRegEx(const set<string> &values) const
|
||||
value_matcher,
|
||||
val_regex))
|
||||
{
|
||||
return true;
|
||||
res = true;
|
||||
if (is_ignore_keyword) {
|
||||
matched_override_keywords.insert(requested_match_value);
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -108,19 +108,50 @@ ParameterException::load(cereal::JSONInputArchive &archive_in)
|
||||
}
|
||||
|
||||
set<ParameterBehavior>
|
||||
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
ParameterException::getBehavior(
|
||||
const unordered_map<string, set<string>> &key_value_pairs,
|
||||
set<string> &matched_override_keywords) const
|
||||
{
|
||||
set<ParameterBehavior> matched_behaviors;
|
||||
|
||||
matched_override_keywords.clear();
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
|
||||
for (const MatchBehaviorPair &match_behavior_pair: match_queries) {
|
||||
if (match_behavior_pair.match.matchAttributes(key_value_pairs)) {
|
||||
MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs);
|
||||
if (match_res.is_match) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches.";
|
||||
matched_behaviors.insert(match_behavior_pair.behavior);
|
||||
// When matching indicators with action=ignore, we expect no behavior override.
|
||||
// Instead, a matched keywords list should be returned which will be later removed from score calculation
|
||||
if (match_res.matched_keywords->size() > 0 && match_behavior_pair.behavior == action_ignore) {
|
||||
matched_override_keywords.insert(match_res.matched_keywords->begin(),
|
||||
match_res.matched_keywords->end());
|
||||
} else {
|
||||
matched_behaviors.insert(match_behavior_pair.behavior);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match_queries.empty() && match.matchAttributes(key_value_pairs)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
|
||||
matched_behaviors.insert(behavior);
|
||||
|
||||
if (match_queries.empty()) {
|
||||
MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs);
|
||||
if (match_res.is_match) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
|
||||
// When matching indicators with action=ignore, we expect no behavior override.
|
||||
// Instead, a matched keywords list should be returned which will be later removed from score calculation
|
||||
if (match_res.matched_keywords->size() > 0 && behavior == action_ignore) {
|
||||
matched_override_keywords.insert(match_res.matched_keywords->begin(),
|
||||
match_res.matched_keywords->end());
|
||||
} else {
|
||||
matched_behaviors.insert(behavior);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matched_behaviors;
|
||||
}
|
||||
|
||||
set<ParameterBehavior>
|
||||
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
{
|
||||
set<string> keywords;
|
||||
return getBehavior(key_value_pairs, keywords);
|
||||
}
|
||||
|
@ -124,16 +124,36 @@ setTriggersFlag(const string &key, cereal::JSONInputArchive &ar, EnumClass flag,
|
||||
}
|
||||
|
||||
static void
|
||||
setLogConfiguration(const ReportIS::StreamType &log_type, const string &log_server_url = "")
|
||||
setLogConfiguration(
|
||||
const ReportIS::StreamType &log_type,
|
||||
const string &log_server_url = "",
|
||||
const string &protocol = ""
|
||||
)
|
||||
{
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url;
|
||||
if (log_server_url != "") {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url);
|
||||
if (log_server_url != "" && protocol != "") {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url, protocol);
|
||||
} else {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type);
|
||||
}
|
||||
}
|
||||
|
||||
static string
|
||||
parseProtocolWithDefault(
|
||||
const std::string &default_value,
|
||||
const std::string &key_name,
|
||||
cereal::JSONInputArchive &archive_in
|
||||
)
|
||||
{
|
||||
string value;
|
||||
try {
|
||||
archive_in(cereal::make_nvp(key_name, value));
|
||||
} catch (const cereal::Exception &e) {
|
||||
return default_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
|
||||
{
|
||||
@ -142,6 +162,9 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
|
||||
parseJSONKey<string>("verbosity", verbosity, archive_in);
|
||||
parseJSONKey<string>("urlForSyslog", url_for_syslog, archive_in);
|
||||
parseJSONKey<string>("urlForCef", url_for_cef, archive_in);
|
||||
parseJSONKey<string>("syslogProtocol", syslog_protocol, archive_in);
|
||||
syslog_protocol = parseProtocolWithDefault("UDP", "syslogProtocol", archive_in);
|
||||
cef_protocol = parseProtocolWithDefault("UDP", "cefProtocol", archive_in);
|
||||
|
||||
setTriggersFlag("webBody", archive_in, WebLogFields::webBody, log_web_fields);
|
||||
setTriggersFlag("webHeaders", archive_in, WebLogFields::webHeaders, log_web_fields);
|
||||
@ -197,11 +220,14 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
|
||||
case ReportIS::StreamType::JSON_LOG_FILE:
|
||||
setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE);
|
||||
break;
|
||||
case ReportIS::StreamType::JSON_K8S_SVC:
|
||||
setLogConfiguration(ReportIS::StreamType::JSON_K8S_SVC);
|
||||
break;
|
||||
case ReportIS::StreamType::SYSLOG:
|
||||
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog());
|
||||
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog(), syslog_protocol);
|
||||
break;
|
||||
case ReportIS::StreamType::CEF:
|
||||
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef());
|
||||
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef(), cef_protocol);
|
||||
break;
|
||||
case ReportIS::StreamType::NONE: break;
|
||||
case ReportIS::StreamType::COUNT: break;
|
||||
|
@ -48,6 +48,7 @@ enum ParamType {
|
||||
HTML_PARAM_TYPE,
|
||||
URL_PARAM_TYPE,
|
||||
FREE_TEXT_PARAM_TYPE,
|
||||
FREE_TEXT_FRENCH_PARAM_TYPE,
|
||||
PIPE_PARAM_TYPE,
|
||||
LONG_RANDOM_TEXT_PARAM_TYPE,
|
||||
BASE64_PARAM_TYPE,
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "cereal/types/string.hpp"
|
||||
@ -45,6 +46,13 @@ public:
|
||||
Domain,
|
||||
NotStatic
|
||||
};
|
||||
struct MatchResult
|
||||
{
|
||||
bool is_match;
|
||||
std::shared_ptr<std::set<std::string>> matched_keywords;
|
||||
};
|
||||
|
||||
MatchQuery(): is_specific_label(false), is_ignore_keyword(false) {}
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
@ -58,6 +66,7 @@ public:
|
||||
const std::vector<IpProtoRange> & getProtoValue() const { return ip_proto_value; }
|
||||
const std::vector<MatchQuery> & getItems() const { return items; }
|
||||
std::string getFirstValue() const { return first_value; }
|
||||
MatchResult getMatch(const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs) const;
|
||||
bool matchAttributes(const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs) const;
|
||||
bool matchException(const std::string &behaviorKey, const std::string &behaviorValue) const;
|
||||
bool isKeyTypeIp() const;
|
||||
@ -69,9 +78,14 @@ public:
|
||||
std::set<std::string> getAllKeys() const;
|
||||
|
||||
private:
|
||||
bool matchAttributes(
|
||||
const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs,
|
||||
std::set<std::string> &matched_override_keywords) const;
|
||||
StaticKeys getKeyByName(const std::string &key_type_name);
|
||||
bool matchAttributes(const std::set<std::string> &values) const;
|
||||
bool matchAttributesRegEx(const std::set<std::string> &values) const;
|
||||
bool matchAttributes(const std::set<std::string> &values,
|
||||
std::set<std::string> &matched_override_keywords) const;
|
||||
bool matchAttributesRegEx(const std::set<std::string> &values,
|
||||
std::set<std::string> &matched_override_keywords) const;
|
||||
bool matchAttributesString(const std::set<std::string> &values) const;
|
||||
bool isRegEx() const;
|
||||
|
||||
@ -88,6 +102,7 @@ private:
|
||||
std::vector<PortsRange> port_value;
|
||||
std::vector<IpProtoRange> ip_proto_value;
|
||||
std::vector<MatchQuery> items;
|
||||
bool is_ignore_keyword;
|
||||
};
|
||||
|
||||
#endif // __MATCH_QUERY_H__
|
||||
|
@ -200,6 +200,11 @@ public:
|
||||
std::set<ParameterBehavior>
|
||||
getBehavior(const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs) const;
|
||||
|
||||
std::set<ParameterBehavior>
|
||||
getBehavior(
|
||||
const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs,
|
||||
std::set<std::string> &matched_override_keywords) const;
|
||||
|
||||
static bool isGeoLocationExceptionExists() { return is_geo_location_exception_exists; }
|
||||
|
||||
private:
|
||||
@ -218,4 +223,6 @@ private:
|
||||
static bool is_geo_location_exception_being_loaded;
|
||||
};
|
||||
|
||||
static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE);
|
||||
|
||||
#endif //__PARAMETERS_CONFIG_H__
|
||||
|
@ -160,8 +160,10 @@ private:
|
||||
|
||||
std::string name;
|
||||
std::string verbosity;
|
||||
std::string url_for_syslog = "";
|
||||
std::string url_for_cef = "";
|
||||
std::string url_for_syslog = "UDP";
|
||||
std::string url_for_cef = "UDP";
|
||||
std::string syslog_protocol = "";
|
||||
std::string cef_protocol = "";
|
||||
Flags<ReportIS::StreamType> active_streams;
|
||||
Flags<SecurityType> should_log_on_detect;
|
||||
Flags<SecurityType> should_log_on_prevent;
|
||||
|
@ -42,7 +42,8 @@ public:
|
||||
const std::string &new_settings_path,
|
||||
const std::vector<std::string> &new_data_files = {},
|
||||
const std::string &tenant_id = "",
|
||||
const std::string &profile_id = ""
|
||||
const std::string &profile_id = "",
|
||||
const bool last_iteration = false
|
||||
) = 0;
|
||||
|
||||
virtual bool isServiceInstalled(const std::string &service_name) = 0;
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include "i_http_manager.h"
|
||||
#include "i_static_resources_handler.h"
|
||||
#include "i_socket_is.h"
|
||||
#include "i_environment.h"
|
||||
#include "i_shell_cmd.h"
|
||||
#include "i_tenant_manager.h"
|
||||
#include "transaction_table_metric.h"
|
||||
#include "nginx_attachment_metric.h"
|
||||
#include "nginx_intaker_metric.h"
|
||||
@ -38,7 +41,10 @@ class NginxAttachment
|
||||
Singleton::Consume<I_HttpManager>,
|
||||
Singleton::Consume<I_TimeGet>,
|
||||
Singleton::Consume<I_Socket>,
|
||||
Singleton::Consume<I_InstanceAwareness>
|
||||
Singleton::Consume<I_InstanceAwareness>,
|
||||
Singleton::Consume<I_Environment>,
|
||||
Singleton::Consume<I_ShellCmd>,
|
||||
Singleton::Consume<I_TenantManager>
|
||||
{
|
||||
public:
|
||||
NginxAttachment();
|
||||
|
@ -28,15 +28,18 @@ ReportMessaging::~ReportMessaging()
|
||||
LogRest log_rest(report);
|
||||
|
||||
auto messaging = Singleton::Consume<I_Messaging>::by<ReportMessaging>();
|
||||
messaging->sendObjectWithPersistence(
|
||||
log_rest,
|
||||
I_Messaging::Method::POST,
|
||||
url,
|
||||
"",
|
||||
true,
|
||||
message_type_tag,
|
||||
is_async_message
|
||||
);
|
||||
try {
|
||||
messaging->sendObjectWithPersistence(
|
||||
log_rest,
|
||||
I_Messaging::Method::POST,
|
||||
url,
|
||||
"",
|
||||
true,
|
||||
message_type_tag,
|
||||
is_async_message
|
||||
);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
ReportMessaging &
|
||||
|
@ -28,14 +28,15 @@ public:
|
||||
|
||||
MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &());
|
||||
|
||||
MOCK_METHOD5(
|
||||
MOCK_METHOD6(
|
||||
updateServiceConfiguration,
|
||||
bool(
|
||||
const std::string &new_policy_path,
|
||||
const std::string &new_settings_path,
|
||||
const std::vector<std::string> &new_data_files,
|
||||
const std::string &tenant_id,
|
||||
const std::string &profile_id
|
||||
const std::string &profile_id,
|
||||
const bool last_iteration
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1 +1,3 @@
|
||||
add_library(local_policy_mgmt_gen local_policy_mgmt_gen.cc)
|
||||
include_directories(include)
|
||||
|
||||
add_library(local_policy_mgmt_gen appsec_practice_section.cc exceptions_section.cc ingress_data.cc local_policy_mgmt_gen.cc policy_maker_utils.cc rules_config_section.cc settings_section.cc snort_section.cc triggers_section.cc trusted_sources_section.cc)
|
||||
|
@ -0,0 +1,571 @@
|
||||
#include "appsec_practice_section.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
void
|
||||
AppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots URI";
|
||||
parseAppsecJSONKey<string>("uri", uri, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecWebBotsURI::getURI() const
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
void
|
||||
AppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots";
|
||||
parseAppsecJSONKey<vector<AppSecWebBotsURI>>("injected-URIs", injected_uris, archive_in);
|
||||
parseAppsecJSONKey<vector<AppSecWebBotsURI>>("validated-URIs", validated_uris, archive_in);
|
||||
parseAppsecJSONKey<string>("override-mode", override_mode, archive_in, "Inactive");
|
||||
}
|
||||
|
||||
void
|
||||
AppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
vector<string> injected;
|
||||
vector<string> validated;
|
||||
for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
|
||||
for (const AppSecWebBotsURI &uri : validated_uris) injected.push_back(uri.getURI());
|
||||
out_ar(
|
||||
cereal::make_nvp("injected", injected),
|
||||
cereal::make_nvp("validated", validated)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
AppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Attack Protections";
|
||||
parseAppsecJSONKey<string>("csrf-enabled", csrf_protection, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("error-disclosure-enabled", error_disclosure, archive_in, "inactive");
|
||||
parseAppsecJSONKey<string>("open-redirect-enabled", open_redirect, archive_in, "inactive");
|
||||
parseAppsecJSONKey<bool>("non-valid-http-methods", non_valid_http_methods, archive_in, false);
|
||||
}
|
||||
|
||||
const string
|
||||
AppSecWebAttackProtections::getCsrfProtectionMode() const
|
||||
{
|
||||
if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) {
|
||||
dbgError(D_K8S_POLICY)
|
||||
<< "Failed to find a value for "
|
||||
<< csrf_protection
|
||||
<< ". Setting CSRF protection to Inactive";
|
||||
return "Inactive";
|
||||
}
|
||||
return key_to_practices_val.at(csrf_protection);
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecWebAttackProtections::getErrorDisclosureMode() const
|
||||
{
|
||||
return error_disclosure;
|
||||
}
|
||||
|
||||
bool
|
||||
AppSecWebAttackProtections::getNonValidHttpMethods() const
|
||||
{
|
||||
return non_valid_http_methods;
|
||||
}
|
||||
|
||||
const string
|
||||
AppSecWebAttackProtections::getOpenRedirectMode() const
|
||||
{
|
||||
if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) {
|
||||
dbgError(D_K8S_POLICY)
|
||||
<< "Failed to find a value for "
|
||||
<< open_redirect
|
||||
<< ". Setting Open Redirect mode to Inactive";
|
||||
return "Inactive";
|
||||
}
|
||||
return key_to_practices_val.at(open_redirect);
|
||||
}
|
||||
|
||||
void
|
||||
AppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec";
|
||||
parseAppsecJSONKey<AppSecWebAttackProtections>("protections", protections, archive_in);
|
||||
if (getMode() == "Prevent") {
|
||||
parseAppsecJSONKey<string>("minimum-confidence", minimum_confidence, archive_in, "critical");
|
||||
} else {
|
||||
minimum_confidence = "Transparent";
|
||||
}
|
||||
parseAppsecJSONKey<string>("override-mode", mode, archive_in, "Unset");
|
||||
parseAppsecJSONKey<int>("max-body-size-kb", max_body_size_kb, archive_in, 1000000);
|
||||
parseAppsecJSONKey<int>("max-header-size-bytes", max_header_size_bytes, archive_in, 102400);
|
||||
parseAppsecJSONKey<int>("max-object-depth", max_object_depth, archive_in, 40);
|
||||
parseAppsecJSONKey<int>("max-url-size-bytes", max_url_size_bytes, archive_in, 32768);
|
||||
}
|
||||
|
||||
int
|
||||
AppSecPracticeWebAttacks::getMaxBodySizeKb() const
|
||||
{
|
||||
return max_body_size_kb;
|
||||
}
|
||||
|
||||
int
|
||||
AppSecPracticeWebAttacks::getMaxHeaderSizeBytes() const
|
||||
{
|
||||
return max_header_size_bytes;
|
||||
}
|
||||
|
||||
int
|
||||
AppSecPracticeWebAttacks::getMaxObjectDepth() const
|
||||
{
|
||||
return max_object_depth;
|
||||
}
|
||||
|
||||
int
|
||||
AppSecPracticeWebAttacks::getMaxUrlSizeBytes() const
|
||||
{
|
||||
return max_url_size_bytes;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecPracticeWebAttacks::getMinimumConfidence() const
|
||||
{
|
||||
return minimum_confidence;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecPracticeWebAttacks::getMode(const string &default_mode) const
|
||||
{
|
||||
if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) {
|
||||
dbgError(D_K8S_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode;
|
||||
return default_mode;
|
||||
}
|
||||
return key_to_practices_val.at(mode);
|
||||
}
|
||||
|
||||
void
|
||||
AppSecPracticeSnortSignatures::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Snort Signatures practice";
|
||||
parseAppsecJSONKey<string>("override-mode", override_mode, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<vector<string>>("configmap", config_map, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecPracticeSnortSignatures::getOverrideMode() const
|
||||
{
|
||||
return override_mode;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppSecPracticeSnortSignatures::getConfigMap() const
|
||||
{
|
||||
return config_map;
|
||||
}
|
||||
|
||||
void
|
||||
AppSecPracticeOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSecPracticeOpenSchemaAPI practice";
|
||||
parseAppsecJSONKey<string>("override-mode", override_mode, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<vector<string>>("configmap", config_map, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecPracticeOpenSchemaAPI::getOverrideMode() const
|
||||
{
|
||||
return override_mode;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppSecPracticeOpenSchemaAPI::getConfigMap() const
|
||||
{
|
||||
return config_map;
|
||||
}
|
||||
|
||||
void
|
||||
AppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec";
|
||||
parseAppsecJSONKey<AppSecPracticeOpenSchemaAPI>(
|
||||
"openapi-schema-validation",
|
||||
openapi_schema_validation,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<AppSecPracticeSnortSignatures>("snort-signatures", snort_signatures, archive_in);
|
||||
parseAppsecJSONKey<AppSecPracticeWebAttacks>("web-attacks", web_attacks, archive_in);
|
||||
parseAppsecJSONKey<AppSecPracticeAntiBot>("anti-bot", anti_bot, archive_in);
|
||||
parseAppsecJSONKey<string>("name", practice_name, archive_in);
|
||||
}
|
||||
|
||||
const AppSecPracticeOpenSchemaAPI &
|
||||
AppSecPracticeSpec::getOpenSchemaValidation() const
|
||||
{
|
||||
return openapi_schema_validation;
|
||||
}
|
||||
|
||||
const AppSecPracticeSnortSignatures &
|
||||
AppSecPracticeSpec::getSnortSignatures() const
|
||||
{
|
||||
return snort_signatures;
|
||||
}
|
||||
|
||||
const AppSecPracticeWebAttacks &
|
||||
AppSecPracticeSpec::getWebAttacks() const
|
||||
{
|
||||
return web_attacks;
|
||||
}
|
||||
|
||||
const AppSecPracticeAntiBot &
|
||||
AppSecPracticeSpec::getAntiBot() const
|
||||
{
|
||||
return anti_bot;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecPracticeSpec::getName() const
|
||||
{
|
||||
return practice_name;
|
||||
}
|
||||
|
||||
void
|
||||
PracticeAdvancedConfig::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("httpHeaderMaxSize", http_header_max_size),
|
||||
cereal::make_nvp("httpIllegalMethodsAllowed", http_illegal_methods_allowed),
|
||||
cereal::make_nvp("httpRequestBodyMaxSize", http_request_body_max_size),
|
||||
cereal::make_nvp("jsonMaxObjectDepth", json_max_object_depth),
|
||||
cereal::make_nvp("urlMaxSize", url_max_size)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
TriggersInWaapSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("$triggerType", trigger_type),
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("log", log)
|
||||
);
|
||||
}
|
||||
|
||||
AppSecOverride::AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources)
|
||||
{
|
||||
string source_ident = parsed_trusted_sources.getSourceIdent();
|
||||
map<string, string> behavior = {{"httpSourceId", source_ident}};
|
||||
parsed_behavior.push_back(behavior);
|
||||
parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}};
|
||||
}
|
||||
|
||||
void
|
||||
AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string parameter_type = "TrustedSource";
|
||||
out_ar(
|
||||
cereal::make_nvp("parsedBehavior", parsed_behavior),
|
||||
cereal::make_nvp("parsedMatch", parsed_match)
|
||||
);
|
||||
}
|
||||
|
||||
WebAppSection::WebAppSection(
|
||||
const string &_application_urls,
|
||||
const string &_asset_id,
|
||||
const string &_asset_name,
|
||||
const string &_rule_id,
|
||||
const string &_rule_name,
|
||||
const string &_practice_id,
|
||||
const string &_practice_name,
|
||||
const AppSecPracticeSpec &parsed_appsec_spec,
|
||||
const LogTriggerSection &parsed_log_trigger,
|
||||
const string &default_mode,
|
||||
const AppSecTrustedSources &parsed_trusted_sources)
|
||||
:
|
||||
application_urls(_application_urls),
|
||||
asset_id(_asset_id),
|
||||
asset_name(_asset_name),
|
||||
rule_id(_rule_id),
|
||||
rule_name(_rule_name),
|
||||
practice_id(_practice_id),
|
||||
practice_name(_practice_name),
|
||||
context("practiceId(" + practice_id +")"),
|
||||
web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()),
|
||||
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
|
||||
practice_advanced_config(parsed_appsec_spec),
|
||||
anti_bots(parsed_appsec_spec.getAntiBot()),
|
||||
trusted_sources({parsed_trusted_sources})
|
||||
{
|
||||
web_attack_mitigation = true;
|
||||
web_attack_mitigation_action =
|
||||
web_attack_mitigation_severity == "critical" ? "low" :
|
||||
web_attack_mitigation_severity == "high" ? "balanced" :
|
||||
web_attack_mitigation_severity == "medium" ? "high" :
|
||||
"Error";
|
||||
|
||||
triggers.push_back(TriggersInWaapSection(parsed_log_trigger));
|
||||
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
|
||||
overrides.push_back(AppSecOverride(source_ident));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebAppSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string disabled_str = "Disabled";
|
||||
string detect_str = "Detect";
|
||||
vector<string> empty_list;
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("webAttackMitigation", web_attack_mitigation),
|
||||
cereal::make_nvp("webAttackMitigationSeverity", web_attack_mitigation_severity),
|
||||
cereal::make_nvp("webAttackMitigationAction", web_attack_mitigation_action),
|
||||
cereal::make_nvp("webAttackMitigationMode", web_attack_mitigation_mode),
|
||||
cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config),
|
||||
cereal::make_nvp("csrfProtection", disabled_str),
|
||||
cereal::make_nvp("openRedirect", disabled_str),
|
||||
cereal::make_nvp("errorDisclosure", disabled_str),
|
||||
cereal::make_nvp("practiceId", practice_id),
|
||||
cereal::make_nvp("practiceName", practice_name),
|
||||
cereal::make_nvp("assetId", asset_id),
|
||||
cereal::make_nvp("assetName", asset_name),
|
||||
cereal::make_nvp("ruleId", rule_id),
|
||||
cereal::make_nvp("ruleName", rule_name),
|
||||
cereal::make_nvp("triggers", triggers),
|
||||
cereal::make_nvp("applicationUrls", application_urls),
|
||||
cereal::make_nvp("overrides", overrides),
|
||||
cereal::make_nvp("trustedSources", trusted_sources),
|
||||
cereal::make_nvp("waapParameters", empty_list),
|
||||
cereal::make_nvp("botProtection", false),
|
||||
cereal::make_nvp("antiBot", anti_bots),
|
||||
cereal::make_nvp("botProtection_v2", detect_str)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
WebAppSection::getPracticeId() const
|
||||
{
|
||||
return practice_id;
|
||||
}
|
||||
|
||||
bool
|
||||
WebAppSection::operator<(const WebAppSection &other) const
|
||||
{
|
||||
return getPracticeId() < other.getPracticeId();
|
||||
}
|
||||
|
||||
void
|
||||
WebAPISection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string disabled_str = "Disabled";
|
||||
vector<string> empty_list;
|
||||
out_ar(
|
||||
cereal::make_nvp("application_urls", application_urls),
|
||||
cereal::make_nvp("asset_id", asset_id),
|
||||
cereal::make_nvp("asset_name", asset_name),
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config),
|
||||
cereal::make_nvp("practice_id", practice_id),
|
||||
cereal::make_nvp("practice_name", practice_name),
|
||||
cereal::make_nvp("ruleId", rule_id),
|
||||
cereal::make_nvp("ruleName", rule_name),
|
||||
cereal::make_nvp("schemaValidation", false),
|
||||
cereal::make_nvp("schemaValidation_v2", disabled_str),
|
||||
cereal::make_nvp("web_attack_mitigation", web_attack_mitigation),
|
||||
cereal::make_nvp("web_attack_mitigation_action", web_attack_mitigation_action),
|
||||
cereal::make_nvp("web_attack_mitigation_severity", web_attack_mitigation_severity),
|
||||
cereal::make_nvp("web_attack_mitigation_mode", web_attack_mitigation_mode),
|
||||
cereal::make_nvp("oas", empty_list),
|
||||
cereal::make_nvp("trustedSources", empty_list),
|
||||
cereal::make_nvp("triggers", empty_list),
|
||||
cereal::make_nvp("waapParameters", empty_list),
|
||||
cereal::make_nvp("overrides", empty_list)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
WebAPISection::getPracticeId() const
|
||||
{
|
||||
return practice_id;
|
||||
}
|
||||
|
||||
void
|
||||
AppSecRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("WebAPISecurity", webAPIPractices),
|
||||
cereal::make_nvp("WebApplicationSecurity", webApplicationPractices)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
AppSecWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(cereal::make_nvp("WAAP", app_sec_rulebase));
|
||||
}
|
||||
|
||||
void
|
||||
ParsedRule::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec ParsedRule";
|
||||
parseAppsecJSONKey<vector<string>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("triggers", log_triggers, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("practices", practices, archive_in);
|
||||
parseAppsecJSONKey<string>("mode", mode, archive_in);
|
||||
parseAppsecJSONKey<string>("custom-response", custom_response, archive_in);
|
||||
parseAppsecJSONKey<string>("source-identifiers", source_identifiers, archive_in);
|
||||
parseAppsecJSONKey<string>("trusted-sources", trusted_sources, archive_in);
|
||||
try {
|
||||
archive_in(cereal::make_nvp("host", host));
|
||||
} catch (const cereal::Exception &e)
|
||||
{} // The default ParsedRule does not hold a host, so no error handling
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
ParsedRule::getExceptions() const
|
||||
{
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
ParsedRule::getLogTriggers() const
|
||||
{
|
||||
return log_triggers;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
ParsedRule::getPractices() const
|
||||
{
|
||||
return practices;
|
||||
}
|
||||
|
||||
const string &
|
||||
ParsedRule::getHost() const
|
||||
{
|
||||
return host;
|
||||
}
|
||||
|
||||
const string &
|
||||
ParsedRule::getMode() const
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
|
||||
void
|
||||
ParsedRule::setHost(const string &_host)
|
||||
{
|
||||
host = _host;
|
||||
}
|
||||
|
||||
void
|
||||
ParsedRule::setMode(const string &_mode)
|
||||
{
|
||||
mode = _mode;
|
||||
}
|
||||
|
||||
const string &
|
||||
ParsedRule::getCustomResponse() const
|
||||
{
|
||||
return custom_response;
|
||||
}
|
||||
|
||||
const string &
|
||||
ParsedRule::getSourceIdentifiers() const
|
||||
{
|
||||
return source_identifiers;
|
||||
}
|
||||
|
||||
const string &
|
||||
ParsedRule::getTrustedSources() const
|
||||
{
|
||||
return trusted_sources;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecPolicySpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec";
|
||||
parseAppsecJSONKey<ParsedRule>("default", default_rule, archive_in);
|
||||
auto default_mode_annot =
|
||||
Singleton::Consume<I_Environment>::by<AppsecPolicySpec>()->get<string>("default mode annotation");
|
||||
if (default_mode_annot.ok() && !default_mode_annot.unpack().empty() && default_rule.getMode().empty()) {
|
||||
default_rule.setMode(default_mode_annot.unpack());
|
||||
}
|
||||
default_rule.setHost("*");
|
||||
parseAppsecJSONKey<list<ParsedRule>>("specific-rules", specific_rules, archive_in);
|
||||
specific_rules.push_front(default_rule);
|
||||
}
|
||||
|
||||
const ParsedRule &
|
||||
AppsecPolicySpec::getDefaultRule() const
|
||||
{
|
||||
return default_rule;
|
||||
}
|
||||
|
||||
const list<ParsedRule> &
|
||||
AppsecPolicySpec::getSpecificRules() const
|
||||
{
|
||||
return specific_rules;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading Appsec Linux Policy";
|
||||
parseAppsecJSONKey<AppsecPolicySpec>("policies", policies, archive_in);
|
||||
parseAppsecJSONKey<vector<AppSecPracticeSpec>>("practices", practices, archive_in);
|
||||
parseAppsecJSONKey<vector<AppsecTriggerSpec>>("log-triggers", log_triggers, archive_in);
|
||||
parseAppsecJSONKey<vector<AppSecCustomResponseSpec>>("custom-responses", custom_responses, archive_in);
|
||||
parseAppsecJSONKey<vector<AppsecExceptionSpec>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<vector<TrustedSourcesSpec>>("trusted-sources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<vector<SourceIdentifierSpecWrapper>>(
|
||||
"source-identifier",
|
||||
sources_identifier,
|
||||
archive_in
|
||||
);
|
||||
}
|
||||
|
||||
const AppsecPolicySpec &
|
||||
AppsecLinuxPolicy::getAppsecPolicySpec() const
|
||||
{
|
||||
return policies;
|
||||
}
|
||||
|
||||
const vector<AppSecPracticeSpec> &
|
||||
AppsecLinuxPolicy::getAppSecPracticeSpecs() const
|
||||
{
|
||||
return practices;
|
||||
}
|
||||
|
||||
const vector<AppsecTriggerSpec> &
|
||||
AppsecLinuxPolicy::getAppsecTriggerSpecs() const
|
||||
{
|
||||
return log_triggers;
|
||||
}
|
||||
|
||||
const vector<AppSecCustomResponseSpec> &
|
||||
AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
|
||||
{
|
||||
return custom_responses;
|
||||
}
|
||||
|
||||
const vector<AppsecExceptionSpec> &
|
||||
AppsecLinuxPolicy::getAppsecExceptionSpecs() const
|
||||
{
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
const vector<TrustedSourcesSpec> &
|
||||
AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const
|
||||
{
|
||||
return trusted_sources;
|
||||
}
|
||||
|
||||
const vector<SourceIdentifierSpecWrapper> &
|
||||
AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
|
||||
{
|
||||
return sources_identifier;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
@ -0,0 +1,242 @@
|
||||
#include "exceptions_section.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
void
|
||||
AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec exception spec";
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<string>("action", action, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("countryCode", country_code, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("countryName", country_name, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("hostName", host_name, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("paramName", param_name, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("paramValue", param_value, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("protectionName", protection_name, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("sourceIdentifier", source_identifier, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("sourceIp", source_ip, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("url", url, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
AppsecExceptionSpec::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppsecExceptionSpec::getAction() const
|
||||
{
|
||||
return action;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getCountryCode() const
|
||||
{
|
||||
return country_code;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getCountryName() const
|
||||
{
|
||||
return country_name;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getHostName() const
|
||||
{
|
||||
return host_name;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getParamName() const
|
||||
{
|
||||
return param_name;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getParamValue() const
|
||||
{
|
||||
return param_value;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getProtectionName() const
|
||||
{
|
||||
return protection_name;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getSourceIdentifier() const
|
||||
{
|
||||
return source_identifier;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getSourceIp() const
|
||||
{
|
||||
return source_ip;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
AppsecExceptionSpec::getUrl() const
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
|
||||
:
|
||||
match_type(MatchType::Operator),
|
||||
op("and")
|
||||
{
|
||||
if (!parsed_exception.getCountryCode().empty()) {
|
||||
items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode()));
|
||||
}
|
||||
if (!parsed_exception.getCountryName().empty()) {
|
||||
items.push_back(ExceptionMatch("countryName", parsed_exception.getCountryName()));
|
||||
}
|
||||
if (!parsed_exception.getHostName().empty()) {
|
||||
items.push_back(ExceptionMatch("hostName", parsed_exception.getHostName()));
|
||||
}
|
||||
if (!parsed_exception.getParamName().empty()) {
|
||||
items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName()));
|
||||
}
|
||||
if (!parsed_exception.getParamValue().empty()) {
|
||||
items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue()));
|
||||
}
|
||||
if (!parsed_exception.getProtectionName().empty()) {
|
||||
items.push_back(ExceptionMatch("protectionName", parsed_exception.getProtectionName()));
|
||||
}
|
||||
if (!parsed_exception.getSourceIdentifier().empty()) {
|
||||
items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier()));
|
||||
}
|
||||
if (!parsed_exception.getSourceIp().empty()) {
|
||||
items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp()));
|
||||
}
|
||||
if (!parsed_exception.getUrl().empty()) {
|
||||
items.push_back(ExceptionMatch("url", parsed_exception.getUrl()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionMatch::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
switch (match_type) {
|
||||
case (MatchType::Condition): {
|
||||
string type_str = "condition";
|
||||
out_ar(
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("op", op),
|
||||
cereal::make_nvp("type", type_str),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case (MatchType::Operator): {
|
||||
string type_str = "operator";
|
||||
out_ar(
|
||||
cereal::make_nvp("op", op),
|
||||
cereal::make_nvp("type", type_str),
|
||||
cereal::make_nvp("items", items)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
dbgError(D_K8S_POLICY) << "No match for exception match type: " << static_cast<int>(match_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionBehavior::ExceptionBehavior(
|
||||
const string &_key,
|
||||
const string &_value)
|
||||
:
|
||||
key(_key),
|
||||
value(_value)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionBehavior::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("value", value),
|
||||
cereal::make_nvp("id", id)
|
||||
);
|
||||
}
|
||||
|
||||
const string
|
||||
ExceptionBehavior::getBehaviorId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
InnerException::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("behavior", behavior),
|
||||
cereal::make_nvp("match", match)
|
||||
);
|
||||
}
|
||||
|
||||
const string
|
||||
InnerException::getBehaviorId() const
|
||||
{
|
||||
return behavior.getBehaviorId();
|
||||
}
|
||||
|
||||
bool
|
||||
InnerException::operator<(const InnerException &other) const
|
||||
{
|
||||
return getBehaviorId() < other.getBehaviorId();
|
||||
}
|
||||
|
||||
ExceptionsRulebase::ExceptionsRulebase(
|
||||
vector<InnerException> _exceptions)
|
||||
:
|
||||
exceptions(_exceptions)
|
||||
{
|
||||
string context_id_str = "";
|
||||
for (const InnerException & exception : exceptions) {
|
||||
string curr_id = "parameterId(" + exception.getBehaviorId() + "), ";
|
||||
context_id_str += curr_id;
|
||||
}
|
||||
context_id_str = context_id_str.substr(0, context_id_str.size() - 2);
|
||||
context = "Any(" + context_id_str + ")";
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionsRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("exceptions", exceptions)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionsWrapper::Exception::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(cereal::make_nvp("exception", exception));
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionsWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulebase", exception_rulebase)
|
||||
);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
@ -14,7 +14,9 @@
|
||||
#ifndef __APPSEC_PRACTICE_SECTION_H__
|
||||
#define __APPSEC_PRACTICE_SECTION_H__
|
||||
|
||||
#include <list>
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/types/list.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
@ -28,67 +30,24 @@
|
||||
#include "trusted_sources_section.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
class AppSecWebBotsURI
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots URI";
|
||||
parseAppsecJSONKey<std::string>("uri", uri, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getURI() const { return uri; }
|
||||
const std::string & getURI() const;
|
||||
|
||||
private:
|
||||
std::string uri;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecWebBotsURI &obj)
|
||||
{
|
||||
os << obj.getURI();
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const std::vector<AppSecWebBotsURI> &obj)
|
||||
{
|
||||
os << "[" << std::endl;
|
||||
makeSeparatedStr(obj, ",");
|
||||
os << std::endl << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecPracticeAntiBot
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots";
|
||||
parseAppsecJSONKey<std::vector<AppSecWebBotsURI>>("injected-URIs", injected_uris, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppSecWebBotsURI>>("validated-URIs", validated_uris, archive_in);
|
||||
parseAppsecJSONKey<std::string>("override-mode", override_mode, archive_in, "Inactive");
|
||||
}
|
||||
|
||||
void
|
||||
save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::vector<std::string> injected;
|
||||
std::vector<std::string> validated;
|
||||
for (const AppSecWebBotsURI &uri : getInjectedURIs()) injected.push_back(uri.getURI());
|
||||
for (const AppSecWebBotsURI &uri : getValidatedURIs()) injected.push_back(uri.getURI());
|
||||
out_ar(
|
||||
cereal::make_nvp("injected", injected),
|
||||
cereal::make_nvp("validated", validated)
|
||||
);
|
||||
}
|
||||
|
||||
const std::vector<AppSecWebBotsURI> & getInjectedURIs() const { return injected_uris; }
|
||||
const std::vector<AppSecWebBotsURI> & getValidatedURIs() const { return validated_uris; }
|
||||
const std::string & getOverrideMode() const { return override_mode; }
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::string override_mode;
|
||||
@ -96,61 +55,15 @@ private:
|
||||
std::vector<AppSecWebBotsURI> validated_uris;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecPracticeAntiBot &obj)
|
||||
{
|
||||
os
|
||||
<< "injected-URIs: "
|
||||
<< obj.getInjectedURIs()
|
||||
<< " validated-URIs: "
|
||||
<< obj.getValidatedURIs()
|
||||
<< ", override_mode: "
|
||||
<< obj.getOverrideMode();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecWebAttackProtections
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Attack Protections";
|
||||
parseAppsecJSONKey<std::string>("csrf-protection", csrf_protection, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<std::string>("error-disclosure", error_disclosure, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<std::string>("open-redirect", open_redirect, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<bool>("non-valid-http-methods", non_valid_http_methods, archive_in, false);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string
|
||||
getCsrfProtectionMode() const
|
||||
{
|
||||
if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) {
|
||||
dbgError(D_K8S_POLICY)
|
||||
<< "Failed to find a value for "
|
||||
<< csrf_protection
|
||||
<< ". Setting CSRF protection to Inactive";
|
||||
return "Inactive";
|
||||
}
|
||||
return key_to_practices_val.at(csrf_protection);
|
||||
}
|
||||
|
||||
const std::string & getErrorDisclosureMode() const { return error_disclosure; }
|
||||
|
||||
bool getNonValidHttpMethods() const { return non_valid_http_methods; }
|
||||
|
||||
const std::string
|
||||
getOpenRedirectMode() const
|
||||
{
|
||||
if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) {
|
||||
dbgError(D_K8S_POLICY)
|
||||
<< "Failed to find a value for "
|
||||
<< open_redirect
|
||||
<< ". Setting Open Redirect mode to Inactive";
|
||||
return "Inactive";
|
||||
}
|
||||
return key_to_practices_val.at(open_redirect);
|
||||
}
|
||||
const std::string getCsrfProtectionMode() const;
|
||||
const std::string & getErrorDisclosureMode() const;
|
||||
bool getNonValidHttpMethods() const;
|
||||
const std::string getOpenRedirectMode() const;
|
||||
|
||||
private:
|
||||
std::string csrf_protection;
|
||||
@ -159,53 +72,18 @@ private:
|
||||
bool non_valid_http_methods;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecWebAttackProtections &obj)
|
||||
{
|
||||
os
|
||||
<< " csrf-protection: "
|
||||
<< obj.getCsrfProtectionMode()
|
||||
<< " error-disclosure: "
|
||||
<< obj.getErrorDisclosureMode()
|
||||
<< " non-valid-http-methods: "
|
||||
<< obj.getNonValidHttpMethods()
|
||||
<< " open-redirect: "
|
||||
<< obj.getOpenRedirectMode();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecPracticeWebAttacks
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec";
|
||||
parseAppsecJSONKey<AppSecWebAttackProtections>("protections", protections, archive_in);
|
||||
parseAppsecJSONKey<std::string>("minimum-confidence", minimum_confidence, archive_in, "critical");
|
||||
parseAppsecJSONKey<std::string>("override-mode", mode, archive_in, "Unset");
|
||||
parseAppsecJSONKey<int>("max-body-size-kb", max_body_size_kb, archive_in, 1000000);
|
||||
parseAppsecJSONKey<int>("max-header-size-bytes", max_header_size_bytes, archive_in, 102400);
|
||||
parseAppsecJSONKey<int>("max-object-depth", max_object_depth, archive_in, 40);
|
||||
parseAppsecJSONKey<int>("max-url-size-bytes", max_url_size_bytes, archive_in, 32768);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
int getMaxBodySizeKb() const { return max_body_size_kb; }
|
||||
int getMaxHeaderSizeBytes() const { return max_header_size_bytes; }
|
||||
int getMaxObjectDepth() const { return max_object_depth; }
|
||||
int getMaxUrlSizeBytes() const { return max_url_size_bytes; }
|
||||
const std::string & getMinimumConfidence() const { return minimum_confidence; }
|
||||
const AppSecWebAttackProtections & getprotections() const { return protections; }
|
||||
|
||||
const std::string &
|
||||
getMode(const std::string &default_mode = "Inactive") const
|
||||
{
|
||||
if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) {
|
||||
dbgError(D_K8S_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode;
|
||||
return default_mode;
|
||||
}
|
||||
return key_to_practices_val.at(mode);
|
||||
}
|
||||
int getMaxBodySizeKb() const;
|
||||
int getMaxHeaderSizeBytes() const;
|
||||
int getMaxObjectDepth() const;
|
||||
int getMaxUrlSizeBytes() const;
|
||||
const std::string & getMinimumConfidence() const;
|
||||
const AppSecWebAttackProtections & getprotections() const;
|
||||
const std::string & getMode(const std::string &default_mode = "Inactive") const;
|
||||
|
||||
private:
|
||||
int max_body_size_kb;
|
||||
@ -217,114 +95,42 @@ private:
|
||||
AppSecWebAttackProtections protections;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecPracticeWebAttacks &obj)
|
||||
{
|
||||
os
|
||||
<< "mode: "
|
||||
<< obj.getMode()
|
||||
<< " max-body-size-kb: "
|
||||
<< obj.getMaxBodySizeKb()
|
||||
<< " max-header-size-bytes: "
|
||||
<< obj.getMaxHeaderSizeBytes()
|
||||
<< " max-object-depth: "
|
||||
<< obj.getMaxObjectDepth()
|
||||
<< " max-url-size-bytes: "
|
||||
<< obj.getMaxUrlSizeBytes()
|
||||
<< " minimum-confidence: "
|
||||
<< obj.getMinimumConfidence()
|
||||
<< " protections: "
|
||||
<< obj.getprotections();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecPracticeSnortSignatures
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Snort Signatures practice";
|
||||
parseAppsecJSONKey<std::string>("override-mode", override_mode, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<std::vector<std::string>>("configmap", config_map, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getOverrideMode() const { return override_mode; }
|
||||
|
||||
const std::vector<std::string> & getConfigMap() const { return config_map; }
|
||||
const std::string & getOverrideMode() const;
|
||||
const std::vector<std::string> & getConfigMap() const;
|
||||
|
||||
private:
|
||||
std::string override_mode;
|
||||
std::vector<std::string> config_map;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecPracticeSnortSignatures &obj)
|
||||
{
|
||||
os
|
||||
<< "override mode: "
|
||||
<< obj.getOverrideMode()
|
||||
<< ". Config map: [" << std::endl
|
||||
<< makeSeparatedStr(obj.getConfigMap(), ",")
|
||||
<< std::endl << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecPracticeOpenSchemaAPI
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSecPracticeOpenSchemaAPI practice";
|
||||
parseAppsecJSONKey<std::string>("override-mode", override_mode, archive_in, "Inactive");
|
||||
parseAppsecJSONKey<std::vector<std::string>>("configmap", config_map, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getOverrideMode() const { return override_mode; }
|
||||
|
||||
const std::vector<std::string> & getConfigMap() const { return config_map; }
|
||||
const std::string & getOverrideMode() const;
|
||||
const std::vector<std::string> & getConfigMap() const;
|
||||
|
||||
private:
|
||||
std::string override_mode;
|
||||
std::vector<std::string> config_map;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecPracticeOpenSchemaAPI &obj)
|
||||
{
|
||||
os
|
||||
<< "override mode: "
|
||||
<< obj.getOverrideMode()
|
||||
<< ". Config map: [" << std::endl
|
||||
<< makeSeparatedStr(obj.getConfigMap(), ",")
|
||||
<< std::endl << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecPracticeSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec";
|
||||
parseAppsecJSONKey<AppSecPracticeOpenSchemaAPI>(
|
||||
"openapi-schema-validation",
|
||||
openapi_schema_validation,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<AppSecPracticeSnortSignatures>("snort-signatures", snort_signatures, archive_in);
|
||||
parseAppsecJSONKey<AppSecPracticeWebAttacks>("web-attacks", web_attacks, archive_in);
|
||||
parseAppsecJSONKey<AppSecPracticeAntiBot>("anti-bot", anti_bot, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", practice_name, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const { return openapi_schema_validation; }
|
||||
const AppSecPracticeSnortSignatures & getSnortSignatures() const { return snort_signatures; }
|
||||
const AppSecPracticeWebAttacks & getWebAttacks() const { return web_attacks; }
|
||||
const AppSecPracticeAntiBot & getAntiBot() const { return anti_bot; }
|
||||
const std::string & getName() const { return practice_name; }
|
||||
const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const;
|
||||
const AppSecPracticeSnortSignatures & getSnortSignatures() const;
|
||||
const AppSecPracticeWebAttacks & getWebAttacks() const;
|
||||
const AppSecPracticeAntiBot & getAntiBot() const;
|
||||
const std::string & getName() const;
|
||||
|
||||
private:
|
||||
AppSecPracticeOpenSchemaAPI openapi_schema_validation;
|
||||
@ -334,24 +140,11 @@ private:
|
||||
std::string practice_name;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecPracticeSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "Open Schema API:" << std::endl
|
||||
<< obj.getOpenSchemaValidation()
|
||||
<< std::endl << "Snort Signatures:" << std::endl
|
||||
<< obj.getOpenSchemaValidation()
|
||||
<< std::endl << "Web Attacks:" << std::endl
|
||||
<< obj.getWebAttacks()
|
||||
<< std::endl << "Web Bots:" << std::endl
|
||||
<< obj.getAntiBot();
|
||||
return os;
|
||||
}
|
||||
|
||||
class PracticeAdvancedConfig
|
||||
{
|
||||
public:
|
||||
PracticeAdvancedConfig() {}
|
||||
|
||||
PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec)
|
||||
:
|
||||
http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()),
|
||||
@ -361,19 +154,7 @@ public:
|
||||
url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes())
|
||||
{}
|
||||
|
||||
void
|
||||
save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("httpHeaderMaxSize", http_header_max_size),
|
||||
cereal::make_nvp("httpIllegalMethodsAllowed", http_illegal_methods_allowed),
|
||||
cereal::make_nvp("httpRequestBodyMaxSize", http_request_body_max_size),
|
||||
cereal::make_nvp("jsonMaxObjectDepth", json_max_object_depth),
|
||||
cereal::make_nvp("urlMaxSize", url_max_size)
|
||||
);
|
||||
}
|
||||
|
||||
void setIllegalMethodsAllowed(int val) { http_illegal_methods_allowed = val; };
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
int http_header_max_size;
|
||||
@ -394,16 +175,7 @@ public:
|
||||
log(log_section)
|
||||
{}
|
||||
|
||||
void
|
||||
save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("$triggerType", trigger_type),
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("log", log)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::string trigger_type;
|
||||
@ -415,23 +187,10 @@ private:
|
||||
class AppSecOverride
|
||||
{
|
||||
public:
|
||||
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources)
|
||||
{
|
||||
std::string source_ident = parsed_trusted_sources.getSourceIdent();
|
||||
std::map<std::string, std::string> behavior = {{"httpSourceId", source_ident}};
|
||||
parsed_behavior.push_back(behavior);
|
||||
parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}};
|
||||
}
|
||||
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources);
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
void
|
||||
save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string parameter_type = "TrustedSource";
|
||||
out_ar(
|
||||
cereal::make_nvp("parsedBehavior", parsed_behavior),
|
||||
cereal::make_nvp("parsedMatch", parsed_match)
|
||||
);
|
||||
}
|
||||
private:
|
||||
std::vector<std::map<std::string, std::string>> parsed_behavior;
|
||||
std::map<std::string, std::string> parsed_match;
|
||||
@ -440,6 +199,8 @@ private:
|
||||
class WebAppSection
|
||||
{
|
||||
public:
|
||||
WebAppSection() {}
|
||||
|
||||
WebAppSection(
|
||||
const std::string &_application_urls,
|
||||
const std::string &_asset_id,
|
||||
@ -451,75 +212,12 @@ public:
|
||||
const AppSecPracticeSpec &parsed_appsec_spec,
|
||||
const LogTriggerSection &parsed_log_trigger,
|
||||
const std::string &default_mode,
|
||||
const AppSecTrustedSources &parsed_trusted_sources)
|
||||
:
|
||||
application_urls(_application_urls),
|
||||
asset_id(_asset_id),
|
||||
asset_name(_asset_name),
|
||||
rule_id(_rule_id),
|
||||
rule_name(_rule_name),
|
||||
practice_id(_practice_id),
|
||||
practice_name(_practice_name),
|
||||
context("practiceId(" + practice_id +")"),
|
||||
web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()),
|
||||
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
|
||||
practice_advanced_config(parsed_appsec_spec),
|
||||
anti_bots(parsed_appsec_spec.getAntiBot()),
|
||||
trusted_sources({parsed_trusted_sources})
|
||||
{
|
||||
web_attack_mitigation = true;
|
||||
web_attack_mitigation_action =
|
||||
web_attack_mitigation_severity == "critical" ? "low" :
|
||||
web_attack_mitigation_severity == "high" ? "balanced" :
|
||||
web_attack_mitigation_severity == "medium" ? "high" :
|
||||
"Error";
|
||||
const AppSecTrustedSources &parsed_trusted_sources
|
||||
);
|
||||
|
||||
triggers.push_back(TriggersInWaapSection(parsed_log_trigger));
|
||||
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
|
||||
overrides.push_back(AppSecOverride(source_ident));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string disabled_str = "Disabled";
|
||||
std::string detect_str = "Detect";
|
||||
std::vector<std::string> empty_list;
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("webAttackMitigation", web_attack_mitigation),
|
||||
cereal::make_nvp("webAttackMitigationSeverity", web_attack_mitigation_severity),
|
||||
cereal::make_nvp("webAttackMitigationAction", web_attack_mitigation_action),
|
||||
cereal::make_nvp("webAttackMitigationMode", web_attack_mitigation_mode),
|
||||
cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config),
|
||||
cereal::make_nvp("csrfProtection", disabled_str),
|
||||
cereal::make_nvp("openRedirect", disabled_str),
|
||||
cereal::make_nvp("errorDisclosure", disabled_str),
|
||||
cereal::make_nvp("practiceId", practice_id),
|
||||
cereal::make_nvp("practiceName", practice_name),
|
||||
cereal::make_nvp("assetId", asset_id),
|
||||
cereal::make_nvp("assetName", asset_name),
|
||||
cereal::make_nvp("ruleId", rule_id),
|
||||
cereal::make_nvp("ruleName", rule_name),
|
||||
cereal::make_nvp("triggers", triggers),
|
||||
cereal::make_nvp("applicationUrls", application_urls),
|
||||
cereal::make_nvp("overrides", overrides),
|
||||
cereal::make_nvp("trustedSources", trusted_sources),
|
||||
cereal::make_nvp("waapParameters", empty_list),
|
||||
cereal::make_nvp("botProtection", false),
|
||||
cereal::make_nvp("antiBot", anti_bots),
|
||||
cereal::make_nvp("botProtection_v2", detect_str)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string & getPracticeId() const { return practice_id; }
|
||||
|
||||
bool
|
||||
operator<(const WebAppSection &other) const
|
||||
{
|
||||
return getPracticeId() < other.getPracticeId();
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::string & getPracticeId() const;
|
||||
bool operator<(const WebAppSection &other) const;
|
||||
|
||||
private:
|
||||
std::string application_urls;
|
||||
@ -573,36 +271,9 @@ public:
|
||||
practice_advanced_config(parsed_appsec_spec)
|
||||
{}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string disabled_str = "Disabled";
|
||||
std::vector<std::string> empty_list;
|
||||
out_ar(
|
||||
cereal::make_nvp("application_urls", application_urls),
|
||||
cereal::make_nvp("asset_id", asset_id),
|
||||
cereal::make_nvp("asset_name", asset_name),
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config),
|
||||
cereal::make_nvp("practice_id", practice_id),
|
||||
cereal::make_nvp("practice_name", practice_name),
|
||||
cereal::make_nvp("ruleId", rule_id),
|
||||
cereal::make_nvp("ruleName", rule_name),
|
||||
cereal::make_nvp("schemaValidation", false),
|
||||
cereal::make_nvp("schemaValidation_v2", disabled_str),
|
||||
cereal::make_nvp("web_attack_mitigation", web_attack_mitigation),
|
||||
cereal::make_nvp("web_attack_mitigation_action", web_attack_mitigation_action),
|
||||
cereal::make_nvp("web_attack_mitigation_severity", web_attack_mitigation_severity),
|
||||
cereal::make_nvp("web_attack_mitigation_mode", web_attack_mitigation_mode),
|
||||
cereal::make_nvp("oas", empty_list),
|
||||
cereal::make_nvp("trustedSources", empty_list),
|
||||
cereal::make_nvp("triggers", empty_list),
|
||||
cereal::make_nvp("waapParameters", empty_list),
|
||||
cereal::make_nvp("overrides", empty_list)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
const std::string & getPracticeId() const { return practice_id; }
|
||||
const std::string & getPracticeId() const;
|
||||
|
||||
private:
|
||||
std::string application_urls;
|
||||
@ -630,14 +301,7 @@ public:
|
||||
webApplicationPractices(_webApplicationPractices),
|
||||
webAPIPractices(_webAPIPractices) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("WebAPISecurity", webAPIPractices),
|
||||
cereal::make_nvp("WebApplicationSecurity", webApplicationPractices)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::vector<WebAppSection> webApplicationPractices;
|
||||
@ -652,54 +316,27 @@ public:
|
||||
app_sec_rulebase(_app_sec)
|
||||
{}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(cereal::make_nvp("WAAP", app_sec_rulebase));
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
AppSecRulebase app_sec_rulebase;
|
||||
};
|
||||
|
||||
|
||||
class ParsedRule
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec ParsedRule";
|
||||
parseAppsecJSONKey<std::vector<std::string>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("triggers", log_triggers, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("practices", practices, archive_in);
|
||||
parseAppsecJSONKey<std::string>("mode", mode, archive_in);
|
||||
parseAppsecJSONKey<std::string>("custom-response", custom_response, archive_in);
|
||||
parseAppsecJSONKey<std::string>("source-identifiers", source_identifiers, archive_in);
|
||||
parseAppsecJSONKey<std::string>("trusted-sources", trusted_sources, archive_in);
|
||||
try {
|
||||
archive_in(cereal::make_nvp("host", host));
|
||||
} catch (const cereal::Exception &e)
|
||||
{} // The default ParsedRule does not hold a host, so no error handling
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::vector<std::string> & getExceptions() const { return exceptions; }
|
||||
|
||||
const std::vector<std::string> & getLogTriggers() const { return log_triggers; }
|
||||
|
||||
const std::vector<std::string> & getPractices() const { return practices; }
|
||||
|
||||
const std::string & getHost() const { return host; }
|
||||
|
||||
const std::string & getMode() const { return mode; }
|
||||
|
||||
void setMode(const std::string &_mode) { mode = _mode; };
|
||||
|
||||
const std::string & getCustomResponse() const { return custom_response; }
|
||||
|
||||
const std::string & getSourceIdentifiers() const { return source_identifiers; }
|
||||
|
||||
const std::string & getTrustedSources() const { return trusted_sources; }
|
||||
const std::vector<std::string> & getExceptions() const;
|
||||
const std::vector<std::string> & getLogTriggers() const;
|
||||
const std::vector<std::string> & getPractices() const;
|
||||
const std::string & getHost() const;
|
||||
const std::string & getMode() const;
|
||||
void setHost(const std::string &_host);
|
||||
void setMode(const std::string &_mode);
|
||||
const std::string & getCustomResponse() const;
|
||||
const std::string & getSourceIdentifiers() const;
|
||||
const std::string & getTrustedSources() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> exceptions;
|
||||
@ -712,88 +349,32 @@ private:
|
||||
std::string trusted_sources;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const ParsedRule &obj)
|
||||
{
|
||||
os
|
||||
<< "host: "
|
||||
<< obj.getHost()
|
||||
<< std::endl << "log trigger: "
|
||||
<< makeSeparatedStr(obj.getLogTriggers(), ",")
|
||||
<< std::endl << "mode: "
|
||||
<< obj.getMode()
|
||||
<< std::endl << "practices: "
|
||||
<< makeSeparatedStr(obj.getPractices(), ",")
|
||||
<< std::endl << "web responce: "
|
||||
<< obj.getCustomResponse()
|
||||
<< std::endl << " Exceptions: [" << std::endl
|
||||
<< makeSeparatedStr(obj.getExceptions(), ",")
|
||||
<< std::endl << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppsecPolicySpec : Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec";
|
||||
parseAppsecJSONKey<ParsedRule>("default", default_rule, archive_in);
|
||||
auto default_mode_annot =
|
||||
Singleton::Consume<I_Environment>::by<AppsecPolicySpec>()->get<std::string>("default mode annotation");
|
||||
if (default_mode_annot.ok() && !default_mode_annot.unpack().empty() && default_rule.getMode().empty()) {
|
||||
default_rule.setMode(default_mode_annot.unpack());
|
||||
}
|
||||
parseAppsecJSONKey<std::vector<ParsedRule>>("specific-rules", specific_rules, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const ParsedRule & getDefaultRule() const { return default_rule; }
|
||||
|
||||
const std::vector<ParsedRule> & getSpecificRules() const { return specific_rules; }
|
||||
const ParsedRule & getDefaultRule() const;
|
||||
const std::list<ParsedRule> & getSpecificRules() const;
|
||||
|
||||
private:
|
||||
ParsedRule default_rule;
|
||||
std::vector<ParsedRule> specific_rules;
|
||||
std::list<ParsedRule> specific_rules;
|
||||
};
|
||||
|
||||
class AppsecLinuxPolicy : Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec";
|
||||
parseAppsecJSONKey<AppsecPolicySpec>("policies", policies, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppSecPracticeSpec>>("practices", practices, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppsecTriggerSpec>>("logtriggers", log_triggers, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppSecCustomResponseSpec>>("customresponses", custom_responses, archive_in);
|
||||
parseAppsecJSONKey<std::vector<AppsecExceptionSpec>>("exceptions", exceptions, archive_in);
|
||||
parseAppsecJSONKey<std::vector<TrustedSourcesSpec>>("trustedsources", trusted_sources, archive_in);
|
||||
parseAppsecJSONKey<std::vector<SourceIdentifierSpecWrapper>>(
|
||||
"sourceidentifiers",
|
||||
sources_identifier,
|
||||
archive_in
|
||||
);
|
||||
}
|
||||
serialize(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const AppsecPolicySpec & getAppsecPolicySpec() const { return policies; }
|
||||
|
||||
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const { return practices; }
|
||||
|
||||
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const { return log_triggers; }
|
||||
|
||||
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const { return custom_responses; }
|
||||
|
||||
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const { return exceptions; }
|
||||
|
||||
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const { return trusted_sources; }
|
||||
|
||||
const std::vector<SourceIdentifierSpecWrapper> &
|
||||
getAppsecSourceIdentifierSpecs() const
|
||||
{
|
||||
return sources_identifier;
|
||||
}
|
||||
const AppsecPolicySpec & getAppsecPolicySpec() const;
|
||||
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const;
|
||||
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const;
|
||||
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const;
|
||||
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const;
|
||||
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
|
||||
const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
|
||||
|
||||
private:
|
||||
AppsecPolicySpec policies;
|
||||
@ -805,16 +386,5 @@ private:
|
||||
std::vector<SourceIdentifierSpecWrapper> sources_identifier;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecPolicySpec &obj)
|
||||
{
|
||||
os
|
||||
<< "Default Rule: "
|
||||
<< obj.getDefaultRule()
|
||||
<< std::endl <<"Specific Rules: [" << std::endl
|
||||
<< makeSeparatedStr(obj.getSpecificRules(), ",")
|
||||
<< std::endl << "]";
|
||||
return os;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
#endif // __APPSEC_PRACTICE_SECTION_H__
|
||||
|
@ -30,34 +30,22 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
class AppsecExceptionSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec exception spec";
|
||||
parseAppsecJSONKey<std::string>("action", action, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("countryCode", country_code, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("countryName", country_name, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("hostName", host_name, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("paramName", param_name, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("paramValue", param_value, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("protectionName", protection_name, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("sourceIdentifier", source_identifier, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("sourceIp", source_ip, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("url", url, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getAction() const { return action; }
|
||||
const std::vector<std::string> & getCountryCode() const { return country_code; }
|
||||
const std::vector<std::string> & getCountryName() const { return country_name; }
|
||||
const std::vector<std::string> & getHostName() const { return host_name; }
|
||||
const std::vector<std::string> & getParamName() const { return param_name; }
|
||||
const std::vector<std::string> & getParamValue() const { return param_value; }
|
||||
const std::vector<std::string> & getProtectionName() const { return protection_name; }
|
||||
const std::vector<std::string> & getSourceIdentifier() const { return source_identifier; }
|
||||
const std::vector<std::string> & getSourceIp() const { return source_ip; }
|
||||
const std::vector<std::string> & getUrl() const { return url; }
|
||||
const std::string & getName() const;
|
||||
const std::string & getAction() const;
|
||||
const std::vector<std::string> & getCountryCode() const;
|
||||
const std::vector<std::string> & getCountryName() const;
|
||||
const std::vector<std::string> & getHostName() const;
|
||||
const std::vector<std::string> & getParamName() const;
|
||||
const std::vector<std::string> & getParamValue() const;
|
||||
const std::vector<std::string> & getProtectionName() const;
|
||||
const std::vector<std::string> & getSourceIdentifier() const;
|
||||
const std::vector<std::string> & getSourceIp() const;
|
||||
const std::vector<std::string> & getUrl() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string action;
|
||||
std::vector<std::string> country_code;
|
||||
std::vector<std::string> country_name;
|
||||
@ -70,71 +58,11 @@ private:
|
||||
std::vector<std::string> url;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecExceptionSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "action: "
|
||||
<< makeSeparatedStr(obj.getAction(), ",")
|
||||
<< "countryCode: "
|
||||
<< makeSeparatedStr(obj.getCountryCode(), ",")
|
||||
<< "countryName: "
|
||||
<< makeSeparatedStr(obj.getCountryName(), ",")
|
||||
<< "hostName: "
|
||||
<< makeSeparatedStr(obj.getHostName(), ",")
|
||||
<< "paramName: "
|
||||
<< makeSeparatedStr(obj.getParamName(), ",")
|
||||
<< "paramValue: "
|
||||
<< makeSeparatedStr(obj.getParamValue(), ",")
|
||||
<< "protectionName: "
|
||||
<< makeSeparatedStr(obj.getProtectionName(), ",")
|
||||
<< "sourceIdentifier: "
|
||||
<< makeSeparatedStr(obj.getSourceIdentifier(), ",")
|
||||
<< "sourceIp: "
|
||||
<< makeSeparatedStr(obj.getSourceIp(), ",")
|
||||
<< "url: "
|
||||
<< makeSeparatedStr(obj.getUrl(), ",");
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
class ExceptionMatch
|
||||
{
|
||||
public:
|
||||
ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
|
||||
:
|
||||
match_type(MatchType::Operator),
|
||||
op("and")
|
||||
{
|
||||
if (!parsed_exception.getCountryCode().empty()) {
|
||||
items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode()));
|
||||
}
|
||||
if (!parsed_exception.getCountryName().empty()) {
|
||||
items.push_back(ExceptionMatch("countryName", parsed_exception.getCountryName()));
|
||||
}
|
||||
if (!parsed_exception.getHostName().empty()) {
|
||||
items.push_back(ExceptionMatch("hostName", parsed_exception.getHostName()));
|
||||
}
|
||||
if (!parsed_exception.getParamName().empty()) {
|
||||
items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName()));
|
||||
}
|
||||
if (!parsed_exception.getParamValue().empty()) {
|
||||
items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue()));
|
||||
}
|
||||
if (!parsed_exception.getProtectionName().empty()) {
|
||||
items.push_back(ExceptionMatch("protectionName", parsed_exception.getProtectionName()));
|
||||
}
|
||||
if (!parsed_exception.getSourceIdentifier().empty()) {
|
||||
items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier()));
|
||||
}
|
||||
if (!parsed_exception.getSourceIp().empty()) {
|
||||
items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp()));
|
||||
}
|
||||
if (!parsed_exception.getUrl().empty()) {
|
||||
items.push_back(ExceptionMatch("url", parsed_exception.getUrl()));
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionMatch() {}
|
||||
ExceptionMatch(const AppsecExceptionSpec &parsed_exception);
|
||||
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value)
|
||||
:
|
||||
match_type(MatchType::Condition),
|
||||
@ -143,34 +71,7 @@ public:
|
||||
value(_value)
|
||||
{}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
switch (match_type) {
|
||||
case (MatchType::Condition): {
|
||||
std::string type_str = "condition";
|
||||
out_ar(
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("op", op),
|
||||
cereal::make_nvp("type", type_str),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case (MatchType::Operator): {
|
||||
std::string type_str = "operator";
|
||||
out_ar(
|
||||
cereal::make_nvp("op", op),
|
||||
cereal::make_nvp("type", type_str),
|
||||
cereal::make_nvp("items", items)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
dbgError(D_K8S_POLICY) << "No match for exception match type: " << static_cast<int>(match_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
MatchType match_type;
|
||||
@ -183,31 +84,14 @@ private:
|
||||
class ExceptionBehavior
|
||||
{
|
||||
public:
|
||||
ExceptionBehavior() {}
|
||||
ExceptionBehavior(
|
||||
const std::string &_key,
|
||||
const std::string &_value)
|
||||
:
|
||||
key(_key),
|
||||
value(_value)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
const std::string &_value
|
||||
);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("value", value),
|
||||
cereal::make_nvp("id", id)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string getBehaviorId() const { return id; }
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::string getBehaviorId() const;
|
||||
|
||||
private:
|
||||
std::string key;
|
||||
@ -218,6 +102,7 @@ private:
|
||||
class InnerException
|
||||
{
|
||||
public:
|
||||
InnerException() {}
|
||||
InnerException(
|
||||
ExceptionBehavior _behavior,
|
||||
ExceptionMatch _match)
|
||||
@ -225,22 +110,9 @@ public:
|
||||
behavior(_behavior),
|
||||
match(_match) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("behavior", behavior),
|
||||
cereal::make_nvp("match", match)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string getBehaviorId() const { return behavior.getBehaviorId(); }
|
||||
|
||||
bool
|
||||
operator<(const InnerException &other) const
|
||||
{
|
||||
return getBehaviorId() < other.getBehaviorId();
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::string getBehaviorId() const;
|
||||
bool operator<(const InnerException &other) const;
|
||||
|
||||
private:
|
||||
ExceptionBehavior behavior;
|
||||
@ -250,28 +122,8 @@ private:
|
||||
class ExceptionsRulebase
|
||||
{
|
||||
public:
|
||||
ExceptionsRulebase(
|
||||
std::vector<InnerException> _exceptions)
|
||||
:
|
||||
exceptions(_exceptions)
|
||||
{
|
||||
std::string context_id_str = "";
|
||||
for (const InnerException exception : exceptions) {
|
||||
std::string curr_id = "parameterId(" + exception.getBehaviorId() + "), ";
|
||||
context_id_str += curr_id;
|
||||
}
|
||||
context_id_str = context_id_str.substr(0, context_id_str.size() - 2);
|
||||
context = "Any(" + context_id_str + ")";
|
||||
}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("exceptions", exceptions)
|
||||
);
|
||||
}
|
||||
ExceptionsRulebase(std::vector<InnerException> _exceptions);
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::string context;
|
||||
@ -286,11 +138,7 @@ public:
|
||||
public:
|
||||
Exception(const std::vector<ExceptionsRulebase> &_exception) : exception(_exception) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(cereal::make_nvp("exception", exception));
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::vector<ExceptionsRulebase> exception;
|
||||
@ -298,13 +146,7 @@ public:
|
||||
ExceptionsWrapper(const std::vector<ExceptionsRulebase> &_exception) : exception_rulebase(Exception(_exception))
|
||||
{}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulebase", exception_rulebase)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
Exception exception_rulebase;
|
||||
|
@ -21,26 +21,21 @@
|
||||
#include "debug.h"
|
||||
#include "rest.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include <cereal/types/map.hpp>
|
||||
|
||||
#include "k8s_policy_common.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
class IngressMetadata
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "IngressMetadata load";
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<std::string>("resourceVersion", resourceVersion, archive_in);
|
||||
parseAppsecJSONKey<std::string>("namespace", namespace_name, archive_in);
|
||||
parseAppsecJSONKey<std::map<std::string, std::string>>("annotations", annotations, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getName() const { return name; }
|
||||
const std::string & getResourceVersion() const { return resourceVersion; }
|
||||
const std::string & getNamespace() const { return namespace_name; }
|
||||
const std::map<std::string, std::string> & getAnnotations() const { return annotations; }
|
||||
const std::string & getName() const;
|
||||
const std::string & getResourceVersion() const;
|
||||
const std::string & getNamespace() const;
|
||||
const std::map<std::string, std::string> & getAnnotations() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
@ -53,19 +48,15 @@ class IngressRulePath
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path";
|
||||
parseAppsecJSONKey<std::string>("path", path, archive_in);
|
||||
}
|
||||
load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getPath() const { return path; }
|
||||
const std::string & getPath() const;
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &os, const IngressRulePath &obj)
|
||||
{
|
||||
os << obj.getPath();
|
||||
@ -75,14 +66,9 @@ operator<<(std::ostream &os, const IngressRulePath &obj)
|
||||
class IngressRulePathsWrapper
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path wrapper";
|
||||
parseAppsecJSONKey<std::vector<IngressRulePath>>("paths", paths, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::vector<IngressRulePath> & getRulePaths() const { return paths; }
|
||||
const std::vector<IngressRulePath> & getRulePaths() const;
|
||||
|
||||
private:
|
||||
std::vector<IngressRulePath> paths;
|
||||
@ -91,23 +77,17 @@ private:
|
||||
class IngressDefinedRule
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule";
|
||||
parseAppsecJSONKey<std::string>("host", host, archive_in);
|
||||
parseAppsecJSONKey<IngressRulePathsWrapper>("http", paths_wrapper, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getHost() const { return host; }
|
||||
const IngressRulePathsWrapper & getPathsWrapper() const { return paths_wrapper; }
|
||||
const std::string & getHost() const;
|
||||
const IngressRulePathsWrapper & getPathsWrapper() const;
|
||||
|
||||
private:
|
||||
std::string host;
|
||||
IngressRulePathsWrapper paths_wrapper;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &os, const IngressDefinedRule &obj)
|
||||
{
|
||||
os
|
||||
@ -123,13 +103,9 @@ class DefaultBackend
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading Default Backend";
|
||||
is_exists = true;
|
||||
}
|
||||
load(cereal::JSONInputArchive &);
|
||||
|
||||
bool isExists() const { return is_exists; }
|
||||
bool isExists() const;
|
||||
|
||||
private:
|
||||
bool is_exists = false;
|
||||
@ -139,17 +115,11 @@ class IngressSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading single ingress spec";
|
||||
parseAppsecJSONKey<std::string>("ingressClassName", ingress_class_name, archive_in);
|
||||
parseAppsecJSONKey<std::vector<IngressDefinedRule>>("rules", rules, archive_in);
|
||||
parseAppsecJSONKey<DefaultBackend>("defaultBackend", default_backend, archive_in);
|
||||
}
|
||||
load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getIngressClassName() const { return ingress_class_name; }
|
||||
const std::vector<IngressDefinedRule> & getRules() const { return rules; }
|
||||
bool isDefaultBackendExists() const { return default_backend.isExists(); }
|
||||
const std::string & getIngressClassName() const;
|
||||
const std::vector<IngressDefinedRule> & getRules() const;
|
||||
bool isDefaultBackendExists() const;
|
||||
|
||||
private:
|
||||
std::string ingress_class_name;
|
||||
@ -157,31 +127,14 @@ private:
|
||||
DefaultBackend default_backend;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const IngressSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "Ingress Spec - ingressClassName: "
|
||||
<< obj.getIngressClassName()
|
||||
<< ", rules: [" << std::endl
|
||||
<< makeSeparatedStr(obj.getRules(), ",")
|
||||
<< std::endl << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class SingleIngressData
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading single ingress data";
|
||||
parseAppsecJSONKey<IngressMetadata>("metadata", metadata, archive_in);
|
||||
parseAppsecJSONKey<IngressSpec>("spec", spec, archive_in);
|
||||
}
|
||||
load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const IngressMetadata & getMetadata() const { return metadata; }
|
||||
const IngressSpec & getSpec() const { return spec; }
|
||||
const IngressMetadata & getMetadata() const;
|
||||
const IngressSpec & getSpec() const;
|
||||
|
||||
private:
|
||||
IngressMetadata metadata;
|
||||
@ -192,29 +145,10 @@ private:
|
||||
class IngressData : public ClientRest
|
||||
{
|
||||
public:
|
||||
bool
|
||||
loadJson(const std::string &json)
|
||||
{
|
||||
std::string modified_json = json;
|
||||
modified_json.pop_back();
|
||||
std::stringstream in;
|
||||
in.str(modified_json);
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress data";
|
||||
try {
|
||||
cereal::JSONInputArchive in_ar(in);
|
||||
in_ar(
|
||||
cereal::make_nvp("apiVersion", apiVersion),
|
||||
cereal::make_nvp("items", items)
|
||||
);
|
||||
} catch (cereal::Exception &e) {
|
||||
dbgError(D_K8S_POLICY) << "Failed to load ingress data JSON. Error: " << e.what();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool loadJson(const std::string &json);
|
||||
|
||||
const std::string & getapiVersion() const { return apiVersion; }
|
||||
const std::vector<SingleIngressData> & getItems() const { return items; }
|
||||
const std::string & getapiVersion() const;
|
||||
const std::vector<SingleIngressData> & getItems() const;
|
||||
|
||||
private:
|
||||
std::string apiVersion;
|
||||
|
@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __POLICY_MAKER_UTILS_H__
|
||||
#define __POLICY_MAKER_UTILS_H__
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include "debug.h"
|
||||
#include "common.h"
|
||||
#include "maybe_res.h"
|
||||
#include "appsec_practice_section.h"
|
||||
#include "ingress_data.h"
|
||||
#include "settings_section.h"
|
||||
#include "triggers_section.h"
|
||||
#include "k8s_policy_common.h"
|
||||
#include "exceptions_section.h"
|
||||
#include "rules_config_section.h"
|
||||
#include "trusted_sources_section.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_POLICY);
|
||||
|
||||
enum class AnnotationTypes {
|
||||
PRACTICE,
|
||||
TRIGGER,
|
||||
EXCEPTION,
|
||||
WEB_USER_RES,
|
||||
SOURCE_IDENTIFIERS,
|
||||
TRUSTED_SOURCES,
|
||||
COUNT
|
||||
};
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
class SecurityAppsWrapper
|
||||
{
|
||||
public:
|
||||
SecurityAppsWrapper(
|
||||
const AppSecWrapper &_waap,
|
||||
const TriggersWrapper &_trrigers,
|
||||
const RulesConfigWrapper &_rules,
|
||||
const ExceptionsWrapper &_exceptions,
|
||||
const std::string &_policy_version)
|
||||
:
|
||||
waap(_waap),
|
||||
trrigers(_trrigers),
|
||||
rules(_rules),
|
||||
exceptions(_exceptions),
|
||||
policy_version(_policy_version) {}
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
AppSecWrapper waap;
|
||||
TriggersWrapper trrigers;
|
||||
RulesConfigWrapper rules;
|
||||
ExceptionsWrapper exceptions;
|
||||
std::string policy_version;
|
||||
};
|
||||
|
||||
class PolicyWrapper
|
||||
{
|
||||
public:
|
||||
PolicyWrapper(
|
||||
const SettingsWrapper &_settings,
|
||||
const SecurityAppsWrapper &_security_apps)
|
||||
:
|
||||
settings(_settings),
|
||||
security_apps(_security_apps) {}
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
SettingsWrapper settings;
|
||||
SecurityAppsWrapper security_apps;
|
||||
};
|
||||
// LCOV_EXCL_STOP
|
||||
class PolicyMakerUtils
|
||||
{
|
||||
public:
|
||||
void clearElementsMaps();
|
||||
|
||||
bool startsWith(const std::string &str, const std::string &prefix);
|
||||
|
||||
bool endsWith(const std::string &str, const std::string &suffix);
|
||||
|
||||
std::tuple<std::string, std::string, std::string> splitHostName(const std::string &host_name);
|
||||
|
||||
std::string dumpPolicyToFile(const PolicyWrapper &policy, const std::string &policy_path) const;
|
||||
|
||||
PolicyWrapper combineElementsToPolicy(const std::string &policy_version);
|
||||
|
||||
void createPolicyElementsByRule(
|
||||
const ParsedRule &rule,
|
||||
const ParsedRule &default_rule,
|
||||
const AppsecLinuxPolicy &policy,
|
||||
const std::string &policy_name
|
||||
);
|
||||
|
||||
void createPolicyElements(
|
||||
const std::vector<ParsedRule> &rules,
|
||||
const ParsedRule &default_rule,
|
||||
const AppsecLinuxPolicy &policy,
|
||||
const std::string &policy_name
|
||||
);
|
||||
|
||||
private:
|
||||
std::map<std::string, LogTriggerSection> log_triggers;
|
||||
std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers;
|
||||
std::map<std::string, InnerException> inner_exceptions;
|
||||
std::map<std::string, WebAppSection> web_apps;
|
||||
std::map<std::string, RulesConfigRulebase> rules_config;
|
||||
};
|
||||
|
||||
#endif // __POLICY_MAKER_UTILS_H__
|
@ -30,100 +30,24 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
class AssetUrlParser
|
||||
{
|
||||
public:
|
||||
AssetUrlParser() {}
|
||||
|
||||
static AssetUrlParser parse(const std::string &uri);
|
||||
std::string query_string, asset_uri, protocol, asset_url, port;
|
||||
|
||||
AssetUrlParser()
|
||||
{}
|
||||
|
||||
AssetUrlParser(const std::string &asset)
|
||||
{
|
||||
parse(asset);
|
||||
}
|
||||
|
||||
private:
|
||||
static AssetUrlParser
|
||||
parse(const std::string &uri)
|
||||
{
|
||||
AssetUrlParser result;
|
||||
|
||||
using iterator_t = std::string::const_iterator;
|
||||
|
||||
if (uri.length() == 0) return result;
|
||||
|
||||
iterator_t uri_end = uri.end();
|
||||
|
||||
// get query start
|
||||
iterator_t query_start = std::find(uri.begin(), uri_end, '?');
|
||||
|
||||
// protocol
|
||||
iterator_t protocol_start = uri.begin();
|
||||
iterator_t protocol_end = std::find(protocol_start, uri_end, ':'); //"://");
|
||||
|
||||
if (protocol_end != uri_end) {
|
||||
std::string http_protocol = &*(protocol_end);
|
||||
if ((http_protocol.length() > 3) && (http_protocol.substr(0, 3) == "://")) {
|
||||
result.protocol = std::string(protocol_start, protocol_end);
|
||||
protocol_end += 3; // ://
|
||||
} else {
|
||||
protocol_end = uri.begin(); // no protocol
|
||||
}
|
||||
} else {
|
||||
protocol_end = uri.begin(); // no protocol
|
||||
}
|
||||
|
||||
// URL
|
||||
iterator_t host_start = protocol_end;
|
||||
iterator_t path_start = std::find(host_start, uri_end, '/');
|
||||
|
||||
iterator_t host_end = std::find(protocol_end, (path_start != uri_end) ? path_start : query_start, ':');
|
||||
|
||||
result.asset_url = std::string(host_start, host_end);
|
||||
|
||||
// port
|
||||
if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { // we have a port
|
||||
host_end++;
|
||||
iterator_t portEnd = (path_start != uri_end) ? path_start : query_start;
|
||||
result.port = std::string(host_end, portEnd);
|
||||
}
|
||||
|
||||
// URI
|
||||
if (path_start != uri_end) result.asset_uri = std::string(path_start, query_start);
|
||||
|
||||
// query
|
||||
if (query_start != uri_end) result.query_string = std::string(query_start, uri.end());
|
||||
|
||||
return result;
|
||||
} // Parse
|
||||
}; // uri
|
||||
};
|
||||
|
||||
class PracticeSection
|
||||
{
|
||||
public:
|
||||
PracticeSection(const std::string &_id, const std::string &_type, const std::string &_practice_name)
|
||||
{
|
||||
auto maybe_type = string_to_practice_type.find(_type);
|
||||
if (maybe_type == string_to_practice_type.end()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal pracrtice type: " << _type;
|
||||
return;
|
||||
}
|
||||
PracticeSection(
|
||||
const std::string &_id,
|
||||
const std::string &_type,
|
||||
const std::string &_practice_name);
|
||||
|
||||
type = _type;
|
||||
name = _practice_name;
|
||||
id = _id;
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("practiceId", id),
|
||||
cereal::make_nvp("practiceName", name),
|
||||
cereal::make_nvp("practiceType", type)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string & getPracticeId() const { return id; }
|
||||
const std::string & getPracticeName() const { return name; }
|
||||
const std::string & getPracticeId() const;
|
||||
const std::string & getPracticeName() const;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
@ -134,30 +58,10 @@ private:
|
||||
class ParametersSection
|
||||
{
|
||||
public:
|
||||
ParametersSection(
|
||||
const std::string &_id,
|
||||
const std::string &_name)
|
||||
:
|
||||
name(_name),
|
||||
id(_id)
|
||||
{
|
||||
if (_id.empty() && _name.empty()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal Parameter values. Name and ID are empty";
|
||||
return;
|
||||
}
|
||||
}
|
||||
ParametersSection(const std::string &_id, const std::string &_name);
|
||||
|
||||
const std::string & getId() const { return id; }
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("parameterId", id),
|
||||
cereal::make_nvp("parameterName", name),
|
||||
cereal::make_nvp("parameterType", type)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::string & getId() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
@ -171,35 +75,12 @@ public:
|
||||
RulesTriggerSection(
|
||||
const std::string &_name,
|
||||
const std::string &_id,
|
||||
const std::string &_type)
|
||||
:
|
||||
name(_name),
|
||||
id(_id)
|
||||
{
|
||||
if (_name.empty() && _id.empty()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal values for trigger. Name and ID are empty";
|
||||
return;
|
||||
}
|
||||
auto maybe_type = string_to_trigger_type.find(_type);
|
||||
if (maybe_type == string_to_trigger_type.end()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal trigger type in rule: " << _type;
|
||||
return;
|
||||
}
|
||||
type = _type;
|
||||
}
|
||||
const std::string &_type);
|
||||
|
||||
const std::string & getId() const { return id; }
|
||||
const std::string & getName() const { return id; }
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("triggerId", id),
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("triggerType", type)
|
||||
);
|
||||
}
|
||||
const std::string & getId() const;
|
||||
const std::string & getName() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
@ -219,84 +100,19 @@ public:
|
||||
const std::string &_uri,
|
||||
std::vector<PracticeSection> _practices,
|
||||
std::vector<ParametersSection> _parameters,
|
||||
std::vector<RulesTriggerSection> _triggers)
|
||||
:
|
||||
name(_name),
|
||||
practices(_practices),
|
||||
parameters(_parameters),
|
||||
triggers(_triggers)
|
||||
{
|
||||
try {
|
||||
id = _url+_uri;
|
||||
bool any = _name == "Any" && _url == "Any" && _uri == "Any";
|
||||
if (_uri != "/") {
|
||||
context = any ? "All()" : "Any("
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(80)" +
|
||||
std::string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
|
||||
"),"
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(443)" +
|
||||
std::string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
|
||||
")"
|
||||
")";
|
||||
} else {
|
||||
context = any ? "All()" : "Any("
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(80)"
|
||||
"),"
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(443)"
|
||||
")"
|
||||
")";
|
||||
}
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate rule UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
std::vector<RulesTriggerSection> _triggers);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string empty_str = "";
|
||||
out_ar(
|
||||
cereal::make_nvp("assetId", id),
|
||||
cereal::make_nvp("assetName", name),
|
||||
cereal::make_nvp("ruleId", id),
|
||||
cereal::make_nvp("ruleName", name),
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("priority", 1),
|
||||
cereal::make_nvp("isCleanup", false),
|
||||
cereal::make_nvp("parameters", parameters),
|
||||
cereal::make_nvp("practices", practices),
|
||||
cereal::make_nvp("triggers", triggers),
|
||||
cereal::make_nvp("zoneId", empty_str),
|
||||
cereal::make_nvp("zoneName", empty_str)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string & getRuleId() const { return id; }
|
||||
const std::string & getAssetName() const { return name; }
|
||||
const std::string & getRuleName() const { return name; }
|
||||
const std::string & getAsstId() const { return id; }
|
||||
const std::string & getPracticeId() const { return practices[0].getPracticeId(); }
|
||||
const std::string & getPracticeName() const { return practices[0].getPracticeName(); }
|
||||
const std::vector<PracticeSection> & getPractice() const { return practices; }
|
||||
const std::vector<ParametersSection> & getParameters() const { return parameters; }
|
||||
const std::vector<RulesTriggerSection> & getTriggers() const { return triggers; }
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
const std::string & getRuleId() const;
|
||||
const std::string & getAssetName() const;
|
||||
const std::string & getRuleName() const;
|
||||
const std::string & getAssetId() const;
|
||||
const std::string & getPracticeId() const;
|
||||
const std::string & getPracticeName() const;
|
||||
const std::vector<PracticeSection> & getPractice() const;
|
||||
const std::vector<ParametersSection> & getParameters() const;
|
||||
const std::vector<RulesTriggerSection> & getTriggers() const;
|
||||
|
||||
private:
|
||||
std::string context;
|
||||
@ -313,60 +129,13 @@ public:
|
||||
class RulesConfig
|
||||
{
|
||||
public:
|
||||
RulesConfig(const std::vector<RulesConfigRulebase> &_rules_config)
|
||||
:
|
||||
rules_config(_rules_config)
|
||||
{
|
||||
sort(rules_config.begin(), rules_config.end(), sortBySpecific);
|
||||
}
|
||||
RulesConfig(const std::vector<RulesConfigRulebase> &_rules_config);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulesConfig", rules_config)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
static bool
|
||||
sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second)
|
||||
{
|
||||
return sortBySpecificAux(first.getAssetName(), second.getAssetName());
|
||||
}
|
||||
|
||||
static bool
|
||||
sortBySpecificAux(const std::string &first, const std::string &second)
|
||||
{
|
||||
if (first.empty()) return false;
|
||||
if (second.empty()) return true;
|
||||
|
||||
AssetUrlParser first_parsed = AssetUrlParser(first);
|
||||
AssetUrlParser second_parsed = AssetUrlParser(second);
|
||||
|
||||
// sort by URL
|
||||
if (first_parsed.asset_url == "*" && second_parsed.asset_url != "*") return false;
|
||||
if (second_parsed.asset_url == "*" && first_parsed.asset_url != "*") return true;
|
||||
|
||||
// sort by port
|
||||
if (first_parsed.port == "*" && second_parsed.port != "*") return false;
|
||||
if (second_parsed.port == "*" && first_parsed.port != "*") return true;
|
||||
|
||||
// sort by URI
|
||||
if (first_parsed.asset_uri == "*" && second_parsed.asset_uri != "*") return false;
|
||||
if (second_parsed.asset_uri == "*" && first_parsed.asset_uri != "*") return true;
|
||||
|
||||
if (first_parsed.asset_uri.empty()) return false;
|
||||
if (second_parsed.asset_uri.empty()) return true;
|
||||
|
||||
if (second_parsed.asset_uri.find(first_parsed.asset_uri) != std::string::npos) return false;
|
||||
if (first_parsed.asset_uri.find(second_parsed.asset_uri) != std::string::npos) return true;
|
||||
|
||||
if (first_parsed.asset_url.empty()) return false;
|
||||
if (second_parsed.asset_url.empty()) return false;
|
||||
|
||||
return second < first;
|
||||
}
|
||||
static bool sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second);
|
||||
static bool sortBySpecificAux(const std::string &first, const std::string &second);
|
||||
|
||||
std::vector<RulesConfigRulebase> rules_config;
|
||||
};
|
||||
@ -376,13 +145,7 @@ public:
|
||||
rules_config_rulebase(RulesConfig(_rules_config))
|
||||
{}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulebase", rules_config_rulebase)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
RulesConfig rules_config_rulebase;
|
||||
|
@ -28,31 +28,10 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
class AgentSettingsSection
|
||||
{
|
||||
public:
|
||||
AgentSettingsSection(
|
||||
const std::string &_key,
|
||||
const std::string &_value)
|
||||
:
|
||||
key(_key),
|
||||
value(_value)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
AgentSettingsSection(const std::string &_key, const std::string &_value);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string & getSettingId() const { return id; }
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::string & getSettingId() const;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
@ -65,20 +44,7 @@ class SettingsRulebase
|
||||
public:
|
||||
SettingsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string profile_type = "Kubernetes";
|
||||
std::string upgrade_mode = "automatic";
|
||||
out_ar(
|
||||
cereal::make_nvp("agentSettings", agentSettings),
|
||||
cereal::make_nvp("agentType", profile_type),
|
||||
cereal::make_nvp("allowOnlyDefinedApplications", false),
|
||||
cereal::make_nvp("anyFog", true),
|
||||
cereal::make_nvp("maxNumberOfAgents", 10),
|
||||
cereal::make_nvp("upgradeMode", upgrade_mode)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::vector<AgentSettingsSection> agentSettings;
|
||||
@ -87,27 +53,9 @@ private:
|
||||
class SettingsWrapper
|
||||
{
|
||||
public:
|
||||
SettingsWrapper(SettingsRulebase _agent) : agent(_agent)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate Settings Wrapper UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
SettingsWrapper(SettingsRulebase _agent);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("profileType", profileType),
|
||||
cereal::make_nvp("tokenType", isToken),
|
||||
cereal::make_nvp("tokenType", tokenType),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("agent", agent)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::string profileType = "agent";
|
||||
|
@ -27,24 +27,9 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
class AgentSettingsSection
|
||||
{
|
||||
public:
|
||||
AgentSettingsSection(std::string _key, std::string _value) : key(_key), value(_value)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
AgentSettingsSection(std::string _key, std::string _value);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
@ -57,20 +42,7 @@ class IpsSnortSigsRulebase
|
||||
public:
|
||||
IpsSnortSigsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string profile_type = "KubernetesProfile";
|
||||
std::string upgrade_mode = "automatic";
|
||||
out_ar(
|
||||
cereal::make_nvp("agentSettings", agentSettings),
|
||||
cereal::make_nvp("agentType", profile_type),
|
||||
cereal::make_nvp("allowOnlyDefinedApplications", false),
|
||||
cereal::make_nvp("anyFog", true),
|
||||
cereal::make_nvp("maxNumberOfAgents", 10),
|
||||
cereal::make_nvp("upgradeMode", upgrade_mode)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::vector<AgentSettingsSection> agentSettings;
|
||||
|
@ -52,76 +52,14 @@ public:
|
||||
const std::string &_cefIpAddress,
|
||||
int _syslogPortNum,
|
||||
const std::string &_syslogIpAddress,
|
||||
bool _beautify_logs)
|
||||
:
|
||||
name(_name),
|
||||
verbosity(_verbosity),
|
||||
extendloggingMinSeverity(_extendloggingMinSeverity),
|
||||
extendlogging(_extendlogging),
|
||||
logToAgent(_logToAgent),
|
||||
logToCef(_logToCef),
|
||||
logToCloud(_logToCloud),
|
||||
logToSyslog(_logToSyslog),
|
||||
responseBody(_responseBody),
|
||||
tpDetect(_tpDetect),
|
||||
tpPrevent(_tpPrevent),
|
||||
webBody(_webBody),
|
||||
webHeaders(_webHeaders),
|
||||
webRequests(_webRequests),
|
||||
webUrlPath(_webUrlPath),
|
||||
webUrlQuery(_webUrlQuery),
|
||||
cefPortNum (_cefPortNum),
|
||||
cefIpAddress (_cefIpAddress),
|
||||
syslogPortNum (_syslogPortNum),
|
||||
syslogIpAddress (_syslogIpAddress),
|
||||
beautify_logs(_beautify_logs)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
context = "triggerId(" + id + ")";
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate log trigger UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
bool _beautify_logs
|
||||
);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string trigger_type = "log";
|
||||
std::string urlForSyslog = syslogIpAddress + ":" + std::to_string(syslogPortNum);
|
||||
std::string urlForCef = cefIpAddress + ":" + std::to_string(cefPortNum);
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("triggerType", trigger_type),
|
||||
cereal::make_nvp("verbosity", verbosity),
|
||||
cereal::make_nvp("acAllow", false),
|
||||
cereal::make_nvp("acDrop", false),
|
||||
cereal::make_nvp("complianceViolations", false),
|
||||
cereal::make_nvp("complianceWarnings", false),
|
||||
cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity),
|
||||
cereal::make_nvp("extendlogging", extendlogging),
|
||||
cereal::make_nvp("logToAgent", logToAgent),
|
||||
cereal::make_nvp("logToCef", logToCef),
|
||||
cereal::make_nvp("logToCloud", logToCloud),
|
||||
cereal::make_nvp("logToSyslog", logToSyslog),
|
||||
cereal::make_nvp("responseBody", responseBody),
|
||||
cereal::make_nvp("responseCode", false),
|
||||
cereal::make_nvp("tpDetect", tpDetect),
|
||||
cereal::make_nvp("tpPrevent", tpPrevent),
|
||||
cereal::make_nvp("webBody", webBody),
|
||||
cereal::make_nvp("webHeaders", webHeaders),
|
||||
cereal::make_nvp("webRequests", webRequests),
|
||||
cereal::make_nvp("webUrlPath", webUrlPath),
|
||||
cereal::make_nvp("webUrlQuery", webUrlQuery),
|
||||
cereal::make_nvp("urlForSyslog", urlForSyslog),
|
||||
cereal::make_nvp("urlForCef", urlForCef),
|
||||
cereal::make_nvp("formatLoggingOutput", beautify_logs)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
const std::string & getTriggerId() const { return id; }
|
||||
const std::string & getTriggerName() const { return name; }
|
||||
const std::string & getTriggerId() const;
|
||||
const std::string & getTriggerName() const;
|
||||
bool operator<(const LogTriggerSection &other) const;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
@ -152,43 +90,22 @@ private:
|
||||
class WebUserResponseTriggerSection
|
||||
{
|
||||
public:
|
||||
WebUserResponseTriggerSection() {}
|
||||
|
||||
WebUserResponseTriggerSection(
|
||||
const std::string &_name,
|
||||
const std::string &_details_level,
|
||||
const std::string &_response_body,
|
||||
int _response_code,
|
||||
const std::string &_response_title)
|
||||
:
|
||||
name(_name),
|
||||
context(),
|
||||
details_level(_details_level),
|
||||
response_body(_response_body),
|
||||
response_title(_response_title),
|
||||
response_code(_response_code)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
context = "triggerId(" + id + ")";
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate webUserResponse trigger UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
const std::string &_response_title
|
||||
);
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("details level", details_level),
|
||||
cereal::make_nvp("response body", response_body),
|
||||
cereal::make_nvp("response code", response_code),
|
||||
cereal::make_nvp("response title", response_title)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
const std::string & getTriggerId() const { return id; }
|
||||
const std::string & getTriggerName() const { return name; }
|
||||
const std::string & getTriggerId() const;
|
||||
const std::string & getTriggerName() const;
|
||||
|
||||
bool operator<(const WebUserResponseTriggerSection &other) const;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
@ -203,34 +120,13 @@ private:
|
||||
class AppSecCustomResponseSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec web user response spec";
|
||||
parseAppsecJSONKey<int>("http-response-code", httpResponseCode, archive_in, 403);
|
||||
parseAppsecJSONKey<std::string>("mode", mode, archive_in, "block-page");
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
if (mode == "block-page") {
|
||||
parseAppsecJSONKey<std::string>(
|
||||
"message-body",
|
||||
messageBody,
|
||||
archive_in,
|
||||
"Openappsec's <b>Application Security</b> has detected an attack and blocked it."
|
||||
);
|
||||
parseAppsecJSONKey<std::string>(
|
||||
"message-title",
|
||||
messageTitle,
|
||||
archive_in,
|
||||
"Attack blocked by web application protection"
|
||||
);
|
||||
}
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
int getHttpResponseCode() const { return httpResponseCode; }
|
||||
const std::string & getMessageBody() const { return messageBody; }
|
||||
const std::string & getMessageTitle() const { return messageTitle; }
|
||||
const std::string & getMode() const { return mode; }
|
||||
const std::string & getName() const { return name; }
|
||||
int getHttpResponseCode() const;
|
||||
const std::string & getMessageBody() const;
|
||||
const std::string & getMessageTitle() const;
|
||||
const std::string & getMode() const;
|
||||
const std::string & getName() const;
|
||||
|
||||
private:
|
||||
int httpResponseCode;
|
||||
@ -240,21 +136,6 @@ private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppSecCustomResponseSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "mode: "
|
||||
<< obj.getMode()
|
||||
<< "," << std::endl << "message-title: "
|
||||
<< obj.getMessageTitle()
|
||||
<< "," << std::endl << "message-body: "
|
||||
<< obj.getMessageBody()
|
||||
<< "," << std::endl << "http-response-code: "
|
||||
<< obj.getHttpResponseCode();
|
||||
return os;
|
||||
}
|
||||
|
||||
class TriggersRulebase
|
||||
{
|
||||
public:
|
||||
@ -266,14 +147,7 @@ public:
|
||||
webUserResponseTriggers(_webUserResponseTriggers) {}
|
||||
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("log", logTriggers),
|
||||
cereal::make_nvp("webUserResponse", webUserResponseTriggers)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
std::vector<LogTriggerSection> logTriggers;
|
||||
@ -283,49 +157,24 @@ private:
|
||||
class AppsecTriggerAccessControlLogging
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Access Control Logging";
|
||||
parseAppsecJSONKey<bool>("allow-events", allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("drop-events", drop_events, archive_in, false);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isAllowEvents() const { return allow_events; }
|
||||
bool isDropEvents() const { return drop_events; }
|
||||
bool isAllowEvents() const;
|
||||
bool isDropEvents() const;
|
||||
|
||||
private:
|
||||
bool allow_events = false;
|
||||
bool drop_events = false;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecTriggerAccessControlLogging &obj)
|
||||
{
|
||||
os
|
||||
<< "AppSec Trigger - Access Control Logging: "
|
||||
<< "isAllowEvents: "
|
||||
<< obj.isAllowEvents()
|
||||
<< " , isDropEvents: "
|
||||
<< obj.isDropEvents();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging";
|
||||
parseAppsecJSONKey<bool>("enabled", enabled, archive_in, true);
|
||||
parseAppsecJSONKey<bool>("response-body", response_body, archive_in, false);
|
||||
parseAppsecJSONKey<std::string>("minimum-severity", minimum_severity, archive_in, "high");
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isEnabled() const { return enabled; }
|
||||
bool isResponseBody() const { return response_body; }
|
||||
const std::string & getMinimumSeverity() const { return minimum_severity; }
|
||||
bool isEnabled() const;
|
||||
bool isResponseBody() const;
|
||||
const std::string & getMinimumSeverity() const;
|
||||
|
||||
private:
|
||||
bool enabled = true;
|
||||
@ -333,37 +182,15 @@ private:
|
||||
std::string minimum_severity = "high";
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecTriggerAdditionalSuspiciousEventsLogging &obj)
|
||||
{
|
||||
os
|
||||
<< "AppsecTriggerAdditionalSuspiciousEventsLogging: "
|
||||
<< "Enabled: "
|
||||
<< obj.isEnabled()
|
||||
<< " response_body: "
|
||||
<< obj.isResponseBody()
|
||||
<< " minimum_severity: "
|
||||
<< obj.getMinimumSeverity();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppsecTriggerLogging : public ClientRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Logging";
|
||||
parseAppsecJSONKey<bool>("all-web-requests", all_web_requests, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("detect-events", detect_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("prevent-events", prevent_events, archive_in, true);
|
||||
}
|
||||
load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isAllWebRequests() const { return all_web_requests; }
|
||||
|
||||
bool isDetectEvents() const { return detect_events; }
|
||||
|
||||
bool isPreventEvents() const { return prevent_events; }
|
||||
bool isAllWebRequests() const;
|
||||
bool isDetectEvents() const;
|
||||
bool isPreventEvents() const;
|
||||
|
||||
private:
|
||||
bool all_web_requests = false;
|
||||
@ -371,37 +198,15 @@ private:
|
||||
bool prevent_events = true;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecTriggerLogging &obj)
|
||||
{
|
||||
os
|
||||
<< "AppsecTriggerLogging: "
|
||||
<< "all_web_requests: "
|
||||
<< obj.isAllWebRequests()
|
||||
<< ", detect_events: "
|
||||
<< obj.isDetectEvents()
|
||||
<< ", prevent_events: "
|
||||
<< obj.isPreventEvents();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppsecTriggerExtendedLogging : public ClientRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Extended Logging";
|
||||
parseAppsecJSONKey<bool>("http-headers", http_headers, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("request-body", request_body, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("url-path", url_path, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("url-query", url_query, archive_in, false);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isHttpHeaders() const { return http_headers; }
|
||||
bool isRequestBody() const { return request_body; }
|
||||
bool isUrlPath() const { return url_path; }
|
||||
bool isUrlQuery() const { return url_query; }
|
||||
bool isHttpHeaders() const;
|
||||
bool isRequestBody() const;
|
||||
bool isUrlPath() const;
|
||||
bool isUrlQuery() const;
|
||||
|
||||
private:
|
||||
bool http_headers = false;
|
||||
@ -410,36 +215,14 @@ private:
|
||||
bool url_query = false;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecTriggerExtendedLogging &obj)
|
||||
{
|
||||
os
|
||||
<< "AppsecTriggerExtendedLogging: "
|
||||
<< "http_headers: "
|
||||
<< obj.isHttpHeaders()
|
||||
<< ", request_body: "
|
||||
<< obj.isRequestBody()
|
||||
<< ", url_path: "
|
||||
<< obj.isUrlPath()
|
||||
<< ", url_query: "
|
||||
<< obj.isUrlQuery();
|
||||
return os;
|
||||
}
|
||||
|
||||
class LoggingService
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseAppsecJSONKey<std::string>("address", address, archive_in);
|
||||
parseAppsecJSONKey<std::string>("proto", proto, archive_in);
|
||||
parseAppsecJSONKey<int>("port", port, archive_in, 514);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getAddress() const { return address; }
|
||||
const std::string & getProto() const { return proto; }
|
||||
int getPort() const { return port; }
|
||||
const std::string & getAddress() const;
|
||||
const std::string & getProto() const;
|
||||
int getPort() const;
|
||||
|
||||
private:
|
||||
std::string address;
|
||||
@ -452,13 +235,8 @@ class StdoutLogging
|
||||
public:
|
||||
StdoutLogging() : format("json") {}
|
||||
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseAppsecJSONKey<std::string>("format", format, archive_in, "json");
|
||||
}
|
||||
|
||||
const std::string & getFormat() const { return format; }
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
const std::string & getFormat() const;
|
||||
|
||||
private:
|
||||
std::string format;
|
||||
@ -467,35 +245,22 @@ private:
|
||||
class AppsecTriggerLogDestination : public ClientRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger LogDestination";
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
StdoutLogging stdout_log;
|
||||
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);
|
||||
agent_local = !(stdout_log.getFormat().empty());
|
||||
beautify_logs = stdout_log.getFormat() == "json-formatted";
|
||||
parseAppsecJSONKey<LoggingService>("syslog-service", syslog_service, archive_in);
|
||||
parseAppsecJSONKey<LoggingService>("cef-service", cef_service, archive_in);
|
||||
}
|
||||
int getCefServerUdpPort() const;
|
||||
int getSyslogServerUdpPort() const;
|
||||
bool isAgentLocal() const;
|
||||
bool shouldBeautifyLogs() const;
|
||||
|
||||
int getCefServerUdpPort() const { return getCefServiceData().getPort(); }
|
||||
int getSyslogServerUdpPort() const { return getSyslogServiceData().getPort(); }
|
||||
bool isAgentLocal() const { return agent_local; }
|
||||
bool shouldBeautifyLogs() const { return beautify_logs; }
|
||||
|
||||
bool getCloud() const { return cloud; }
|
||||
bool isCefNeeded() const { return !getCefServiceData().getAddress().empty(); }
|
||||
bool isSyslogNeeded() const { return !getSyslogServiceData().getAddress().empty(); }
|
||||
const std::string & getSyslogServerIpv4Address() const { return getSyslogServiceData().getAddress(); }
|
||||
const std::string & getCefServerIpv4Address() const { return getCefServiceData().getAddress(); }
|
||||
bool getCloud() const;
|
||||
bool isCefNeeded() const;
|
||||
bool isSyslogNeeded() const;
|
||||
const std::string & getSyslogServerIpv4Address() const;
|
||||
const std::string & getCefServerIpv4Address() const;
|
||||
|
||||
private:
|
||||
const LoggingService & getSyslogServiceData() const { return syslog_service; }
|
||||
const LoggingService & getCefServiceData() const { return cef_service; }
|
||||
const LoggingService & getSyslogServiceData() const;
|
||||
const LoggingService & getCefServiceData() const;
|
||||
|
||||
bool cloud = false;
|
||||
bool agent_local = true;
|
||||
@ -504,90 +269,17 @@ private:
|
||||
LoggingService cef_service;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecTriggerLogDestination &obj)
|
||||
{
|
||||
os
|
||||
<< "AppSec Trigger Log Destination:" << std::endl
|
||||
<< "agent_local: "
|
||||
<< obj.isAgentLocal()
|
||||
<< ", beautify_logs: "
|
||||
<< obj.shouldBeautifyLogs()
|
||||
<< ", cef_server_udp_port: "
|
||||
<< obj.getCefServerUdpPort()
|
||||
<< ", syslog_server_udp_port: "
|
||||
<< obj.getSyslogServerUdpPort()
|
||||
<< ", cef_service: "
|
||||
<< obj.isCefNeeded()
|
||||
<< ", cloud: "
|
||||
<< obj.getCloud()
|
||||
<< ", syslog: "
|
||||
<< obj.isSyslogNeeded()
|
||||
<< ", syslog_server_ipv4_address: "
|
||||
<< obj.getSyslogServerIpv4Address()
|
||||
<< ", cef_server_ipv4_address: "
|
||||
<< obj.getCefServerIpv4Address();
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppsecTriggerSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec trigger spec";
|
||||
parseAppsecJSONKey<AppsecTriggerAccessControlLogging>(
|
||||
"access-control-logging",
|
||||
access_control_logging,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<AppsecTriggerAdditionalSuspiciousEventsLogging>(
|
||||
"additional-suspicious-events-logging",
|
||||
additional_suspicious_events_logging,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<AppsecTriggerLogging>("appsec-logging", appsec_logging, archive_in);
|
||||
parseAppsecJSONKey<AppsecTriggerExtendedLogging>("extended-logging", extended_logging, archive_in);
|
||||
parseAppsecJSONKey<AppsecTriggerLogDestination>("log-destination", log_destination, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const AppsecTriggerAccessControlLogging &
|
||||
getAppsecTriggerAccessControlLogging() const
|
||||
{
|
||||
return access_control_logging;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const AppsecTriggerAdditionalSuspiciousEventsLogging &
|
||||
getAppsecTriggerAdditionalSuspiciousEventsLogging() const
|
||||
{
|
||||
return additional_suspicious_events_logging;
|
||||
}
|
||||
|
||||
const AppsecTriggerLogging &
|
||||
getAppsecTriggerLogging() const
|
||||
{
|
||||
return appsec_logging;
|
||||
}
|
||||
|
||||
const AppsecTriggerExtendedLogging &
|
||||
getAppsecTriggerExtendedLogging() const
|
||||
{
|
||||
return extended_logging;
|
||||
}
|
||||
|
||||
const AppsecTriggerLogDestination &
|
||||
getAppsecTriggerLogDestination() const
|
||||
{
|
||||
return log_destination;
|
||||
}
|
||||
const AppsecTriggerAccessControlLogging & getAppsecTriggerAccessControlLogging() const;
|
||||
const std::string & getName() const;
|
||||
const AppsecTriggerAdditionalSuspiciousEventsLogging & getAppsecTriggerAdditionalSuspiciousEventsLogging() const;
|
||||
const AppsecTriggerLogging & getAppsecTriggerLogging() const;
|
||||
const AppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const;
|
||||
const AppsecTriggerLogDestination & getAppsecTriggerLogDestination() const;
|
||||
|
||||
private:
|
||||
AppsecTriggerAccessControlLogging access_control_logging;
|
||||
@ -598,36 +290,13 @@ private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const AppsecTriggerSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "AppSec Access Control Logging:" << std::endl
|
||||
<< obj.getAppsecTriggerAccessControlLogging()
|
||||
<< std::endl << "AppSec Additional Suspocious Events Logging:" << std::endl
|
||||
<< obj.getAppsecTriggerAdditionalSuspiciousEventsLogging()
|
||||
<< std::endl << "AppSec Trigger Logging:" << std::endl
|
||||
<< obj.getAppsecTriggerLogging()
|
||||
<< std::endl << "Appsec Trigger Extended Logging:" << std::endl
|
||||
<< obj.getAppsecTriggerExtendedLogging()
|
||||
<< std::endl << "AppSec Trigger Log Destination:" << std::endl
|
||||
<< obj.getAppsecTriggerLogDestination();
|
||||
return os;
|
||||
}
|
||||
|
||||
class TriggersWrapper
|
||||
{
|
||||
public:
|
||||
TriggersWrapper(const TriggersRulebase &_triggers) : triggers_rulebase(_triggers)
|
||||
{}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulebase", triggers_rulebase)
|
||||
);
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
private:
|
||||
TriggersRulebase triggers_rulebase;
|
||||
|
@ -29,51 +29,18 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
class TrustedSourcesSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
|
||||
parseAppsecJSONKey<int>("minNumOfSources", min_num_of_sources, archive_in, 3);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("sourcesIdentifiers", sources_identifiers, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
int
|
||||
getMinNumOfSources() const
|
||||
{
|
||||
return min_num_of_sources;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &
|
||||
getSourcesIdentifiers() const
|
||||
{
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
int getMinNumOfSources() const;
|
||||
const std::vector<std::string> & getSourcesIdentifiers() const;
|
||||
const std::string & getName() const;
|
||||
|
||||
private:
|
||||
int min_num_of_sources;
|
||||
int min_num_of_sources = 0;
|
||||
std::string name;
|
||||
std::vector<std::string> sources_identifiers;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const TrustedSourcesSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "Min number of sources: "
|
||||
<< obj.getMinNumOfSources()
|
||||
<< ", SourceIdentifiers: ["
|
||||
<< makeSeparatedStr(obj.getSourcesIdentifiers(), ",")
|
||||
<< "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class SourcesIdentifiers
|
||||
{
|
||||
public:
|
||||
@ -83,20 +50,8 @@ public:
|
||||
value(_value)
|
||||
{}
|
||||
|
||||
void
|
||||
save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("sourceIdentifier", source_identifier),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
}
|
||||
|
||||
const std::string &
|
||||
getSourceIdent() const
|
||||
{
|
||||
return source_identifier;
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::string & getSourceIdent() const;
|
||||
|
||||
private:
|
||||
std::string source_identifier;
|
||||
@ -106,25 +61,10 @@ private:
|
||||
class SourceIdentifierSpec
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
|
||||
parseAppsecJSONKey<std::string>("sourceIdentifier", source_identifier, archive_in);
|
||||
parseAppsecJSONKey<std::vector<std::string>>("value", value, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string &
|
||||
getSourceIdentifier() const
|
||||
{
|
||||
return source_identifier;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &
|
||||
getValues() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
const std::string & getSourceIdentifier() const;
|
||||
const std::vector<std::string> & getValues() const;
|
||||
|
||||
private:
|
||||
std::string source_identifier;
|
||||
@ -134,43 +74,16 @@ private:
|
||||
class SourceIdentifierSpecWrapper
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading Source Identifier Spec Wrapper";
|
||||
parseAppsecJSONKey<std::vector<SourceIdentifierSpec>>("identifiers", identifiers, archive_in);
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
}
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string &
|
||||
getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::vector<SourceIdentifierSpec> &
|
||||
getIdentifiers() const
|
||||
{
|
||||
return identifiers;
|
||||
}
|
||||
const std::string & getName() const;
|
||||
const std::vector<SourceIdentifierSpec> & getIdentifiers() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<SourceIdentifierSpec> identifiers;
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const SourceIdentifierSpec &obj)
|
||||
{
|
||||
os
|
||||
<< "sourceIdentifier: "
|
||||
<< obj.getSourceIdentifier()
|
||||
<< ", values: ["
|
||||
<< makeSeparatedStr(obj.getValues(), ",")
|
||||
<< "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
class AppSecTrustedSources
|
||||
{
|
||||
public:
|
||||
@ -180,42 +93,16 @@ public:
|
||||
AppSecTrustedSources(
|
||||
const std::string &_name,
|
||||
int _num_of_sources,
|
||||
const std::vector<SourcesIdentifiers> &_sources_identifiers)
|
||||
:
|
||||
name(_name),
|
||||
num_of_sources(_num_of_sources),
|
||||
sources_identifiers(_sources_identifiers)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate Trusted Sources ID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
const std::vector<SourcesIdentifiers> &_sources_identifiers
|
||||
);
|
||||
|
||||
void
|
||||
save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
std::string parameter_type = "TrustedSource";
|
||||
out_ar(
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("numOfSources", num_of_sources),
|
||||
cereal::make_nvp("sourcesIdentifiers", sources_identifiers),
|
||||
cereal::make_nvp("parameterType", parameter_type)
|
||||
);
|
||||
}
|
||||
|
||||
const std::vector<SourcesIdentifiers> &
|
||||
getSourcesIdentifiers() const
|
||||
{
|
||||
return sources_identifiers;
|
||||
}
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
const std::vector<SourcesIdentifiers> & getSourcesIdentifiers() const;
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
std::string name;
|
||||
int num_of_sources;
|
||||
int num_of_sources = 0;
|
||||
std::vector<SourcesIdentifiers> sources_identifiers;
|
||||
};
|
||||
// LCOV_EXCL_STOP
|
||||
|
@ -0,0 +1,178 @@
|
||||
#include "ingress_data.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
void
|
||||
IngressMetadata::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "IngressMetadata load";
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<string>("resourceVersion", resourceVersion, archive_in);
|
||||
parseAppsecJSONKey<string>("namespace", namespace_name, archive_in);
|
||||
parseAppsecJSONKey<map<string, string>>("annotations", annotations, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressMetadata::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressMetadata::getResourceVersion() const
|
||||
{
|
||||
return resourceVersion;
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressMetadata::getNamespace() const
|
||||
{
|
||||
return namespace_name;
|
||||
}
|
||||
|
||||
const map<string, string> &
|
||||
IngressMetadata::getAnnotations() const
|
||||
{
|
||||
return annotations;
|
||||
}
|
||||
|
||||
void
|
||||
IngressRulePath::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path";
|
||||
parseAppsecJSONKey<string>("path", path, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressRulePath::getPath() const
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
void
|
||||
IngressRulePathsWrapper::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path wrapper";
|
||||
parseAppsecJSONKey<vector<IngressRulePath>>("paths", paths, archive_in);
|
||||
}
|
||||
|
||||
const vector<IngressRulePath> &
|
||||
IngressRulePathsWrapper::getRulePaths() const
|
||||
{
|
||||
return paths;
|
||||
}
|
||||
|
||||
void
|
||||
IngressDefinedRule::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule";
|
||||
parseAppsecJSONKey<string>("host", host, archive_in);
|
||||
parseAppsecJSONKey<IngressRulePathsWrapper>("http", paths_wrapper, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressDefinedRule::getHost() const
|
||||
{
|
||||
return host;
|
||||
}
|
||||
|
||||
const IngressRulePathsWrapper &
|
||||
IngressDefinedRule::getPathsWrapper() const
|
||||
{
|
||||
return paths_wrapper;
|
||||
}
|
||||
|
||||
void
|
||||
DefaultBackend::load(cereal::JSONInputArchive &)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading Default Backend";
|
||||
is_exists = true;
|
||||
}
|
||||
|
||||
bool
|
||||
DefaultBackend::isExists() const
|
||||
{
|
||||
return is_exists;
|
||||
}
|
||||
|
||||
void
|
||||
IngressSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading single ingress spec";
|
||||
parseAppsecJSONKey<string>("ingressClassName", ingress_class_name, archive_in);
|
||||
parseAppsecJSONKey<vector<IngressDefinedRule>>("rules", rules, archive_in);
|
||||
parseAppsecJSONKey<DefaultBackend>("defaultBackend", default_backend, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressSpec::getIngressClassName() const
|
||||
{
|
||||
return ingress_class_name;
|
||||
}
|
||||
|
||||
const vector<IngressDefinedRule> &
|
||||
IngressSpec::getRules() const
|
||||
{
|
||||
return rules;
|
||||
}
|
||||
bool
|
||||
IngressSpec::isDefaultBackendExists() const
|
||||
{
|
||||
return default_backend.isExists();
|
||||
}
|
||||
|
||||
void
|
||||
SingleIngressData::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading single ingress data";
|
||||
parseAppsecJSONKey<IngressMetadata>("metadata", metadata, archive_in);
|
||||
parseAppsecJSONKey<IngressSpec>("spec", spec, archive_in);
|
||||
}
|
||||
|
||||
const IngressMetadata &
|
||||
SingleIngressData::getMetadata() const
|
||||
{
|
||||
return metadata;
|
||||
}
|
||||
|
||||
const IngressSpec &
|
||||
SingleIngressData::getSpec() const
|
||||
{
|
||||
return spec;
|
||||
}
|
||||
|
||||
bool
|
||||
IngressData::loadJson(const string &json)
|
||||
{
|
||||
string modified_json = json;
|
||||
modified_json.pop_back();
|
||||
stringstream in;
|
||||
in.str(modified_json);
|
||||
dbgTrace(D_K8S_POLICY) << "Loading ingress data";
|
||||
try {
|
||||
cereal::JSONInputArchive in_ar(in);
|
||||
in_ar(
|
||||
cereal::make_nvp("apiVersion", apiVersion),
|
||||
cereal::make_nvp("items", items)
|
||||
);
|
||||
} catch (cereal::Exception &e) {
|
||||
dbgError(D_K8S_POLICY) << "Failed to load ingress data JSON. Error: " << e.what();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const string &
|
||||
IngressData::getapiVersion() const
|
||||
{
|
||||
return apiVersion;
|
||||
}
|
||||
|
||||
const vector<SingleIngressData> &
|
||||
IngressData::getItems() const
|
||||
{
|
||||
return items;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
@ -44,6 +44,7 @@
|
||||
#include "include/exceptions_section.h"
|
||||
#include "include/rules_config_section.h"
|
||||
#include "include/trusted_sources_section.h"
|
||||
#include "include/policy_maker_utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -56,62 +57,6 @@ const static string syslog_key = "syslog";
|
||||
const static string mode_key = "mode";
|
||||
const static string local_mgmt_policy_path = "/conf/local_policy.yaml";
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
class SecurityAppsWrapper
|
||||
{
|
||||
public:
|
||||
SecurityAppsWrapper(
|
||||
const AppSecWrapper &_waap,
|
||||
const TriggersWrapper &_trrigers,
|
||||
const RulesConfigWrapper &_rules,
|
||||
const ExceptionsWrapper &_exceptions,
|
||||
const string &_policy_version)
|
||||
:
|
||||
waap(_waap),
|
||||
trrigers(_trrigers),
|
||||
rules(_rules),
|
||||
exceptions(_exceptions),
|
||||
policy_version(_policy_version) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("waap", waap),
|
||||
cereal::make_nvp("triggers", trrigers),
|
||||
cereal::make_nvp("rules", rules),
|
||||
cereal::make_nvp("exceptions", exceptions),
|
||||
cereal::make_nvp("version", policy_version)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
AppSecWrapper waap;
|
||||
TriggersWrapper trrigers;
|
||||
RulesConfigWrapper rules;
|
||||
ExceptionsWrapper exceptions;
|
||||
string policy_version;
|
||||
};
|
||||
|
||||
class K8sPolicyWrapper
|
||||
{
|
||||
public:
|
||||
K8sPolicyWrapper(
|
||||
const SettingsWrapper &_settings,
|
||||
const SecurityAppsWrapper &_security_apps)
|
||||
:
|
||||
settings(_settings),
|
||||
security_apps(_security_apps) {}
|
||||
|
||||
void
|
||||
serialize(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
security_apps.serialize(out_ar);
|
||||
}
|
||||
|
||||
private:
|
||||
SettingsWrapper settings;
|
||||
SecurityAppsWrapper security_apps;
|
||||
};
|
||||
|
||||
class NamespaceMetadata
|
||||
{
|
||||
@ -120,16 +65,16 @@ public:
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgInfo(D_K8S_POLICY) << "NamespaceMetadata load";
|
||||
parseAppsecJSONKey<std::string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<std::string>("uid", uid, archive_in);
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
parseAppsecJSONKey<string>("uid", uid, archive_in);
|
||||
}
|
||||
|
||||
const std::string & getName() const { return name; }
|
||||
const std::string & getUID() const { return uid; }
|
||||
const string & getName() const { return name; }
|
||||
const string & getUID() const { return uid; }
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string uid;
|
||||
string name;
|
||||
string uid;
|
||||
};
|
||||
|
||||
class SingleNamespaceData
|
||||
@ -151,12 +96,12 @@ class NamespaceData : public ClientRest
|
||||
{
|
||||
public:
|
||||
bool
|
||||
loadJson(const std::string &json)
|
||||
loadJson(const string &json)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading namespace data";
|
||||
std::string modified_json = json;
|
||||
string modified_json = json;
|
||||
modified_json.pop_back();
|
||||
std::stringstream in;
|
||||
stringstream in;
|
||||
in.str(modified_json);
|
||||
try {
|
||||
cereal::JSONInputArchive in_ar(in);
|
||||
@ -170,10 +115,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<SingleNamespaceData> & getItems() const { return items; }
|
||||
const vector<SingleNamespaceData> & getItems() const { return items; }
|
||||
|
||||
private:
|
||||
std::vector<SingleNamespaceData> items;
|
||||
vector<SingleNamespaceData> items;
|
||||
};
|
||||
|
||||
class LocalPolicyMgmtGenerator::Impl
|
||||
@ -289,7 +234,7 @@ public:
|
||||
return appsec_policy;
|
||||
});
|
||||
|
||||
vector<ParsedRule> specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules();
|
||||
list<ParsedRule> specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules();
|
||||
ParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule();
|
||||
|
||||
string asset;
|
||||
@ -461,7 +406,7 @@ public:
|
||||
);
|
||||
string port = "80";
|
||||
string full_url = asset_name == "Any" ? "" : url + uri + ":" + port;
|
||||
string asset_id = rules_config.getAsstId();
|
||||
string asset_id = rules_config.getAssetId();
|
||||
string practice_id = rules_config.getPracticeId();
|
||||
|
||||
if (!generated_apps.count(full_url)) {
|
||||
@ -483,7 +428,7 @@ public:
|
||||
parsed_rules.push_back(rules_config);
|
||||
generated_apps.insert(full_url);
|
||||
}
|
||||
}
|
||||
} //end specific rules
|
||||
|
||||
string exception_name;
|
||||
if (!default_rule.getExceptions().empty()) {
|
||||
@ -563,9 +508,9 @@ public:
|
||||
);
|
||||
|
||||
SettingsWrapper profiles_section = createProfilesSection();
|
||||
K8sPolicyWrapper k8s_policy = K8sPolicyWrapper(profiles_section, security_app_section);
|
||||
PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section);
|
||||
|
||||
return dumpPolicyToFile(k8s_policy);
|
||||
return dumpPolicyToFile(policy_wrapper);
|
||||
}
|
||||
|
||||
LocalPolicyEnv getEnvType() const { return env_type;}
|
||||
@ -608,14 +553,6 @@ public:
|
||||
dbgTrace(D_K8S_POLICY) << "Ingress items ammount: " << ingress.getItems().size();
|
||||
// TBD: break to methods : INXT-31445
|
||||
for (const SingleIngressData &item : ingress.getItems()) {
|
||||
dbgTrace(D_K8S_POLICY)
|
||||
<< "Metadata name is: "
|
||||
<< item.getMetadata().getName()
|
||||
<< ", Namespace is: "
|
||||
<< item.getMetadata().getNamespace()
|
||||
<< ", Spec: "
|
||||
<< item.getSpec();
|
||||
|
||||
set<pair<string, string>> specific_assets_from_ingress;
|
||||
for (const IngressDefinedRule &rule : item.getSpec().getRules()) {
|
||||
string url = rule.getHost();
|
||||
@ -670,9 +607,8 @@ public:
|
||||
}
|
||||
|
||||
AppsecSpecParser<AppsecPolicySpec> appsec_policy = maybe_appsec_policy.unpack();
|
||||
dbgTrace(D_K8S_POLICY) << "Succeessfully retrieved AppSec policy: " << appsec_policy.getSpec();
|
||||
|
||||
vector<ParsedRule> specific_rules = appsec_policy.getSpec().getSpecificRules();
|
||||
list<ParsedRule> specific_rules = appsec_policy.getSpec().getSpecificRules();
|
||||
ParsedRule default_rule = appsec_policy.getSpec().getDefaultRule();
|
||||
|
||||
for (const ParsedRule &parsed_rule : specific_rules) {
|
||||
@ -799,10 +735,6 @@ public:
|
||||
|
||||
AppsecSpecParser<AppSecPracticeSpec> appsec_practice = maybe_appsec_practice.unpack();
|
||||
practice_map.emplace(practice_annotation_name, appsec_practice.getSpec());
|
||||
dbgTrace(D_K8S_POLICY)
|
||||
<< "Successfully retrieved AppSec practice"
|
||||
<< practice_annotation_name
|
||||
<< appsec_practice.getSpec();
|
||||
}
|
||||
|
||||
string log_trigger_id;
|
||||
@ -830,7 +762,7 @@ public:
|
||||
);
|
||||
string port = "80";
|
||||
string full_url = asset_name == "Any" ? "" : url + "/" + uri + ":" + port;
|
||||
string asset_id = rules_config.getAsstId();
|
||||
string asset_id = rules_config.getAssetId();
|
||||
string practice_id = rules_config.getPracticeId();
|
||||
|
||||
if (!generated_apps.count(full_url)) {
|
||||
@ -917,10 +849,6 @@ public:
|
||||
|
||||
AppsecSpecParser<AppSecPracticeSpec> appsec_practice = maybe_appsec_practice.unpack();
|
||||
practice_map.emplace(practice_name, appsec_practice.getSpec());
|
||||
dbgTrace(D_K8S_POLICY)
|
||||
<< "Successfully retrieved AppSec practice"
|
||||
<< practice_name
|
||||
<< appsec_practice.getSpec();
|
||||
}
|
||||
|
||||
if (item.getSpec().isDefaultBackendExists()) {
|
||||
@ -978,7 +906,7 @@ public:
|
||||
parsed_rules.push_back(default_rule_config);
|
||||
}
|
||||
|
||||
string asset_id = default_rule_config.getAsstId();
|
||||
string asset_id = default_rule_config.getAssetId();
|
||||
string practice_id = default_rule_config.getPracticeId();
|
||||
|
||||
if (!generated_apps.count(asset.first + asset.second)) {
|
||||
@ -1035,7 +963,7 @@ public:
|
||||
);
|
||||
|
||||
SettingsWrapper profiles_section = createProfilesSection();
|
||||
K8sPolicyWrapper k8s_policy = K8sPolicyWrapper(profiles_section, security_app_section);
|
||||
PolicyWrapper k8s_policy = PolicyWrapper(profiles_section, security_app_section);
|
||||
|
||||
return dumpPolicyToFile(k8s_policy);
|
||||
}
|
||||
@ -1238,7 +1166,7 @@ private:
|
||||
env_value.begin(),
|
||||
env_value.end(),
|
||||
env_value.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); }
|
||||
[](unsigned char c) { return tolower(c); }
|
||||
);
|
||||
return env_value == "true";
|
||||
}
|
||||
@ -1283,12 +1211,12 @@ private:
|
||||
}
|
||||
|
||||
const string
|
||||
dumpPolicyToFile(const K8sPolicyWrapper &k8s_policy) const
|
||||
dumpPolicyToFile(const PolicyWrapper &policy) const
|
||||
{
|
||||
stringstream ss;
|
||||
{
|
||||
cereal::JSONOutputArchive ar(ss);
|
||||
k8s_policy.serialize(ar);
|
||||
policy.save(ar);
|
||||
}
|
||||
string policy_str = ss.str();
|
||||
ofstream policy_file(local_appsec_policy_path);
|
||||
@ -1300,12 +1228,18 @@ private:
|
||||
string
|
||||
readFileContent(const string&file_path)
|
||||
{
|
||||
ifstream file(file_path);
|
||||
stringstream buffer;
|
||||
|
||||
buffer << file.rdbuf();
|
||||
|
||||
return buffer.str();
|
||||
try {
|
||||
ifstream file(file_path);
|
||||
stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
return buffer.str();
|
||||
} catch (ifstream::failure &f) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Cannot read the file"
|
||||
<< " File: " << file_path
|
||||
<< " Error: " << f.what();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
@ -1436,12 +1370,6 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
dbgTrace(D_K8S_POLICY)
|
||||
<< "Successfuly retrieved AppSec exceptions for "
|
||||
<< trigger_annotation_name
|
||||
<< ":\n"
|
||||
<< *maybe_appsec_trigger_spec;
|
||||
|
||||
LogTriggerSection log_triggers_section =
|
||||
createLogTriggersSection(trigger_annotation_name, false, "", *maybe_appsec_trigger_spec);
|
||||
log_triggers_map.emplace(trigger_annotation_name, log_triggers_section);
|
||||
@ -1688,12 +1616,6 @@ private:
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
dbgTrace(D_K8S_POLICY)
|
||||
<< "Successfuly retrieved AppSec web user response for: "
|
||||
<< web_user_res_annotation_name
|
||||
<< ":\n"
|
||||
<< appsec_web_user_res_spec;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,579 @@
|
||||
#include "policy_maker_utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_POLICY);
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
void
|
||||
SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("waap", waap),
|
||||
cereal::make_nvp("triggers", trrigers),
|
||||
cereal::make_nvp("rules", rules),
|
||||
cereal::make_nvp("exceptions", exceptions),
|
||||
cereal::make_nvp("version", policy_version)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
PolicyWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
security_apps.save(out_ar);
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::clearElementsMaps()
|
||||
{
|
||||
log_triggers.clear();
|
||||
web_user_res_triggers.clear();
|
||||
inner_exceptions.clear();
|
||||
web_apps.clear();
|
||||
rules_config.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
PolicyMakerUtils::startsWith(const string &str, const string &prefix)
|
||||
{
|
||||
return str.rfind(prefix, 0) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
PolicyMakerUtils::endsWith(const string &str, const string &suffix)
|
||||
{
|
||||
return str.size() >= suffix.size() &&
|
||||
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
tuple<string, string, string>
|
||||
PolicyMakerUtils::splitHostName(const string &host_name)
|
||||
{
|
||||
string url = host_name;
|
||||
string uri;
|
||||
string port;
|
||||
if (startsWith(url, "http://")) {
|
||||
url = url.substr(7, url.length() - 1);
|
||||
port = "80";
|
||||
} else if (startsWith(url, "https://")) {
|
||||
url = url.substr(8, url.length() - 1);
|
||||
port = "443";
|
||||
}
|
||||
|
||||
if (url.find("/") != string::npos) {
|
||||
uri = url.substr(url.find("/"));
|
||||
url = url.substr(0, url.find("/"));
|
||||
} else {
|
||||
uri = "";
|
||||
}
|
||||
|
||||
if (url.find(":") != string::npos) {
|
||||
port = url.substr(url.find(":") + 1, url.length() - 1);
|
||||
url = url.substr(0, url.find(":"));
|
||||
}
|
||||
|
||||
if (host_name == "*") {
|
||||
url = "Any";
|
||||
uri = "Any";
|
||||
}
|
||||
return make_tuple(url, port, uri);
|
||||
}
|
||||
|
||||
string
|
||||
PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &policy_path) const
|
||||
{
|
||||
stringstream ss;
|
||||
{
|
||||
cereal::JSONOutputArchive ar(ss);
|
||||
policy.save(ar);
|
||||
}
|
||||
string policy_str = ss.str();
|
||||
dbgTrace(D_NGINX_POLICY) << "policy: " << policy_str;
|
||||
try {
|
||||
ofstream policy_file(policy_path);
|
||||
policy_file << policy_str;
|
||||
policy_file.close();
|
||||
} catch (const ofstream::failure &e) {
|
||||
dbgDebug(D_NGINX_POLICY) << "Error while writing new policy to " << policy_path << ", Error: " << e.what();
|
||||
return "";
|
||||
}
|
||||
return policy_str;
|
||||
}
|
||||
|
||||
map<AnnotationTypes, string>
|
||||
extractAnnotationsNames(
|
||||
const ParsedRule &parsed_rule,
|
||||
const ParsedRule &default_rule,
|
||||
const string &policy_name)
|
||||
{
|
||||
map<AnnotationTypes, string> rule_annotation;
|
||||
string practice_annotation_name;
|
||||
// TBD: support multiple practices
|
||||
if (!parsed_rule.getPractices().empty() && !parsed_rule.getPractices()[0].empty()) {
|
||||
practice_annotation_name = parsed_rule.getPractices()[0];
|
||||
} else if (!default_rule.getPractices().empty() && !default_rule.getPractices()[0].empty()) {
|
||||
practice_annotation_name = default_rule.getPractices()[0];
|
||||
}
|
||||
|
||||
if (!practice_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::PRACTICE] = policy_name + "/" + practice_annotation_name;
|
||||
}
|
||||
|
||||
string trigger_annotation_name;
|
||||
// TBD: support multiple triggers
|
||||
if (!parsed_rule.getLogTriggers().empty() && !parsed_rule.getLogTriggers()[0].empty()) {
|
||||
trigger_annotation_name = parsed_rule.getLogTriggers()[0];
|
||||
} else if (!default_rule.getLogTriggers().empty() && !default_rule.getLogTriggers()[0].empty()) {
|
||||
trigger_annotation_name = default_rule.getLogTriggers()[0];
|
||||
}
|
||||
|
||||
if (!trigger_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name;
|
||||
}
|
||||
|
||||
string exception_annotation_name;
|
||||
// TBD: support multiple exceptions
|
||||
if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) {
|
||||
exception_annotation_name = parsed_rule.getExceptions()[0];
|
||||
} else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) {
|
||||
exception_annotation_name = default_rule.getExceptions()[0];
|
||||
}
|
||||
|
||||
if (!exception_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name;
|
||||
}
|
||||
|
||||
string web_user_res_annotation_name =
|
||||
parsed_rule.getCustomResponse().empty() ?
|
||||
default_rule.getCustomResponse() :
|
||||
parsed_rule.getCustomResponse();
|
||||
|
||||
if (!web_user_res_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::WEB_USER_RES] = policy_name + "/" + web_user_res_annotation_name;
|
||||
}
|
||||
|
||||
string source_identifiers_annotation_name =
|
||||
parsed_rule.getSourceIdentifiers().empty() ?
|
||||
default_rule.getSourceIdentifiers() :
|
||||
parsed_rule.getSourceIdentifiers();
|
||||
|
||||
if (!source_identifiers_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::SOURCE_IDENTIFIERS] = policy_name + "/" + source_identifiers_annotation_name;
|
||||
}
|
||||
|
||||
string trusted_sources_annotation_name =
|
||||
parsed_rule.getTrustedSources ().empty() ?
|
||||
default_rule.getTrustedSources() :
|
||||
parsed_rule.getTrustedSources();
|
||||
|
||||
if (!trusted_sources_annotation_name.empty()) {
|
||||
rule_annotation[AnnotationTypes::TRUSTED_SOURCES] = policy_name + "/" + trusted_sources_annotation_name;
|
||||
}
|
||||
return rule_annotation;
|
||||
}
|
||||
|
||||
template<class container_it>
|
||||
container_it
|
||||
extractElement(container_it begin, container_it end, const string &element_name)
|
||||
{
|
||||
dbgTrace(D_NGINX_POLICY) << "Tryting to find element: " << element_name;
|
||||
string clean_element_name = element_name.substr(element_name.find("/") + 1);
|
||||
for (container_it it = begin; it < end; it++) {
|
||||
if (clean_element_name == it->getName()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was found";
|
||||
return it;
|
||||
}
|
||||
}
|
||||
dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was not found";
|
||||
return end;
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
vector<V>
|
||||
convertMapToVector(map<K, V> map)
|
||||
{
|
||||
vector<V> vec;
|
||||
vec.reserve(map.size());
|
||||
if (map.empty()) {
|
||||
return vec;
|
||||
}
|
||||
for (const auto &m : map) {
|
||||
if (!m.first.empty()) vec.push_back(m.second);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
AppSecPracticeSpec
|
||||
getAppsecPracticeSpec(const string &practice_annotation_name, const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
auto practices_vec = policy.getAppSecPracticeSpecs();
|
||||
auto practice_it = extractElement(practices_vec.begin(), practices_vec.end(), practice_annotation_name);
|
||||
|
||||
if (practice_it == practices_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec practice";
|
||||
return AppSecPracticeSpec();
|
||||
}
|
||||
return *practice_it;
|
||||
}
|
||||
|
||||
AppsecTriggerSpec
|
||||
getAppsecTriggerSpec(const string &trigger_annotation_name, const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
auto triggers_vec = policy.getAppsecTriggerSpecs();
|
||||
auto trigger_it = extractElement(triggers_vec.begin(), triggers_vec.end(), trigger_annotation_name);
|
||||
|
||||
if (trigger_it == triggers_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trigger";
|
||||
return AppsecTriggerSpec();
|
||||
}
|
||||
return *trigger_it;
|
||||
}
|
||||
|
||||
AppsecExceptionSpec
|
||||
getAppsecExceptionSpec(const string &exception_annotation_name, const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
auto exceptions_vec = policy.getAppsecExceptionSpecs();
|
||||
auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name);
|
||||
|
||||
if (exception_it == exceptions_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec exception";
|
||||
return AppsecExceptionSpec();
|
||||
}
|
||||
return *exception_it;
|
||||
}
|
||||
|
||||
AppSecCustomResponseSpec
|
||||
getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
auto custom_response_vec = policy.getAppSecCustomResponseSpecs();
|
||||
auto custom_response_it = extractElement(
|
||||
custom_response_vec.begin(),
|
||||
custom_response_vec.end(),
|
||||
custom_response_annotation_name);
|
||||
|
||||
if (custom_response_it == custom_response_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec custom response";
|
||||
return AppSecCustomResponseSpec();
|
||||
}
|
||||
return *custom_response_it;
|
||||
}
|
||||
|
||||
SourceIdentifierSpecWrapper
|
||||
getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
auto source_identifiers_vec = policy.getAppsecSourceIdentifierSpecs();
|
||||
auto source_identifier_it = extractElement(
|
||||
source_identifiers_vec.begin(),
|
||||
source_identifiers_vec.end(),
|
||||
source_identifiers_annotation_name);
|
||||
|
||||
if (source_identifier_it == source_identifiers_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec source identifier";
|
||||
return SourceIdentifierSpecWrapper();
|
||||
}
|
||||
return *source_identifier_it;
|
||||
}
|
||||
|
||||
TrustedSourcesSpec
|
||||
getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
auto trusted_sources_vec = policy.getAppsecTrustedSourceSpecs();
|
||||
auto trusted_sources_it = extractElement(
|
||||
trusted_sources_vec.begin(),
|
||||
trusted_sources_vec.end(),
|
||||
trusted_sources_annotation_name);
|
||||
|
||||
if (trusted_sources_it == trusted_sources_vec.end()) {
|
||||
dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trusted source";
|
||||
return TrustedSourcesSpec();
|
||||
}
|
||||
return *trusted_sources_it;
|
||||
}
|
||||
|
||||
LogTriggerSection
|
||||
createLogTriggerSection(
|
||||
const string &trigger_annotation_name,
|
||||
const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
AppsecTriggerSpec trigger_spec = getAppsecTriggerSpec(trigger_annotation_name, policy);
|
||||
|
||||
string verbosity = "Standard";
|
||||
string extendLoggingMinSeverity =
|
||||
trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().getMinimumSeverity();
|
||||
bool tpDetect = trigger_spec.getAppsecTriggerLogging().isDetectEvents();
|
||||
bool tpPrevent = trigger_spec.getAppsecTriggerLogging().isPreventEvents();
|
||||
bool webRequests = trigger_spec.getAppsecTriggerLogging().isAllWebRequests();
|
||||
bool webUrlPath = trigger_spec.getAppsecTriggerExtendedLogging().isUrlPath();
|
||||
bool webUrlQuery = trigger_spec.getAppsecTriggerExtendedLogging().isUrlQuery();
|
||||
bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders();
|
||||
bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody();
|
||||
bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud();
|
||||
bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal();
|
||||
bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs();
|
||||
bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded();
|
||||
bool logToSyslog = trigger_spec.getAppsecTriggerLogDestination().isSyslogNeeded();
|
||||
bool responseBody = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isResponseBody();
|
||||
bool extendLogging = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isEnabled();
|
||||
int cefPortNum = logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerUdpPort() : 0;
|
||||
string cefIpAddress =
|
||||
logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerIpv4Address() : "";
|
||||
int syslogPortNum =
|
||||
logToSyslog ?
|
||||
trigger_spec.getAppsecTriggerLogDestination().getSyslogServerUdpPort() :
|
||||
514;
|
||||
string syslogIpAddress =
|
||||
logToSyslog ?
|
||||
trigger_spec.getAppsecTriggerLogDestination().getSyslogServerIpv4Address() :
|
||||
"";
|
||||
|
||||
LogTriggerSection log(
|
||||
trigger_annotation_name,
|
||||
verbosity,
|
||||
extendLoggingMinSeverity,
|
||||
extendLogging,
|
||||
logToAgent,
|
||||
logToCef,
|
||||
logToCloud,
|
||||
logToSyslog,
|
||||
responseBody,
|
||||
tpDetect,
|
||||
tpPrevent,
|
||||
webBody,
|
||||
webHeaders,
|
||||
webRequests,
|
||||
webUrlPath,
|
||||
webUrlQuery,
|
||||
cefPortNum,
|
||||
cefIpAddress,
|
||||
syslogPortNum,
|
||||
syslogIpAddress,
|
||||
beautify_logs
|
||||
);
|
||||
return log;
|
||||
}
|
||||
|
||||
WebUserResponseTriggerSection
|
||||
createWebUserResponseTriggerSection(
|
||||
const string &web_user_res_annotation_name,
|
||||
const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
AppSecCustomResponseSpec web_user_res_spec = getAppsecCustomResponseSpec(web_user_res_annotation_name, policy);
|
||||
string mode = web_user_res_spec.getMode();
|
||||
string response_body = web_user_res_spec.getMessageBody();
|
||||
string response_title = web_user_res_spec.getMessageTitle();
|
||||
int response_code = web_user_res_spec.getHttpResponseCode();
|
||||
|
||||
WebUserResponseTriggerSection web_user_res(
|
||||
web_user_res_annotation_name,
|
||||
mode,
|
||||
response_body,
|
||||
response_code,
|
||||
response_title
|
||||
);
|
||||
|
||||
return web_user_res;
|
||||
}
|
||||
|
||||
InnerException
|
||||
createExceptionSection(
|
||||
const string &exception_annotation_name,
|
||||
const AppsecLinuxPolicy &policy)
|
||||
{
|
||||
AppsecExceptionSpec exception_spec = getAppsecExceptionSpec(exception_annotation_name, policy);
|
||||
ExceptionMatch exception_match(exception_spec);
|
||||
string behavior =
|
||||
exception_spec.getAction() == "skip" ?
|
||||
"ignore" :
|
||||
exception_spec.getAction();
|
||||
ExceptionBehavior exception_behavior("action", behavior);
|
||||
InnerException inner_exception(exception_behavior, exception_match);
|
||||
return inner_exception;
|
||||
}
|
||||
|
||||
RulesConfigRulebase
|
||||
createMultiRulesSections(
|
||||
const string &url,
|
||||
const string &uri,
|
||||
const string &practice_id,
|
||||
const string &practice_name,
|
||||
const string &practice_type,
|
||||
const string &log_trigger_name,
|
||||
const string &log_trigger_id,
|
||||
const string &log_trigger_type,
|
||||
const string &web_user_res_vec_name,
|
||||
const string &web_user_res_vec_id,
|
||||
const string &web_user_res_vec_type,
|
||||
const string &asset_name,
|
||||
const string &exception_name,
|
||||
const string &exception_id)
|
||||
{
|
||||
PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name);
|
||||
ParametersSection exception_param = ParametersSection(exception_id, exception_name);
|
||||
|
||||
vector<RulesTriggerSection> triggers;
|
||||
if (!log_trigger_id.empty()) {
|
||||
triggers.push_back(RulesTriggerSection(log_trigger_name, log_trigger_id, log_trigger_type));
|
||||
}
|
||||
if (!web_user_res_vec_id.empty()) {
|
||||
triggers.push_back(RulesTriggerSection(
|
||||
web_user_res_vec_name,
|
||||
web_user_res_vec_id,
|
||||
web_user_res_vec_type)
|
||||
);
|
||||
}
|
||||
|
||||
RulesConfigRulebase rules_config = RulesConfigRulebase(
|
||||
asset_name,
|
||||
url,
|
||||
uri,
|
||||
{practice},
|
||||
{exception_param},
|
||||
triggers
|
||||
);
|
||||
return rules_config;
|
||||
}
|
||||
|
||||
SettingsWrapper
|
||||
createProfilesSection()
|
||||
{
|
||||
string agent_settings_key = "agent.test.policy";
|
||||
string agent_settings_value = "local policy";
|
||||
AgentSettingsSection agent_setting_1 = AgentSettingsSection(agent_settings_key, agent_settings_value);
|
||||
|
||||
SettingsRulebase settings_rulebase_1 = SettingsRulebase({agent_setting_1});
|
||||
return SettingsWrapper(settings_rulebase_1);
|
||||
}
|
||||
|
||||
PolicyWrapper
|
||||
PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
|
||||
{
|
||||
TriggersWrapper triggers_section(
|
||||
TriggersRulebase(
|
||||
convertMapToVector(log_triggers), convertMapToVector(web_user_res_triggers)
|
||||
)
|
||||
);
|
||||
ExceptionsWrapper exceptions_section({
|
||||
ExceptionsRulebase(convertMapToVector(inner_exceptions))
|
||||
});
|
||||
|
||||
AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {}));
|
||||
RulesConfigWrapper rules_config_section(convertMapToVector(rules_config));
|
||||
SecurityAppsWrapper security_app_section = SecurityAppsWrapper(
|
||||
appses_section,
|
||||
triggers_section,
|
||||
rules_config_section,
|
||||
exceptions_section,
|
||||
policy_version
|
||||
);
|
||||
|
||||
SettingsWrapper profiles_section = createProfilesSection();
|
||||
PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section);
|
||||
|
||||
return policy_wrapper;
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::createPolicyElementsByRule(
|
||||
const ParsedRule &rule,
|
||||
const ParsedRule &default_rule,
|
||||
const AppsecLinuxPolicy &policy,
|
||||
const string &policy_name)
|
||||
{
|
||||
map<AnnotationTypes, string> rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name);
|
||||
if (
|
||||
!rule_annotations[AnnotationTypes::TRIGGER].empty() &&
|
||||
!log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER])
|
||||
) {
|
||||
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]] =
|
||||
createLogTriggerSection(
|
||||
rule_annotations[AnnotationTypes::TRIGGER],
|
||||
policy
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!rule_annotations[AnnotationTypes::WEB_USER_RES].empty() &&
|
||||
!web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES])
|
||||
) {
|
||||
web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]] =
|
||||
createWebUserResponseTriggerSection(
|
||||
rule_annotations[AnnotationTypes::WEB_USER_RES],
|
||||
policy
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!rule_annotations[AnnotationTypes::EXCEPTION].empty() &&
|
||||
!inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION])
|
||||
) {
|
||||
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] =
|
||||
createExceptionSection(
|
||||
rule_annotations[AnnotationTypes::EXCEPTION],
|
||||
policy
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!rule_annotations[AnnotationTypes::PRACTICE].empty() &&
|
||||
!web_apps.count(rule_annotations[AnnotationTypes::PRACTICE])
|
||||
) {
|
||||
string practice_id = "";
|
||||
try {
|
||||
practice_id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
//TBD: return Maybe as part of future error handling
|
||||
}
|
||||
tuple<string, string, string> splited_host_name = splitHostName(rule.getHost());
|
||||
string full_url = rule.getHost() == "*"
|
||||
? "Any"
|
||||
: rule.getHost();
|
||||
|
||||
|
||||
RulesConfigRulebase rule_config = createMultiRulesSections(
|
||||
std::get<0>(splited_host_name),
|
||||
std::get<2>(splited_host_name),
|
||||
practice_id,
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
"WebApplication",
|
||||
rule_annotations[AnnotationTypes::TRIGGER],
|
||||
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(),
|
||||
"log",
|
||||
rule_annotations[AnnotationTypes::WEB_USER_RES],
|
||||
web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(),
|
||||
"WebUserResponse",
|
||||
full_url,
|
||||
rule_annotations[AnnotationTypes::EXCEPTION],
|
||||
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]].getBehaviorId()
|
||||
);
|
||||
rules_config[rule_config.getAssetName()] = rule_config;
|
||||
|
||||
WebAppSection web_app = WebAppSection(
|
||||
full_url == "Any" ? "" : full_url,
|
||||
rule_config.getAssetId(),
|
||||
rule_config.getAssetName(),
|
||||
rule_config.getAssetId(),
|
||||
rule_config.getAssetName(),
|
||||
practice_id,
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
getAppsecPracticeSpec(rule_annotations[AnnotationTypes::PRACTICE], policy),
|
||||
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],
|
||||
rule.getMode(),
|
||||
AppSecTrustedSources()
|
||||
);
|
||||
web_apps[rule_annotations[AnnotationTypes::PRACTICE]] = web_app;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::createPolicyElements(
|
||||
const vector<ParsedRule> &rules,
|
||||
const ParsedRule &default_rule,
|
||||
const AppsecLinuxPolicy &policy,
|
||||
const string &policy_name)
|
||||
{
|
||||
for (const ParsedRule &rule : rules) {
|
||||
createPolicyElementsByRule(rule, default_rule, policy, policy_name);
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
@ -0,0 +1,365 @@
|
||||
#include "rules_config_section.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
AssetUrlParser
|
||||
AssetUrlParser::parse(const string &uri)
|
||||
{
|
||||
AssetUrlParser result;
|
||||
|
||||
using iterator_t = string::const_iterator;
|
||||
|
||||
if (uri.length() == 0) return result;
|
||||
|
||||
iterator_t uri_end = uri.end();
|
||||
|
||||
// get query start
|
||||
iterator_t query_start = find(uri.begin(), uri_end, '?');
|
||||
|
||||
// protocol
|
||||
iterator_t protocol_start = uri.begin();
|
||||
iterator_t protocol_end = find(protocol_start, uri_end, ':'); //"://");
|
||||
|
||||
if (protocol_end != uri_end) {
|
||||
string http_protocol = &*(protocol_end);
|
||||
if ((http_protocol.length() > 3) && (http_protocol.substr(0, 3) == "://")) {
|
||||
result.protocol = string(protocol_start, protocol_end);
|
||||
protocol_end += 3; // ://
|
||||
} else {
|
||||
protocol_end = uri.begin(); // no protocol
|
||||
}
|
||||
} else {
|
||||
protocol_end = uri.begin(); // no protocol
|
||||
}
|
||||
|
||||
// URL
|
||||
iterator_t host_start = protocol_end;
|
||||
iterator_t path_start = find(host_start, uri_end, '/');
|
||||
|
||||
iterator_t host_end = find(protocol_end, (path_start != uri_end) ? path_start : query_start, ':');
|
||||
|
||||
result.asset_url = string(host_start, host_end);
|
||||
|
||||
// port
|
||||
if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { // we have a port
|
||||
host_end++;
|
||||
iterator_t portEnd = (path_start != uri_end) ? path_start : query_start;
|
||||
result.port = string(host_end, portEnd);
|
||||
}
|
||||
|
||||
// URI
|
||||
if (path_start != uri_end) result.asset_uri = string(path_start, query_start);
|
||||
|
||||
// query
|
||||
if (query_start != uri_end) result.query_string = string(query_start, uri.end());
|
||||
|
||||
return result;
|
||||
} // Parse
|
||||
|
||||
PracticeSection::PracticeSection(
|
||||
const string &_id,
|
||||
const string &_type,
|
||||
const string &_practice_name
|
||||
)
|
||||
{
|
||||
auto maybe_type = string_to_practice_type.find(_type);
|
||||
if (maybe_type == string_to_practice_type.end()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal pracrtice type: " << _type;
|
||||
return;
|
||||
}
|
||||
|
||||
type = _type;
|
||||
name = _practice_name;
|
||||
id = _id;
|
||||
}
|
||||
|
||||
void
|
||||
PracticeSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("practiceId", id),
|
||||
cereal::make_nvp("practiceName", name),
|
||||
cereal::make_nvp("practiceType", type)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
PracticeSection::getPracticeId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const string &
|
||||
PracticeSection::getPracticeName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
ParametersSection::ParametersSection(
|
||||
const string &_id,
|
||||
const string &_name)
|
||||
:
|
||||
name(_name),
|
||||
id(_id)
|
||||
{
|
||||
if (_id.empty() && _name.empty()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal Parameter values. Name and ID are empty";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParametersSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("parameterId", id),
|
||||
cereal::make_nvp("parameterName", name),
|
||||
cereal::make_nvp("parameterType", type)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
ParametersSection::getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
RulesTriggerSection::RulesTriggerSection(
|
||||
const string &_name,
|
||||
const string &_id,
|
||||
const string &_type)
|
||||
:
|
||||
name(_name),
|
||||
id(_id)
|
||||
{
|
||||
if (_name.empty() && _id.empty()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal values for trigger. Name and ID are empty";
|
||||
return;
|
||||
}
|
||||
auto maybe_type = string_to_trigger_type.find(_type);
|
||||
if (maybe_type == string_to_trigger_type.end()) {
|
||||
dbgError(D_K8S_POLICY) << "Illegal trigger type in rule: " << _type;
|
||||
return;
|
||||
}
|
||||
type = _type;
|
||||
}
|
||||
|
||||
void
|
||||
RulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("triggerId", id),
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("triggerType", type)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesTriggerSection::getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesTriggerSection::getName() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
RulesConfigRulebase::RulesConfigRulebase(
|
||||
const string &_name,
|
||||
const string &_url,
|
||||
const string &_uri,
|
||||
vector<PracticeSection> _practices,
|
||||
vector<ParametersSection> _parameters,
|
||||
vector<RulesTriggerSection> _triggers)
|
||||
:
|
||||
name(_name),
|
||||
practices(_practices),
|
||||
parameters(_parameters),
|
||||
triggers(_triggers)
|
||||
{
|
||||
try {
|
||||
bool any = _name == "Any" && _url == "Any" && _uri == "Any";
|
||||
id = any ? "Any" : _url+_uri;
|
||||
if (_uri != "/") {
|
||||
context = any ? "All()" : "Any("
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(80)" +
|
||||
string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
|
||||
"),"
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(443)" +
|
||||
string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
|
||||
")"
|
||||
")";
|
||||
} else {
|
||||
context = any ? "All()" : "Any("
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(80)"
|
||||
"),"
|
||||
"All("
|
||||
"Any("
|
||||
"EqualHost(" + _url + ")"
|
||||
"),"
|
||||
"EqualListeningPort(443)"
|
||||
")"
|
||||
")";
|
||||
}
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate rule UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RulesConfigRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string empty_str = "";
|
||||
out_ar(
|
||||
cereal::make_nvp("assetId", id),
|
||||
cereal::make_nvp("assetName", name),
|
||||
cereal::make_nvp("ruleId", id),
|
||||
cereal::make_nvp("ruleName", name),
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("priority", 1),
|
||||
cereal::make_nvp("isCleanup", false),
|
||||
cereal::make_nvp("parameters", parameters),
|
||||
cereal::make_nvp("practices", practices),
|
||||
cereal::make_nvp("triggers", triggers),
|
||||
cereal::make_nvp("zoneId", empty_str),
|
||||
cereal::make_nvp("zoneName", empty_str)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesConfigRulebase::getRuleId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesConfigRulebase::getAssetName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesConfigRulebase::getRuleName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesConfigRulebase::getAssetId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesConfigRulebase::getPracticeId() const
|
||||
{
|
||||
return practices[0].getPracticeId();
|
||||
}
|
||||
|
||||
const string &
|
||||
RulesConfigRulebase::getPracticeName() const
|
||||
{
|
||||
return practices[0].getPracticeName();
|
||||
}
|
||||
|
||||
const vector<PracticeSection> &
|
||||
RulesConfigRulebase::getPractice() const
|
||||
{
|
||||
return practices;
|
||||
}
|
||||
|
||||
const vector<ParametersSection> &
|
||||
RulesConfigRulebase::getParameters() const
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const vector<RulesTriggerSection> &
|
||||
RulesConfigRulebase::getTriggers() const
|
||||
{
|
||||
return triggers;
|
||||
}
|
||||
|
||||
RulesConfigWrapper::RulesConfig::RulesConfig(const vector<RulesConfigRulebase> &_rules_config)
|
||||
:
|
||||
rules_config(_rules_config)
|
||||
{
|
||||
sort(rules_config.begin(), rules_config.end(), sortBySpecific);
|
||||
}
|
||||
|
||||
void
|
||||
RulesConfigWrapper::RulesConfig::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulesConfig", rules_config)
|
||||
);
|
||||
}
|
||||
|
||||
bool
|
||||
RulesConfigWrapper::RulesConfig::sortBySpecific(
|
||||
const RulesConfigRulebase &first,
|
||||
const RulesConfigRulebase &second
|
||||
)
|
||||
{
|
||||
return sortBySpecificAux(first.getAssetName(), second.getAssetName());
|
||||
}
|
||||
|
||||
bool
|
||||
RulesConfigWrapper::RulesConfig::sortBySpecificAux(const string &first, const string &second)
|
||||
{
|
||||
if (first.empty()) return false;
|
||||
if (second.empty()) return true;
|
||||
|
||||
AssetUrlParser first_parsed = AssetUrlParser::parse(first);
|
||||
AssetUrlParser second_parsed = AssetUrlParser::parse(second);
|
||||
|
||||
// sort by URL
|
||||
if (first_parsed.asset_url == "Any" && second_parsed.asset_url != "Any") return false;
|
||||
if (second_parsed.asset_url == "Any" && first_parsed.asset_url != "Any") return true;
|
||||
|
||||
// sort by port
|
||||
if (first_parsed.port == "*" && second_parsed.port != "*") return false;
|
||||
if (second_parsed.port == "*" && first_parsed.port != "*") return true;
|
||||
|
||||
// sort by URI
|
||||
if (first_parsed.asset_uri == "*" && second_parsed.asset_uri != "*") return false;
|
||||
if (second_parsed.asset_uri == "*" && first_parsed.asset_uri != "*") return true;
|
||||
|
||||
if (first_parsed.asset_uri.empty()) return false;
|
||||
if (second_parsed.asset_uri.empty()) return true;
|
||||
|
||||
if (second_parsed.asset_uri.find(first_parsed.asset_uri) != string::npos) return false;
|
||||
if (first_parsed.asset_uri.find(second_parsed.asset_uri) != string::npos) return true;
|
||||
|
||||
if (first_parsed.asset_url.empty()) return false;
|
||||
if (second_parsed.asset_url.empty()) return false;
|
||||
|
||||
return second < first;
|
||||
}
|
||||
|
||||
void
|
||||
RulesConfigWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulebase", rules_config_rulebase)
|
||||
);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
@ -0,0 +1,74 @@
|
||||
#include "settings_section.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
AgentSettingsSection::AgentSettingsSection(
|
||||
const string &_key,
|
||||
const string &_value)
|
||||
:
|
||||
key(_key),
|
||||
value(_value)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AgentSettingsSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
AgentSettingsSection::getSettingId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
SettingsRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string profile_type = "Kubernetes";
|
||||
string upgrade_mode = "automatic";
|
||||
out_ar(
|
||||
cereal::make_nvp("agentSettings", agentSettings),
|
||||
cereal::make_nvp("agentType", profile_type),
|
||||
cereal::make_nvp("allowOnlyDefinedApplications", false),
|
||||
cereal::make_nvp("anyFog", true),
|
||||
cereal::make_nvp("maxNumberOfAgents", 10),
|
||||
cereal::make_nvp("upgradeMode", upgrade_mode)
|
||||
);
|
||||
}
|
||||
|
||||
SettingsWrapper::SettingsWrapper(SettingsRulebase _agent) : agent(_agent)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate Settings Wrapper UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SettingsWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("profileType", profileType),
|
||||
cereal::make_nvp("tokenType", isToken),
|
||||
cereal::make_nvp("tokenType", tokenType),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("agent", agent)
|
||||
);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
@ -0,0 +1,41 @@
|
||||
#include "snort_section.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
AgentSettingsSection::AgentSettingsSection(string _key, string _value) : key(_key), value(_value)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AgentSettingsSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("key", key),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
IpsSnortSigsRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string profile_type = "KubernetesProfile";
|
||||
string upgrade_mode = "automatic";
|
||||
out_ar(
|
||||
cereal::make_nvp("agentSettings", agentSettings),
|
||||
cereal::make_nvp("agentType", profile_type),
|
||||
cereal::make_nvp("allowOnlyDefinedApplications", false),
|
||||
cereal::make_nvp("anyFog", true),
|
||||
cereal::make_nvp("maxNumberOfAgents", 10),
|
||||
cereal::make_nvp("upgradeMode", upgrade_mode)
|
||||
);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
@ -0,0 +1,522 @@
|
||||
#include "triggers_section.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
LogTriggerSection::LogTriggerSection(
|
||||
const string &_name,
|
||||
const string &_verbosity,
|
||||
const string &_extendloggingMinSeverity,
|
||||
bool _extendlogging,
|
||||
bool _logToAgent,
|
||||
bool _logToCef,
|
||||
bool _logToCloud,
|
||||
bool _logToSyslog,
|
||||
bool _responseBody,
|
||||
bool _tpDetect,
|
||||
bool _tpPrevent,
|
||||
bool _webBody,
|
||||
bool _webHeaders,
|
||||
bool _webRequests,
|
||||
bool _webUrlPath,
|
||||
bool _webUrlQuery,
|
||||
int _cefPortNum,
|
||||
const string &_cefIpAddress,
|
||||
int _syslogPortNum,
|
||||
const string &_syslogIpAddress,
|
||||
bool _beautify_logs)
|
||||
:
|
||||
name(_name),
|
||||
verbosity(_verbosity),
|
||||
extendloggingMinSeverity(_extendloggingMinSeverity),
|
||||
extendlogging(_extendlogging),
|
||||
logToAgent(_logToAgent),
|
||||
logToCef(_logToCef),
|
||||
logToCloud(_logToCloud),
|
||||
logToSyslog(_logToSyslog),
|
||||
responseBody(_responseBody),
|
||||
tpDetect(_tpDetect),
|
||||
tpPrevent(_tpPrevent),
|
||||
webBody(_webBody),
|
||||
webHeaders(_webHeaders),
|
||||
webRequests(_webRequests),
|
||||
webUrlPath(_webUrlPath),
|
||||
webUrlQuery(_webUrlQuery),
|
||||
cefPortNum (_cefPortNum),
|
||||
cefIpAddress (_cefIpAddress),
|
||||
syslogPortNum (_syslogPortNum),
|
||||
syslogIpAddress (_syslogIpAddress),
|
||||
beautify_logs(_beautify_logs)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
context = "triggerId(" + id + ")";
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate log trigger UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string trigger_type = "log";
|
||||
string urlForSyslog = syslogIpAddress + ":" + to_string(syslogPortNum);
|
||||
string urlForCef = cefIpAddress + ":" + to_string(cefPortNum);
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("triggerType", trigger_type),
|
||||
cereal::make_nvp("verbosity", verbosity),
|
||||
cereal::make_nvp("acAllow", false),
|
||||
cereal::make_nvp("acDrop", false),
|
||||
cereal::make_nvp("complianceViolations", false),
|
||||
cereal::make_nvp("complianceWarnings", false),
|
||||
cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity),
|
||||
cereal::make_nvp("extendlogging", extendlogging),
|
||||
cereal::make_nvp("logToAgent", logToAgent),
|
||||
cereal::make_nvp("logToCef", logToCef),
|
||||
cereal::make_nvp("logToCloud", logToCloud),
|
||||
cereal::make_nvp("logToSyslog", logToSyslog),
|
||||
cereal::make_nvp("responseBody", responseBody),
|
||||
cereal::make_nvp("responseCode", false),
|
||||
cereal::make_nvp("tpDetect", tpDetect),
|
||||
cereal::make_nvp("tpPrevent", tpPrevent),
|
||||
cereal::make_nvp("webBody", webBody),
|
||||
cereal::make_nvp("webHeaders", webHeaders),
|
||||
cereal::make_nvp("webRequests", webRequests),
|
||||
cereal::make_nvp("webUrlPath", webUrlPath),
|
||||
cereal::make_nvp("webUrlQuery", webUrlQuery),
|
||||
cereal::make_nvp("urlForSyslog", urlForSyslog),
|
||||
cereal::make_nvp("urlForCef", urlForCef),
|
||||
cereal::make_nvp("formatLoggingOutput", beautify_logs)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
LogTriggerSection::getTriggerId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const string &
|
||||
LogTriggerSection::getTriggerName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
bool
|
||||
LogTriggerSection::operator<(const LogTriggerSection &other) const
|
||||
{
|
||||
return getTriggerName() < other.getTriggerName();
|
||||
}
|
||||
|
||||
WebUserResponseTriggerSection::WebUserResponseTriggerSection(
|
||||
const string &_name,
|
||||
const string &_details_level,
|
||||
const string &_response_body,
|
||||
int _response_code,
|
||||
const string &_response_title)
|
||||
:
|
||||
name(_name),
|
||||
context(),
|
||||
details_level(_details_level),
|
||||
response_body(_response_body),
|
||||
response_title(_response_title),
|
||||
response_code(_response_code)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
context = "triggerId(" + id + ")";
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate webUserResponse trigger UUID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebUserResponseTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("context", context),
|
||||
cereal::make_nvp("triggerName", name),
|
||||
cereal::make_nvp("details level", details_level),
|
||||
cereal::make_nvp("response body", response_body),
|
||||
cereal::make_nvp("response code", response_code),
|
||||
cereal::make_nvp("response title", response_title)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
WebUserResponseTriggerSection::getTriggerId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const string &
|
||||
WebUserResponseTriggerSection::getTriggerName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
bool
|
||||
WebUserResponseTriggerSection::operator<(const WebUserResponseTriggerSection &other) const
|
||||
{
|
||||
return getTriggerName() < other.getTriggerName();
|
||||
}
|
||||
|
||||
void
|
||||
AppSecCustomResponseSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec web user response spec";
|
||||
parseAppsecJSONKey<int>("http-response-code", httpResponseCode, archive_in, 403);
|
||||
parseAppsecJSONKey<string>("mode", mode, archive_in, "block-page");
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
if (mode == "block-page") {
|
||||
parseAppsecJSONKey<string>(
|
||||
"message-body",
|
||||
messageBody,
|
||||
archive_in,
|
||||
"Openappsec's <b>Application Security</b> has detected an attack and blocked it."
|
||||
);
|
||||
parseAppsecJSONKey<string>(
|
||||
"message-title",
|
||||
messageTitle,
|
||||
archive_in,
|
||||
"Attack blocked by web application protection"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
AppSecCustomResponseSpec::getHttpResponseCode() const
|
||||
{
|
||||
return httpResponseCode;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecCustomResponseSpec::getMessageBody() const
|
||||
{
|
||||
return messageBody;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecCustomResponseSpec::getMessageTitle() const
|
||||
{
|
||||
return messageTitle;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecCustomResponseSpec::getMode() const
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppSecCustomResponseSpec::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
TriggersRulebase::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("log", logTriggers),
|
||||
cereal::make_nvp("webUserResponse", webUserResponseTriggers)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
AppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Access Control Logging";
|
||||
parseAppsecJSONKey<bool>("allow-events", allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("drop-events", drop_events, archive_in, false);
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerAccessControlLogging::isAllowEvents() const
|
||||
{
|
||||
return allow_events;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerAccessControlLogging::isDropEvents() const
|
||||
{
|
||||
return drop_events;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging";
|
||||
parseAppsecJSONKey<bool>("enabled", enabled, archive_in, true);
|
||||
parseAppsecJSONKey<bool>("response-body", response_body, archive_in, false);
|
||||
parseAppsecJSONKey<string>("minimum-severity", minimum_severity, archive_in, "high");
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerAdditionalSuspiciousEventsLogging::isEnabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerAdditionalSuspiciousEventsLogging::isResponseBody() const
|
||||
{
|
||||
return response_body;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppsecTriggerAdditionalSuspiciousEventsLogging::getMinimumSeverity() const
|
||||
{
|
||||
return minimum_severity;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecTriggerLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Logging";
|
||||
parseAppsecJSONKey<bool>("all-web-requests", all_web_requests, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("detect-events", detect_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("prevent-events", prevent_events, archive_in, true);
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogging::isAllWebRequests() const
|
||||
{
|
||||
return all_web_requests;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogging::isDetectEvents() const
|
||||
{
|
||||
return detect_events;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogging::isPreventEvents() const
|
||||
{
|
||||
return prevent_events;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecTriggerExtendedLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Extended Logging";
|
||||
parseAppsecJSONKey<bool>("http-headers", http_headers, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("request-body", request_body, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("url-path", url_path, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("url-query", url_query, archive_in, false);
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerExtendedLogging::isHttpHeaders() const
|
||||
{
|
||||
return http_headers;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerExtendedLogging::isRequestBody() const
|
||||
{
|
||||
return request_body;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerExtendedLogging::isUrlPath() const
|
||||
{
|
||||
return url_path;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerExtendedLogging::isUrlQuery() const
|
||||
{
|
||||
return url_query;
|
||||
}
|
||||
|
||||
void
|
||||
LoggingService::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseAppsecJSONKey<string>("address", address, archive_in);
|
||||
parseAppsecJSONKey<string>("proto", proto, archive_in);
|
||||
parseAppsecJSONKey<int>("port", port, archive_in, 514);
|
||||
}
|
||||
|
||||
const string &
|
||||
LoggingService::getAddress() const
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
const string &
|
||||
LoggingService::getProto() const
|
||||
{
|
||||
return proto;
|
||||
}
|
||||
|
||||
int
|
||||
LoggingService::getPort() const
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StdoutLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseAppsecJSONKey<string>("format", format, archive_in, "json");
|
||||
}
|
||||
|
||||
const string &
|
||||
StdoutLogging::getFormat() const
|
||||
{
|
||||
return format;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger LogDestination";
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
|
||||
StdoutLogging stdout_log;
|
||||
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);
|
||||
agent_local = !(stdout_log.getFormat().empty());
|
||||
beautify_logs = stdout_log.getFormat() == "json-formatted";
|
||||
parseAppsecJSONKey<LoggingService>("syslog-service", syslog_service, archive_in);
|
||||
parseAppsecJSONKey<LoggingService>("cef-service", cef_service, archive_in);
|
||||
}
|
||||
|
||||
int
|
||||
AppsecTriggerLogDestination::getCefServerUdpPort() const
|
||||
{
|
||||
return getCefServiceData().getPort();
|
||||
}
|
||||
|
||||
int
|
||||
AppsecTriggerLogDestination::getSyslogServerUdpPort() const
|
||||
{
|
||||
return getSyslogServiceData().getPort();
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::isAgentLocal() const
|
||||
{
|
||||
return agent_local;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::shouldBeautifyLogs() const
|
||||
{
|
||||
return beautify_logs;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::getCloud() const
|
||||
{
|
||||
return cloud;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::isCefNeeded() const
|
||||
{
|
||||
return !getCefServiceData().getAddress().empty();
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::isSyslogNeeded() const
|
||||
{
|
||||
return !getSyslogServiceData().getAddress().empty();
|
||||
}
|
||||
|
||||
const
|
||||
string & AppsecTriggerLogDestination::getSyslogServerIpv4Address() const
|
||||
{
|
||||
return getSyslogServiceData().getAddress();
|
||||
}
|
||||
|
||||
const string &
|
||||
AppsecTriggerLogDestination::getCefServerIpv4Address() const
|
||||
{
|
||||
return getCefServiceData().getAddress();
|
||||
}
|
||||
|
||||
const LoggingService &
|
||||
AppsecTriggerLogDestination::getSyslogServiceData() const
|
||||
{
|
||||
return syslog_service;
|
||||
}
|
||||
|
||||
const LoggingService &
|
||||
AppsecTriggerLogDestination::getCefServiceData() const
|
||||
{
|
||||
return cef_service;
|
||||
}
|
||||
|
||||
void
|
||||
AppsecTriggerSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading AppSec trigger spec";
|
||||
parseAppsecJSONKey<AppsecTriggerAccessControlLogging>(
|
||||
"access-control-logging",
|
||||
access_control_logging,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<AppsecTriggerAdditionalSuspiciousEventsLogging>(
|
||||
"additional-suspicious-events-logging",
|
||||
additional_suspicious_events_logging,
|
||||
archive_in
|
||||
);
|
||||
parseAppsecJSONKey<AppsecTriggerLogging>("appsec-logging", appsec_logging, archive_in);
|
||||
parseAppsecJSONKey<AppsecTriggerExtendedLogging>("extended-logging", extended_logging, archive_in);
|
||||
parseAppsecJSONKey<AppsecTriggerLogDestination>("log-destination", log_destination, archive_in);
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
}
|
||||
|
||||
const AppsecTriggerAccessControlLogging &
|
||||
AppsecTriggerSpec::getAppsecTriggerAccessControlLogging() const
|
||||
{
|
||||
return access_control_logging;
|
||||
}
|
||||
|
||||
const string &
|
||||
AppsecTriggerSpec::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const AppsecTriggerAdditionalSuspiciousEventsLogging &
|
||||
AppsecTriggerSpec::getAppsecTriggerAdditionalSuspiciousEventsLogging() const
|
||||
{
|
||||
return additional_suspicious_events_logging;
|
||||
}
|
||||
|
||||
const AppsecTriggerLogging &
|
||||
AppsecTriggerSpec::getAppsecTriggerLogging() const
|
||||
{
|
||||
return appsec_logging;
|
||||
}
|
||||
|
||||
const AppsecTriggerExtendedLogging &
|
||||
AppsecTriggerSpec::getAppsecTriggerExtendedLogging() const
|
||||
{
|
||||
return extended_logging;
|
||||
}
|
||||
|
||||
const AppsecTriggerLogDestination &
|
||||
AppsecTriggerSpec::getAppsecTriggerLogDestination() const
|
||||
{
|
||||
return log_destination;
|
||||
}
|
||||
|
||||
void
|
||||
TriggersWrapper::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("rulebase", triggers_rulebase)
|
||||
);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
@ -0,0 +1,125 @@
|
||||
#include "policy_maker_utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_K8S_POLICY);
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
|
||||
void
|
||||
TrustedSourcesSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
|
||||
parseAppsecJSONKey<int>("minNumOfSources", min_num_of_sources, archive_in, 3);
|
||||
parseAppsecJSONKey<vector<string>>("sourcesIdentifiers", sources_identifiers, archive_in);
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
}
|
||||
|
||||
int
|
||||
TrustedSourcesSpec::getMinNumOfSources() const
|
||||
{
|
||||
return min_num_of_sources;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
TrustedSourcesSpec::getSourcesIdentifiers() const
|
||||
{
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
const string &
|
||||
TrustedSourcesSpec::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
SourcesIdentifiers::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
out_ar(
|
||||
cereal::make_nvp("sourceIdentifier", source_identifier),
|
||||
cereal::make_nvp("value", value)
|
||||
);
|
||||
}
|
||||
|
||||
const string &
|
||||
SourcesIdentifiers::getSourceIdent() const
|
||||
{
|
||||
return source_identifier;
|
||||
}
|
||||
|
||||
void
|
||||
SourceIdentifierSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
|
||||
parseAppsecJSONKey<string>("sourceIdentifier", source_identifier, archive_in);
|
||||
parseAppsecJSONKey<vector<string>>("value", value, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
SourceIdentifierSpec::getSourceIdentifier() const
|
||||
{
|
||||
return source_identifier;
|
||||
}
|
||||
|
||||
const vector<string> &
|
||||
SourceIdentifierSpec::getValues() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
SourceIdentifierSpecWrapper::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_K8S_POLICY) << "Loading Source Identifier Spec Wrapper";
|
||||
parseAppsecJSONKey<vector<SourceIdentifierSpec>>("identifiers", identifiers, archive_in);
|
||||
parseAppsecJSONKey<string>("name", name, archive_in);
|
||||
}
|
||||
|
||||
const string &
|
||||
SourceIdentifierSpecWrapper::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const vector<SourceIdentifierSpec> &
|
||||
SourceIdentifierSpecWrapper::getIdentifiers() const
|
||||
{
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
AppSecTrustedSources::AppSecTrustedSources(
|
||||
const string &_name,
|
||||
int _num_of_sources,
|
||||
const vector<SourcesIdentifiers> &_sources_identifiers)
|
||||
:
|
||||
name(_name),
|
||||
num_of_sources(_num_of_sources),
|
||||
sources_identifiers(_sources_identifiers)
|
||||
{
|
||||
try {
|
||||
id = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_K8S_POLICY) << "Failed to generate Trusted Sources ID. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AppSecTrustedSources::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
string parameter_type = "TrustedSource";
|
||||
out_ar(
|
||||
cereal::make_nvp("id", id),
|
||||
cereal::make_nvp("name", name),
|
||||
cereal::make_nvp("numOfSources", num_of_sources),
|
||||
cereal::make_nvp("sourcesIdentifiers", sources_identifiers),
|
||||
cereal::make_nvp("parameterType", parameter_type)
|
||||
);
|
||||
}
|
||||
|
||||
const vector<SourcesIdentifiers> &
|
||||
AppSecTrustedSources::getSourcesIdentifiers() const
|
||||
{
|
||||
return sources_identifiers;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
@ -389,17 +389,17 @@ public:
|
||||
void
|
||||
writeStatusToFile()
|
||||
{
|
||||
auto orchestrations_status_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/orchestrations_status.json",
|
||||
auto orchestration_status_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/orchestration_status.json",
|
||||
"orchestration",
|
||||
"Orchestration status path"
|
||||
);
|
||||
auto write_result =
|
||||
orchestration_tools->objectToJsonFile<Status>(status, orchestrations_status_path);
|
||||
orchestration_tools->objectToJsonFile<Status>(status, orchestration_status_path);
|
||||
if (!write_result) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to write Orchestration status. File: " << orchestrations_status_path;
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to write Orchestration status. File: " << orchestration_status_path;
|
||||
}
|
||||
dbgTrace(D_ORCHESTRATOR) << "Orchestration status file has been updated. File: " << orchestrations_status_path;
|
||||
dbgTrace(D_ORCHESTRATOR) << "Orchestration status file has been updated. File: " << orchestration_status_path;
|
||||
}
|
||||
|
||||
void
|
||||
@ -440,10 +440,10 @@ public:
|
||||
{
|
||||
time = Singleton::Consume<I_TimeGet>::by<OrchestrationStatus>();
|
||||
orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationStatus>();
|
||||
filesystem_prefix = getFilesystemPathConfig();
|
||||
initValues();
|
||||
loadFromFile();
|
||||
|
||||
filesystem_prefix = getFilesystemPathConfig();
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
<< "Initializing Orchestration status, file system path prefix: "
|
||||
<< filesystem_prefix;
|
||||
@ -473,13 +473,13 @@ private:
|
||||
void
|
||||
loadFromFile()
|
||||
{
|
||||
auto orchestrations_status_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/orchestrations_status.json",
|
||||
auto orchestration_status_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/orchestration_status.json",
|
||||
"orchestration",
|
||||
"Orchestration status path"
|
||||
);
|
||||
Maybe<Status> maybe_status_file =
|
||||
orchestration_tools->jsonFileToObject<Status>(orchestrations_status_path);
|
||||
orchestration_tools->jsonFileToObject<Status>(orchestration_status_path);
|
||||
if (!maybe_status_file.ok()) {
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
<< "Failed to load Orchestration status, start with clear status."
|
||||
@ -489,7 +489,7 @@ private:
|
||||
|
||||
status = maybe_status_file.unpack();
|
||||
|
||||
dbgInfo(D_ORCHESTRATOR) << "Orchestration status loaded from file." << " File: " << orchestrations_status_path;
|
||||
dbgInfo(D_ORCHESTRATOR) << "Orchestration status loaded from file." << " File: " << orchestration_status_path;
|
||||
}
|
||||
|
||||
const string & getLastUpdateAttempt() const override { return status.getLastUpdateAttempt(); }
|
||||
|
@ -124,6 +124,29 @@ private:
|
||||
map<string, HealthCheckStatus> field_types_status;
|
||||
};
|
||||
|
||||
class setAgentUninstall : public ServerRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
doCall() override
|
||||
{
|
||||
dbgTrace(D_ORCHESTRATOR) << "Send 'agent uninstall process started' log to fog";
|
||||
setConfiguration(false, "Logging", "Enable bulk of logs");
|
||||
LogGen log (
|
||||
"Agent started uninstall process",
|
||||
Audience::INTERNAL,
|
||||
Severity::INFO,
|
||||
Priority::URGENT,
|
||||
LogField("issuingEngine", "agentUninstallProvider"),
|
||||
Tags::ORCHESTRATOR
|
||||
);
|
||||
notify_uninstall_to_fog = true;
|
||||
}
|
||||
|
||||
private:
|
||||
S2C_PARAM(bool, notify_uninstall_to_fog);
|
||||
};
|
||||
|
||||
class OrchestrationComp::Impl
|
||||
{
|
||||
public:
|
||||
@ -144,6 +167,7 @@ public:
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<OrchestrationComp>();
|
||||
rest->addRestCall<getStatusRest>(RestAction::SHOW, "orchestration-status");
|
||||
rest->addRestCall<AddProxyRest>(RestAction::ADD, "proxy");
|
||||
rest->addRestCall<setAgentUninstall>(RestAction::SET, "agent-uninstall");
|
||||
// Main loop of the Orchestration.
|
||||
Singleton::Consume<I_MainLoop>::by<OrchestrationComp>()->addOneTimeRoutine(
|
||||
I_MainLoop::RoutineType::RealTime,
|
||||
@ -982,7 +1006,7 @@ private:
|
||||
const Maybe<vector<CheckUpdateRequest::Tenants>> &updated_policy_tenants,
|
||||
const vector<string> &new_data_files)
|
||||
{
|
||||
dbgFlow(D_ORCHESTRATOR) << "Hanlding virtual files";
|
||||
dbgFlow(D_ORCHESTRATOR) << "Handling virtual files";
|
||||
if (!updated_policy_tenants.ok()) return;
|
||||
|
||||
// Sorting files by tenant id;
|
||||
@ -1053,26 +1077,31 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto downloade_files: sorted_files) {
|
||||
auto files = downloade_files.second;
|
||||
for (auto it = sorted_files.begin(); it != sorted_files.end(); it++) {
|
||||
const auto &downloaded_files = *it;
|
||||
auto files = downloaded_files.second;
|
||||
string policy_file = files[0];
|
||||
string setting_file = "";
|
||||
if (files.size() > 1) {
|
||||
setting_file = files[1];
|
||||
auto handled_settings = updateSettingsFile(
|
||||
setting_file,
|
||||
downloade_files.first.getTenantId(),
|
||||
downloade_files.first.getPfofileId()
|
||||
downloaded_files.first.getTenantId(),
|
||||
downloaded_files.first.getProfileId()
|
||||
);
|
||||
if (handled_settings.ok()) setting_file = *handled_settings;
|
||||
}
|
||||
|
||||
bool last_iteration = false;
|
||||
if (next(it) == sorted_files.end()) last_iteration = true;
|
||||
|
||||
Singleton::Consume<I_ServiceController>::by<OrchestrationComp>()->updateServiceConfiguration(
|
||||
policy_file,
|
||||
setting_file,
|
||||
new_data_files,
|
||||
downloade_files.first.getTenantId(),
|
||||
downloade_files.first.getPfofileId()
|
||||
downloaded_files.first.getTenantId(),
|
||||
downloaded_files.first.getProfileId(),
|
||||
last_iteration
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1087,9 +1116,9 @@ private:
|
||||
"Conf dir"
|
||||
) + (tenant_id != "" ? "tenant_" + tenant_id + "_profile_" + profile_id + "_" : "");
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << conf_dir;
|
||||
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
|
||||
string settings_file_path = conf_dir + "settings.json";
|
||||
dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << settings_file_path;
|
||||
if (!orchestration_tools->copyFile(new_settings_file, settings_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings.";
|
||||
return genError("Failed to update the settings");
|
||||
@ -1278,7 +1307,7 @@ private:
|
||||
int sleep_interval = policy.getErrorSleepInterval();
|
||||
Maybe<void> start_state(genError("Not running yet."));
|
||||
while (!(start_state = start()).ok()) {
|
||||
dbgError(D_ORCHESTRATOR) << "Failed to start the Orchestration. Error: " << start_state.getErr();
|
||||
dbgDebug(D_ORCHESTRATOR) << "Orchestration not started yet. Status: " << start_state.getErr();
|
||||
health_check_status_listener.setStatus(
|
||||
HealthCheckStatus::UNHEALTHY,
|
||||
OrchestrationStatusFieldType::REGISTRATION,
|
||||
|
@ -65,7 +65,12 @@ public:
|
||||
|
||||
EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)).WillOnce(
|
||||
WithArg<2>(Invoke(this, &OrchestrationMultitenancyTest::setRestStatus)));
|
||||
|
||||
|
||||
EXPECT_CALL(
|
||||
rest,
|
||||
mockRestCall(RestAction::SET, "agent-uninstall", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
doEncrypt();
|
||||
orchestration_comp.init();
|
||||
}
|
||||
@ -417,7 +422,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
|
||||
"/etc/cp/conf/settings.json",
|
||||
expected_data_types,
|
||||
"",
|
||||
""
|
||||
"",
|
||||
false
|
||||
)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
@ -428,7 +434,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
|
||||
"/etc/cp/conf/tenant_1236_profile_2611_settings.json",
|
||||
expected_data_types,
|
||||
"1236",
|
||||
"2611"
|
||||
"2611",
|
||||
false
|
||||
)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
@ -439,7 +446,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
|
||||
"/etc/cp/conf/tenant_1235_profile_2311_settings.json",
|
||||
expected_data_types,
|
||||
"1235",
|
||||
"2311"
|
||||
"2311",
|
||||
true
|
||||
)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
|
@ -79,6 +79,11 @@ public:
|
||||
WithArg<2>(Invoke(this, &OrchestrationTest::setRestStatus))
|
||||
);
|
||||
|
||||
EXPECT_CALL(
|
||||
rest,
|
||||
mockRestCall(RestAction::SET, "agent-uninstall", _)
|
||||
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandlerAgentUninstall)));
|
||||
|
||||
string message_body;
|
||||
EXPECT_CALL(mock_message, mockSendPersistentMessage(
|
||||
false,
|
||||
@ -101,6 +106,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
restHandlerAgentUninstall(const unique_ptr<RestInit> &p)
|
||||
{
|
||||
agent_uninstall = p->getRest();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
doEncrypt()
|
||||
@ -249,6 +260,7 @@ public:
|
||||
}
|
||||
|
||||
unique_ptr<ServerRest> rest_handler;
|
||||
unique_ptr<ServerRest> agent_uninstall;
|
||||
unique_ptr<ServerRest> declare_variable;
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
NiceMock<MockTimeGet> mock_time_get;
|
||||
@ -295,8 +307,36 @@ private:
|
||||
I_MainLoop::Routine status_routine;
|
||||
};
|
||||
|
||||
TEST_F(OrchestrationTest, doNothing)
|
||||
TEST_F(OrchestrationTest, testAgentUninstallRest)
|
||||
{
|
||||
EXPECT_CALL(
|
||||
rest,
|
||||
mockRestCall(RestAction::ADD, "proxy", _)
|
||||
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler)));
|
||||
|
||||
init();
|
||||
|
||||
Report report;
|
||||
EXPECT_CALL(mock_log, sendLog(_)).WillRepeatedly(SaveArg<0>(&report));
|
||||
|
||||
stringstream ss("{}");
|
||||
Maybe<string> maybe_res = agent_uninstall->performRestCall(ss);
|
||||
EXPECT_TRUE(maybe_res.ok());
|
||||
EXPECT_EQ(maybe_res.unpack(),
|
||||
"{\n"
|
||||
" \"notify_uninstall_to_fog\": true\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
stringstream report_ss;
|
||||
{
|
||||
cereal::JSONOutputArchive ar(report_ss);
|
||||
report.serialize(ar);
|
||||
}
|
||||
|
||||
string report_str = report_ss.str();
|
||||
EXPECT_THAT(report_str, HasSubstr("\"eventName\": \"Agent started uninstall process\""));
|
||||
EXPECT_THAT(report_str, HasSubstr("\"issuingEngine\": \"agentUninstallProvider\""));
|
||||
}
|
||||
|
||||
TEST_F(OrchestrationTest, register_config)
|
||||
@ -530,12 +570,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "")
|
||||
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(
|
||||
@ -633,7 +673,7 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).Times(2).WillRepeatedly(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(Return(true));
|
||||
@ -753,7 +793,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
|
||||
@ -887,7 +927,7 @@ TEST_F(OrchestrationTest, manifestUpdate)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
|
||||
@ -1037,7 +1077,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).Times(2).WillRepeatedly(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
|
||||
@ -1118,7 +1158,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "")).WillOnce(Return(false)
|
||||
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _)).WillOnce(Return(false)
|
||||
);
|
||||
|
||||
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
|
||||
@ -1183,7 +1223,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
|
||||
@ -1401,7 +1441,7 @@ TEST_P(OrchestrationTest, orchestrationFirstRun)
|
||||
vector<string> expected_data_types = {};
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
|
||||
@ -1582,13 +1622,13 @@ TEST_F(OrchestrationTest, dataUpdate)
|
||||
vector<string> expected_empty_data_types = {};
|
||||
ExpectationSet expectation_set = EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "")
|
||||
updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "", _)
|
||||
).WillOnce(Return(true));
|
||||
|
||||
vector<string> expected_ips_data_types = { "ips" };
|
||||
EXPECT_CALL(
|
||||
mock_service_controller,
|
||||
updateServiceConfiguration("", "", expected_ips_data_types, "", "")
|
||||
updateServiceConfiguration("", "", expected_ips_data_types, "", "", _)
|
||||
).After(expectation_set).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesDirectoryExist("/etc/cp/conf/data")).WillOnce(Return(true));
|
||||
|
@ -272,7 +272,8 @@ public:
|
||||
const string &new_settings_path,
|
||||
const vector<string> &new_data_files,
|
||||
const string &tenant_id,
|
||||
const string &profile_id
|
||||
const string &profile_id,
|
||||
const bool last_iteration
|
||||
) override;
|
||||
|
||||
bool isServiceInstalled(const string &service_name) override;
|
||||
@ -325,6 +326,7 @@ private:
|
||||
map<int, string> services_reconf_names;
|
||||
map<int, string> services_reconf_ids;
|
||||
string filesystem_prefix;
|
||||
bool is_multi_tenant_env = false;
|
||||
};
|
||||
|
||||
class GetServicesPorts : public ServerRest
|
||||
@ -412,6 +414,11 @@ ServiceController::Impl::init()
|
||||
filesystem_prefix = getFilesystemPathConfig();
|
||||
|
||||
loadRegisteredServicesFromFile();
|
||||
|
||||
auto agent_type = getSetting<string>("agentType");
|
||||
if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) {
|
||||
is_multi_tenant_env = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -592,7 +599,8 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
const string &new_settings_path,
|
||||
const vector<string> &new_data_files,
|
||||
const string &tenant_id,
|
||||
const string &profile_id)
|
||||
const string &profile_id,
|
||||
const bool last_iteration)
|
||||
{
|
||||
dbgFlow(D_ORCHESTRATOR)
|
||||
<< "new_policy_path: "
|
||||
@ -746,7 +754,10 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
}
|
||||
}
|
||||
|
||||
was_policy_updated &= sendSignalForServices(nano_services_to_update, version_value);
|
||||
// In a multi-tenant env, we send the signal to the services only on the last iteration
|
||||
was_policy_updated &= (is_multi_tenant_env && !last_iteration) ?
|
||||
true :
|
||||
sendSignalForServices(nano_services_to_update, version_value);
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR) << "was_policy_updated: " << (was_policy_updated ? "true" : "false");
|
||||
|
||||
@ -965,6 +976,11 @@ ServiceController::Impl::updateReconfStatus(int id, ReconfStatus status)
|
||||
dbgError(D_ORCHESTRATOR) << "Service reconfiguration monitor received illegal id :" << id;
|
||||
return;
|
||||
}
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
<< "Updating reconf status for reconfiguration ID "
|
||||
<< id
|
||||
<< ". Status: "
|
||||
<< static_cast<int>(status);
|
||||
services_reconf_status[id] = status;
|
||||
}
|
||||
|
||||
@ -975,6 +991,15 @@ ServiceController::Impl::startReconfStatus(
|
||||
const string &service_name,
|
||||
const string &service_id)
|
||||
{
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
<< "Starting reconf status. Configuration ID: "
|
||||
<< id
|
||||
<< ", service name: "
|
||||
<< service_name
|
||||
<< ", service ID: "
|
||||
<< service_id
|
||||
<< ", status: "
|
||||
<< static_cast<int>(status);
|
||||
services_reconf_status.emplace(id, status);
|
||||
services_reconf_names.emplace(id, service_name);
|
||||
services_reconf_ids.emplace(id, service_id);
|
||||
|
@ -122,9 +122,9 @@ LocalCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
LocalCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
|
||||
LocalCommunication::downloadAttributeFile(const GetResourceFile &resource_file)
|
||||
{
|
||||
auto file_name = resourse_file.getFileName();
|
||||
auto file_name = resource_file.getFileName();
|
||||
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<LocalCommunication>();
|
||||
if (file_name.compare("policy") == 0) {
|
||||
@ -163,8 +163,8 @@ LocalCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
|
||||
));
|
||||
}
|
||||
|
||||
dbgError(D_ORCHESTRATOR) << "Unknown resourse file name " << file_name;
|
||||
return genError("Failed to detect resourse file name " + file_name);
|
||||
dbgError(D_ORCHESTRATOR) << "Unknown resource file name " << file_name;
|
||||
return genError("Failed to detect resource file name " + file_name);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -191,7 +191,7 @@ protected:
|
||||
dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i;
|
||||
mainloop->yield(true);
|
||||
}
|
||||
dbgError(D_WAAP) << "Failed to send object, reached maximum attempts: " <<
|
||||
dbgError(D_WAAP) << "Failed to send object to " << uri << ", reached maximum attempts: " <<
|
||||
max_send_obj_retries;
|
||||
return false;
|
||||
}
|
||||
@ -245,7 +245,7 @@ protected:
|
||||
dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i;
|
||||
mainloop->yield(true);
|
||||
}
|
||||
dbgError(D_WAAP) << "Failed to send object, reached maximum attempts: " <<
|
||||
dbgError(D_WAAP) << "Failed to send object to " << uri << ", reached maximum attempts: " <<
|
||||
max_send_obj_retries;
|
||||
return false;
|
||||
}
|
||||
|
@ -129,17 +129,29 @@ SourceReputationFeaturesAgg::addHeaders(const ReputationFeaturesEntry &entry)
|
||||
}
|
||||
|
||||
const auto &referer_header_itr = headers.find("referer");
|
||||
if (referer_header_itr == headers.cend()) {
|
||||
if (referer_header_itr == headers.cend() || referer_header_itr->second.empty()) {
|
||||
m_referer_count.na++;
|
||||
} else {
|
||||
const string &uri = referer_header_itr->second;
|
||||
size_t scheme_end_pos = uri.find("://") + 3;
|
||||
size_t authority_end_pos = uri.find("/", scheme_end_pos + 1);
|
||||
string authority = uri.substr(scheme_end_pos + 1, authority_end_pos);
|
||||
if (authority.find(entry.getHost()) != string::npos) {
|
||||
m_referer_count.external_host++;
|
||||
size_t scheme_end_pos = uri.find("://");
|
||||
if (scheme_end_pos != string::npos) {
|
||||
string authority;
|
||||
scheme_end_pos = scheme_end_pos + 3;
|
||||
size_t authority_end_pos = uri.find("/", scheme_end_pos);
|
||||
if (authority_end_pos == string::npos) {
|
||||
authority = uri.substr(scheme_end_pos);
|
||||
} else {
|
||||
authority = uri.substr(scheme_end_pos, authority_end_pos - scheme_end_pos);
|
||||
}
|
||||
|
||||
if (authority.find(entry.getHost()) != string::npos) {
|
||||
m_referer_count.internal_host++;
|
||||
} else {
|
||||
m_referer_count.external_host++;
|
||||
}
|
||||
} else {
|
||||
m_referer_count.internal_host++;
|
||||
m_referer_count.external_host++;
|
||||
dbgTrace(D_WAAP_REPUTATION) << "No scheme found in referer header: " << uri;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ add_library(waap_clib
|
||||
SyncLearningNotification.cc
|
||||
LogGenWrapper.cc
|
||||
WaapSampleValue.cc
|
||||
ParserGql.cc
|
||||
)
|
||||
|
||||
add_definitions("-Wno-unused-function")
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "ParserUrlEncode.h"
|
||||
#include "PHPSerializedDataParser.h"
|
||||
#include "ParserJson.h"
|
||||
#include "ParserGql.h"
|
||||
#include "ParserConfluence.h"
|
||||
#include "ParserXML.h"
|
||||
#include "ParserHTML.h"
|
||||
@ -231,26 +232,30 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i
|
||||
|
||||
bool base64ParamFound = false;
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << " ===Processing potential base64===";
|
||||
std::string base64_decoded_val, base64_key;
|
||||
std::string decoded_val, key;
|
||||
base64_variants base64_status = Waap::Util::b64Test (cur_val,
|
||||
base64_key,
|
||||
base64_decoded_val);
|
||||
key,
|
||||
decoded_val);
|
||||
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << " status = " << base64_status
|
||||
<< " key = " << base64_key
|
||||
<< " value = " << base64_decoded_val;
|
||||
dbgTrace(D_WAAP_DEEP_PARSER)
|
||||
<< " status = "
|
||||
<< base64_status
|
||||
<< " key = "
|
||||
<< key
|
||||
<< " value = "
|
||||
<< decoded_val;
|
||||
|
||||
switch (base64_status) {
|
||||
case SINGLE_B64_CHUNK_CONVERT:
|
||||
cur_val = base64_decoded_val;
|
||||
cur_val = decoded_val;
|
||||
base64ParamFound = true;
|
||||
break;
|
||||
case KEY_VALUE_B64_PAIR:
|
||||
// going deep with new pair in case value is not empty
|
||||
if (base64_decoded_val.size() > 0) {
|
||||
cur_val = base64_decoded_val;
|
||||
if (decoded_val.size() > 0) {
|
||||
cur_val = decoded_val;
|
||||
base64ParamFound = true;
|
||||
rc = onKv(base64_key.c_str(), base64_key.size(), cur_val.data(), cur_val.size(), flags);
|
||||
rc = onKv(key.c_str(), key.size(), cur_val.data(), cur_val.size(), flags);
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc;
|
||||
if (rc != CONTINUE_PARSING) {
|
||||
return rc;
|
||||
@ -323,6 +328,7 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse buffer
|
||||
|
||||
// Note: API report does not include output of "PIPE" and similar extracted stuff.
|
||||
@ -365,6 +371,21 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (Waap::Util::detectJSONasParameter(cur_val, key, decoded_val)) {
|
||||
dbgTrace(D_WAAP_DEEP_PARSER)
|
||||
<< " detectJSONasParameter was true: key = "
|
||||
<< key
|
||||
<< " value = "
|
||||
<< decoded_val;
|
||||
|
||||
rc = onKv(key.c_str(), key.size(), decoded_val.data(), decoded_val.size(), flags);
|
||||
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << " After processing potential JSON rc = " << rc;
|
||||
if (rc != CONTINUE_PARSING) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
m_depth--;
|
||||
|
||||
// Send key/value pair to the Signature scanner
|
||||
@ -878,6 +899,11 @@ void DeepParser::createInternalParser(const char *k, size_t k_len, std::string&
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse phpSerializedData";
|
||||
m_parsersDeque.push_front(std::make_shared<BufferedParser<PHPSerializedDataParser>>(*this));
|
||||
}
|
||||
else if (isPotentialGqlQuery && cur_val.size() > 0 && !validateJson(cur_val.data(), cur_val.size())) {
|
||||
// Graphql value detected
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse graphql";
|
||||
m_parsersDeque.push_front(std::make_shared<BufferedParser<ParserGql>>(*this));
|
||||
}
|
||||
else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{'))
|
||||
{
|
||||
boost::smatch confulence_match;
|
||||
|
@ -25,7 +25,8 @@ IndicatorsFiltersManager::IndicatorsFiltersManager(const std::string& remotePath
|
||||
:
|
||||
SerializeToFileBase(pWaapAssetState->getWaapDataDir() + "/6.data"),
|
||||
m_ignoreSources(pWaapAssetState->getWaapDataDir(), remotePath, assetId),
|
||||
m_tuning(remotePath)
|
||||
m_tuning(remotePath),
|
||||
m_matchedOverrideKeywords()
|
||||
{
|
||||
restore();
|
||||
m_keywordsFreqFilter = std::make_unique<KeywordIndicatorFilter>(
|
||||
@ -88,6 +89,12 @@ bool IndicatorsFiltersManager::shouldFilterKeyword(const std::string &key, const
|
||||
shouldFilter |= m_keywordsFreqFilter->shouldFilterKeyword(type, keyword);
|
||||
}
|
||||
}
|
||||
if (m_matchedOverrideKeywords.size() > 0 &&
|
||||
m_matchedOverrideKeywords.find(keyword) != m_matchedOverrideKeywords.end())
|
||||
{
|
||||
dbgTrace(D_WAAP_OVERRIDE) << "Filtering keyword '" << keyword << "' due to override";
|
||||
shouldFilter = true;
|
||||
}
|
||||
return shouldFilter;
|
||||
}
|
||||
|
||||
@ -315,3 +322,8 @@ void IndicatorsFiltersManager::pushSample(
|
||||
}
|
||||
m_typeFilter->registerKeywords(key, sample, pTransaction);
|
||||
}
|
||||
|
||||
std::set<std::string> & IndicatorsFiltersManager::getMatchedOverrideKeywords(void)
|
||||
{
|
||||
return m_matchedOverrideKeywords;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
virtual bool shouldFilterKeyword(const std::string &key, const std::string &keyword) const;
|
||||
virtual void filterKeywords(const std::string &key, Waap::Keywords::KeywordsSet& keywords,
|
||||
std::vector<std::string>& filteredKeywords);
|
||||
std::set<std::string> &getMatchedOverrideKeywords(void);
|
||||
|
||||
void pushSample(const std::string& key, const std::string& sample, IWaf2Transaction* pTransaction);
|
||||
|
||||
@ -67,4 +68,5 @@ private:
|
||||
std::shared_ptr<Waap::TrustedSources::TrustedSourcesParameter> m_trustedSrcParams;
|
||||
ScannerDetector m_ignoreSources;
|
||||
TuningDecision m_tuning;
|
||||
std::set<std::string> m_matchedOverrideKeywords;
|
||||
};
|
||||
|
@ -43,6 +43,7 @@ struct IParserReceiver2 {
|
||||
virtual void onEndMap() = 0;
|
||||
virtual void onStartArray() = 0;
|
||||
virtual void onEndArray() = 0;
|
||||
virtual void onEndOfData() = 0;
|
||||
};
|
||||
|
||||
// Interface for receiver classes that can accept not only full key/value pairs, but also partial content
|
||||
|
134
components/security_apps/waap/waap_clib/ParserGql.cc
Normal file
134
components/security_apps/waap/waap_clib/ParserGql.cc
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ParserGql.h"
|
||||
#include "graphqlparser/AstNode.h"
|
||||
#include "graphqlparser/AstVisitor.h"
|
||||
#include "graphqlparser/GraphQLParser.h"
|
||||
#include "debug.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_WAAP_PARSER_GQL);
|
||||
|
||||
const std::string ParserGql::m_parserName = "gqlParser";
|
||||
|
||||
ParserGql::ParserGql(IParserReceiver& receiver) :
|
||||
m_receiver(receiver),
|
||||
m_error(false),
|
||||
m_curNameValues(0)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
}
|
||||
|
||||
ParserGql::~ParserGql() {
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
}
|
||||
|
||||
size_t ParserGql::push(const char* buf, size_t len) {
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << "buf='" << std::string(buf, len) << "'";
|
||||
if (len > 0) {
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << "appending " << len << " bytes ...";
|
||||
m_buffer.append(buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
const char *errorstr = nullptr;
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << "parsing ...";
|
||||
std::unique_ptr<facebook::graphql::ast::Node> ast = facebook::graphql::parseString(m_buffer.c_str(), &errorstr);
|
||||
if (!ast) {
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << "GraphQL parser failed: " << errorstr;
|
||||
m_error = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Walk over AST and call the visitXXX callbacks
|
||||
ast->accept(this);
|
||||
|
||||
// Handle corner case of last name visited without value: don't forget to output that name too
|
||||
if (m_curNameValues == 0 && !m_curNodeName.empty()) {
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << "handle last name: '" << m_curNodeName << "'";
|
||||
if (m_receiver.onKv(m_curNodeName.data(), m_curNodeName.size(), "", 0, BUFFERED_RECEIVER_F_BOTH) != 0) {
|
||||
m_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void ParserGql::finish() {
|
||||
push(NULL, 0);
|
||||
}
|
||||
|
||||
const std::string &
|
||||
ParserGql::name() const {
|
||||
return m_parserName;
|
||||
}
|
||||
|
||||
bool ParserGql::error() const {
|
||||
return m_error;
|
||||
}
|
||||
|
||||
bool ParserGql::visitValue(const char *value)
|
||||
{
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << "'" << value << "'";
|
||||
m_curNameValues++;
|
||||
return m_receiver.onKv(m_curNodeName.data(), m_curNodeName.size(), value, strlen(value), BUFFERED_RECEIVER_F_BOTH);
|
||||
}
|
||||
|
||||
bool ParserGql::visitName(const facebook::graphql::ast::Name &node)
|
||||
{
|
||||
dbgTrace(D_WAAP_PARSER_GQL) << node.getValue() << "'";
|
||||
bool ret = true;
|
||||
if (m_curNameValues == 0 && !m_curNodeName.empty()) {
|
||||
ret = m_receiver.onKv(m_curNodeName.data(), m_curNodeName.size(), "", 0, BUFFERED_RECEIVER_F_BOTH);
|
||||
}
|
||||
// wait for next name
|
||||
m_curNodeName = std::string(node.getValue());
|
||||
m_curNameValues = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ParserGql::visitIntValue(const facebook::graphql::ast::IntValue &node)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
return visitValue(node.getValue());
|
||||
}
|
||||
|
||||
bool ParserGql::visitFloatValue(const facebook::graphql::ast::FloatValue &node)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
return visitValue(node.getValue());
|
||||
}
|
||||
|
||||
bool ParserGql::visitStringValue(const facebook::graphql::ast::StringValue &node)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
return visitValue(node.getValue());
|
||||
}
|
||||
|
||||
bool ParserGql::visitBooleanValue(const facebook::graphql::ast::BooleanValue &node)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
return visitValue(node.getValue() ? "true" : "false");
|
||||
}
|
||||
|
||||
bool ParserGql::visitNullValue(const facebook::graphql::ast::NullValue &node)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
return visitValue("null");
|
||||
}
|
||||
|
||||
bool ParserGql::visitEnumValue(const facebook::graphql::ast::EnumValue &node)
|
||||
{
|
||||
dbgFlow(D_WAAP_PARSER_GQL);
|
||||
return visitValue(node.getValue());
|
||||
}
|
56
components/security_apps/waap/waap_clib/ParserGql.h
Normal file
56
components/security_apps/waap/waap_clib/ParserGql.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __PARSER_GQL_H
|
||||
#define __PARSER_GQL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "ParserBase.h"
|
||||
#include "graphqlparser/Ast.h"
|
||||
#include "graphqlparser/AstNode.h"
|
||||
#include "graphqlparser/AstVisitor.h"
|
||||
#include "KeyStack.h"
|
||||
|
||||
class ParserGql : public ParserBase, public facebook::graphql::ast::visitor::AstVisitor {
|
||||
public:
|
||||
ParserGql(IParserReceiver &receiver);
|
||||
virtual ~ParserGql();
|
||||
size_t push(const char *data, size_t data_len);
|
||||
void finish();
|
||||
virtual const std::string &name() const;
|
||||
bool error() const;
|
||||
virtual size_t depth() { return 0; }
|
||||
private:
|
||||
IParserReceiver &m_receiver;
|
||||
bool m_error;
|
||||
std::string m_buffer;
|
||||
std::string m_curNodeName;
|
||||
int m_curNameValues;
|
||||
|
||||
bool visitValue(const char *value);
|
||||
|
||||
// Callbacks from the parser
|
||||
bool visitName(const facebook::graphql::ast::Name &node) override;
|
||||
bool visitIntValue(const facebook::graphql::ast::IntValue &node) override;
|
||||
bool visitFloatValue(const facebook::graphql::ast::FloatValue &node) override;
|
||||
bool visitStringValue(const facebook::graphql::ast::StringValue &node) override;
|
||||
bool visitBooleanValue(const facebook::graphql::ast::BooleanValue &node) override;
|
||||
bool visitNullValue(const facebook::graphql::ast::NullValue &node) override;
|
||||
bool visitEnumValue(const facebook::graphql::ast::EnumValue &node) override;
|
||||
public:
|
||||
static const std::string m_parserName;
|
||||
};
|
||||
|
||||
#endif // __PARSER_JQL_H
|
@ -270,6 +270,10 @@ size_t ParserJson::push(const char* buf, size_t len) {
|
||||
m_state = s_error;
|
||||
}
|
||||
|
||||
if (m_receiver2) {
|
||||
m_receiver2->onEndOfData();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -44,18 +44,19 @@ static const string defaultSharedStorageHost = "appsec-shared-storage-svc";
|
||||
#define LEARNING_HOST_ENV_NAME "LEARNING_HOST"
|
||||
|
||||
static bool
|
||||
isGZipped(const std::string &stream)
|
||||
isGZipped(const string &stream)
|
||||
{
|
||||
if (stream.size() < 2) return false;
|
||||
auto unsinged_stream = reinterpret_cast<const u_char *>(stream.data());
|
||||
return unsinged_stream[0] == 0x1f && unsinged_stream[1] == 0x8b;
|
||||
}
|
||||
|
||||
bool RestGetFile::loadJson(const std::string& json)
|
||||
bool RestGetFile::loadJson(const string& json)
|
||||
{
|
||||
string json_str;
|
||||
|
||||
std::string json_str = json;
|
||||
if (isGZipped(json_str) == 0)
|
||||
json_str = json;
|
||||
if (!isGZipped(json_str))
|
||||
{
|
||||
return ClientRest::loadJson(json_str);
|
||||
}
|
||||
@ -66,7 +67,7 @@ bool RestGetFile::loadJson(const std::string& json)
|
||||
reinterpret_cast<const unsigned char *>(json_str.c_str()));
|
||||
|
||||
if (res.ok){
|
||||
json_str = std::string((const char *)res.output, res.num_output_bytes);
|
||||
json_str = string((const char *)res.output, res.num_output_bytes);
|
||||
if (res.output) free(res.output);
|
||||
res.output = nullptr;
|
||||
res.num_output_bytes = 0;
|
||||
@ -76,12 +77,12 @@ bool RestGetFile::loadJson(const std::string& json)
|
||||
return ClientRest::loadJson(json_str);
|
||||
}
|
||||
|
||||
Maybe<std::string> RestGetFile::genJson() const
|
||||
Maybe<string> RestGetFile::genJson() const
|
||||
{
|
||||
Maybe<std::string> json = ClientRest::genJson();
|
||||
Maybe<string> json = ClientRest::genJson();
|
||||
if (json.ok())
|
||||
{
|
||||
std::string data = json.unpack();
|
||||
string data = json.unpack();
|
||||
auto compression_stream = initCompressionStream();
|
||||
CompressionResult res = compressData(
|
||||
compression_stream,
|
||||
@ -94,7 +95,7 @@ Maybe<std::string> RestGetFile::genJson() const
|
||||
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "Failed to gzip data";
|
||||
return genError("Failed to compress data");
|
||||
}
|
||||
data = std::string((const char *)res.output, res.num_output_bytes);
|
||||
data = string((const char *)res.output, res.num_output_bytes);
|
||||
|
||||
json = data;
|
||||
|
||||
@ -104,7 +105,7 @@ Maybe<std::string> RestGetFile::genJson() const
|
||||
}
|
||||
return json;
|
||||
}
|
||||
SerializeToFilePeriodically::SerializeToFilePeriodically(std::chrono::seconds pollingIntervals, std::string filePath) :
|
||||
SerializeToFilePeriodically::SerializeToFilePeriodically(ch::seconds pollingIntervals, string filePath) :
|
||||
SerializeToFileBase(filePath),
|
||||
m_lastSerialization(0),
|
||||
m_interval(pollingIntervals)
|
||||
@ -140,7 +141,7 @@ void SerializeToFilePeriodically::backupWorker()
|
||||
}
|
||||
}
|
||||
|
||||
void SerializeToFilePeriodically::setInterval(std::chrono::seconds newInterval)
|
||||
void SerializeToFilePeriodically::setInterval(ch::seconds newInterval)
|
||||
{
|
||||
if (m_interval != newInterval)
|
||||
{
|
||||
@ -150,7 +151,7 @@ void SerializeToFilePeriodically::setInterval(std::chrono::seconds newInterval)
|
||||
}
|
||||
}
|
||||
|
||||
SerializeToFileBase::SerializeToFileBase(std::string fileName) : m_filePath(fileName)
|
||||
SerializeToFileBase::SerializeToFileBase(string fileName) : m_filePath(fileName)
|
||||
{
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "SerializeToFileBase::SerializeToFileBase() fname='" << m_filePath
|
||||
<< "'";
|
||||
@ -163,12 +164,12 @@ SerializeToFileBase::~SerializeToFileBase()
|
||||
|
||||
void SerializeToFileBase::saveData()
|
||||
{
|
||||
std::fstream filestream;
|
||||
fstream filestream;
|
||||
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "saving to file: " << m_filePath;
|
||||
filestream.open(m_filePath, std::fstream::out);
|
||||
filestream.open(m_filePath, fstream::out);
|
||||
|
||||
std::stringstream ss;
|
||||
stringstream ss;
|
||||
|
||||
if (filestream.is_open() == false) {
|
||||
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << m_filePath << " Error: "
|
||||
@ -182,12 +183,12 @@ void SerializeToFileBase::saveData()
|
||||
filestream.close();
|
||||
}
|
||||
|
||||
void SerializeToFileBase::loadFromFile(std::string filePath)
|
||||
void SerializeToFileBase::loadFromFile(string filePath)
|
||||
{
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "loadFromFile() file: " << filePath;
|
||||
std::fstream filestream;
|
||||
fstream filestream;
|
||||
|
||||
filestream.open(filePath, std::fstream::in);
|
||||
filestream.open(filePath, fstream::in);
|
||||
|
||||
if (filestream.is_open() == false) {
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << filePath << " Error: " <<
|
||||
@ -200,14 +201,14 @@ void SerializeToFileBase::loadFromFile(std::string filePath)
|
||||
// try to strip the unique ID from the path and load the file from the parent directory
|
||||
// that might exist in previous run where instance awareness didn't exits.
|
||||
I_InstanceAwareness* instanceAwareness = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>();
|
||||
Maybe<std::string> id = instanceAwareness->getUniqueID();
|
||||
Maybe<string> id = instanceAwareness->getUniqueID();
|
||||
if (!id.ok())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::string idStr = "/" + id.unpack() + "/";
|
||||
string idStr = "/" + id.unpack() + "/";
|
||||
size_t idPosition = filePath.find(idStr);
|
||||
if (idPosition != std::string::npos)
|
||||
if (idPosition != string::npos)
|
||||
{
|
||||
filePath.erase(idPosition, idStr.length() - 1);
|
||||
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "retry to load file from : " << filePath;
|
||||
@ -219,12 +220,12 @@ void SerializeToFileBase::loadFromFile(std::string filePath)
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "loading from file: " << filePath;
|
||||
|
||||
int length;
|
||||
filestream.seekg(0, std::ios::end); // go to the end
|
||||
filestream.seekg(0, ios::end); // go to the end
|
||||
length = filestream.tellg(); // report location (this is the length)
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "file length: " << length;
|
||||
assert(length >= 0); // length -1 really happens if filePath is a directory (!)
|
||||
char* buffer = new char[length]; // allocate memory for a buffer of appropriate dimension
|
||||
filestream.seekg(0, std::ios::beg); // go back to the beginning
|
||||
filestream.seekg(0, ios::beg); // go back to the beginning
|
||||
if (!filestream.read(buffer, length)) // read the whole file into the buffer
|
||||
{
|
||||
filestream.close();
|
||||
@ -234,18 +235,18 @@ void SerializeToFileBase::loadFromFile(std::string filePath)
|
||||
}
|
||||
filestream.close();
|
||||
|
||||
std::string dataObfuscated(buffer, length);
|
||||
string dataObfuscated(buffer, length);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
|
||||
std::stringstream ss(dataObfuscated);
|
||||
stringstream ss(dataObfuscated);
|
||||
|
||||
try
|
||||
{
|
||||
deserialize(ss);
|
||||
}
|
||||
catch (std::runtime_error & e) {
|
||||
catch (runtime_error & e) {
|
||||
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to deserialize file: " << m_filePath << ", error: " <<
|
||||
e.what();
|
||||
}
|
||||
@ -263,7 +264,7 @@ RemoteFilesList::RemoteFilesList() : files(), filesPathsList()
|
||||
|
||||
// parses xml instead of json
|
||||
// extracts a file list in <Contents><Key>
|
||||
bool RemoteFilesList::loadJson(const std::string& xml)
|
||||
bool RemoteFilesList::loadJson(const string& xml)
|
||||
{
|
||||
xmlDocPtr doc; // the resulting document tree
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "XML input: " << xml;
|
||||
@ -293,22 +294,22 @@ bool RemoteFilesList::loadJson(const std::string& xml)
|
||||
{
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Contents element";
|
||||
xmlNodePtr contents_node = node->children;
|
||||
std::string file;
|
||||
std::string lastModified;
|
||||
string file;
|
||||
string lastModified;
|
||||
while (contents_node != NULL)
|
||||
{
|
||||
if (xmlStrEqual(key_name, contents_node->name) == 1)
|
||||
{
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Key element";
|
||||
xmlChar* xml_file = xmlNodeGetContent(contents_node);
|
||||
file = std::string(reinterpret_cast<const char*>(xml_file));
|
||||
file = string(reinterpret_cast<const char*>(xml_file));
|
||||
xmlFree(xml_file);
|
||||
}
|
||||
if (xmlStrEqual(last_modified_name, contents_node->name) == 1)
|
||||
{
|
||||
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the LastModified element";
|
||||
xmlChar* xml_file = xmlNodeGetContent(contents_node);
|
||||
lastModified = std::string(reinterpret_cast<const char*>(xml_file));
|
||||
lastModified = string(reinterpret_cast<const char*>(xml_file));
|
||||
xmlFree(xml_file);
|
||||
}
|
||||
if (!file.empty() && !lastModified.empty())
|
||||
@ -333,24 +334,24 @@ bool RemoteFilesList::loadJson(const std::string& xml)
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& RemoteFilesList::getFilesList() const
|
||||
const vector<string>& RemoteFilesList::getFilesList() const
|
||||
{
|
||||
return filesPathsList;
|
||||
}
|
||||
|
||||
const std::vector<FileMetaData>& RemoteFilesList::getFilesMetadataList() const
|
||||
const vector<FileMetaData>& RemoteFilesList::getFilesMetadataList() const
|
||||
{
|
||||
return files.get();
|
||||
}
|
||||
|
||||
|
||||
SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
|
||||
std::chrono::minutes interval,
|
||||
std::chrono::seconds waitForSync,
|
||||
const std::string& filePath,
|
||||
const std::string& remotePath,
|
||||
const std::string& assetId,
|
||||
const std::string& owner)
|
||||
ch::minutes interval,
|
||||
ch::seconds waitForSync,
|
||||
const string& filePath,
|
||||
const string& remotePath,
|
||||
const string& assetId,
|
||||
const string& owner)
|
||||
:
|
||||
SerializeToFileBase(filePath),
|
||||
m_remotePath(remotePath),
|
||||
@ -400,7 +401,7 @@ SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
|
||||
if (parts[0].empty()) {
|
||||
offset = 1;
|
||||
}
|
||||
std::string type = "";
|
||||
string type = "";
|
||||
for (size_t i = offset + 2; i < parts.size(); i++)
|
||||
{
|
||||
type += type.empty() ? parts[i] : "/" + parts[i];
|
||||
@ -417,7 +418,7 @@ bool SerializeToLocalAndRemoteSyncBase::isBase()
|
||||
return m_remotePath == "";
|
||||
}
|
||||
|
||||
std::string SerializeToLocalAndRemoteSyncBase::getUri()
|
||||
string SerializeToLocalAndRemoteSyncBase::getUri()
|
||||
{
|
||||
static const string hybridModeUri = "/api";
|
||||
static const string onlineModeUri = "/storage/waap";
|
||||
@ -437,24 +438,24 @@ SerializeToLocalAndRemoteSyncBase::~SerializeToLocalAndRemoteSyncBase()
|
||||
|
||||
}
|
||||
|
||||
std::string SerializeToLocalAndRemoteSyncBase::getWindowId()
|
||||
string SerializeToLocalAndRemoteSyncBase::getWindowId()
|
||||
{
|
||||
return "window_" + std::to_string(m_daysCount) + "_" + std::to_string(m_windowsCount);
|
||||
return "window_" + to_string(m_daysCount) + "_" + to_string(m_windowsCount);
|
||||
}
|
||||
|
||||
std::string SerializeToLocalAndRemoteSyncBase::getPostDataUrl()
|
||||
string SerializeToLocalAndRemoteSyncBase::getPostDataUrl()
|
||||
{
|
||||
std::string agentId = Singleton::Consume<I_AgentDetails>::by<WaapComponent>()->getAgentId();
|
||||
string agentId = Singleton::Consume<I_AgentDetails>::by<WaapComponent>()->getAgentId();
|
||||
if (Singleton::exists<I_InstanceAwareness>())
|
||||
{
|
||||
I_InstanceAwareness* instance = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>();
|
||||
Maybe<std::string> uniqueId = instance->getUniqueID();
|
||||
Maybe<string> uniqueId = instance->getUniqueID();
|
||||
if (uniqueId.ok())
|
||||
{
|
||||
agentId += "/" + uniqueId.unpack();
|
||||
}
|
||||
}
|
||||
std::string windowId = getWindowId();
|
||||
string windowId = getWindowId();
|
||||
return getUri() + "/" + m_remotePath + "/" + windowId + "/" + agentId + "/data.data";
|
||||
}
|
||||
void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled)
|
||||
@ -462,7 +463,7 @@ void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled)
|
||||
m_remoteSyncEnabled = enabled;
|
||||
}
|
||||
|
||||
void SerializeToLocalAndRemoteSyncBase::setInterval(std::chrono::seconds newInterval)
|
||||
void SerializeToLocalAndRemoteSyncBase::setInterval(ch::seconds newInterval)
|
||||
{
|
||||
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "setInterval: from " << m_interval.count() << " to " <<
|
||||
newInterval.count() << " seconds. assetId='" << m_assetId << "', owner='" << m_owner << "'";
|
||||
@ -495,7 +496,7 @@ void SerializeToLocalAndRemoteSyncBase::setInterval(std::chrono::seconds newInte
|
||||
size_t slicesCount = m_interval / assetSyncTimeSliceLength;
|
||||
size_t sliceIndex = 0;
|
||||
if (slicesCount != 0 && m_assetId != "") {
|
||||
sliceIndex = std::hash<std::string>{}(m_assetId) % slicesCount;
|
||||
sliceIndex = hash<string>{}(m_assetId) % slicesCount;
|
||||
}
|
||||
ch::seconds sliceOffset = assetSyncTimeSliceLength * sliceIndex;
|
||||
|
||||
@ -572,7 +573,7 @@ bool SerializeToLocalAndRemoteSyncBase::localSyncAndProcess()
|
||||
return true;
|
||||
}
|
||||
|
||||
std::chrono::seconds SerializeToLocalAndRemoteSyncBase::getIntervalDuration() const
|
||||
ch::seconds SerializeToLocalAndRemoteSyncBase::getIntervalDuration() const
|
||||
{
|
||||
return m_interval;
|
||||
}
|
||||
@ -581,14 +582,14 @@ void SerializeToLocalAndRemoteSyncBase::updateStateFromRemoteService()
|
||||
{
|
||||
for (int i = 0; i < remoteSyncMaxPollingAttempts; i++)
|
||||
{
|
||||
m_pMainLoop->yield(std::chrono::seconds(60));
|
||||
m_pMainLoop->yield(ch::seconds(60));
|
||||
RemoteFilesList remoteFiles = getRemoteProcessedFilesList();
|
||||
if (remoteFiles.getFilesMetadataList().empty())
|
||||
{
|
||||
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "no files generated by the remote service were found";
|
||||
continue;
|
||||
}
|
||||
std::string lastModified = remoteFiles.getFilesMetadataList().begin()->modified;
|
||||
string lastModified = remoteFiles.getFilesMetadataList().begin()->modified;
|
||||
if (lastModified != m_lastProcessedModified)
|
||||
{
|
||||
m_lastProcessedModified = lastModified;
|
||||
@ -618,7 +619,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker()
|
||||
<< "Did not synchronize the data. Remote URL: "
|
||||
<< m_remotePath
|
||||
<< " is enabled: "
|
||||
<< std::to_string(m_remoteSyncEnabled);
|
||||
<< to_string(m_remoteSyncEnabled);
|
||||
processData();
|
||||
saveData();
|
||||
return;
|
||||
@ -659,7 +660,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker()
|
||||
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::EXTERNAL);
|
||||
std::string tenant_header = "X-Tenant-Id: " + agentDetails->getTenantId();
|
||||
string tenant_header = "X-Tenant-Id: " + agentDetails->getTenantId();
|
||||
bool ok = messaging->sendNoReplyObject(syncObj,
|
||||
I_Messaging::Method::POST,
|
||||
getLearningHost(),
|
||||
@ -735,7 +736,7 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList()
|
||||
|
||||
if (!processedFilesList.getFilesList().empty())
|
||||
{
|
||||
const std::vector<FileMetaData>& filesMD = processedFilesList.getFilesMetadataList();
|
||||
const vector<FileMetaData>& filesMD = processedFilesList.getFilesMetadataList();
|
||||
if (filesMD.size() > 1) {
|
||||
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "got more than 1 expected processed file";
|
||||
}
|
||||
@ -764,7 +765,7 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList()
|
||||
return processedFilesList;
|
||||
}
|
||||
// backward compatibility - try to get backup file with the buggy prefix tenantID/assetID/instanceID/
|
||||
std::string bcRemotePath = m_remotePath;
|
||||
string bcRemotePath = m_remotePath;
|
||||
size_t pos = bcRemotePath.find('/');
|
||||
pos = bcRemotePath.find('/', pos + 1);
|
||||
if (!Singleton::exists<I_InstanceAwareness>())
|
||||
@ -774,14 +775,14 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList()
|
||||
return processedFilesList;
|
||||
}
|
||||
I_InstanceAwareness* instanceAwareness = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>();
|
||||
Maybe<std::string> id = instanceAwareness->getUniqueID();
|
||||
Maybe<string> id = instanceAwareness->getUniqueID();
|
||||
if (!id.ok())
|
||||
{
|
||||
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to get instance id err: " << id.getErr() <<
|
||||
". can't check backward compatibility";
|
||||
return processedFilesList;
|
||||
}
|
||||
std::string idStr = id.unpack();
|
||||
string idStr = id.unpack();
|
||||
bcRemotePath.insert(pos + 1, idStr + "/");
|
||||
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "List of files is empty - trying to get the file from " <<
|
||||
bcRemotePath;
|
||||
|
@ -65,7 +65,8 @@ bool TypeIndicatorFilter::shouldFilterKeyword(const std::string &key, const std:
|
||||
key.compare(key.size() - htmlParam.size(), htmlParam.size(), htmlParam) == 0);
|
||||
for (auto keyType : keyTypes)
|
||||
{
|
||||
if (keyType == "free_text" && !isHtmlInput)
|
||||
static const std::string free_text = "free_text";
|
||||
if (!keyType.compare(0, free_text.size(), free_text) && !isHtmlInput)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -1993,7 +1993,7 @@ void WaapAssetState::filterKeywordsByParameters(
|
||||
}
|
||||
else
|
||||
{
|
||||
dbgTrace(D_WAAP_ASSET_STATE) << "No keywords need to be filter for this parameter";
|
||||
dbgTrace(D_WAAP_ASSET_STATE) << "No keywords need to be filtered for this parameter";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,15 @@ set<string> WaapConfigApplication::assets_ids{};
|
||||
set<string> WaapConfigApplication::assets_ids_aggregation{};
|
||||
|
||||
bool WaapConfigApplication::getWaapSiteConfig(WaapConfigApplication& ngenSiteConfig) {
|
||||
auto maybe_tenant_id = Singleton::Consume<I_Environment>::by<WaapConfigApplication>()->get<string>(
|
||||
"ActiveTenantId"
|
||||
);
|
||||
auto maybe_profile_id = Singleton::Consume<I_Environment>::by<WaapConfigApplication>()->get<string>(
|
||||
"ActiveProfileId"
|
||||
);
|
||||
string tenant_id = (maybe_tenant_id.ok() ? *maybe_tenant_id : "not found");
|
||||
string profile_id = (maybe_profile_id.ok() ? *maybe_profile_id : "not found");
|
||||
dbgTrace(D_WAAP) << "Tenant ID: " << tenant_id << ", Profile ID: " << profile_id;
|
||||
auto &maybe_ngen_config = getConfiguration<WaapConfigApplication>(
|
||||
"WAAP",
|
||||
"WebApplicationSecurity"
|
||||
|
@ -19,9 +19,13 @@
|
||||
|
||||
#include "WaapConfigBase.h"
|
||||
#include "log_generator.h"
|
||||
#include "i_environment.h"
|
||||
#include "debug.h"
|
||||
|
||||
class WaapConfigApplication : public WaapConfigBase
|
||||
class WaapConfigApplication
|
||||
:
|
||||
public WaapConfigBase,
|
||||
Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
WaapConfigApplication();
|
||||
|
@ -31,6 +31,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
|
||||
std::string param_name = IndicatorsFiltersManager::generateKey(res.location, res.param_name, m_transaction);
|
||||
dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name;
|
||||
m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction);
|
||||
|
||||
m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords);
|
||||
if (m_transaction->getSiteConfig() != nullptr)
|
||||
{
|
||||
@ -41,6 +42,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
|
||||
}
|
||||
m_transaction->getAssetState()->filterKeywordsByParameters(res.param_name, keywordsSet);
|
||||
|
||||
|
||||
// The keywords are only removed in production, they are still used while building scores
|
||||
if (!m_transaction->get_ignoreScore()) {
|
||||
m_transaction->getAssetState()->removeKeywords(keywordsSet);
|
||||
@ -66,6 +68,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
|
||||
std::sort(res.keyword_matches.begin(), res.keyword_matches.end());
|
||||
|
||||
std::string keywords_string;
|
||||
std::vector<std::string> strippedKeywords;
|
||||
for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) {
|
||||
// Add spaces between the items, but not before the first one
|
||||
if (pKeyword != keywordsSet.begin()) {
|
||||
@ -75,15 +78,21 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
|
||||
std::string k = *pKeyword;
|
||||
stripSpaces(k);
|
||||
keywords_string += k;
|
||||
strippedKeywords.push_back(k);
|
||||
}
|
||||
|
||||
std::vector<std::string> newKeywords;
|
||||
for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) {
|
||||
std::string k = *pKeyword;
|
||||
stripSpaces(k);
|
||||
// if keyword_string.count(key) < 2: new_keywords.append(key)
|
||||
if (countSubstrings(keywords_string, k) < 2) {
|
||||
newKeywords.push_back(k);
|
||||
} else {
|
||||
if ((std::count(strippedKeywords.begin(), strippedKeywords.end(), k) > 1) ) {
|
||||
if ((std::count(newKeywords.begin(), newKeywords.end(), k) < 1)) {
|
||||
newKeywords.push_back(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,6 +136,10 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp,
|
||||
res.location = location;
|
||||
res.param_name = param_name; // remember the param name (analyzer needs it for reporting)
|
||||
|
||||
// call shouldIgnoreOverride prior to score calculation, so that matched override keywords will be filtered
|
||||
// when an ignore override action is detected
|
||||
bool ignoreOverride = m_transaction->shouldIgnoreOverride(res);
|
||||
|
||||
// Select scores pool by location
|
||||
std::string poolName = Waap::Scores::getScorePoolNameByLocation(location);
|
||||
|
||||
@ -145,7 +158,7 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp,
|
||||
);
|
||||
}
|
||||
|
||||
if (isKeyCspReport(key, res, dp) || m_transaction->shouldIgnoreOverride(res)) {
|
||||
if (isKeyCspReport(key, res, dp) || ignoreOverride) {
|
||||
dbgTrace(D_WAAP_SCANNER) << "Ignoring parameter key/value " << res.param_name <<
|
||||
" due to ignore action in override";
|
||||
m_bIgnoreOverride = true;
|
||||
|
@ -67,8 +67,6 @@ using namespace ReportIS;
|
||||
// Score threshold below which the match won't be considered
|
||||
#define SCORE_THRESHOLD (1.4f)
|
||||
|
||||
static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE);
|
||||
|
||||
void Waf2Transaction::learnScore(ScoreBuilderData& data, const std::string &poolName)
|
||||
{
|
||||
m_pWaapAssetState->scoreBuilder.analyzeFalseTruePositive(data, poolName, !m_ignoreScore);
|
||||
@ -1372,7 +1370,7 @@ Waf2Transaction::checkShouldInject()
|
||||
std::string uri = m_uriPath;
|
||||
std::string low_method = m_methodStr;
|
||||
std::transform(low_method.begin(), low_method.end(), low_method.begin(), ::tolower);
|
||||
|
||||
|
||||
auto csrfPolicy = m_siteConfig ? m_siteConfig->get_CsrfPolicy() : NULL;
|
||||
bool csrf = false;
|
||||
dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): received the relevant Application configuration "
|
||||
@ -1384,7 +1382,7 @@ Waf2Transaction::checkShouldInject()
|
||||
{
|
||||
dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): Should not inject CSRF scripts.";
|
||||
}
|
||||
|
||||
|
||||
if(csrf) {
|
||||
dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): Should inject CSRF script";
|
||||
m_responseInjectReasons.setCsrf(true);
|
||||
@ -1554,6 +1552,8 @@ void Waf2Transaction::appendCommonLogFields(LogGen& waapLog,
|
||||
const std::string& incidentType) const
|
||||
{
|
||||
auto env = Singleton::Consume<I_Environment>::by<WaapComponent>();
|
||||
auto active_id = env->get<std::string>("ActiveTenantId");
|
||||
if (active_id.ok()) waapLog.addToOrigin(LogField("tenantId", *active_id));
|
||||
auto proxy_ip = env->get<std::string>(HttpTransactionData::proxy_ip_ctx);
|
||||
if (proxy_ip.ok() && m_remote_addr != proxy_ip.unpack())
|
||||
{
|
||||
@ -2155,7 +2155,7 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
|
||||
auto exceptions = getConfiguration<ParameterException>("rulebase", "exception");
|
||||
if (!exceptions.ok()) return false;
|
||||
|
||||
dbgTrace(D_WAAP) << "matching exceptions";
|
||||
dbgTrace(D_WAAP_OVERRIDE) << "matching exceptions";
|
||||
|
||||
std::unordered_map<std::string, std::set<std::string>> exceptions_dict;
|
||||
|
||||
@ -2184,11 +2184,16 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
|
||||
exceptions_dict["url"].insert(getUriStr());
|
||||
exceptions_dict["hostName"].insert(m_hostStr);
|
||||
|
||||
for (auto &keyword : res.keyword_matches) {
|
||||
exceptions_dict["indicator"].insert(keyword);
|
||||
}
|
||||
|
||||
// calling behavior and check if there is a behavior that match to this specific param name.
|
||||
auto behaviors = exceptions.unpack().getBehavior(exceptions_dict);
|
||||
auto behaviors = exceptions.unpack().getBehavior(exceptions_dict,
|
||||
getAssetState()->m_filtersMngr->getMatchedOverrideKeywords());
|
||||
for (auto const &behavior : behaviors) {
|
||||
if (behavior == action_ignore) {
|
||||
dbgTrace(D_WAAP) << "matched exceptions for " << res.param_name << " should ignore.";
|
||||
dbgTrace(D_WAAP_OVERRIDE) << "matched exceptions for " << res.param_name << " should ignore.";
|
||||
std::string overrideId = behavior.getId();
|
||||
if (!overrideId.empty()) {
|
||||
m_matchedOverrideIds.insert(overrideId);
|
||||
|
@ -41,6 +41,7 @@ using namespace std;
|
||||
USE_DEBUG_FLAG(D_WAAP);
|
||||
USE_DEBUG_FLAG(D_WAAP_EVASIONS);
|
||||
USE_DEBUG_FLAG(D_WAAP_BASE64);
|
||||
USE_DEBUG_FLAG(D_WAAP_JSON);
|
||||
|
||||
#define MIN_HEX_LENGTH 6
|
||||
#define charToDigit(c) (c - '0')
|
||||
@ -1144,6 +1145,8 @@ namespace Util {
|
||||
#define B64_TRAILERCHAR '='
|
||||
|
||||
static bool err = false;
|
||||
// based on malicious JSON "{1:\x00}"
|
||||
static const int minimal_legal_json_size = 8;
|
||||
|
||||
static const SingleRegex invalid_hex_evasion_re(
|
||||
"%([g-zG-Z][0-9a-zA-Z]|[0-9a-zA-Z][g-zG-Z])",
|
||||
@ -1161,11 +1164,15 @@ static const SingleRegex csp_report_policy_re(
|
||||
"csp_report_policy"
|
||||
);
|
||||
static const SingleRegex base64_key_value_detector_re(
|
||||
"^[^<>;&\\?|=\\s]+={1}\\s*.+",
|
||||
"^[^<>{};,&\\?|=\\s]+={1}\\s*.+",
|
||||
err,
|
||||
"base64_key_value");
|
||||
static const SingleRegex json_key_value_detector_re(
|
||||
"^[^<>{};,&\\?|=\\s]+={.+:.+}\\z",
|
||||
err,
|
||||
"json_key_value");
|
||||
static const SingleRegex base64_key_detector_re(
|
||||
"^[^<>;&\\?|=\\s]+={1}",
|
||||
"^[^<>{};,&\\?|=\\s]+={1}",
|
||||
err,
|
||||
"base64_key");
|
||||
static const SingleRegex base64_prefix_detector_re(
|
||||
@ -1173,6 +1180,44 @@ static const SingleRegex base64_prefix_detector_re(
|
||||
err,
|
||||
"base64_prefix");
|
||||
|
||||
// looks for combination <param>={<some text>*:<some text>*}
|
||||
//used to allow parsing param=JSON to reduce false positives
|
||||
bool detectJSONasParameter(const string &string_buffer,
|
||||
string &key,
|
||||
string &value)
|
||||
{
|
||||
key.clear();
|
||||
value.clear();
|
||||
bool is_json_candidate_detected = json_key_value_detector_re.hasMatch(string_buffer);
|
||||
|
||||
if (is_json_candidate_detected) {
|
||||
dbgTrace(D_WAAP_JSON) << "===JSONdetect===: json_key_value_detector_re test passed - looking for key";
|
||||
string::const_iterator it = string_buffer.begin();
|
||||
for (; it != string_buffer.end(); ++it) {
|
||||
if (*it != '{') {
|
||||
continue;
|
||||
}
|
||||
// candidate should have size 8 or more - minimum for JSON with attack
|
||||
if ((string_buffer.end() - it) < minimal_legal_json_size) {
|
||||
dbgTrace(D_WAAP_JSON)
|
||||
<< "===JSONdetect===: candidate is shorter then the length"
|
||||
"of the shortest known json attack which is: " << minimal_legal_json_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
key = std::string(string_buffer.begin(), it-1);
|
||||
value = std::string(it, string_buffer.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
dbgTrace(D_WAAP_JSON)
|
||||
<< "===JSONdetect===: key = '"
|
||||
<< key
|
||||
<< "', value = '"
|
||||
<< value <<"'";
|
||||
return is_json_candidate_detected;
|
||||
}
|
||||
|
||||
static void b64TestChunk(const string &s,
|
||||
string::const_iterator chunkStart,
|
||||
string::const_iterator chunkEnd,
|
||||
@ -2115,6 +2160,8 @@ string convertParamTypeToStr(ParamType type)
|
||||
return "urls";
|
||||
case FREE_TEXT_PARAM_TYPE:
|
||||
return "free_text";
|
||||
case FREE_TEXT_FRENCH_PARAM_TYPE:
|
||||
return "free_text_french";
|
||||
case PIPE_PARAM_TYPE:
|
||||
return "pipes";
|
||||
case LONG_RANDOM_TEXT_PARAM_TYPE:
|
||||
@ -2148,6 +2195,7 @@ ParamType convertTypeStrToEnum(const string& typeStr)
|
||||
{"administration_config", ParamType::ADMINISTRATOR_CONFIG_PARAM_TYPE},
|
||||
{"base64", ParamType::BASE64_PARAM_TYPE },
|
||||
{"free_text", ParamType::FREE_TEXT_PARAM_TYPE},
|
||||
{"free_text_french", ParamType::FREE_TEXT_FRENCH_PARAM_TYPE},
|
||||
{"html_input", ParamType::HTML_PARAM_TYPE},
|
||||
{"long_random_text", ParamType::LONG_RANDOM_TEXT_PARAM_TYPE},
|
||||
{"pipes", ParamType::PIPE_PARAM_TYPE},
|
||||
|
@ -858,6 +858,10 @@ namespace Util {
|
||||
std::string::const_iterator e,
|
||||
std::string &repl);
|
||||
|
||||
bool detectJSONasParameter(const std::string &s,
|
||||
std::string &key,
|
||||
std::string &value);
|
||||
|
||||
void b64Decode(
|
||||
const std::string &s,
|
||||
RegexSubCallback_f cb,
|
||||
|
@ -1,2 +1,3 @@
|
||||
add_subdirectory(http_transaction_data)
|
||||
add_subdirectory(ip_utilities)
|
||||
add_subdirectory(pm)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "config.h"
|
||||
#include "config_component.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <boost/regex.hpp>
|
||||
@ -66,11 +67,24 @@ public:
|
||||
void
|
||||
doCall() override
|
||||
{
|
||||
auto i_config = Singleton::Consume<I_Config>::from<ConfigComponent>();
|
||||
static const map<I_Config::AsyncLoadConfigStatus, string> status_map {
|
||||
{I_Config::AsyncLoadConfigStatus::Success, "Success"},
|
||||
{I_Config::AsyncLoadConfigStatus::InProgress, "In Progress"},
|
||||
{I_Config::AsyncLoadConfigStatus::Error, "Error"}
|
||||
};
|
||||
|
||||
auto i_config = Singleton::Consume<I_Config>::from<ConfigComponent>();
|
||||
I_Config::AsyncLoadConfigStatus load_config_staus = i_config->reloadConfiguration(policy_version, true, id);
|
||||
finished = load_config_staus == I_Config::AsyncLoadConfigStatus::InProgress;
|
||||
|
||||
finished = load_config_staus != I_Config::AsyncLoadConfigStatus::InProgress;
|
||||
error = load_config_staus == I_Config::AsyncLoadConfigStatus::Error;
|
||||
|
||||
if (error) {
|
||||
dbgWarning(D_CONFIG) << "Configuration reload status: " << status_map.at(load_config_staus);
|
||||
} else {
|
||||
dbgDebug(D_CONFIG) << "Configuration reload status: " << status_map.at(load_config_staus);
|
||||
}
|
||||
|
||||
if (!finished) {
|
||||
error_message = "Reload already in progress - can't start another one";
|
||||
}
|
||||
@ -669,8 +683,8 @@ ConfigComponent::Impl::clearOldTenants()
|
||||
bool
|
||||
ConfigComponent::Impl::areTenantAndProfileActive(const TenantProfilePair &tenant_profile) const
|
||||
{
|
||||
return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getPfofileId() == default_profile_id)
|
||||
|| tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getPfofileId());
|
||||
return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getProfileId() == default_profile_id)
|
||||
|| tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getProfileId());
|
||||
}
|
||||
|
||||
void
|
||||
@ -723,12 +737,21 @@ ConfigComponent::Impl::loadConfiguration(vector<shared_ptr<JSONInputArchive>> &f
|
||||
string curr_profile = default_profile_id;
|
||||
try {
|
||||
(*archive)(cereal::make_nvp("tenantID", curr_tenant));
|
||||
dbgTrace(D_CONFIG) << "Found a tenant ID in the file: " << curr_tenant;
|
||||
} catch (cereal::Exception &e) {}
|
||||
try {
|
||||
(*archive)(cereal::make_nvp("profileID", curr_profile));
|
||||
} catch (cereal::Exception &e) {
|
||||
}
|
||||
dbgTrace(D_CONFIG) << "Found a profile ID in the file " << curr_profile;
|
||||
} catch (cereal::Exception &e) {}
|
||||
|
||||
dbgTrace(D_CONFIG)
|
||||
<< "Loading configuration for tenant: "
|
||||
<< curr_tenant
|
||||
<< " and profile: "
|
||||
<< curr_profile
|
||||
<< ", for the archive: "
|
||||
<< (*archive).getNodeName();
|
||||
|
||||
dbgTrace(D_CONFIG) <<
|
||||
"Loading configuration for tenant: " << curr_tenant << " and profile: " << curr_profile;
|
||||
TenantProfilePair tenant_profile(curr_tenant, curr_profile);
|
||||
for (auto &config : expected_configs) {
|
||||
auto loaded = config->loadConfiguration(*archive);
|
||||
@ -800,6 +823,7 @@ ConfigComponent::Impl::commitFailure(const string &error)
|
||||
bool
|
||||
ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_async)
|
||||
{
|
||||
dbgFlow(D_CONFIG) << "Reloading configuration";
|
||||
auto env = Singleton::Consume<I_Environment>::by<ConfigComponent>();
|
||||
env->registerValue<string>("New Policy Version", version);
|
||||
auto cleanup = make_scope_exit([env] () { env->unregisterKey<string>("New Policy Version"); } );
|
||||
@ -812,6 +836,8 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
|
||||
|
||||
const auto &active_tenants = tenant_mananger ? tenant_mananger->fetchAllActiveTenants() : vector<string>();
|
||||
|
||||
dbgTrace(D_CONFIG) << "Number of active tenants found while reloading configuration: " << active_tenants.size();
|
||||
|
||||
for (const auto &config_file : expected_configuration_files) {
|
||||
for (const auto &type : config_file.second) {
|
||||
if (type == ConfigFileType::RawData) continue;
|
||||
@ -835,7 +861,9 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
|
||||
const vector<string> &profile_ids =
|
||||
tenant_mananger ? tenant_mananger->fetchProfileIds(tenant) : vector<string>();
|
||||
for (auto &profile_id : profile_ids) {
|
||||
string settings_path = config_directory_path + "tenant_" + tenant + "_" + profile_id + "_settings.json";
|
||||
string settings_path =
|
||||
config_directory_path + "tenant_" + tenant + "_profile_"+ profile_id + "_settings.json";
|
||||
dbgTrace(D_CONFIG) << "Inserting a settings path: " << settings_path;
|
||||
files.emplace(settings_path, make_shared<ifstream>(settings_path));
|
||||
}
|
||||
}
|
||||
@ -843,10 +871,10 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
|
||||
vector<shared_ptr<JSONInputArchive>> archives;
|
||||
for (const auto &file : files) {
|
||||
if (file.second->is_open()) {
|
||||
dbgDebug(D_CONFIG) << "Succesfully opened configuration file. File: " << file.first;
|
||||
dbgTrace(D_CONFIG) << "Succesfully opened configuration file. File: " << file.first;
|
||||
archives.push_back(make_shared<JSONInputArchive>(*file.second));
|
||||
} else {
|
||||
dbgDebug(D_CONFIG) << "Could not open configuration file. Path: " << file.first;
|
||||
dbgTrace(D_CONFIG) << "Could not open configuration file. Path: " << file.first;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,26 +161,6 @@ IPAddr::createIPAddr(const string &ip_text)
|
||||
|
||||
bool IPAddr::isValidIPAddr(const string &ip_text) { return createIPAddr(ip_text).ok(); }
|
||||
|
||||
IPAddressConfig::IPAddressConfig(const string &ip_string)
|
||||
{
|
||||
auto maybe_address = IPAddr::createIPAddr(ip_string);
|
||||
if (maybe_address.ok()) address = maybe_address.unpack();
|
||||
}
|
||||
|
||||
void
|
||||
IPAddressConfig::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
string ip_string;
|
||||
ar(cereal::make_nvp("IPAddress", ip_string));
|
||||
auto ip_address = IPAddr::createIPAddr(ip_string);
|
||||
if (!ip_address.ok()) {
|
||||
throw Config::ConfigException(
|
||||
"Failed to create an IP address from " + ip_string + ": " + ip_address.getErr()
|
||||
);
|
||||
}
|
||||
address = ip_address.unpack();
|
||||
}
|
||||
|
||||
const string ConnKey::network_key = "NetworkKey";
|
||||
|
||||
template<typename Num>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "i_socket_is.h"
|
||||
#include "component.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_shell_cmd.h"
|
||||
|
||||
class LoggingComp
|
||||
:
|
||||
@ -35,7 +36,8 @@ class LoggingComp
|
||||
Singleton::Consume<I_TimeGet>,
|
||||
Singleton::Consume<I_Logging>,
|
||||
Singleton::Consume<I_Socket>,
|
||||
Singleton::Consume<I_AgentDetails>
|
||||
Singleton::Consume<I_AgentDetails>,
|
||||
Singleton::Consume<I_ShellCmd>
|
||||
{
|
||||
public:
|
||||
LoggingComp();
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
}
|
||||
|
||||
std::string
|
||||
getPfofileId() const
|
||||
getProfileId() const
|
||||
{
|
||||
return profile_id;
|
||||
}
|
||||
|
@ -25,7 +25,11 @@ public:
|
||||
using GeneralModifier = std::function<void(LogBulkRest &)>;
|
||||
|
||||
virtual bool addStream(ReportIS::StreamType type) = 0;
|
||||
virtual bool addStream(ReportIS::StreamType type, const std::string &log_server_url) = 0;
|
||||
virtual bool addStream(
|
||||
ReportIS::StreamType type,
|
||||
const std::string &log_server_url,
|
||||
const std::string &protocol
|
||||
) = 0;
|
||||
virtual bool delStream(ReportIS::StreamType type) = 0;
|
||||
|
||||
virtual void sendLog(const Report &msg) = 0;
|
||||
|
@ -41,6 +41,8 @@ public:
|
||||
|
||||
virtual std::chrono::microseconds getTimeoutVal() const = 0;
|
||||
|
||||
virtual std::string getProfileId(const std::string &tenant_id, const std::string ®ion) const = 0;
|
||||
|
||||
private:
|
||||
friend class LoadNewTenants;
|
||||
friend class LoadNewTenantsAndProfiles;
|
||||
|
@ -10,7 +10,7 @@ class MockLogging : public Singleton::Provide<I_Logging>::From<MockProvider<I_Lo
|
||||
public:
|
||||
MOCK_METHOD1(sendLog, void (const Report &));
|
||||
MOCK_METHOD1(addStream, bool (ReportIS::StreamType));
|
||||
MOCK_METHOD2(addStream, bool (ReportIS::StreamType, const std::string &));
|
||||
MOCK_METHOD3(addStream, bool (ReportIS::StreamType, const std::string &, const std::string &));
|
||||
MOCK_METHOD1(delStream, bool (ReportIS::StreamType));
|
||||
MOCK_METHOD0(getCurrentLogId, uint64_t ());
|
||||
MOCK_METHOD1(addGeneralModifier, void (const GeneralModifier &));
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
MOCK_CONST_METHOD2(areTenantAndProfileActive, bool(const std::string &, const std::string &));
|
||||
MOCK_METHOD2(addActiveTenantAndProfile, void(const std::string &, const std::string &));
|
||||
MOCK_METHOD2(deactivateTenant, void(const std::string &, const std::string &));
|
||||
MOCK_CONST_METHOD2(getProfileId, std::string(const std::string &, const std::string &));
|
||||
|
||||
MOCK_CONST_METHOD0(getTimeoutVal, std::chrono::microseconds());
|
||||
|
||||
|
@ -74,6 +74,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
|
||||
DEFINE_FLAG(D_WAAP_SCANNER, D_WAAP)
|
||||
DEFINE_FLAG(D_WAAP_DEEP_PARSER, D_WAAP)
|
||||
DEFINE_FLAG(D_WAAP_BASE64, D_WAAP)
|
||||
DEFINE_FLAG(D_WAAP_JSON, D_WAAP)
|
||||
DEFINE_FLAG(D_WAAP_BOT_PROTECTION, D_WAAP)
|
||||
DEFINE_FLAG(D_WAAP_PARSER, D_WAAP)
|
||||
DEFINE_FLAG(D_WAAP_PARSER_XML, D_WAAP_PARSER)
|
||||
@ -122,6 +123,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
|
||||
DEFINE_FLAG(D_HEALTH_CHECK, D_ORCHESTRATOR)
|
||||
DEFINE_FLAG(D_AGENT_DETAILS, D_ORCHESTRATOR)
|
||||
DEFINE_FLAG(D_K8S_POLICY, D_ORCHESTRATOR)
|
||||
DEFINE_FLAG(D_NGINX_POLICY, D_ORCHESTRATOR)
|
||||
|
||||
DEFINE_FLAG(D_GRADUAL_DEPLOYMENT, D_COMPONENT)
|
||||
DEFINE_FLAG(D_C8_CONTROLLER, D_COMPONENT)
|
||||
|
@ -23,6 +23,7 @@ enum class StreamType {
|
||||
JSON_DEBUG,
|
||||
JSON_FOG,
|
||||
JSON_LOG_FILE,
|
||||
JSON_K8S_SVC,
|
||||
SYSLOG,
|
||||
CEF,
|
||||
|
||||
@ -55,6 +56,7 @@ enum class Tags {
|
||||
HTTP_GEO_FILTER,
|
||||
FILE_UPLOAD,
|
||||
IDENTITY_AWARENESS,
|
||||
RATE_LIMIT,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
@ -199,21 +199,6 @@ private:
|
||||
RangeType end;
|
||||
};
|
||||
|
||||
class IPAddressConfig
|
||||
{
|
||||
public:
|
||||
IPAddressConfig() = default;
|
||||
IPAddressConfig(const std::string &ip_string);
|
||||
|
||||
void load(cereal::JSONInputArchive &ar);
|
||||
const IPAddr & getAddress() const { return address; }
|
||||
|
||||
operator IPAddr() const { return address; }
|
||||
|
||||
private:
|
||||
IPAddr address;
|
||||
};
|
||||
|
||||
// Specialization of std::hash<> for IPAddr
|
||||
namespace std
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
Maybe<string> instance_id = checkIfValueIsConfigured("id");
|
||||
if (instance_id.ok()) return instance_id;
|
||||
|
||||
return genError("Instance Awareness isn't active");
|
||||
return genError("Instance Awareness isn't active, Error: " + instance_id.getErr());
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
@ -42,14 +42,14 @@ public:
|
||||
Maybe<string> family_id = checkIfValueIsConfigured("family");
|
||||
if (family_id.ok()) return family_id;
|
||||
|
||||
return genError("Family ID isn't active");
|
||||
return genError("Family ID isn't active, Error: " + family_id.getErr());
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
getUniqueID() override
|
||||
{
|
||||
Maybe<string> instance_id(getInstanceID());
|
||||
if (!instance_id.ok()) return genError("Instance Awareness isn't active");
|
||||
if (!instance_id.ok()) return genError("Can't get instance ID, Error: " + instance_id.getErr());
|
||||
|
||||
Maybe<string> family_id(getFamilyID());
|
||||
if (!family_id.ok()) return *instance_id;
|
||||
|
@ -43,9 +43,12 @@ TEST_F(InstanceAwarenessTest, emptyInit)
|
||||
|
||||
init(args);
|
||||
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active"));
|
||||
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found"));
|
||||
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found"));
|
||||
EXPECT_THAT(
|
||||
getUniqueID(),
|
||||
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(InstanceAwarenessTest, badFamilyID)
|
||||
@ -55,7 +58,7 @@ TEST_F(InstanceAwarenessTest, badFamilyID)
|
||||
init(args);
|
||||
|
||||
EXPECT_THAT(getInstanceID(), IsValue("9"));
|
||||
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active"));
|
||||
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Illegal flag: family"));
|
||||
EXPECT_THAT(getUniqueID(), IsValue("9"));
|
||||
}
|
||||
|
||||
@ -65,9 +68,12 @@ TEST_F(InstanceAwarenessTest, badInstanceID)
|
||||
|
||||
init(args);
|
||||
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Illegal flag: id"));
|
||||
EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5"));
|
||||
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(
|
||||
getUniqueID(),
|
||||
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Illegal flag: id")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(InstanceAwarenessTest, emptyInstanceID)
|
||||
@ -76,9 +82,12 @@ TEST_F(InstanceAwarenessTest, emptyInstanceID)
|
||||
|
||||
init(args);
|
||||
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found"));
|
||||
EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5"));
|
||||
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(
|
||||
getUniqueID(),
|
||||
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(InstanceAwarenessTest, noInstanceID)
|
||||
@ -87,9 +96,12 @@ TEST_F(InstanceAwarenessTest, noInstanceID)
|
||||
|
||||
init(args);
|
||||
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found"));
|
||||
EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5"));
|
||||
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
|
||||
EXPECT_THAT(
|
||||
getUniqueID(),
|
||||
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(InstanceAwarenessTest, init)
|
||||
@ -111,7 +123,7 @@ TEST_F(InstanceAwarenessTest, initIDOnly)
|
||||
|
||||
EXPECT_THAT(getUniqueID(), IsValue("9"));
|
||||
EXPECT_THAT(getInstanceID(), IsValue("9"));
|
||||
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active"));
|
||||
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found"));
|
||||
}
|
||||
|
||||
TEST_F(InstanceAwarenessTest, defaultValues)
|
||||
|
@ -1,3 +1,3 @@
|
||||
add_library(logging logging.cc log_generator.cc debug_stream.cc file_stream.cc fog_stream.cc syslog_stream.cc cef_stream.cc)
|
||||
add_library(logging logging.cc log_generator.cc debug_stream.cc file_stream.cc fog_stream.cc syslog_stream.cc cef_stream.cc k8s_svc_stream.cc)
|
||||
|
||||
add_subdirectory(logging_ut)
|
||||
|
@ -11,6 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "logging_comp.h"
|
||||
#include "log_streams.h"
|
||||
|
||||
@ -19,11 +21,16 @@ using namespace cereal;
|
||||
|
||||
USE_DEBUG_FLAG(D_REPORT);
|
||||
|
||||
CefStream::CefStream(const string &_ip_address, int _port)
|
||||
static string lookup_cmd = "nslookup ";
|
||||
static string line_selection_cmd = "| grep Address | sed -n 2p";
|
||||
static string parsing_cmd = "| cut -f2 -d' ' | tr -d '\n'";
|
||||
|
||||
CefStream::CefStream(const string &_address, int _port, I_Socket::SocketType _protocol)
|
||||
:
|
||||
i_socket(Singleton::Consume<I_Socket>::by<LoggingComp>()),
|
||||
ip_address(_ip_address),
|
||||
port(_port)
|
||||
address(_address),
|
||||
port(_port),
|
||||
protocol(_protocol)
|
||||
{
|
||||
connect();
|
||||
if (!socket.ok()) {
|
||||
@ -65,17 +72,57 @@ CefStream::sendLog(const Report &log)
|
||||
void
|
||||
CefStream::connect()
|
||||
{
|
||||
auto cef_ip_address = getProfileAgentSettingWithDefault<string>(ip_address, "agent.config.log.cefServer.IP");
|
||||
auto cef_address = getProfileAgentSettingWithDefault<string>(address, "agent.config.log.cefServer.IP");
|
||||
auto cef_port = getProfileAgentSettingWithDefault<uint>(port, "agent.config.log.cefServer.port");
|
||||
|
||||
if (cef_ip_address.empty()) {
|
||||
dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP is not configured.";
|
||||
if (cef_address.empty()) {
|
||||
dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP/Domain is not configured.";
|
||||
return;
|
||||
}
|
||||
|
||||
struct in_addr addr;
|
||||
if (inet_pton(AF_INET, cef_address.data(), &addr) != 1) {
|
||||
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<LoggingComp>();
|
||||
string host_cmd = lookup_cmd + cef_address + line_selection_cmd + parsing_cmd;
|
||||
Maybe<string> res = shell_cmd->getExecOutput(host_cmd, 500);
|
||||
if (!res.ok()) {
|
||||
dbgWarning(D_REPORT)
|
||||
<< "Failed to execute domain lookup command. "
|
||||
<< "CEF Domain: "
|
||||
<< cef_address
|
||||
<< "Error: "
|
||||
<< res.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.unpack().empty()) {
|
||||
dbgWarning(D_REPORT)
|
||||
<< "Got en empty ip address from lookup command. "
|
||||
<< "CEF Domain: "
|
||||
<< cef_address
|
||||
<< "Got bad ip address: "
|
||||
<< res.unpack();
|
||||
return;
|
||||
}
|
||||
|
||||
dbgDebug(D_REPORT) << "CEF Domain lookup result: " << res.unpack();
|
||||
if (inet_pton(AF_INET, res.unpack().data(), &addr) != 1) {
|
||||
dbgWarning(D_REPORT)
|
||||
<< "Got a faulty ip address from lookup command. "
|
||||
<< "CEF Domain: "
|
||||
<< cef_address
|
||||
<< "Got bad ip address: "
|
||||
<< res.unpack();
|
||||
return;
|
||||
}
|
||||
|
||||
cef_address = res.unpack();
|
||||
}
|
||||
|
||||
socket = i_socket->genSocket(
|
||||
I_Socket::SocketType::UDP,
|
||||
protocol,
|
||||
false,
|
||||
false,
|
||||
cef_ip_address + ":" + to_string(cef_port)
|
||||
cef_address + ":" + to_string(cef_port)
|
||||
);
|
||||
}
|
||||
|
97
core/logging/k8s_svc_stream.cc
Normal file
97
core/logging/k8s_svc_stream.cc
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "log_streams.h"
|
||||
#include "logging_comp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const static string default_host = "open-appsec-tuning-svc";
|
||||
const static string default_bulk_uri = "/api/v1/agents/events/bulk";
|
||||
const static string default_log_uri = "/api/v1/agents/events";
|
||||
|
||||
USE_DEBUG_FLAG(D_REPORT);
|
||||
|
||||
K8sSvcStream::K8sSvcStream()
|
||||
:
|
||||
i_msg(Singleton::Consume<I_Messaging>::by<LoggingComp>())
|
||||
{
|
||||
}
|
||||
|
||||
K8sSvcStream::~K8sSvcStream()
|
||||
{
|
||||
}
|
||||
|
||||
string
|
||||
K8sSvcStream::genHeader()
|
||||
{
|
||||
return "X-Tenant-Id: " + Singleton::Consume<I_AgentDetails>::by<LoggingComp>()->getTenantId();
|
||||
}
|
||||
|
||||
void
|
||||
K8sSvcStream::sendLog(const Report &log)
|
||||
{
|
||||
auto svc_host = getConfigurationWithDefault(default_host, "Logging", "K8sSvc Log host");
|
||||
auto K8sSvc_log_uri = getConfigurationWithDefault(default_log_uri, "Logging", "K8sSvc Log URI");
|
||||
LogRest rest(log);
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::EXTERNAL);
|
||||
|
||||
bool ok = i_msg->sendNoReplyObject(
|
||||
rest,
|
||||
I_Messaging::Method::POST,
|
||||
svc_host,
|
||||
80,
|
||||
conn_flags,
|
||||
K8sSvc_log_uri,
|
||||
genHeader(),
|
||||
nullptr,
|
||||
MessageTypeTag::LOG
|
||||
);
|
||||
|
||||
if (!ok) {
|
||||
dbgWarning(D_REPORT) << "failed to send log";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
K8sSvcStream::sendLog(const LogBulkRest &logs, bool persistence_only)
|
||||
{
|
||||
dbgFlow(D_REPORT) << "send bulk logs";
|
||||
|
||||
if (persistence_only) {
|
||||
dbgWarning(D_REPORT) << "Skipping logs due to persistence only setting";
|
||||
return;
|
||||
}
|
||||
|
||||
auto svc_host = getConfigurationWithDefault(default_host, "Logging", "K8sSvc Log host");
|
||||
auto K8sSvc_log_uri = getConfigurationWithDefault(default_bulk_uri, "Logging", "K8sSvc Bulk Log URI");
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::EXTERNAL);
|
||||
|
||||
bool ok = i_msg->sendNoReplyObject(
|
||||
logs,
|
||||
I_Messaging::Method::POST,
|
||||
svc_host,
|
||||
80,
|
||||
conn_flags,
|
||||
K8sSvc_log_uri,
|
||||
genHeader(),
|
||||
nullptr,
|
||||
MessageTypeTag::LOG
|
||||
);
|
||||
|
||||
if (!ok) {
|
||||
dbgWarning(D_REPORT) << "failed to send bulk logs";
|
||||
}
|
||||
}
|
@ -80,10 +80,24 @@ private:
|
||||
I_Messaging *i_msg = nullptr;
|
||||
};
|
||||
|
||||
class K8sSvcStream : public Stream
|
||||
{
|
||||
public:
|
||||
K8sSvcStream();
|
||||
~K8sSvcStream();
|
||||
|
||||
void sendLog(const Report &log) override;
|
||||
void sendLog(const LogBulkRest &logs, bool persistance_only) override;
|
||||
|
||||
private:
|
||||
std::string genHeader();
|
||||
I_Messaging *i_msg = nullptr;
|
||||
};
|
||||
|
||||
class SyslogStream : public Stream
|
||||
{
|
||||
public:
|
||||
SyslogStream(const std::string &_ip_address, int _port);
|
||||
SyslogStream(const std::string &_address, int _port, I_Socket::SocketType protocol);
|
||||
~SyslogStream();
|
||||
|
||||
void sendLog(const Report &log) override;
|
||||
@ -93,8 +107,9 @@ private:
|
||||
|
||||
I_Socket *i_socket = nullptr;
|
||||
I_MainLoop *mainloop = nullptr;
|
||||
std::string ip_address;
|
||||
std::string address;
|
||||
int port;
|
||||
I_Socket::SocketType protocol = I_Socket::SocketType::UDP;
|
||||
I_MainLoop::RoutineID log_send_routine = -1;
|
||||
Maybe<I_Socket::socketFd> socket = genError("Not set yet");
|
||||
};
|
||||
@ -102,7 +117,7 @@ private:
|
||||
class CefStream : public Stream
|
||||
{
|
||||
public:
|
||||
CefStream(const std::string &_ip_address, int _port);
|
||||
CefStream(const std::string &_address, int _port, I_Socket::SocketType _protocol);
|
||||
~CefStream();
|
||||
|
||||
void sendLog(const Report &log) override;
|
||||
@ -111,8 +126,9 @@ private:
|
||||
void connect();
|
||||
|
||||
I_Socket *i_socket = nullptr;
|
||||
std::string ip_address;
|
||||
std::string address;
|
||||
int port;
|
||||
I_Socket::SocketType protocol = I_Socket::SocketType::UDP;
|
||||
Maybe<I_Socket::socketFd> socket = genError("Not set yet");
|
||||
};
|
||||
|
||||
|
@ -111,7 +111,11 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
addStream(ReportIS::StreamType type, const string &log_server_url) override
|
||||
addStream(
|
||||
ReportIS::StreamType type,
|
||||
const string &log_server_url,
|
||||
const string &_protocol
|
||||
) override
|
||||
{
|
||||
string log_type = TagAndEnumManagement::convertToString(type);
|
||||
if (streams_preperation.find(type) != streams_preperation.end()) {
|
||||
@ -124,8 +128,9 @@ public:
|
||||
string ip = log_server_url.substr(0, log_server_url.find(':'));
|
||||
string port = log_server_url.substr(log_server_url.find(':') + 1, log_server_url.length());
|
||||
int port_num = stoi(port);
|
||||
auto protocol = (_protocol == "TCP") ? I_Socket::SocketType::TCP : I_Socket::SocketType::UDP;
|
||||
|
||||
streams_preperation[type] = makeStream(type, ip, port_num);
|
||||
streams_preperation[type] = makeStream(type, ip, port_num, protocol);
|
||||
dbgInfo(D_REPORT)
|
||||
<< "Successfully added log stream. Stream type: "
|
||||
<< log_type
|
||||
@ -265,6 +270,7 @@ private:
|
||||
case StreamType::JSON_DEBUG: return make_shared<DebugStream>();
|
||||
case StreamType::JSON_FOG: return make_shared<FogStream>();
|
||||
case StreamType::JSON_LOG_FILE: return make_shared<LogFileStream>();
|
||||
case StreamType::JSON_K8S_SVC: return make_shared<K8sSvcStream>();
|
||||
case StreamType::SYSLOG: return nullptr;
|
||||
case StreamType::CEF: return nullptr;
|
||||
case StreamType::NONE: return nullptr;
|
||||
@ -275,12 +281,11 @@ private:
|
||||
}
|
||||
|
||||
shared_ptr<Stream>
|
||||
makeStream(StreamType type, const string &ip, int port)
|
||||
makeStream(StreamType type, const string &ip, int port, I_Socket::SocketType protocol)
|
||||
{
|
||||
switch (type) {
|
||||
case StreamType::SYSLOG:
|
||||
return make_shared<SyslogStream>(ip, port);
|
||||
case StreamType::CEF: return make_shared<CefStream>(ip, port);
|
||||
case StreamType::SYSLOG: return make_shared<SyslogStream>(ip, port, protocol);
|
||||
case StreamType::CEF: return make_shared<CefStream>(ip, port, protocol);
|
||||
default:
|
||||
dbgWarning(D_REPORT) << "Invalid stream type with url";
|
||||
return NULL;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mock/mock_encryptor.h"
|
||||
#include "mock/mock_agent_details.h"
|
||||
#include "metric/all_metric_event.h"
|
||||
#include "mock/mock_shell_cmd.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace testing;
|
||||
@ -33,6 +34,7 @@ class TestEnd {};
|
||||
|
||||
static bool should_fail = false;
|
||||
static bool should_load_file_stream = false;
|
||||
static bool should_load_k8s_stream = false;
|
||||
|
||||
class fakeConfig : Singleton::Consume<I_Logging>
|
||||
{
|
||||
@ -57,19 +59,45 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
load(cereal::JSONInputArchive &)
|
||||
load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
if (should_fail) throw cereal::Exception("Should fail load");
|
||||
if (should_load_file_stream) {
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_LOG_FILE);
|
||||
return;
|
||||
}
|
||||
if (should_load_k8s_stream) {
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_K8S_SVC);
|
||||
return;
|
||||
}
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_DEBUG);
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_FOG);
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::CEF, "1.3.3.0:123");
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::SYSLOG, "1.2.3.4:567");
|
||||
}
|
||||
|
||||
bool is_domain;
|
||||
ar(cereal::make_nvp("IsDomain", is_domain));
|
||||
if (is_domain) {
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
|
||||
ReportIS::StreamType::CEF,
|
||||
"www.youtube.com:123",
|
||||
"UDP"
|
||||
);
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
|
||||
ReportIS::StreamType::SYSLOG,
|
||||
"www.google.com:567",
|
||||
"UDP"
|
||||
);
|
||||
} else {
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
|
||||
ReportIS::StreamType::CEF,
|
||||
"1.3.3.0:123", "UDP"
|
||||
);
|
||||
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
|
||||
ReportIS::StreamType::SYSLOG,
|
||||
"1.2.3.4:567",
|
||||
"UDP"
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class LogTest : public testing::TestWithParam<bool>
|
||||
@ -81,8 +109,10 @@ public:
|
||||
i_agent_details(Singleton::Consume<I_AgentDetails>::from(agent_details)),
|
||||
logger(Singleton::Consume<I_Logging>::from(log_comp))
|
||||
{
|
||||
is_domain = false;
|
||||
should_fail = false;
|
||||
should_load_file_stream = false;
|
||||
should_load_k8s_stream = false;
|
||||
env.preload();
|
||||
log_comp.preload();
|
||||
env.init();
|
||||
@ -143,8 +173,10 @@ public:
|
||||
|
||||
~LogTest()
|
||||
{
|
||||
is_domain = false;
|
||||
should_fail = false;
|
||||
should_load_file_stream = false;
|
||||
should_load_k8s_stream = false;
|
||||
env.fini();
|
||||
log_comp.fini();
|
||||
Debug::setUnitTestFlag(D_REPORT, Debug::DebugLevel::INFO);
|
||||
@ -208,15 +240,23 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
loadFakeConfiguration(const bool &enable_bulk, const string &log_file_name = "", int bulks_size = -1)
|
||||
loadFakeConfiguration(
|
||||
bool enable_bulk,
|
||||
bool domain = false,
|
||||
const string &log_file_name = "",
|
||||
int bulks_size = -1)
|
||||
{
|
||||
string is_enable_bulks = enable_bulk ? "true" : "false";
|
||||
string is_domain = domain ? "true" : "false";
|
||||
fakeConfig::preload();
|
||||
output_filename = log_file_name == "" ? file.fname : log_file_name;
|
||||
|
||||
stringstream str_stream;
|
||||
str_stream
|
||||
<< "{\"fake config\": [{}], \"Logging\": {\"Log file name\": [{\"value\": \""
|
||||
<< "{\"fake config\": [{\"IsDomain\": "
|
||||
<< is_domain
|
||||
<< "}],"
|
||||
<< "\"Logging\": {\"Log file name\": [{\"value\": \""
|
||||
<< output_filename
|
||||
<< "\"}],"
|
||||
<< "\"Enable bulk of logs\": [{\"value\": "
|
||||
@ -247,6 +287,8 @@ public:
|
||||
ConfigComponent config;
|
||||
vector<string> capture_syslog_cef_data;
|
||||
I_MainLoop::Routine sysog_routine = nullptr;
|
||||
StrictMock<MockShellCmd> mock_shell_cmd;
|
||||
bool is_domain;
|
||||
|
||||
private:
|
||||
string body;
|
||||
@ -259,6 +301,16 @@ TEST_F(LogTest, load_policy)
|
||||
EXPECT_TRUE(loadFakeConfiguration(false));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, loadPolicyDomain)
|
||||
{
|
||||
is_domain = true;
|
||||
string result = "172.28.1.6";
|
||||
EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillRepeatedly(Return(result));
|
||||
EXPECT_TRUE(loadFakeConfiguration(false, true));
|
||||
string failed_str = "Failed to connect to the CEF server";
|
||||
EXPECT_THAT(getMessages(), Not(HasSubstr(failed_str)));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, loadPolicyFailure)
|
||||
{
|
||||
should_fail = true;
|
||||
@ -690,9 +742,117 @@ TEST_F(LogTest, FogBulkLogs)
|
||||
EXPECT_EQ(local_body, str1);
|
||||
}
|
||||
|
||||
TEST_F(LogTest, OfflineK8sSvcTest)
|
||||
{
|
||||
i_agent_details->setOrchestrationMode(OrchestrationMode::HYBRID);
|
||||
should_load_k8s_stream = true;
|
||||
loadFakeConfiguration(false);
|
||||
Tags tag1 = Tags::POLICY_INSTALLATION;
|
||||
Tags tag2 = Tags::ACCESS_CONTROL;
|
||||
string local_body;
|
||||
string res("[{\"id\": 1, \"code\": 400, \"message\": \"yes\"}]");
|
||||
EXPECT_CALL(
|
||||
mock_fog_msg,
|
||||
sendMessage(_, _, _, "open-appsec-tuning-svc", _, _, "/api/v1/agents/events", _, _, MessageTypeTag::LOG)
|
||||
).WillRepeatedly(DoAll(SaveArg<1>(&local_body), Return(res)));
|
||||
|
||||
string str1(
|
||||
"{\n"
|
||||
" \"log\": {\n"
|
||||
" \"eventTime\": \"0:0:0\",\n"
|
||||
" \"eventName\": \"Install policy\",\n"
|
||||
" \"eventSeverity\": \"Info\",\n"
|
||||
" \"eventPriority\": \"Low\",\n"
|
||||
" \"eventType\": \"Event Driven\",\n"
|
||||
" \"eventLevel\": \"Log\",\n"
|
||||
" \"eventLogLevel\": \"info\",\n"
|
||||
" \"eventAudience\": \"Internal\",\n"
|
||||
" \"eventAudienceTeam\": \"\",\n"
|
||||
" \"eventFrequency\": 0,\n"
|
||||
" \"eventTags\": [\n"
|
||||
" \"Access Control\",\n"
|
||||
" \"Policy Installation\"\n"
|
||||
" ],\n"
|
||||
" \"eventSource\": {\n"
|
||||
" \"agentId\": \"Unknown\",\n"
|
||||
" \"eventTraceId\": \"\",\n"
|
||||
" \"eventSpanId\": \"\",\n"
|
||||
" \"issuingEngineVersion\": \"\",\n"
|
||||
" \"serviceName\": \"Unnamed Nano Service\"\n"
|
||||
" },\n"
|
||||
" \"eventData\": {\n"
|
||||
" \"logIndex\": 1\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
LogGen("Install policy", Audience::INTERNAL, Severity::INFO, Priority::LOW, tag1, tag2);
|
||||
EXPECT_EQ(local_body, str1);
|
||||
}
|
||||
|
||||
TEST_F(LogTest, OfflineK8sSvcBulkLogs)
|
||||
{
|
||||
i_agent_details->setOrchestrationMode(OrchestrationMode::HYBRID);
|
||||
should_load_k8s_stream = true;
|
||||
loadFakeConfiguration(true);
|
||||
string local_body;
|
||||
string res("[{\"id\": 1, \"code\": 400, \"message\": \"yes\"}]");
|
||||
EXPECT_CALL(
|
||||
mock_fog_msg,
|
||||
sendMessage(_, _, _, "open-appsec-tuning-svc", _, _, "/api/v1/agents/events/bulk", _, _, MessageTypeTag::LOG)
|
||||
).WillRepeatedly(DoAll(SaveArg<1>(&local_body), Return(res)));
|
||||
|
||||
Tags tag1 = Tags::POLICY_INSTALLATION;
|
||||
Tags tag2 = Tags::ACCESS_CONTROL;
|
||||
|
||||
|
||||
string str1(
|
||||
"{\n"
|
||||
" \"logs\": [\n"
|
||||
" {\n"
|
||||
" \"id\": 1,\n"
|
||||
" \"log\": {\n"
|
||||
" \"eventTime\": \"0:0:0\",\n"
|
||||
" \"eventName\": \"Install policy\",\n"
|
||||
" \"eventSeverity\": \"Info\",\n"
|
||||
" \"eventPriority\": \"Low\",\n"
|
||||
" \"eventType\": \"Event Driven\",\n"
|
||||
" \"eventLevel\": \"Log\",\n"
|
||||
" \"eventLogLevel\": \"info\",\n"
|
||||
" \"eventAudience\": \"Internal\",\n"
|
||||
" \"eventAudienceTeam\": \"\",\n"
|
||||
" \"eventFrequency\": 0,\n"
|
||||
" \"eventTags\": [\n"
|
||||
" \"Access Control\",\n"
|
||||
" \"Policy Installation\"\n"
|
||||
" ],\n"
|
||||
" \"eventSource\": {\n"
|
||||
" \"agentId\": \"Unknown\",\n"
|
||||
" \"eventTraceId\": \"\",\n"
|
||||
" \"eventSpanId\": \"\",\n"
|
||||
" \"issuingEngineVersion\": \"\",\n"
|
||||
" \"serviceName\": \"Unnamed Nano Service\"\n"
|
||||
" },\n"
|
||||
" \"eventData\": {\n"
|
||||
" \"logIndex\": 1\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
"}"
|
||||
);
|
||||
{
|
||||
LogGen("Install policy", Audience::INTERNAL, Severity::INFO, Priority::LOW, tag1, tag2);
|
||||
}
|
||||
bulk_routine();
|
||||
|
||||
EXPECT_EQ(local_body, str1);
|
||||
}
|
||||
|
||||
TEST_P(LogTest, metrics_check)
|
||||
{
|
||||
loadFakeConfiguration(true, "", 3);
|
||||
loadFakeConfiguration(true, false, "", 3);
|
||||
Tags tag1 = Tags::POLICY_INSTALLATION;
|
||||
Tags tag2 = Tags::ACCESS_CONTROL;
|
||||
|
||||
@ -837,7 +997,7 @@ TEST_F(LogTest, ShouldRetryAfterFailedWriteToFile)
|
||||
EXPECT_TRUE(logger->delStream(ReportIS::StreamType::JSON_LOG_FILE));
|
||||
|
||||
static const string invalid_file_path = "/proc/gibberish";
|
||||
loadFakeConfiguration(false, invalid_file_path, -1);
|
||||
loadFakeConfiguration(false, false, invalid_file_path, -1);
|
||||
|
||||
LogGen(
|
||||
"Install policy",
|
||||
|
@ -11,6 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "log_streams.h"
|
||||
#include "logging_comp.h"
|
||||
|
||||
@ -18,12 +20,17 @@ using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_REPORT);
|
||||
|
||||
SyslogStream::SyslogStream(const string &_ip_address, int _port)
|
||||
static string lookup_cmd = "nslookup ";
|
||||
static string line_selection_cmd = "| grep Address | sed -n 2p";
|
||||
static string parsing_cmd = "| cut -f2 -d' ' | tr -d '\n'";
|
||||
|
||||
SyslogStream::SyslogStream(const string &_address, int _port, I_Socket::SocketType _protocol)
|
||||
:
|
||||
i_socket(Singleton::Consume<I_Socket>::by<LoggingComp>()),
|
||||
mainloop(Singleton::Consume<I_MainLoop>::by<LoggingComp>()),
|
||||
ip_address(_ip_address),
|
||||
port(_port)
|
||||
address(_address),
|
||||
port(_port),
|
||||
protocol(_protocol)
|
||||
{
|
||||
connect();
|
||||
if (!socket.ok()) {
|
||||
@ -43,21 +50,21 @@ SyslogStream::~SyslogStream()
|
||||
void
|
||||
SyslogStream::sendLog(const Report &log)
|
||||
{
|
||||
if (!socket.ok()) {
|
||||
connect();
|
||||
if (!socket.ok()) {
|
||||
dbgWarning(D_REPORT) << "Failed to connect to the syslog server, Log will not be sent.";
|
||||
return;
|
||||
}
|
||||
dbgTrace(D_REPORT) << "Successfully connect to the syslog server";
|
||||
}
|
||||
|
||||
string syslog_report = log.getSyslog();
|
||||
vector<char> data(syslog_report.begin(), syslog_report.end());
|
||||
mainloop->addOneTimeRoutine(
|
||||
I_MainLoop::RoutineType::Offline,
|
||||
[this, data] ()
|
||||
{
|
||||
if (!socket.ok()) {
|
||||
connect();
|
||||
if (!socket.ok()) {
|
||||
dbgWarning(D_REPORT) << "Failed to connect to the syslog server, Log will not be sent.";
|
||||
return;
|
||||
}
|
||||
dbgTrace(D_REPORT) << "Successfully connect to the syslog server";
|
||||
}
|
||||
|
||||
int tries = 1;
|
||||
for (; tries <=3; tries++) {
|
||||
if (i_socket->writeData(socket.unpack(), data)) {
|
||||
@ -75,18 +82,57 @@ SyslogStream::sendLog(const Report &log)
|
||||
void
|
||||
SyslogStream::connect()
|
||||
{
|
||||
auto syslog_ip_address = getProfileAgentSettingWithDefault<string>(ip_address, "agent.config.log.syslogServer.IP");
|
||||
auto syslog_address = getProfileAgentSettingWithDefault<string>(address, "agent.config.log.syslogServer.IP");
|
||||
auto syslog_port = getProfileAgentSettingWithDefault<uint>(port, "agent.config.log.syslogServer.port");
|
||||
|
||||
if (syslog_ip_address.empty()) {
|
||||
dbgWarning(D_REPORT) << "Cannot connect to Syslog server, IP is not configured.";
|
||||
if (syslog_address.empty()) {
|
||||
dbgWarning(D_REPORT) << "Cannot connect to Syslog server, Address IP/Domain not configured.";
|
||||
return;
|
||||
}
|
||||
|
||||
struct in_addr addr;
|
||||
if (inet_pton(AF_INET, syslog_address.data(), &addr) != 1) {
|
||||
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<LoggingComp>();
|
||||
string host_cmd = lookup_cmd + syslog_address + line_selection_cmd + parsing_cmd;
|
||||
Maybe<string> res = shell_cmd->getExecOutput(host_cmd, 500);
|
||||
if (!res.ok()) {
|
||||
dbgWarning(D_REPORT)
|
||||
<< "Failed to execute domain lookup command. "
|
||||
<< "SYSLOG Domain: "
|
||||
<< syslog_address
|
||||
<< "Error: "
|
||||
<< res.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.unpack().empty()) {
|
||||
dbgWarning(D_REPORT)
|
||||
<< "Got en empty ip address from lookup command. "
|
||||
<< "SYSLOG Domain: "
|
||||
<< syslog_address
|
||||
<< "Got bad ip address: "
|
||||
<< res.unpack();
|
||||
return;
|
||||
}
|
||||
|
||||
dbgDebug(D_REPORT) << "SYSLOG Domain lookup result: " << res.unpack();
|
||||
if (inet_pton(AF_INET, res.unpack().data(), &addr) != 1) {
|
||||
dbgWarning(D_REPORT)
|
||||
<< "Got a faulty ip address from lookup command. "
|
||||
<< "SYSLOG Domain: "
|
||||
<< syslog_address
|
||||
<< "Got bad ip address: "
|
||||
<< res.unpack();
|
||||
return;
|
||||
}
|
||||
|
||||
syslog_address = res.unpack();
|
||||
}
|
||||
|
||||
socket = i_socket->genSocket(
|
||||
I_Socket::SocketType::UDP,
|
||||
protocol,
|
||||
false,
|
||||
false,
|
||||
syslog_ip_address + ":" + to_string(syslog_port)
|
||||
syslog_address + ":" + to_string(syslog_port)
|
||||
);
|
||||
}
|
||||
|
@ -98,7 +98,8 @@ TagAndEnumManagement::convertStringToTag(const string &tag)
|
||||
{"Reverse Proxy", ReportIS::Tags::REVERSE_PROXY},
|
||||
{"Http Geo Filter", ReportIS::Tags::HTTP_GEO_FILTER},
|
||||
{"File Upload", ReportIS::Tags::FILE_UPLOAD},
|
||||
{"Identity Awareness", ReportIS::Tags::IDENTITY_AWARENESS}
|
||||
{"Identity Awareness", ReportIS::Tags::IDENTITY_AWARENESS},
|
||||
{"Rate Limit", ReportIS::Tags::RATE_LIMIT}
|
||||
};
|
||||
|
||||
auto report_is_tag = strings_to_tags.find(tag);
|
||||
@ -135,6 +136,7 @@ TagAndEnumManagement::convertToString(const StreamType &stream_type)
|
||||
case StreamType::JSON_DEBUG: return "JSON Debug stream";
|
||||
case StreamType::JSON_FOG: return "JSON FOG stream";
|
||||
case StreamType::JSON_LOG_FILE: return "JSON File stream";
|
||||
case StreamType::JSON_K8S_SVC: return "JSON K8S service stream";
|
||||
case StreamType::SYSLOG: return "Syslog stream";
|
||||
case StreamType::CEF: return "CEF stream";
|
||||
|
||||
@ -307,7 +309,8 @@ EnumArray<Tags, string> TagAndEnumManagement::tags_translation_arr {
|
||||
"Reverse Proxy",
|
||||
"Http Geo Filter",
|
||||
"File Upload",
|
||||
"Identity Awareness"
|
||||
"Identity Awareness",
|
||||
"Rate Limit"
|
||||
};
|
||||
|
||||
EnumArray<AudienceTeam, string> TagAndEnumManagement::audience_team_translation {
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
|
||||
chrono::microseconds getTimeoutVal() const override;
|
||||
|
||||
string getProfileId(const string &tenant_id, const string ®ion) const override;
|
||||
|
||||
void
|
||||
addInstance(const string &tenant_id, const string &profile_id, const string &instace_id)
|
||||
{
|
||||
@ -183,7 +185,7 @@ TenantManager::Impl::init()
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<TenantManager>();
|
||||
rest->addRestCall<LoadNewTenants>(RestAction::SET, "tenant-id");
|
||||
rest->addRestCall<FetchActiveTenants>(RestAction::SHOW, "active-tenants");
|
||||
rest->addRestCall<FetchActiveTenants>(RestAction::SHOW, "profile-ids");
|
||||
rest->addRestCall<FetchProfileIds>(RestAction::SHOW, "profile-ids");
|
||||
}
|
||||
|
||||
if (type == TenantManagerType::CLIENT) {
|
||||
@ -307,14 +309,14 @@ TenantManager::Impl::getAllTenants() const
|
||||
}
|
||||
|
||||
vector<string>
|
||||
TenantManager::Impl::getProfileIds(const string &tenant_id) const
|
||||
TenantManager::Impl::getProfileIds(const string &_tenant_id) const
|
||||
{
|
||||
dbgFlow(D_TENANT_MANAGER) << "Tenant Manager is a client. Requesting the active tenants";
|
||||
dbgFlow(D_TENANT_MANAGER) << "Tenant Manager is a client. Requesting the active profiles";
|
||||
|
||||
GetProfileIds profile_id(tenant_id);
|
||||
GetProfileIds tenant_id(_tenant_id);
|
||||
|
||||
auto res = i_messaging->sendObject(
|
||||
profile_id,
|
||||
tenant_id,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
7777,
|
||||
@ -324,7 +326,7 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const
|
||||
|
||||
if (!res) {
|
||||
i_messaging->sendObject(
|
||||
profile_id,
|
||||
tenant_id,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
7778,
|
||||
@ -333,7 +335,53 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const
|
||||
);
|
||||
}
|
||||
|
||||
return profile_id.profile_ids.get();
|
||||
return tenant_id.profile_ids.get();
|
||||
}
|
||||
|
||||
string
|
||||
TenantManager::Impl::getProfileId(const string &tenant_id, const string ®ion) const
|
||||
{
|
||||
if (region.empty()) {
|
||||
dbgWarning(D_TENANT_MANAGER) << "Can't find the profile ID. Region is empty";
|
||||
return "";
|
||||
}
|
||||
|
||||
vector<string> profile_ids = fetchProfileIds(tenant_id);
|
||||
|
||||
dbgTrace(D_TENANT_MANAGER) << "Fetched " << profile_ids.size() << " profiles";
|
||||
|
||||
auto i_env = Singleton::Consume<I_Environment>::by<TenantManager>();
|
||||
auto unset_tenant_on_exit = make_scope_exit([&]() { i_env->unsetActiveTenantAndProfile(); });
|
||||
for (const string &profile_id : profile_ids) {
|
||||
dbgDebug(D_TENANT_MANAGER)
|
||||
<< "Checking if the profile ID: "
|
||||
<< profile_id
|
||||
<< " corresponds to the tenant ID: "
|
||||
<< tenant_id
|
||||
<< " and the region "
|
||||
<< region;
|
||||
|
||||
i_env->setActiveTenantAndProfile(tenant_id, profile_id);
|
||||
|
||||
auto maybe_region = getSetting<string>("region");
|
||||
if (maybe_region.ok() && region == maybe_region.unpack()) {
|
||||
dbgDebug(D_TENANT_MANAGER) << "The region corresponds to profile ID " << profile_id;
|
||||
return profile_id;
|
||||
} else {
|
||||
if (maybe_region.ok()) {
|
||||
dbgTrace(D_TENANT_MANAGER)
|
||||
<< "The region does not corresponds to profile ID "
|
||||
<< profile_id
|
||||
<< " region "
|
||||
<< *maybe_region;
|
||||
} else {
|
||||
dbgDebug(D_TENANT_MANAGER) << "Failed to get region for profile ID " << profile_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbgWarning(D_TENANT_MANAGER) << "Found no profile ID for tenant " << tenant_id << " and region " << region;
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
@ -351,7 +399,16 @@ TenantManager::Impl::areTenantAndProfileActive(const string &tenant_id, const st
|
||||
void
|
||||
TenantManager::Impl::addActiveTenantAndProfile(const string &tenant_id, const string &profile_id)
|
||||
{
|
||||
if (tenant_id.empty() || profile_id.empty()) {
|
||||
dbgWarning(D_TENANT_MANAGER) << "Tenant ID and Profile ID should not be empty.";
|
||||
return;
|
||||
}
|
||||
auto tenant_profile = TenantProfilePair(tenant_id, profile_id);
|
||||
dbgTrace(D_TENANT_MANAGER)
|
||||
<< "Adding an active tenant and profile. Tenant ID: "
|
||||
<< tenant_id
|
||||
<< ", Profile ID: "
|
||||
<< profile_id;
|
||||
active_tenants.createEntry(tenant_profile);
|
||||
if (type == TenantManagerType::CLIENT) {
|
||||
sendTenantAndProfile(tenant_id, profile_id);
|
||||
@ -410,7 +467,8 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const
|
||||
|
||||
for (auto iter = begin(active_tenants); iter != end(active_tenants); iter++) {
|
||||
if (iter->first.getTenantId() == tenant_id) {
|
||||
tenant_profile_ids.push_back(iter->first.getPfofileId());
|
||||
dbgTrace(D_TENANT_MANAGER) << "Returning a fetched profile ID: " << iter->first.getProfileId();
|
||||
tenant_profile_ids.push_back(iter->first.getProfileId());
|
||||
}
|
||||
}
|
||||
return tenant_profile_ids;
|
||||
@ -419,7 +477,7 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const
|
||||
vector<string>
|
||||
TenantManager::Impl::fetchProfileIds(const string &tenant_id) const
|
||||
{
|
||||
dbgFlow(D_TENANT_MANAGER) << "Fetching all profile ids for tenant " << tenant_id;
|
||||
dbgFlow(D_TENANT_MANAGER) << "Fetching all profile IDs for tenant " << tenant_id;
|
||||
return (type == TenantManagerType::CLIENT) ? getProfileIds(tenant_id) : fetchAllProfileIds(tenant_id);
|
||||
}
|
||||
|
||||
@ -462,4 +520,5 @@ TenantManager::preload()
|
||||
{
|
||||
registerExpectedConfiguration<uint32_t>("Tenant Manager", "Tenant timeout");
|
||||
registerExpectedConfiguration<string>("Tenant Manager", "Tenant manager type");
|
||||
registerExpectedSetting<string>("region");
|
||||
}
|
||||
|
1
external/CMakeLists.txt
vendored
1
external/CMakeLists.txt
vendored
@ -1,2 +1,3 @@
|
||||
add_subdirectory(graphqlparser)
|
||||
add_subdirectory(yajl)
|
||||
add_subdirectory(yq)
|
||||
|
326
external/graphqlparser/.clang-tidy
vendored
Normal file
326
external/graphqlparser/.clang-tidy
vendored
Normal file
@ -0,0 +1,326 @@
|
||||
---
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,cppcoreguidelines*,modernize*,performance*,readability*,google*,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-readability-implicit-bool*,-cppcoreguidelines-pro-bounds-array-to-pointer-decay'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
CheckOptions:
|
||||
- key: cert-oop11-cpp.UseCERTSemantics
|
||||
value: '1'
|
||||
- key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
|
||||
value: ''
|
||||
- key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
|
||||
value: '0'
|
||||
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
|
||||
value: '0'
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||
value: '10'
|
||||
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||
value: '2'
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: '16'
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-auto.RemoveStars
|
||||
value: '0'
|
||||
- key: modernize-use-emplace.ContainersWithPushBack
|
||||
value: '::std::vector;::std::list;::std::deque'
|
||||
- key: modernize-use-emplace.SmartPointers
|
||||
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: 'NULL'
|
||||
- key: performance-faster-string-find.StringLikeClasses
|
||||
value: 'std::basic_string'
|
||||
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
||||
value: '0'
|
||||
- key: performance-unnecessary-value-param.IncludeStyle
|
||||
value: llvm
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: '0'
|
||||
- key: readability-function-size.BranchThreshold
|
||||
value: '4294967295'
|
||||
- key: readability-function-size.LineThreshold
|
||||
value: '4294967295'
|
||||
- key: readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: readability-identifier-naming.AbstractClassCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.AbstractClassPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.AbstractClassSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ClassConstantCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ClassConstantPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassConstantSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassMemberCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ClassMemberPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassMemberSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassMethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ClassMethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassMethodSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ClassSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstantCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ConstantMemberCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ConstantMemberPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstantMemberSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstantParameterCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ConstantParameterPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstantParameterSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstantPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstantSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstexprFunctionCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ConstexprFunctionPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstexprFunctionSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstexprMethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ConstexprMethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstexprMethodSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstexprVariableCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ConstexprVariablePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ConstexprVariableSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.EnumCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.EnumConstantCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.EnumConstantPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.EnumConstantSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.EnumPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.EnumSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.FunctionPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.FunctionSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.GlobalConstantCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.GlobalConstantPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.GlobalConstantSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.GlobalFunctionCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.GlobalFunctionPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.GlobalFunctionSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.GlobalVariableCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.GlobalVariablePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.GlobalVariableSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.IgnoreFailedSplit
|
||||
value: '0'
|
||||
- key: readability-identifier-naming.InlineNamespaceCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.InlineNamespacePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.InlineNamespaceSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.LocalConstantCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.LocalConstantPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.LocalConstantSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.LocalVariableCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.LocalVariablePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.LocalVariableSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.MacroDefinitionCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.MacroDefinitionPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.MacroDefinitionSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.MemberCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.MemberPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.MemberSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.MethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.MethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.MethodSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.NamespaceCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.NamespacePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.NamespaceSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ParameterCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ParameterPackCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ParameterPackPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ParameterPackSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ParameterPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ParameterSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PrivateMemberCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.PrivateMemberPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PrivateMemberSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PrivateMethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.PrivateMethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PrivateMethodSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ProtectedMemberCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ProtectedMemberPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ProtectedMemberSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ProtectedMethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ProtectedMethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ProtectedMethodSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PublicMemberCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.PublicMemberPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PublicMemberSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PublicMethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.PublicMethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.PublicMethodSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.StaticConstantCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.StaticConstantPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.StaticConstantSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.StaticVariableCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.StaticVariablePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.StaticVariableSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.StructCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.StructPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.StructSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TemplateParameterCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.TemplateParameterPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TemplateParameterSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TemplateTemplateParameterCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.TemplateTemplateParameterPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TemplateTemplateParameterSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TypeAliasCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.TypeAliasPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TypeAliasSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TypeTemplateParameterCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.TypeTemplateParameterPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TypeTemplateParameterSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TypedefCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.TypedefPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.TypedefSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.UnionCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.UnionPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.UnionSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ValueTemplateParameterCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.ValueTemplateParameterPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.ValueTemplateParameterSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.VariableCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.VariablePrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.VariableSuffix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.VirtualMethodCase
|
||||
value: aNy_CasE
|
||||
- key: readability-identifier-naming.VirtualMethodPrefix
|
||||
value: ''
|
||||
- key: readability-identifier-naming.VirtualMethodSuffix
|
||||
value: ''
|
||||
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
|
||||
value: '0'
|
||||
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
|
||||
value: '0'
|
||||
...
|
||||
|
23
external/graphqlparser/.gitignore
vendored
Normal file
23
external/graphqlparser/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
bison.tab.cpp
|
||||
bison.tab.hpp
|
||||
*.o
|
||||
parser.output
|
||||
dump_json_ast
|
||||
Ast.h
|
||||
Ast.cpp
|
||||
AstVisitor.h
|
||||
*.dSYM
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
*.a
|
||||
*.dylib
|
||||
*.so
|
||||
GraphQLParser.py
|
||||
install_manifest.txt
|
||||
build/
|
||||
libgraphqlparser.pc
|
||||
JsonVisitor.cpp.inc
|
||||
JsonVisitor.h.inc
|
21
external/graphqlparser/.travis.yml
vendored
Normal file
21
external/graphqlparser/.travis.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
language: cpp
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- valgrind
|
||||
|
||||
before_install:
|
||||
# Versions of g++ prior to 4.8 don't have very good C++11 support.
|
||||
- wget https://codeload.github.com/google/googletest/zip/release-1.8.0
|
||||
&& cd test
|
||||
&& unzip ../release-1.8.0
|
||||
&& cd ..
|
||||
&& rm release-1.8.0
|
||||
|
||||
script: mkdir build && cd build && cmake .. -Dtest=ON -DCMAKE_BUILD_TYPE=Debug && make && test/runTests && make memcheck
|
36
external/graphqlparser/AstNode.h
vendored
Normal file
36
external/graphqlparser/AstNode.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2019-present, GraphQL Foundation
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "location.hh"
|
||||
|
||||
namespace facebook {
|
||||
namespace graphql {
|
||||
namespace ast {
|
||||
|
||||
namespace visitor {
|
||||
class AstVisitor;
|
||||
}
|
||||
|
||||
class Node {
|
||||
yy::location location_;
|
||||
public:
|
||||
explicit Node(const yy::location &location)
|
||||
: location_(location) {}
|
||||
|
||||
virtual ~Node() {}
|
||||
|
||||
const yy::location &getLocation() const
|
||||
{ return location_; }
|
||||
|
||||
virtual void accept(visitor::AstVisitor *visitor) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
148
external/graphqlparser/CMakeLists.txt
vendored
Normal file
148
external/graphqlparser/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
PROJECT(libgraphqlparser C CXX)
|
||||
|
||||
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}")
|
||||
|
||||
INCLUDE(version)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
|
||||
|
||||
FIND_PACKAGE(PythonInterp 2 REQUIRED)
|
||||
IF (NOT PYTHON_VERSION_MAJOR EQUAL 2)
|
||||
MESSAGE(FATAL_ERROR "Python 2 is required.")
|
||||
ENDIF()
|
||||
|
||||
FIND_PROGRAM(CTYPESGEN_FOUND ctypesgen.py)
|
||||
|
||||
FIND_PACKAGE(BISON 3)
|
||||
FIND_PACKAGE(FLEX)
|
||||
IF (BISON_FOUND)
|
||||
BISON_TARGET(graphqlparser_bison parser.ypp ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.cpp)
|
||||
SET(BISON_LOCATION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/location.hh)
|
||||
ELSE()
|
||||
SET(BISON_graphqlparser_bison_OUTPUT_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.cpp)
|
||||
SET(BISON_graphqlparser_bison_OUTPUT_HEADER ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.hpp)
|
||||
SET(BISON_graphqlparser_bison_OUTPUTS
|
||||
${BISON_graphqlparser_bison_OUTPUT_SOURCE}
|
||||
${BISON_graphqlparser_bison_OUTPUT_HEADER}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/location.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/position.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/stack.hh)
|
||||
SET(BISON_LOCATION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/location.hh)
|
||||
FILE(COPY
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/parser.tab.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/parser.tab.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/location.hh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/position.hh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/stack.hh
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
ENDIF()
|
||||
|
||||
IF(FLEX_FOUND)
|
||||
FLEX_TARGET(GraphQLScanner lexer.lpp ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp COMPILE_FLAGS "--header-file=${CMAKE_CURRENT_BINARY_DIR}/lexer.h")
|
||||
IF (BISON_FOUND)
|
||||
ADD_FLEX_BISON_DEPENDENCY(GraphQLScanner graphqlparser_bison)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET(FLEX_GraphQLScanner_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)
|
||||
FILE(COPY
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/lexer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parsergen/lexer.h
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
ENDIF()
|
||||
|
||||
FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/c)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
ADD_LIBRARY(graphqlparser
|
||||
JsonVisitor.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Ast.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Ast.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/AstVisitor.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/c/GraphQLAst.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/c/GraphQLAst.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/c/GraphQLAstForEachConcreteType.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/JsonVisitor.h.inc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/JsonVisitor.cpp.inc
|
||||
${BISON_graphqlparser_bison_OUTPUTS}
|
||||
${FLEX_GraphQLScanner_OUTPUTS}
|
||||
c/GraphQLAstNode.cpp
|
||||
c/GraphQLAstToJSON.cpp
|
||||
c/GraphQLAstVisitor.h
|
||||
c/GraphQLAstVisitor.cpp
|
||||
c/GraphQLParser.cpp
|
||||
GraphQLParser.cpp)
|
||||
|
||||
# Enable this and remove CMAKE_CXX_FLAGS fiddle above when we are able
|
||||
# to upgrade to CMake 2.8.12. Blocker seems to be Travis CI being on
|
||||
# Ubuntu Precise; Trusty has 2.8.12.
|
||||
# TARGET_COMPILE_OPTIONS(graphqlparser PUBLIC -std=gnu++11)
|
||||
|
||||
ADD_EXECUTABLE(dump_json_ast dump_json_ast.cpp)
|
||||
TARGET_LINK_LIBRARIES(dump_json_ast graphqlparser)
|
||||
|
||||
FUNCTION(GENERATE_AST_FILE FILE_TYPE FILE_RELATIVE_PATH)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${FILE_RELATIVE_PATH}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.py ${FILE_TYPE} ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.ast > ${CMAKE_CURRENT_BINARY_DIR}/${FILE_RELATIVE_PATH}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.ast ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.py ${CMAKE_CURRENT_SOURCE_DIR}/ast/${FILE_TYPE}.py)
|
||||
ENDFUNCTION(GENERATE_AST_FILE)
|
||||
|
||||
GENERATE_AST_FILE(cxx Ast.h)
|
||||
|
||||
GENERATE_AST_FILE(cxx_visitor AstVisitor.h)
|
||||
|
||||
GENERATE_AST_FILE(cxx_impl Ast.cpp)
|
||||
|
||||
GENERATE_AST_FILE(c c/GraphQLAst.h)
|
||||
|
||||
GENERATE_AST_FILE(c_impl c/GraphQLAst.cpp)
|
||||
|
||||
GENERATE_AST_FILE(c_visitor_impl c/GraphQLAstForEachConcreteType.h)
|
||||
|
||||
GENERATE_AST_FILE(cxx_json_visitor_header JsonVisitor.h.inc)
|
||||
|
||||
GENERATE_AST_FILE(cxx_json_visitor_impl JsonVisitor.cpp.inc)
|
||||
|
||||
ADD_SUBDIRECTORY(python)
|
||||
|
||||
OPTION(test "Build tests." OFF)
|
||||
|
||||
INSTALL(DIRECTORY c ${CMAKE_CURRENT_BINARY_DIR}/c DESTINATION include/graphqlparser
|
||||
FILES_MATCHING PATTERN "*.h"
|
||||
PATTERN "build" EXCLUDE)
|
||||
|
||||
INSTALL(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Ast.h
|
||||
AstNode.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/AstVisitor.h
|
||||
GraphQLParser.h
|
||||
JsonVisitor.h
|
||||
${BISON_LOCATION_HEADER}
|
||||
DESTINATION include/graphqlparser)
|
||||
INSTALL(TARGETS graphqlparser
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
if (UNIX)
|
||||
# generate pkgconfig file
|
||||
include(FindPkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
# generate .pc and install
|
||||
configure_file("libgraphqlparser.pc.in" "libgraphqlparser.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libgraphqlparser.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
IF (test)
|
||||
ADD_SUBDIRECTORY(test)
|
||||
|
||||
if(UNIX)
|
||||
# setup valgrind
|
||||
ADD_CUSTOM_TARGET(memcheck
|
||||
valgrind --leak-check=full --suppressions=./test/valgrind.supp --dsymutil=yes --error-exitcode=1 ./test/runTests >/dev/null
|
||||
)
|
||||
endif()
|
||||
|
||||
ENDIF()
|
23
external/graphqlparser/CONTRIBUTING.md
vendored
Normal file
23
external/graphqlparser/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# Contributing to libgraphqlparser
|
||||
|
||||
Please see the Code of Conduct featured at https://github.com/graphql/foundation
|
||||
|
||||
## Pull Requests
|
||||
We actively welcome your pull requests.
|
||||
|
||||
1. Fork the repo and create your branch from `master`.
|
||||
2. If you've added code that should be tested, add tests
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes.
|
||||
5. Make sure your code lints.
|
||||
|
||||
## Issues
|
||||
We use GitHub issues to track public bugs. Please ensure your description is
|
||||
clear and has sufficient instructions to be able to reproduce the issue.
|
||||
|
||||
If you find a security bug, please contact the project administrators,
|
||||
and do not file a public issue.
|
||||
|
||||
## License
|
||||
By contributing to libgraphqlparser, you agree that your contributions
|
||||
will be licensed under the LICENSE file in the project root directory.
|
76
external/graphqlparser/GraphQLParser.cpp
vendored
Normal file
76
external/graphqlparser/GraphQLParser.cpp
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright 2019-present, GraphQL Foundation
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "GraphQLParser.h"
|
||||
|
||||
#include "AstNode.h"
|
||||
|
||||
#include "parser.tab.hpp"
|
||||
#include "lexer.h"
|
||||
#include "syntaxdefs.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace graphql {
|
||||
|
||||
// Given properly-configured yylex, run the parser and return the
|
||||
// result.
|
||||
static std::unique_ptr<ast::Node> doParse(const char **outError, yyscan_t scanner, bool enableSchema) {
|
||||
Node *outAST = nullptr;
|
||||
yy::GraphQLParserImpl parser(enableSchema, &outAST, outError, scanner);
|
||||
int failure = parser.parse();
|
||||
if (failure) {
|
||||
delete outAST;
|
||||
}
|
||||
return !failure ? std::unique_ptr<ast::Node>(outAST) : nullptr;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ast::Node> parseStringImpl(const char *text, const char **error, bool enableSchema) {
|
||||
yyscan_t scanner;
|
||||
struct LexerExtra extra;
|
||||
yylex_init_extra(&extra, &scanner);
|
||||
YY_BUFFER_STATE buffer = yy_scan_string(text, scanner);
|
||||
yy_switch_to_buffer(buffer, scanner);
|
||||
|
||||
auto result = doParse(error, scanner, enableSchema);
|
||||
yylex_destroy(scanner);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<ast::Node> parseString(const char *text, const char **error) {
|
||||
return parseStringImpl(text, error, false);
|
||||
}
|
||||
|
||||
std::unique_ptr<ast::Node> parseStringWithExperimentalSchemaSupport(
|
||||
const char *text, const char **error) {
|
||||
return parseStringImpl(text, error, true);
|
||||
}
|
||||
|
||||
static std::unique_ptr<ast::Node> parseFileImpl(
|
||||
FILE *file, const char **error, bool enableSchema) {
|
||||
yyscan_t scanner;
|
||||
struct LexerExtra extra;
|
||||
yylex_init_extra(&extra, &scanner);
|
||||
yyset_in(file, scanner);
|
||||
|
||||
auto result = doParse(error, scanner, enableSchema);
|
||||
yylex_destroy(scanner);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<ast::Node> parseFile(FILE *file, const char **error) {
|
||||
return parseFileImpl(file, error, false);
|
||||
}
|
||||
|
||||
std::unique_ptr<ast::Node> parseFileWithExperimentalSchemaSupport(
|
||||
FILE *file, const char **error) {
|
||||
return parseFileImpl(file, error, true);
|
||||
}
|
||||
|
||||
|
||||
} // namespace graphql
|
||||
} // namespace facebook
|
55
external/graphqlparser/GraphQLParser.h
vendored
Normal file
55
external/graphqlparser/GraphQLParser.h
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright 2019-present, GraphQL Foundation
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The purpose of this file is to provide a nice interface to parsing
|
||||
* GraphQL, rather than the old-fashioned interface provided by bison
|
||||
* and flex.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace graphql {
|
||||
|
||||
namespace ast {
|
||||
class Node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given GraphQL source string, returning an AST. Returns
|
||||
* nullptr on error and, if error is not null, places a string
|
||||
* describing what went wrong in error that must be freed with free(3).
|
||||
*/
|
||||
std::unique_ptr<ast::Node> parseString(const char *text, const char **error);
|
||||
|
||||
/**
|
||||
* Like parseString, but enables support for the experimental type
|
||||
* definition syntax from https://github.com/facebook/graphql/pull/90 .
|
||||
*/
|
||||
std::unique_ptr<ast::Node> parseStringWithExperimentalSchemaSupport(
|
||||
const char *text, const char **error);
|
||||
|
||||
/**
|
||||
* Read and parse GraphQL source from the given file, returning an
|
||||
* AST. Returns nullptr on error and, if error is not null, places an
|
||||
* error string in error that must be freed with free(3).
|
||||
*/
|
||||
std::unique_ptr<ast::Node> parseFile(FILE *file, const char **error);
|
||||
|
||||
/**
|
||||
* Like parseFile, but enables support for the experimental type
|
||||
* definition syntax from https://github.com/facebook/graphql/pull/90 .
|
||||
*/
|
||||
std::unique_ptr<ast::Node> parseFileWithExperimentalSchemaSupport(
|
||||
FILE *file, const char **error);
|
||||
|
||||
}
|
||||
}
|
161
external/graphqlparser/JsonVisitor.cpp
vendored
Normal file
161
external/graphqlparser/JsonVisitor.cpp
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Copyright 2019-present, GraphQL Foundation
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "position.hh"
|
||||
#include "JsonVisitor.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
namespace facebook {
|
||||
namespace graphql {
|
||||
namespace ast {
|
||||
namespace visitor {
|
||||
|
||||
static std::string escape(const char *s) {
|
||||
static char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
std::string result;
|
||||
while (unsigned char ch = *s++) {
|
||||
if (ch >= '\0' && ch <= '\x1f') {
|
||||
result.push_back('\\');
|
||||
result.push_back('u');
|
||||
result.push_back('0');
|
||||
result.push_back('0');
|
||||
result.push_back(ch >= 16 ? '1' : '0');
|
||||
result.push_back(hex[ch % 16]);
|
||||
} else if (ch == '"') {
|
||||
result.push_back('\\');
|
||||
result.push_back('"');
|
||||
} else if (ch == '\\') {
|
||||
result.push_back('\\');
|
||||
result.push_back('\\');
|
||||
} else {
|
||||
result.push_back(ch);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JsonVisitor::NodeFieldPrinter::NodeFieldPrinter(
|
||||
JsonVisitor &visitor,
|
||||
const char *nodeKind,
|
||||
const Node &node)
|
||||
: visitor_(visitor)
|
||||
{
|
||||
if (!visitor_.printed_.empty()) {
|
||||
nextChild_ = visitor_.printed_.back().begin();
|
||||
}
|
||||
// NOTE: If you're an Emacs user and this file's use of C++11 raw
|
||||
// strings doesn't highlight correctly in c++-mode, try upgrading to
|
||||
// Emacs 26 if you can.
|
||||
out_ << R"({"kind":")" << nodeKind << R"(","loc":)";
|
||||
printLocation(out_, node.getLocation());
|
||||
}
|
||||
|
||||
std::string JsonVisitor::NodeFieldPrinter::finishPrinting() {
|
||||
assert(!out_.str().empty());
|
||||
out_ << '}';
|
||||
auto result(out_.str());
|
||||
#ifndef NDEBUG
|
||||
out_.str("");
|
||||
#endif
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void JsonVisitor::NodeFieldPrinter::printFieldSeparator()
|
||||
{
|
||||
out_ << ',';
|
||||
}
|
||||
|
||||
void JsonVisitor::NodeFieldPrinter::printSingularPrimitiveField(
|
||||
const char *fieldName,
|
||||
const char *value) {
|
||||
printFieldSeparator();
|
||||
out_ << '"' << fieldName << R"(":)";
|
||||
out_ << '"' << escape(value) << '"';
|
||||
}
|
||||
|
||||
void JsonVisitor::NodeFieldPrinter::printSingularBooleanField(
|
||||
const char *fieldName,
|
||||
bool value) {
|
||||
printFieldSeparator();
|
||||
out_ << '"' << fieldName << R"(":)";
|
||||
out_ << (value ? "true" : "false");
|
||||
}
|
||||
|
||||
void JsonVisitor::NodeFieldPrinter::printSingularObjectField(const char *fieldName) {
|
||||
printFieldSeparator();
|
||||
out_ << '"' << fieldName << R"(":)";
|
||||
assert(!visitor_.printed_.empty());
|
||||
out_ << *nextChild_++;
|
||||
}
|
||||
|
||||
void JsonVisitor::NodeFieldPrinter::printNullableSingularObjectField(
|
||||
const char *fieldName,
|
||||
const void *value) {
|
||||
printFieldSeparator();
|
||||
out_ << '"' << fieldName << R"(":)";
|
||||
if (value != nullptr) {
|
||||
assert(!visitor_.printed_.empty());
|
||||
out_ << *nextChild_++;
|
||||
} else {
|
||||
out_ << "null";
|
||||
}
|
||||
}
|
||||
|
||||
// Method invariant: printed_ contains strings for this node's children.
|
||||
void JsonVisitor::NodeFieldPrinter::printLocation(
|
||||
std::ostringstream &out,
|
||||
const yy::location &location)
|
||||
{
|
||||
out << R"({"start": {"line": )" << location.begin.line
|
||||
<< R"(,"column":)" << location.begin.column
|
||||
<< R"(}, "end": {"line":)" << location.end.line
|
||||
<< R"(,"column":)" << location.end.column
|
||||
<< "}}";
|
||||
}
|
||||
|
||||
void JsonVisitor::NodeFieldPrinter::printChildList(
|
||||
std::ostringstream &out,
|
||||
const std::vector<std::string>::const_iterator &childIterator,
|
||||
size_t numChildren) {
|
||||
out << '[';
|
||||
for (size_t ii = 0; ii < numChildren; ++ii) {
|
||||
if (ii != 0) {
|
||||
out << ',';
|
||||
}
|
||||
out << *(childIterator + ii);
|
||||
}
|
||||
out << ']';
|
||||
}
|
||||
|
||||
JsonVisitor::JsonVisitor() {
|
||||
printed_.emplace_back();
|
||||
}
|
||||
|
||||
void JsonVisitor::visitNode() {
|
||||
printed_.emplace_back();
|
||||
}
|
||||
|
||||
void JsonVisitor::endVisitNode(std::string &&str) {
|
||||
printed_.pop_back();
|
||||
printed_.back().emplace_back(std::move(str));
|
||||
}
|
||||
|
||||
std::string JsonVisitor::getResult() const {
|
||||
assert(printed_.size() == 1);
|
||||
assert(printed_[0].size() == 1);
|
||||
return printed_[0][0];
|
||||
}
|
||||
|
||||
#include "JsonVisitor.cpp.inc"
|
||||
|
||||
} // namespace visitor
|
||||
} // namespace ast
|
||||
} // namespace graphql
|
||||
} // namespace facebook
|
121
external/graphqlparser/JsonVisitor.h
vendored
Normal file
121
external/graphqlparser/JsonVisitor.h
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright 2019-present, GraphQL Foundation
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AstNode.h"
|
||||
#include "AstVisitor.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace facebook {
|
||||
namespace graphql {
|
||||
namespace ast {
|
||||
namespace visitor {
|
||||
|
||||
/**
|
||||
* Produces a JSON string describing the visited AST, in a format that
|
||||
* would be a valid graphql-js AST when parsed.
|
||||
*/
|
||||
class JsonVisitor : public AstVisitor {
|
||||
private:
|
||||
using ChildrenList = std::vector<std::string>;
|
||||
// Stack of lists of printed children.
|
||||
// Postvisit method precondition: printed.back() contains strings
|
||||
// for this node's children.
|
||||
// Postvisit method postcondition: *(printed.rbegin() - 1) has had this
|
||||
std::vector<ChildrenList> printed_;
|
||||
|
||||
// Interface to print fields for each kind of node.
|
||||
// Note that, because of the post-order traversal for printing,
|
||||
// field values need not be passed explicitly; they are grabbed from
|
||||
// the passed-in visitor!
|
||||
class NodeFieldPrinter {
|
||||
private:
|
||||
JsonVisitor &visitor_;
|
||||
ChildrenList::const_iterator nextChild_;
|
||||
std::ostringstream out_;
|
||||
|
||||
void printFieldSeparator();
|
||||
|
||||
// Prints a non-null array of n children from the given
|
||||
// iterator. Does not update the iterator.
|
||||
void printChildList(
|
||||
std::ostringstream &out,
|
||||
const std::vector<std::string>::const_iterator &childIterator,
|
||||
size_t numChildren);
|
||||
|
||||
void printLocation(std::ostringstream &out, const yy::location &location);
|
||||
|
||||
public:
|
||||
// Begin printing the fields for a node of the given kind at the
|
||||
// given location.
|
||||
NodeFieldPrinter(
|
||||
JsonVisitor &visitor,
|
||||
const char *nodeKind,
|
||||
const Node &node);
|
||||
|
||||
std::string finishPrinting();
|
||||
|
||||
void printSingularPrimitiveField(const char *fieldName, const char *value);
|
||||
void printSingularBooleanField(const char *fieldName, bool value);
|
||||
void printSingularObjectField(const char *fieldName);
|
||||
void printNullableSingularObjectField(const char *fieldName, const void *value);
|
||||
|
||||
template <typename T>
|
||||
void printPluralField(
|
||||
const char *fieldName,
|
||||
const std::vector<std::unique_ptr<T>> &value) {
|
||||
printFieldSeparator();
|
||||
out_ << '"' << fieldName << "\":";
|
||||
printChildList(out_, nextChild_, value.size());
|
||||
nextChild_ += value.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void printNullablePluralField(
|
||||
const char *fieldName,
|
||||
const std::vector<std::unique_ptr<T>> *value) {
|
||||
printFieldSeparator();
|
||||
out_ << '"' << fieldName << "\":";
|
||||
if (value == nullptr) {
|
||||
out_ << "null";
|
||||
} else {
|
||||
printChildList(out_, nextChild_, value->size());
|
||||
nextChild_ += value->size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Must be called at the start of all visit methods for node types
|
||||
// that have children. Maintains printed_.
|
||||
void visitNode();
|
||||
|
||||
// Must be called at the end of all visit methods for node types
|
||||
// that have children, passing the text for this node. Maintains
|
||||
// printed_.
|
||||
void endVisitNode(std::string &&str);
|
||||
|
||||
// Prints one of the many FooValue types that is prepresented with a
|
||||
// single string.
|
||||
template <typename ValueNode>
|
||||
void endVisitValueRepresentedAsString(const char *valueKind, const ValueNode &value);
|
||||
|
||||
public:
|
||||
JsonVisitor();
|
||||
~JsonVisitor() {}
|
||||
|
||||
std::string getResult() const;
|
||||
|
||||
#include "JsonVisitor.h.inc"
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
external/graphqlparser/LICENSE
vendored
Normal file
21
external/graphqlparser/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) GraphQL Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
7
external/graphqlparser/README.clang-tidy
vendored
Normal file
7
external/graphqlparser/README.clang-tidy
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
* readability-implicit-bool is disabled because I disagree with it.
|
||||
|
||||
* cppcoreguidelines-pro-type-reinterpret-cast is disabled because we use it
|
||||
to implement our C API.
|
||||
|
||||
* cppcoreguidelines-pro-bounds-array-to-pointer-decay is disabled
|
||||
because it fires a false positive on every use of assert().
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user