Feb 15th 2023 update

This commit is contained in:
Ned Wright 2023-02-15 19:09:38 +00:00
parent f7934cd09d
commit 6a9b33ff93
159 changed files with 16474 additions and 2096 deletions

View File

@ -78,12 +78,13 @@ Before compiling the services, you'll need to ensure the latest development vers
* GTest * GTest
* GMock * GMock
* cURL * cURL
* Python2
An example of installing the packages on Alpine: An example of installing the packages on Alpine:
```bash ```bash
$ apk update $ 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 ## Compiling and packaging the agent code

View File

@ -1,6 +1,5 @@
add_subdirectory(report_messaging) add_subdirectory(report_messaging)
add_subdirectory(http_manager) add_subdirectory(http_manager)
add_subdirectory(http_transaction_data)
add_subdirectory(generic_rulebase) add_subdirectory(generic_rulebase)
add_subdirectory(signal_handler) add_subdirectory(signal_handler)
add_subdirectory(gradual_deployment) add_subdirectory(gradual_deployment)

View File

@ -149,6 +149,7 @@ public:
{ {
dbgFlow(D_NGINX_ATTACHMENT) << "Initializing NGINX attachment"; dbgFlow(D_NGINX_ATTACHMENT) << "Initializing NGINX attachment";
i_env = Singleton::Consume<I_Environment>::by<NginxAttachment>();
timer = Singleton::Consume<I_TimeGet>::by<NginxAttachment>(); timer = Singleton::Consume<I_TimeGet>::by<NginxAttachment>();
i_socket = Singleton::Consume<I_Socket>::by<NginxAttachment>(); i_socket = Singleton::Consume<I_Socket>::by<NginxAttachment>();
mainloop = Singleton::Consume<I_MainLoop>::by<NginxAttachment>(); mainloop = Singleton::Consume<I_MainLoop>::by<NginxAttachment>();
@ -156,6 +157,30 @@ public:
i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>(); i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
inst_awareness = Singleton::Consume<I_InstanceAwareness>::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( metric_report_interval = chrono::seconds(
getConfigurationWithDefault<uint>( getConfigurationWithDefault<uint>(
METRIC_PERIODIC_TIMEOUT, METRIC_PERIODIC_TIMEOUT,
@ -237,6 +262,73 @@ public:
dbgInfo(D_NGINX_ATTACHMENT) << "Successfully initialized NGINX Attachment"; 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 void
fini() fini()
{ {
@ -1714,6 +1806,7 @@ private:
I_Socket *i_socket = nullptr; I_Socket *i_socket = nullptr;
I_TimeGet *timer = nullptr; I_TimeGet *timer = nullptr;
I_MainLoop *mainloop = nullptr; I_MainLoop *mainloop = nullptr;
I_Environment *i_env = nullptr;
I_HttpManager *http_manager = nullptr; I_HttpManager *http_manager = nullptr;
I_InstanceAwareness *inst_awareness = nullptr; I_InstanceAwareness *inst_awareness = nullptr;
I_TableSpecific<SessionID> *i_transaction_table = nullptr; I_TableSpecific<SessionID> *i_transaction_table = nullptr;
@ -1750,6 +1843,7 @@ void
NginxAttachment::preload() NginxAttachment::preload()
{ {
pimpl->preload(); pimpl->preload();
registerExpectedSetting<string>("agentType");
registerExpectedConfiguration<bool>("HTTP manager", "Container mode"); registerExpectedConfiguration<bool>("HTTP manager", "Container mode");
registerExpectedConfiguration<uint>("HTTP manager", "Shared memory segment size in KB"); registerExpectedConfiguration<uint>("HTTP manager", "Shared memory segment size in KB");
registerExpectedConfiguration<string>("HTTP manager", "Nginx permission"); registerExpectedConfiguration<string>("HTTP manager", "Nginx permission");

View File

@ -22,6 +22,8 @@
using namespace std; using namespace std;
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
string AssetMatcher::ctx_key = "asset_id"; string AssetMatcher::ctx_key = "asset_id";
AssetMatcher::AssetMatcher(const vector<string> &params) AssetMatcher::AssetMatcher(const vector<string> &params)
@ -36,5 +38,15 @@ AssetMatcher::evalVariable() const
I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>(); I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>();
auto bc_asset_id_ctx = env->get<GenericConfigId>(AssetMatcher::ctx_key); 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; return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id;
} }

View File

@ -95,6 +95,8 @@ MatchQuery::load(cereal::JSONInputArchive &archive_in)
is_specific_label = false; is_specific_label = false;
} }
} }
is_ignore_keyword = (key == "indicator");
if (condition_type != Conditions::Exist) { if (condition_type != Conditions::Exist) {
archive_in(cereal::make_nvp("value", value)); archive_in(cereal::make_nvp("value", value));
for(const auto &val: value) { for(const auto &val: value) {
@ -221,23 +223,34 @@ MatchQuery::getAllKeys() const
} }
bool 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) { if (type == MatchType::Condition) {
auto key_value_pair = key_value_pairs.find(key); auto key_value_pair = key_value_pairs.find(key);
if (key_value_pair == key_value_pairs.end()) { if (key_value_pair == key_value_pairs.end()) {
dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key; dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key;
return false; 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) { } else if (type == MatchType::Operator && operator_type == Operators::And) {
for (const MatchQuery &inner_match: items) { 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; return true;
} else if (type == MatchType::Operator && operator_type == Operators::Or) { } 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) { 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; return false;
} else { } else {
@ -246,18 +259,39 @@ MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_
return false; 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 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; auto &type = condition_type;
bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn; 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; return negate ? !match : match;
} }
bool 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; boost::cmatch value_matcher;
for (const boost::regex &val_regex : regex_values) { for (const boost::regex &val_regex : regex_values) {
for (const string &requested_match_value : values) { for (const string &requested_match_value : values) {
@ -268,11 +302,16 @@ MatchQuery::matchAttributesRegEx(const set<string> &values) const
value_matcher, value_matcher,
val_regex)) 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 bool

View File

@ -108,19 +108,50 @@ ParameterException::load(cereal::JSONInputArchive &archive_in)
} }
set<ParameterBehavior> 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; set<ParameterBehavior> matched_behaviors;
matched_override_keywords.clear();
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception"; dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
for (const MatchBehaviorPair &match_behavior_pair: match_queries) { 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."; dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches.";
// 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); matched_behaviors.insert(match_behavior_pair.behavior);
} }
} }
if (match_queries.empty() && match.matchAttributes(key_value_pairs)) { }
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."; 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); matched_behaviors.insert(behavior);
} }
}
}
return matched_behaviors; 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);
}

View File

@ -124,16 +124,36 @@ setTriggersFlag(const string &key, cereal::JSONInputArchive &ar, EnumClass flag,
} }
static void 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; dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url;
if (log_server_url != "") { if (log_server_url != "" && protocol != "") {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url); Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url, protocol);
} else { } else {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type); 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 void
LogTriggerConf::load(cereal::JSONInputArchive& archive_in) LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
{ {
@ -142,6 +162,9 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
parseJSONKey<string>("verbosity", verbosity, archive_in); parseJSONKey<string>("verbosity", verbosity, archive_in);
parseJSONKey<string>("urlForSyslog", url_for_syslog, archive_in); parseJSONKey<string>("urlForSyslog", url_for_syslog, archive_in);
parseJSONKey<string>("urlForCef", url_for_cef, 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("webBody", archive_in, WebLogFields::webBody, log_web_fields);
setTriggersFlag("webHeaders", archive_in, WebLogFields::webHeaders, 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: case ReportIS::StreamType::JSON_LOG_FILE:
setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE); setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE);
break; break;
case ReportIS::StreamType::JSON_K8S_SVC:
setLogConfiguration(ReportIS::StreamType::JSON_K8S_SVC);
break;
case ReportIS::StreamType::SYSLOG: case ReportIS::StreamType::SYSLOG:
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog()); setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog(), syslog_protocol);
break; break;
case ReportIS::StreamType::CEF: case ReportIS::StreamType::CEF:
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef()); setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef(), cef_protocol);
break; break;
case ReportIS::StreamType::NONE: break; case ReportIS::StreamType::NONE: break;
case ReportIS::StreamType::COUNT: break; case ReportIS::StreamType::COUNT: break;

View File

@ -48,6 +48,7 @@ enum ParamType {
HTML_PARAM_TYPE, HTML_PARAM_TYPE,
URL_PARAM_TYPE, URL_PARAM_TYPE,
FREE_TEXT_PARAM_TYPE, FREE_TEXT_PARAM_TYPE,
FREE_TEXT_FRENCH_PARAM_TYPE,
PIPE_PARAM_TYPE, PIPE_PARAM_TYPE,
LONG_RANDOM_TEXT_PARAM_TYPE, LONG_RANDOM_TEXT_PARAM_TYPE,
BASE64_PARAM_TYPE, BASE64_PARAM_TYPE,

View File

@ -18,6 +18,7 @@
#include <string> #include <string>
#include <set> #include <set>
#include <map> #include <map>
#include <memory>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "cereal/types/string.hpp" #include "cereal/types/string.hpp"
@ -45,6 +46,13 @@ public:
Domain, Domain,
NotStatic 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); void load(cereal::JSONInputArchive &archive_in);
@ -58,6 +66,7 @@ public:
const std::vector<IpProtoRange> & getProtoValue() const { return ip_proto_value; } const std::vector<IpProtoRange> & getProtoValue() const { return ip_proto_value; }
const std::vector<MatchQuery> & getItems() const { return items; } const std::vector<MatchQuery> & getItems() const { return items; }
std::string getFirstValue() const { return first_value; } 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 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 matchException(const std::string &behaviorKey, const std::string &behaviorValue) const;
bool isKeyTypeIp() const; bool isKeyTypeIp() const;
@ -69,9 +78,14 @@ public:
std::set<std::string> getAllKeys() const; std::set<std::string> getAllKeys() const;
private: 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); StaticKeys getKeyByName(const std::string &key_type_name);
bool matchAttributes(const std::set<std::string> &values) const; bool matchAttributes(const std::set<std::string> &values,
bool matchAttributesRegEx(const std::set<std::string> &values) const; 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 matchAttributesString(const std::set<std::string> &values) const;
bool isRegEx() const; bool isRegEx() const;
@ -88,6 +102,7 @@ private:
std::vector<PortsRange> port_value; std::vector<PortsRange> port_value;
std::vector<IpProtoRange> ip_proto_value; std::vector<IpProtoRange> ip_proto_value;
std::vector<MatchQuery> items; std::vector<MatchQuery> items;
bool is_ignore_keyword;
}; };
#endif // __MATCH_QUERY_H__ #endif // __MATCH_QUERY_H__

View File

@ -200,6 +200,11 @@ public:
std::set<ParameterBehavior> std::set<ParameterBehavior>
getBehavior(const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs) const; 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; } static bool isGeoLocationExceptionExists() { return is_geo_location_exception_exists; }
private: private:
@ -218,4 +223,6 @@ private:
static bool is_geo_location_exception_being_loaded; static bool is_geo_location_exception_being_loaded;
}; };
static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE);
#endif //__PARAMETERS_CONFIG_H__ #endif //__PARAMETERS_CONFIG_H__

View File

@ -160,8 +160,10 @@ private:
std::string name; std::string name;
std::string verbosity; std::string verbosity;
std::string url_for_syslog = ""; std::string url_for_syslog = "UDP";
std::string url_for_cef = ""; std::string url_for_cef = "UDP";
std::string syslog_protocol = "";
std::string cef_protocol = "";
Flags<ReportIS::StreamType> active_streams; Flags<ReportIS::StreamType> active_streams;
Flags<SecurityType> should_log_on_detect; Flags<SecurityType> should_log_on_detect;
Flags<SecurityType> should_log_on_prevent; Flags<SecurityType> should_log_on_prevent;

View File

@ -42,7 +42,8 @@ public:
const std::string &new_settings_path, const std::string &new_settings_path,
const std::vector<std::string> &new_data_files = {}, const std::vector<std::string> &new_data_files = {},
const std::string &tenant_id = "", const std::string &tenant_id = "",
const std::string &profile_id = "" const std::string &profile_id = "",
const bool last_iteration = false
) = 0; ) = 0;
virtual bool isServiceInstalled(const std::string &service_name) = 0; virtual bool isServiceInstalled(const std::string &service_name) = 0;

View File

@ -21,6 +21,9 @@
#include "i_http_manager.h" #include "i_http_manager.h"
#include "i_static_resources_handler.h" #include "i_static_resources_handler.h"
#include "i_socket_is.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 "transaction_table_metric.h"
#include "nginx_attachment_metric.h" #include "nginx_attachment_metric.h"
#include "nginx_intaker_metric.h" #include "nginx_intaker_metric.h"
@ -38,7 +41,10 @@ class NginxAttachment
Singleton::Consume<I_HttpManager>, Singleton::Consume<I_HttpManager>,
Singleton::Consume<I_TimeGet>, Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Socket>, 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: public:
NginxAttachment(); NginxAttachment();

View File

@ -28,6 +28,7 @@ ReportMessaging::~ReportMessaging()
LogRest log_rest(report); LogRest log_rest(report);
auto messaging = Singleton::Consume<I_Messaging>::by<ReportMessaging>(); auto messaging = Singleton::Consume<I_Messaging>::by<ReportMessaging>();
try {
messaging->sendObjectWithPersistence( messaging->sendObjectWithPersistence(
log_rest, log_rest,
I_Messaging::Method::POST, I_Messaging::Method::POST,
@ -37,6 +38,8 @@ ReportMessaging::~ReportMessaging()
message_type_tag, message_type_tag,
is_async_message is_async_message
); );
} catch (...) {
}
} }
ReportMessaging & ReportMessaging &

View File

@ -28,14 +28,15 @@ public:
MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &()); MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &());
MOCK_METHOD5( MOCK_METHOD6(
updateServiceConfiguration, updateServiceConfiguration,
bool( bool(
const std::string &new_policy_path, const std::string &new_policy_path,
const std::string &new_settings_path, const std::string &new_settings_path,
const std::vector<std::string> &new_data_files, const std::vector<std::string> &new_data_files,
const std::string &tenant_id, const std::string &tenant_id,
const std::string &profile_id const std::string &profile_id,
const bool last_iteration
) )
); );

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -14,7 +14,9 @@
#ifndef __APPSEC_PRACTICE_SECTION_H__ #ifndef __APPSEC_PRACTICE_SECTION_H__
#define __APPSEC_PRACTICE_SECTION_H__ #define __APPSEC_PRACTICE_SECTION_H__
#include <list>
#include <cereal/archives/json.hpp> #include <cereal/archives/json.hpp>
#include <cereal/types/list.hpp>
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_io.hpp>
@ -28,67 +30,24 @@
#include "trusted_sources_section.h" #include "trusted_sources_section.h"
USE_DEBUG_FLAG(D_K8S_POLICY); USE_DEBUG_FLAG(D_K8S_POLICY);
// LCOV_EXCL_START Reason: no test exist // LCOV_EXCL_START Reason: no test exist
class AppSecWebBotsURI class AppSecWebBotsURI
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots URI";
parseAppsecJSONKey<std::string>("uri", uri, archive_in);
}
const std::string & getURI() const { return uri; } const std::string & getURI() const;
private: private:
std::string uri; 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 class AppSecPracticeAntiBot
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
load(cereal::JSONInputArchive &archive_in) void save(cereal::JSONOutputArchive &out_ar) const;
{
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; }
private: private:
std::string override_mode; std::string override_mode;
@ -96,61 +55,15 @@ private:
std::vector<AppSecWebBotsURI> validated_uris; 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 class AppSecWebAttackProtections
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string const std::string getCsrfProtectionMode() const;
getCsrfProtectionMode() const const std::string & getErrorDisclosureMode() const;
{ bool getNonValidHttpMethods() const;
if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) { const std::string getOpenRedirectMode() const;
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);
}
private: private:
std::string csrf_protection; std::string csrf_protection;
@ -159,53 +72,18 @@ private:
bool non_valid_http_methods; 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 class AppSecPracticeWebAttacks
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
int getMaxBodySizeKb() const { return max_body_size_kb; } int getMaxBodySizeKb() const;
int getMaxHeaderSizeBytes() const { return max_header_size_bytes; } int getMaxHeaderSizeBytes() const;
int getMaxObjectDepth() const { return max_object_depth; } int getMaxObjectDepth() const;
int getMaxUrlSizeBytes() const { return max_url_size_bytes; } int getMaxUrlSizeBytes() const;
const std::string & getMinimumConfidence() const { return minimum_confidence; } const std::string & getMinimumConfidence() const;
const AppSecWebAttackProtections & getprotections() const { return protections; } const AppSecWebAttackProtections & getprotections() const;
const std::string & getMode(const std::string &default_mode = "Inactive") const;
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);
}
private: private:
int max_body_size_kb; int max_body_size_kb;
@ -217,114 +95,42 @@ private:
AppSecWebAttackProtections protections; 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 class AppSecPracticeSnortSignatures
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & getOverrideMode() const { return override_mode; } const std::string & getOverrideMode() const;
const std::vector<std::string> & getConfigMap() const;
const std::vector<std::string> & getConfigMap() const { return config_map; }
private: private:
std::string override_mode; std::string override_mode;
std::vector<std::string> config_map; 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 class AppSecPracticeOpenSchemaAPI
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & getOverrideMode() const { return override_mode; } const std::string & getOverrideMode() const;
const std::vector<std::string> & getConfigMap() const;
const std::vector<std::string> & getConfigMap() const { return config_map; }
private: private:
std::string override_mode; std::string override_mode;
std::vector<std::string> config_map; 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 class AppSecPracticeSpec
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const { return openapi_schema_validation; } const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const;
const AppSecPracticeSnortSignatures & getSnortSignatures() const { return snort_signatures; } const AppSecPracticeSnortSignatures & getSnortSignatures() const;
const AppSecPracticeWebAttacks & getWebAttacks() const { return web_attacks; } const AppSecPracticeWebAttacks & getWebAttacks() const;
const AppSecPracticeAntiBot & getAntiBot() const { return anti_bot; } const AppSecPracticeAntiBot & getAntiBot() const;
const std::string & getName() const { return practice_name; } const std::string & getName() const;
private: private:
AppSecPracticeOpenSchemaAPI openapi_schema_validation; AppSecPracticeOpenSchemaAPI openapi_schema_validation;
@ -334,24 +140,11 @@ private:
std::string practice_name; 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 class PracticeAdvancedConfig
{ {
public: public:
PracticeAdvancedConfig() {}
PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec) PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec)
: :
http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()), http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()),
@ -361,19 +154,7 @@ public:
url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes()) url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes())
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
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; };
private: private:
int http_header_max_size; int http_header_max_size;
@ -394,16 +175,7 @@ public:
log(log_section) log(log_section)
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
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)
);
}
private: private:
std::string trigger_type; std::string trigger_type;
@ -415,23 +187,10 @@ private:
class AppSecOverride class AppSecOverride
{ {
public: public:
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources) AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources);
{
std::string source_ident = parsed_trusted_sources.getSourceIdent(); void save(cereal::JSONOutputArchive &out_ar) const;
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"}};
}
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: private:
std::vector<std::map<std::string, std::string>> parsed_behavior; std::vector<std::map<std::string, std::string>> parsed_behavior;
std::map<std::string, std::string> parsed_match; std::map<std::string, std::string> parsed_match;
@ -440,6 +199,8 @@ private:
class WebAppSection class WebAppSection
{ {
public: public:
WebAppSection() {}
WebAppSection( WebAppSection(
const std::string &_application_urls, const std::string &_application_urls,
const std::string &_asset_id, const std::string &_asset_id,
@ -451,75 +212,12 @@ public:
const AppSecPracticeSpec &parsed_appsec_spec, const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger, const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode, const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources) 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
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; } void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getPracticeId() const;
bool bool operator<(const WebAppSection &other) const;
operator<(const WebAppSection &other) const
{
return getPracticeId() < other.getPracticeId();
}
private: private:
std::string application_urls; std::string application_urls;
@ -573,36 +271,9 @@ public:
practice_advanced_config(parsed_appsec_spec) practice_advanced_config(parsed_appsec_spec)
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
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)
);
}
const std::string & getPracticeId() const { return practice_id; } const std::string & getPracticeId() const;
private: private:
std::string application_urls; std::string application_urls;
@ -630,14 +301,7 @@ public:
webApplicationPractices(_webApplicationPractices), webApplicationPractices(_webApplicationPractices),
webAPIPractices(_webAPIPractices) {} webAPIPractices(_webAPIPractices) {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("WebAPISecurity", webAPIPractices),
cereal::make_nvp("WebApplicationSecurity", webApplicationPractices)
);
}
private: private:
std::vector<WebAppSection> webApplicationPractices; std::vector<WebAppSection> webApplicationPractices;
@ -652,54 +316,27 @@ public:
app_sec_rulebase(_app_sec) app_sec_rulebase(_app_sec)
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(cereal::make_nvp("WAAP", app_sec_rulebase));
}
private: private:
AppSecRulebase app_sec_rulebase; AppSecRulebase app_sec_rulebase;
}; };
class ParsedRule class ParsedRule
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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
}
const std::vector<std::string> & getExceptions() const { return exceptions; } const std::vector<std::string> & getExceptions() const;
const std::vector<std::string> & getLogTriggers() const;
const std::vector<std::string> & getLogTriggers() const { return log_triggers; } const std::vector<std::string> & getPractices() const;
const std::string & getHost() const;
const std::vector<std::string> & getPractices() const { return practices; } const std::string & getMode() const;
void setHost(const std::string &_host);
const std::string & getHost() const { return host; } void setMode(const std::string &_mode);
const std::string & getCustomResponse() const;
const std::string & getMode() const { return mode; } const std::string & getSourceIdentifiers() const;
const std::string & getTrustedSources() const;
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; }
private: private:
std::vector<std::string> exceptions; std::vector<std::string> exceptions;
@ -712,88 +349,32 @@ private:
std::string trusted_sources; 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> class AppsecPolicySpec : Singleton::Consume<I_Environment>
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const ParsedRule & getDefaultRule() const { return default_rule; } const ParsedRule & getDefaultRule() const;
const std::list<ParsedRule> & getSpecificRules() const;
const std::vector<ParsedRule> & getSpecificRules() const { return specific_rules; }
private: private:
ParsedRule default_rule; ParsedRule default_rule;
std::vector<ParsedRule> specific_rules; std::list<ParsedRule> specific_rules;
}; };
class AppsecLinuxPolicy : Singleton::Consume<I_Environment> class AppsecLinuxPolicy : Singleton::Consume<I_Environment>
{ {
public: public:
void void
serialize(cereal::JSONInputArchive &archive_in) 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
);
}
const AppsecPolicySpec & getAppsecPolicySpec() const { return policies; } const AppsecPolicySpec & getAppsecPolicySpec() const;
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const { return practices; } const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const;
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const;
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const { return log_triggers; } const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const;
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const { return custom_responses; } const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
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;
}
private: private:
AppsecPolicySpec policies; AppsecPolicySpec policies;
@ -805,16 +386,5 @@ private:
std::vector<SourceIdentifierSpecWrapper> sources_identifier; 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 // LCOV_EXCL_STOP
#endif // __APPSEC_PRACTICE_SECTION_H__ #endif // __APPSEC_PRACTICE_SECTION_H__

View File

@ -30,34 +30,22 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AppsecExceptionSpec class AppsecExceptionSpec
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & getAction() const { return action; } const std::string & getName() const;
const std::vector<std::string> & getCountryCode() const { return country_code; } const std::string & getAction() const;
const std::vector<std::string> & getCountryName() const { return country_name; } const std::vector<std::string> & getCountryCode() const;
const std::vector<std::string> & getHostName() const { return host_name; } const std::vector<std::string> & getCountryName() const;
const std::vector<std::string> & getParamName() const { return param_name; } const std::vector<std::string> & getHostName() const;
const std::vector<std::string> & getParamValue() const { return param_value; } const std::vector<std::string> & getParamName() const;
const std::vector<std::string> & getProtectionName() const { return protection_name; } const std::vector<std::string> & getParamValue() const;
const std::vector<std::string> & getSourceIdentifier() const { return source_identifier; } const std::vector<std::string> & getProtectionName() const;
const std::vector<std::string> & getSourceIp() const { return source_ip; } const std::vector<std::string> & getSourceIdentifier() const;
const std::vector<std::string> & getUrl() const { return url; } const std::vector<std::string> & getSourceIp() const;
const std::vector<std::string> & getUrl() const;
private: private:
std::string name;
std::string action; std::string action;
std::vector<std::string> country_code; std::vector<std::string> country_code;
std::vector<std::string> country_name; std::vector<std::string> country_name;
@ -70,71 +58,11 @@ private:
std::vector<std::string> url; 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 class ExceptionMatch
{ {
public: public:
ExceptionMatch(const AppsecExceptionSpec &parsed_exception) 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()));
}
}
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value) ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value)
: :
match_type(MatchType::Condition), match_type(MatchType::Condition),
@ -143,34 +71,7 @@ public:
value(_value) value(_value)
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
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);
}
}
}
private: private:
MatchType match_type; MatchType match_type;
@ -183,31 +84,14 @@ private:
class ExceptionBehavior class ExceptionBehavior
{ {
public: public:
ExceptionBehavior() {}
ExceptionBehavior( ExceptionBehavior(
const std::string &_key, const std::string &_key,
const std::string &_value) 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();
}
}
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: private:
std::string key; std::string key;
@ -218,6 +102,7 @@ private:
class InnerException class InnerException
{ {
public: public:
InnerException() {}
InnerException( InnerException(
ExceptionBehavior _behavior, ExceptionBehavior _behavior,
ExceptionMatch _match) ExceptionMatch _match)
@ -225,22 +110,9 @@ public:
behavior(_behavior), behavior(_behavior),
match(_match) {} match(_match) {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const const std::string getBehaviorId() const;
{ bool operator<(const InnerException &other) 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();
}
private: private:
ExceptionBehavior behavior; ExceptionBehavior behavior;
@ -250,28 +122,8 @@ private:
class ExceptionsRulebase class ExceptionsRulebase
{ {
public: public:
ExceptionsRulebase( ExceptionsRulebase(std::vector<InnerException> _exceptions);
std::vector<InnerException> _exceptions) void save(cereal::JSONOutputArchive &out_ar) const;
:
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)
);
}
private: private:
std::string context; std::string context;
@ -286,11 +138,7 @@ public:
public: public:
Exception(const std::vector<ExceptionsRulebase> &_exception) : exception(_exception) {} Exception(const std::vector<ExceptionsRulebase> &_exception) : exception(_exception) {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(cereal::make_nvp("exception", exception));
}
private: private:
std::vector<ExceptionsRulebase> exception; std::vector<ExceptionsRulebase> exception;
@ -298,13 +146,7 @@ public:
ExceptionsWrapper(const std::vector<ExceptionsRulebase> &_exception) : exception_rulebase(Exception(_exception)) ExceptionsWrapper(const std::vector<ExceptionsRulebase> &_exception) : exception_rulebase(Exception(_exception))
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", exception_rulebase)
);
}
private: private:
Exception exception_rulebase; Exception exception_rulebase;

View File

@ -21,26 +21,21 @@
#include "debug.h" #include "debug.h"
#include "rest.h" #include "rest.h"
#include "cereal/archives/json.hpp" #include "cereal/archives/json.hpp"
#include <cereal/types/map.hpp>
#include "k8s_policy_common.h"
USE_DEBUG_FLAG(D_K8S_POLICY); USE_DEBUG_FLAG(D_K8S_POLICY);
// LCOV_EXCL_START Reason: no test exist // LCOV_EXCL_START Reason: no test exist
class IngressMetadata class IngressMetadata
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & getName() const { return name; } const std::string & getName() const;
const std::string & getResourceVersion() const { return resourceVersion; } const std::string & getResourceVersion() const;
const std::string & getNamespace() const { return namespace_name; } const std::string & getNamespace() const;
const std::map<std::string, std::string> & getAnnotations() const { return annotations; } const std::map<std::string, std::string> & getAnnotations() const;
private: private:
std::string name; std::string name;
@ -53,19 +48,15 @@ class IngressRulePath
{ {
public: public:
void void
load(cereal::JSONInputArchive &archive_in) load(cereal::JSONInputArchive &archive_in);
{
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path";
parseAppsecJSONKey<std::string>("path", path, archive_in);
}
const std::string & getPath() const { return path; } const std::string & getPath() const;
private: private:
std::string path; std::string path;
}; };
std::ostream & inline std::ostream &
operator<<(std::ostream &os, const IngressRulePath &obj) operator<<(std::ostream &os, const IngressRulePath &obj)
{ {
os << obj.getPath(); os << obj.getPath();
@ -75,14 +66,9 @@ operator<<(std::ostream &os, const IngressRulePath &obj)
class IngressRulePathsWrapper class IngressRulePathsWrapper
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path wrapper";
parseAppsecJSONKey<std::vector<IngressRulePath>>("paths", paths, archive_in);
}
const std::vector<IngressRulePath> & getRulePaths() const { return paths; } const std::vector<IngressRulePath> & getRulePaths() const;
private: private:
std::vector<IngressRulePath> paths; std::vector<IngressRulePath> paths;
@ -91,23 +77,17 @@ private:
class IngressDefinedRule class IngressDefinedRule
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & getHost() const { return host; } const std::string & getHost() const;
const IngressRulePathsWrapper & getPathsWrapper() const { return paths_wrapper; } const IngressRulePathsWrapper & getPathsWrapper() const;
private: private:
std::string host; std::string host;
IngressRulePathsWrapper paths_wrapper; IngressRulePathsWrapper paths_wrapper;
}; };
std::ostream & inline std::ostream &
operator<<(std::ostream &os, const IngressDefinedRule &obj) operator<<(std::ostream &os, const IngressDefinedRule &obj)
{ {
os os
@ -123,13 +103,9 @@ class DefaultBackend
{ {
public: public:
void void
load(cereal::JSONInputArchive &) load(cereal::JSONInputArchive &);
{
dbgTrace(D_K8S_POLICY) << "Loading Default Backend";
is_exists = true;
}
bool isExists() const { return is_exists; } bool isExists() const;
private: private:
bool is_exists = false; bool is_exists = false;
@ -139,17 +115,11 @@ class IngressSpec
{ {
public: public:
void void
load(cereal::JSONInputArchive &archive_in) 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);
}
const std::string & getIngressClassName() const { return ingress_class_name; } const std::string & getIngressClassName() const;
const std::vector<IngressDefinedRule> & getRules() const { return rules; } const std::vector<IngressDefinedRule> & getRules() const;
bool isDefaultBackendExists() const { return default_backend.isExists(); } bool isDefaultBackendExists() const;
private: private:
std::string ingress_class_name; std::string ingress_class_name;
@ -157,31 +127,14 @@ private:
DefaultBackend default_backend; 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 class SingleIngressData
{ {
public: public:
void void
load(cereal::JSONInputArchive &archive_in) 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 & getMetadata() const { return metadata; } const IngressMetadata & getMetadata() const;
const IngressSpec & getSpec() const { return spec; } const IngressSpec & getSpec() const;
private: private:
IngressMetadata metadata; IngressMetadata metadata;
@ -192,29 +145,10 @@ private:
class IngressData : public ClientRest class IngressData : public ClientRest
{ {
public: public:
bool bool loadJson(const std::string &json);
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;
}
const std::string & getapiVersion() const { return apiVersion; } const std::string & getapiVersion() const;
const std::vector<SingleIngressData> & getItems() const { return items; } const std::vector<SingleIngressData> & getItems() const;
private: private:
std::string apiVersion; std::string apiVersion;

View File

@ -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__

View File

@ -30,100 +30,24 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AssetUrlParser class AssetUrlParser
{ {
public: public:
AssetUrlParser() {}
static AssetUrlParser parse(const std::string &uri);
std::string query_string, asset_uri, protocol, asset_url, port; 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 class PracticeSection
{ {
public: public:
PracticeSection(const std::string &_id, const std::string &_type, const std::string &_practice_name) PracticeSection(
{ const std::string &_id,
auto maybe_type = string_to_practice_type.find(_type); const std::string &_type,
if (maybe_type == string_to_practice_type.end()) { const std::string &_practice_name);
dbgError(D_K8S_POLICY) << "Illegal pracrtice type: " << _type;
return;
}
type = _type; void save(cereal::JSONOutputArchive &out_ar) const;
name = _practice_name;
id = _id;
}
void const std::string & getPracticeId() const;
serialize(cereal::JSONOutputArchive &out_ar) const const std::string & getPracticeName() 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; }
private: private:
std::string id; std::string id;
@ -134,30 +58,10 @@ private:
class ParametersSection class ParametersSection
{ {
public: public:
ParametersSection( ParametersSection(const std::string &_id, const std::string &_name);
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;
}
}
const std::string & getId() const { return id; } void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getId() const;
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("parameterId", id),
cereal::make_nvp("parameterName", name),
cereal::make_nvp("parameterType", type)
);
}
private: private:
std::string name; std::string name;
@ -171,35 +75,12 @@ public:
RulesTriggerSection( RulesTriggerSection(
const std::string &_name, const std::string &_name,
const std::string &_id, const std::string &_id,
const std::string &_type) 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 & getId() const { return id; } void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getName() const { return id; }
void const std::string & getId() const;
serialize(cereal::JSONOutputArchive &out_ar) const const std::string & getName() const;
{
out_ar(
cereal::make_nvp("triggerId", id),
cereal::make_nvp("triggerName", name),
cereal::make_nvp("triggerType", type)
);
}
private: private:
std::string name; std::string name;
@ -219,84 +100,19 @@ public:
const std::string &_uri, const std::string &_uri,
std::vector<PracticeSection> _practices, std::vector<PracticeSection> _practices,
std::vector<ParametersSection> _parameters, std::vector<ParametersSection> _parameters,
std::vector<RulesTriggerSection> _triggers) 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();
}
}
void void save(cereal::JSONOutputArchive &out_ar) const;
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; }
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: private:
std::string context; std::string context;
@ -313,60 +129,13 @@ public:
class RulesConfig class RulesConfig
{ {
public: public:
RulesConfig(const std::vector<RulesConfigRulebase> &_rules_config) RulesConfig(const std::vector<RulesConfigRulebase> &_rules_config);
:
rules_config(_rules_config)
{
sort(rules_config.begin(), rules_config.end(), sortBySpecific);
}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulesConfig", rules_config)
);
}
private: private:
static bool static bool sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second);
sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second) static bool sortBySpecificAux(const std::string &first, const std::string &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;
}
std::vector<RulesConfigRulebase> rules_config; std::vector<RulesConfigRulebase> rules_config;
}; };
@ -376,13 +145,7 @@ public:
rules_config_rulebase(RulesConfig(_rules_config)) rules_config_rulebase(RulesConfig(_rules_config))
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", rules_config_rulebase)
);
}
private: private:
RulesConfig rules_config_rulebase; RulesConfig rules_config_rulebase;

View File

@ -28,31 +28,10 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AgentSettingsSection class AgentSettingsSection
{ {
public: public:
AgentSettingsSection( AgentSettingsSection(const std::string &_key, const std::string &_value);
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();
}
}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const const std::string & getSettingId() 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; }
private: private:
std::string id; std::string id;
@ -65,20 +44,7 @@ class SettingsRulebase
public: public:
SettingsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {} SettingsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
void void save(cereal::JSONOutputArchive &out_ar) const;
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)
);
}
private: private:
std::vector<AgentSettingsSection> agentSettings; std::vector<AgentSettingsSection> agentSettings;
@ -87,27 +53,9 @@ private:
class SettingsWrapper class SettingsWrapper
{ {
public: public:
SettingsWrapper(SettingsRulebase _agent) : agent(_agent) SettingsWrapper(SettingsRulebase _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 void save(cereal::JSONOutputArchive &out_ar) const;
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)
);
}
private: private:
std::string profileType = "agent"; std::string profileType = "agent";

View File

@ -27,24 +27,9 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AgentSettingsSection class AgentSettingsSection
{ {
public: public:
AgentSettingsSection(std::string _key, std::string _value) : key(_key), value(_value) AgentSettingsSection(std::string _key, std::string _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 void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("key", key),
cereal::make_nvp("value", value)
);
}
private: private:
std::string id; std::string id;
@ -57,20 +42,7 @@ class IpsSnortSigsRulebase
public: public:
IpsSnortSigsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {} IpsSnortSigsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
void void save(cereal::JSONOutputArchive &out_ar) const;
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)
);
}
private: private:
std::vector<AgentSettingsSection> agentSettings; std::vector<AgentSettingsSection> agentSettings;

View File

@ -52,76 +52,14 @@ public:
const std::string &_cefIpAddress, const std::string &_cefIpAddress,
int _syslogPortNum, int _syslogPortNum,
const std::string &_syslogIpAddress, const std::string &_syslogIpAddress,
bool _beautify_logs) 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
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)
); );
}
const std::string & getTriggerId() const { return id; } void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getTriggerName() const { return name; }
const std::string & getTriggerId() const;
const std::string & getTriggerName() const;
bool operator<(const LogTriggerSection &other) const;
private: private:
std::string id; std::string id;
@ -152,43 +90,22 @@ private:
class WebUserResponseTriggerSection class WebUserResponseTriggerSection
{ {
public: public:
WebUserResponseTriggerSection() {}
WebUserResponseTriggerSection( WebUserResponseTriggerSection(
const std::string &_name, const std::string &_name,
const std::string &_details_level, const std::string &_details_level,
const std::string &_response_body, const std::string &_response_body,
int _response_code, int _response_code,
const std::string &_response_title) 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();
}
}
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)
); );
}
const std::string & getTriggerId() const { return id; } void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getTriggerName() const { return name; }
const std::string & getTriggerId() const;
const std::string & getTriggerName() const;
bool operator<(const WebUserResponseTriggerSection &other) const;
private: private:
std::string id; std::string id;
@ -203,34 +120,13 @@ private:
class AppSecCustomResponseSpec class AppSecCustomResponseSpec
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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"
);
}
}
int getHttpResponseCode() const { return httpResponseCode; } int getHttpResponseCode() const;
const std::string & getMessageBody() const { return messageBody; } const std::string & getMessageBody() const;
const std::string & getMessageTitle() const { return messageTitle; } const std::string & getMessageTitle() const;
const std::string & getMode() const { return mode; } const std::string & getMode() const;
const std::string & getName() const { return name; } const std::string & getName() const;
private: private:
int httpResponseCode; int httpResponseCode;
@ -240,21 +136,6 @@ private:
std::string name; 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 class TriggersRulebase
{ {
public: public:
@ -266,14 +147,7 @@ public:
webUserResponseTriggers(_webUserResponseTriggers) {} webUserResponseTriggers(_webUserResponseTriggers) {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("log", logTriggers),
cereal::make_nvp("webUserResponse", webUserResponseTriggers)
);
}
private: private:
std::vector<LogTriggerSection> logTriggers; std::vector<LogTriggerSection> logTriggers;
@ -283,49 +157,24 @@ private:
class AppsecTriggerAccessControlLogging class AppsecTriggerAccessControlLogging
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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 isAllowEvents() const { return allow_events; } bool isAllowEvents() const;
bool isDropEvents() const { return drop_events; } bool isDropEvents() const;
private: private:
bool allow_events = false; bool allow_events = false;
bool drop_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 class AppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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");
}
bool isEnabled() const { return enabled; } bool isEnabled() const;
bool isResponseBody() const { return response_body; } bool isResponseBody() const;
const std::string & getMinimumSeverity() const { return minimum_severity; } const std::string & getMinimumSeverity() const;
private: private:
bool enabled = true; bool enabled = true;
@ -333,37 +182,15 @@ private:
std::string minimum_severity = "high"; 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 class AppsecTriggerLogging : public ClientRest
{ {
public: public:
void void
load(cereal::JSONInputArchive &archive_in) 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 isAllWebRequests() const { return all_web_requests; } bool isAllWebRequests() const;
bool isDetectEvents() const;
bool isDetectEvents() const { return detect_events; } bool isPreventEvents() const;
bool isPreventEvents() const { return prevent_events; }
private: private:
bool all_web_requests = false; bool all_web_requests = false;
@ -371,37 +198,15 @@ private:
bool prevent_events = true; 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 class AppsecTriggerExtendedLogging : public ClientRest
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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 isHttpHeaders() const { return http_headers; } bool isHttpHeaders() const;
bool isRequestBody() const { return request_body; } bool isRequestBody() const;
bool isUrlPath() const { return url_path; } bool isUrlPath() const;
bool isUrlQuery() const { return url_query; } bool isUrlQuery() const;
private: private:
bool http_headers = false; bool http_headers = false;
@ -410,36 +215,14 @@ private:
bool url_query = false; 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 class LoggingService
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & getAddress() const { return address; } const std::string & getAddress() const;
const std::string & getProto() const { return proto; } const std::string & getProto() const;
int getPort() const { return port; } int getPort() const;
private: private:
std::string address; std::string address;
@ -452,13 +235,8 @@ class StdoutLogging
public: public:
StdoutLogging() : format("json") {} StdoutLogging() : format("json") {}
void void load(cereal::JSONInputArchive &archive_in);
load(cereal::JSONInputArchive &archive_in) const std::string & getFormat() const;
{
parseAppsecJSONKey<std::string>("format", format, archive_in, "json");
}
const std::string & getFormat() const { return format; }
private: private:
std::string format; std::string format;
@ -467,35 +245,22 @@ private:
class AppsecTriggerLogDestination : public ClientRest class AppsecTriggerLogDestination : public ClientRest
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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; int getCefServerUdpPort() const;
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in); int getSyslogServerUdpPort() const;
agent_local = !(stdout_log.getFormat().empty()); bool isAgentLocal() const;
beautify_logs = stdout_log.getFormat() == "json-formatted"; bool shouldBeautifyLogs() const;
parseAppsecJSONKey<LoggingService>("syslog-service", syslog_service, archive_in);
parseAppsecJSONKey<LoggingService>("cef-service", cef_service, archive_in);
}
int getCefServerUdpPort() const { return getCefServiceData().getPort(); } bool getCloud() const;
int getSyslogServerUdpPort() const { return getSyslogServiceData().getPort(); } bool isCefNeeded() const;
bool isAgentLocal() const { return agent_local; } bool isSyslogNeeded() const;
bool shouldBeautifyLogs() const { return beautify_logs; } const std::string & getSyslogServerIpv4Address() const;
const std::string & getCefServerIpv4Address() const;
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(); }
private: private:
const LoggingService & getSyslogServiceData() const { return syslog_service; } const LoggingService & getSyslogServiceData() const;
const LoggingService & getCefServiceData() const { return cef_service; } const LoggingService & getCefServiceData() const;
bool cloud = false; bool cloud = false;
bool agent_local = true; bool agent_local = true;
@ -504,90 +269,17 @@ private:
LoggingService cef_service; 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 class AppsecTriggerSpec
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const AppsecTriggerAccessControlLogging & const AppsecTriggerAccessControlLogging & getAppsecTriggerAccessControlLogging() const;
getAppsecTriggerAccessControlLogging() const const std::string & getName() const;
{ const AppsecTriggerAdditionalSuspiciousEventsLogging & getAppsecTriggerAdditionalSuspiciousEventsLogging() const;
return access_control_logging; const AppsecTriggerLogging & getAppsecTriggerLogging() const;
} const AppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const;
const AppsecTriggerLogDestination & getAppsecTriggerLogDestination() const;
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;
}
private: private:
AppsecTriggerAccessControlLogging access_control_logging; AppsecTriggerAccessControlLogging access_control_logging;
@ -598,36 +290,13 @@ private:
std::string name; 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 class TriggersWrapper
{ {
public: public:
TriggersWrapper(const TriggersRulebase &_triggers) : triggers_rulebase(_triggers) TriggersWrapper(const TriggersRulebase &_triggers) : triggers_rulebase(_triggers)
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", triggers_rulebase)
);
}
private: private:
TriggersRulebase triggers_rulebase; TriggersRulebase triggers_rulebase;

View File

@ -29,51 +29,18 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class TrustedSourcesSpec class TrustedSourcesSpec
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
int int getMinNumOfSources() const;
getMinNumOfSources() const const std::vector<std::string> & getSourcesIdentifiers() const;
{ const std::string & getName() const;
return min_num_of_sources;
}
const std::vector<std::string> &
getSourcesIdentifiers() const
{
return sources_identifiers;
}
const std::string &
getName() const
{
return name;
}
private: private:
int min_num_of_sources; int min_num_of_sources = 0;
std::string name; std::string name;
std::vector<std::string> sources_identifiers; 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 class SourcesIdentifiers
{ {
public: public:
@ -83,20 +50,8 @@ public:
value(_value) value(_value)
{} {}
void void save(cereal::JSONOutputArchive &out_ar) const;
save(cereal::JSONOutputArchive &out_ar) const const std::string & getSourceIdent() const;
{
out_ar(
cereal::make_nvp("sourceIdentifier", source_identifier),
cereal::make_nvp("value", value)
);
}
const std::string &
getSourceIdent() const
{
return source_identifier;
}
private: private:
std::string source_identifier; std::string source_identifier;
@ -106,25 +61,10 @@ private:
class SourceIdentifierSpec class SourceIdentifierSpec
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & const std::string & getSourceIdentifier() const;
getSourceIdentifier() const const std::vector<std::string> & getValues() const;
{
return source_identifier;
}
const std::vector<std::string> &
getValues() const
{
return value;
}
private: private:
std::string source_identifier; std::string source_identifier;
@ -134,43 +74,16 @@ private:
class SourceIdentifierSpecWrapper class SourceIdentifierSpecWrapper
{ {
public: public:
void void load(cereal::JSONInputArchive &archive_in);
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);
}
const std::string & const std::string & getName() const;
getName() const const std::vector<SourceIdentifierSpec> & getIdentifiers() const;
{
return name;
}
const std::vector<SourceIdentifierSpec> &
getIdentifiers() const
{
return identifiers;
}
private: private:
std::string name; std::string name;
std::vector<SourceIdentifierSpec> identifiers; 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 class AppSecTrustedSources
{ {
public: public:
@ -180,42 +93,16 @@ public:
AppSecTrustedSources( AppSecTrustedSources(
const std::string &_name, const std::string &_name,
int _num_of_sources, int _num_of_sources,
const std::vector<SourcesIdentifiers> &_sources_identifiers) 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();
}
}
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> & void save(cereal::JSONOutputArchive &out_ar) const;
getSourcesIdentifiers() const const std::vector<SourcesIdentifiers> & getSourcesIdentifiers() const;
{
return sources_identifiers;
}
private: private:
std::string id; std::string id;
std::string name; std::string name;
int num_of_sources; int num_of_sources = 0;
std::vector<SourcesIdentifiers> sources_identifiers; std::vector<SourcesIdentifiers> sources_identifiers;
}; };
// LCOV_EXCL_STOP // LCOV_EXCL_STOP

View File

@ -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

View File

@ -44,6 +44,7 @@
#include "include/exceptions_section.h" #include "include/exceptions_section.h"
#include "include/rules_config_section.h" #include "include/rules_config_section.h"
#include "include/trusted_sources_section.h" #include "include/trusted_sources_section.h"
#include "include/policy_maker_utils.h"
using namespace std; using namespace std;
@ -56,62 +57,6 @@ const static string syslog_key = "syslog";
const static string mode_key = "mode"; const static string mode_key = "mode";
const static string local_mgmt_policy_path = "/conf/local_policy.yaml"; const static string local_mgmt_policy_path = "/conf/local_policy.yaml";
// LCOV_EXCL_START Reason: no test exist // 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 class NamespaceMetadata
{ {
@ -120,16 +65,16 @@ public:
load(cereal::JSONInputArchive &archive_in) load(cereal::JSONInputArchive &archive_in)
{ {
dbgInfo(D_K8S_POLICY) << "NamespaceMetadata load"; dbgInfo(D_K8S_POLICY) << "NamespaceMetadata load";
parseAppsecJSONKey<std::string>("name", name, archive_in); parseAppsecJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<std::string>("uid", uid, archive_in); parseAppsecJSONKey<string>("uid", uid, archive_in);
} }
const std::string & getName() const { return name; } const string & getName() const { return name; }
const std::string & getUID() const { return uid; } const string & getUID() const { return uid; }
private: private:
std::string name; string name;
std::string uid; string uid;
}; };
class SingleNamespaceData class SingleNamespaceData
@ -151,12 +96,12 @@ class NamespaceData : public ClientRest
{ {
public: public:
bool bool
loadJson(const std::string &json) loadJson(const string &json)
{ {
dbgTrace(D_K8S_POLICY) << "Loading namespace data"; dbgTrace(D_K8S_POLICY) << "Loading namespace data";
std::string modified_json = json; string modified_json = json;
modified_json.pop_back(); modified_json.pop_back();
std::stringstream in; stringstream in;
in.str(modified_json); in.str(modified_json);
try { try {
cereal::JSONInputArchive in_ar(in); cereal::JSONInputArchive in_ar(in);
@ -170,10 +115,10 @@ public:
return true; return true;
} }
const std::vector<SingleNamespaceData> & getItems() const { return items; } const vector<SingleNamespaceData> & getItems() const { return items; }
private: private:
std::vector<SingleNamespaceData> items; vector<SingleNamespaceData> items;
}; };
class LocalPolicyMgmtGenerator::Impl class LocalPolicyMgmtGenerator::Impl
@ -289,7 +234,7 @@ public:
return appsec_policy; 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(); ParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule();
string asset; string asset;
@ -461,7 +406,7 @@ public:
); );
string port = "80"; string port = "80";
string full_url = asset_name == "Any" ? "" : url + uri + ":" + port; 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(); string practice_id = rules_config.getPracticeId();
if (!generated_apps.count(full_url)) { if (!generated_apps.count(full_url)) {
@ -483,7 +428,7 @@ public:
parsed_rules.push_back(rules_config); parsed_rules.push_back(rules_config);
generated_apps.insert(full_url); generated_apps.insert(full_url);
} }
} } //end specific rules
string exception_name; string exception_name;
if (!default_rule.getExceptions().empty()) { if (!default_rule.getExceptions().empty()) {
@ -563,9 +508,9 @@ public:
); );
SettingsWrapper profiles_section = createProfilesSection(); 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;} LocalPolicyEnv getEnvType() const { return env_type;}
@ -608,14 +553,6 @@ public:
dbgTrace(D_K8S_POLICY) << "Ingress items ammount: " << ingress.getItems().size(); dbgTrace(D_K8S_POLICY) << "Ingress items ammount: " << ingress.getItems().size();
// TBD: break to methods : INXT-31445 // TBD: break to methods : INXT-31445
for (const SingleIngressData &item : ingress.getItems()) { 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; set<pair<string, string>> specific_assets_from_ingress;
for (const IngressDefinedRule &rule : item.getSpec().getRules()) { for (const IngressDefinedRule &rule : item.getSpec().getRules()) {
string url = rule.getHost(); string url = rule.getHost();
@ -670,9 +607,8 @@ public:
} }
AppsecSpecParser<AppsecPolicySpec> appsec_policy = maybe_appsec_policy.unpack(); 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(); ParsedRule default_rule = appsec_policy.getSpec().getDefaultRule();
for (const ParsedRule &parsed_rule : specific_rules) { for (const ParsedRule &parsed_rule : specific_rules) {
@ -799,10 +735,6 @@ public:
AppsecSpecParser<AppSecPracticeSpec> appsec_practice = maybe_appsec_practice.unpack(); AppsecSpecParser<AppSecPracticeSpec> appsec_practice = maybe_appsec_practice.unpack();
practice_map.emplace(practice_annotation_name, appsec_practice.getSpec()); 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; string log_trigger_id;
@ -830,7 +762,7 @@ public:
); );
string port = "80"; string port = "80";
string full_url = asset_name == "Any" ? "" : url + "/" + uri + ":" + port; 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(); string practice_id = rules_config.getPracticeId();
if (!generated_apps.count(full_url)) { if (!generated_apps.count(full_url)) {
@ -917,10 +849,6 @@ public:
AppsecSpecParser<AppSecPracticeSpec> appsec_practice = maybe_appsec_practice.unpack(); AppsecSpecParser<AppSecPracticeSpec> appsec_practice = maybe_appsec_practice.unpack();
practice_map.emplace(practice_name, appsec_practice.getSpec()); 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()) { if (item.getSpec().isDefaultBackendExists()) {
@ -978,7 +906,7 @@ public:
parsed_rules.push_back(default_rule_config); 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(); string practice_id = default_rule_config.getPracticeId();
if (!generated_apps.count(asset.first + asset.second)) { if (!generated_apps.count(asset.first + asset.second)) {
@ -1035,7 +963,7 @@ public:
); );
SettingsWrapper profiles_section = createProfilesSection(); 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); return dumpPolicyToFile(k8s_policy);
} }
@ -1238,7 +1166,7 @@ private:
env_value.begin(), env_value.begin(),
env_value.end(), env_value.end(),
env_value.begin(), env_value.begin(),
[](unsigned char c) { return std::tolower(c); } [](unsigned char c) { return tolower(c); }
); );
return env_value == "true"; return env_value == "true";
} }
@ -1283,12 +1211,12 @@ private:
} }
const string const string
dumpPolicyToFile(const K8sPolicyWrapper &k8s_policy) const dumpPolicyToFile(const PolicyWrapper &policy) const
{ {
stringstream ss; stringstream ss;
{ {
cereal::JSONOutputArchive ar(ss); cereal::JSONOutputArchive ar(ss);
k8s_policy.serialize(ar); policy.save(ar);
} }
string policy_str = ss.str(); string policy_str = ss.str();
ofstream policy_file(local_appsec_policy_path); ofstream policy_file(local_appsec_policy_path);
@ -1300,12 +1228,18 @@ private:
string string
readFileContent(const string&file_path) readFileContent(const string&file_path)
{ {
try {
ifstream file(file_path); ifstream file(file_path);
stringstream buffer; stringstream buffer;
buffer << file.rdbuf(); buffer << file.rdbuf();
return buffer.str(); return buffer.str();
} catch (ifstream::failure &f) {
dbgWarning(D_ORCHESTRATOR)
<< "Cannot read the file"
<< " File: " << file_path
<< " Error: " << f.what();
return "";
}
} }
string string
@ -1436,12 +1370,6 @@ private:
return false; return false;
} }
dbgTrace(D_K8S_POLICY)
<< "Successfuly retrieved AppSec exceptions for "
<< trigger_annotation_name
<< ":\n"
<< *maybe_appsec_trigger_spec;
LogTriggerSection log_triggers_section = LogTriggerSection log_triggers_section =
createLogTriggersSection(trigger_annotation_name, false, "", *maybe_appsec_trigger_spec); createLogTriggersSection(trigger_annotation_name, false, "", *maybe_appsec_trigger_spec);
log_triggers_map.emplace(trigger_annotation_name, log_triggers_section); 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; return true;
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -389,17 +389,17 @@ public:
void void
writeStatusToFile() writeStatusToFile()
{ {
auto orchestrations_status_path = getConfigurationWithDefault<string>( auto orchestration_status_path = getConfigurationWithDefault<string>(
filesystem_prefix + "/conf/orchestrations_status.json", filesystem_prefix + "/conf/orchestration_status.json",
"orchestration", "orchestration",
"Orchestration status path" "Orchestration status path"
); );
auto write_result = auto write_result =
orchestration_tools->objectToJsonFile<Status>(status, orchestrations_status_path); orchestration_tools->objectToJsonFile<Status>(status, orchestration_status_path);
if (!write_result) { 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 void
@ -440,10 +440,10 @@ public:
{ {
time = Singleton::Consume<I_TimeGet>::by<OrchestrationStatus>(); time = Singleton::Consume<I_TimeGet>::by<OrchestrationStatus>();
orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationStatus>(); orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationStatus>();
filesystem_prefix = getFilesystemPathConfig();
initValues(); initValues();
loadFromFile(); loadFromFile();
filesystem_prefix = getFilesystemPathConfig();
dbgTrace(D_ORCHESTRATOR) dbgTrace(D_ORCHESTRATOR)
<< "Initializing Orchestration status, file system path prefix: " << "Initializing Orchestration status, file system path prefix: "
<< filesystem_prefix; << filesystem_prefix;
@ -473,13 +473,13 @@ private:
void void
loadFromFile() loadFromFile()
{ {
auto orchestrations_status_path = getConfigurationWithDefault<string>( auto orchestration_status_path = getConfigurationWithDefault<string>(
filesystem_prefix + "/conf/orchestrations_status.json", filesystem_prefix + "/conf/orchestration_status.json",
"orchestration", "orchestration",
"Orchestration status path" "Orchestration status path"
); );
Maybe<Status> maybe_status_file = Maybe<Status> maybe_status_file =
orchestration_tools->jsonFileToObject<Status>(orchestrations_status_path); orchestration_tools->jsonFileToObject<Status>(orchestration_status_path);
if (!maybe_status_file.ok()) { if (!maybe_status_file.ok()) {
dbgTrace(D_ORCHESTRATOR) dbgTrace(D_ORCHESTRATOR)
<< "Failed to load Orchestration status, start with clear status." << "Failed to load Orchestration status, start with clear status."
@ -489,7 +489,7 @@ private:
status = maybe_status_file.unpack(); 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(); } const string & getLastUpdateAttempt() const override { return status.getLastUpdateAttempt(); }

View File

@ -124,6 +124,29 @@ private:
map<string, HealthCheckStatus> field_types_status; 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 class OrchestrationComp::Impl
{ {
public: public:
@ -144,6 +167,7 @@ public:
auto rest = Singleton::Consume<I_RestApi>::by<OrchestrationComp>(); auto rest = Singleton::Consume<I_RestApi>::by<OrchestrationComp>();
rest->addRestCall<getStatusRest>(RestAction::SHOW, "orchestration-status"); rest->addRestCall<getStatusRest>(RestAction::SHOW, "orchestration-status");
rest->addRestCall<AddProxyRest>(RestAction::ADD, "proxy"); rest->addRestCall<AddProxyRest>(RestAction::ADD, "proxy");
rest->addRestCall<setAgentUninstall>(RestAction::SET, "agent-uninstall");
// Main loop of the Orchestration. // Main loop of the Orchestration.
Singleton::Consume<I_MainLoop>::by<OrchestrationComp>()->addOneTimeRoutine( Singleton::Consume<I_MainLoop>::by<OrchestrationComp>()->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime, I_MainLoop::RoutineType::RealTime,
@ -982,7 +1006,7 @@ private:
const Maybe<vector<CheckUpdateRequest::Tenants>> &updated_policy_tenants, const Maybe<vector<CheckUpdateRequest::Tenants>> &updated_policy_tenants,
const vector<string> &new_data_files) const vector<string> &new_data_files)
{ {
dbgFlow(D_ORCHESTRATOR) << "Hanlding virtual files"; dbgFlow(D_ORCHESTRATOR) << "Handling virtual files";
if (!updated_policy_tenants.ok()) return; if (!updated_policy_tenants.ok()) return;
// Sorting files by tenant id; // Sorting files by tenant id;
@ -1053,26 +1077,31 @@ private:
} }
} }
for (const auto downloade_files: sorted_files) { for (auto it = sorted_files.begin(); it != sorted_files.end(); it++) {
auto files = downloade_files.second; const auto &downloaded_files = *it;
auto files = downloaded_files.second;
string policy_file = files[0]; string policy_file = files[0];
string setting_file = ""; string setting_file = "";
if (files.size() > 1) { if (files.size() > 1) {
setting_file = files[1]; setting_file = files[1];
auto handled_settings = updateSettingsFile( auto handled_settings = updateSettingsFile(
setting_file, setting_file,
downloade_files.first.getTenantId(), downloaded_files.first.getTenantId(),
downloade_files.first.getPfofileId() downloaded_files.first.getProfileId()
); );
if (handled_settings.ok()) setting_file = *handled_settings; 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( Singleton::Consume<I_ServiceController>::by<OrchestrationComp>()->updateServiceConfiguration(
policy_file, policy_file,
setting_file, setting_file,
new_data_files, new_data_files,
downloade_files.first.getTenantId(), downloaded_files.first.getTenantId(),
downloade_files.first.getPfofileId() downloaded_files.first.getProfileId(),
last_iteration
); );
} }
} }
@ -1087,9 +1116,9 @@ private:
"Conf dir" "Conf dir"
) + (tenant_id != "" ? "tenant_" + tenant_id + "_profile_" + profile_id + "_" : ""); ) + (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>(); auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
string settings_file_path = conf_dir + "settings.json"; 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)) { if (!orchestration_tools->copyFile(new_settings_file, settings_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings."; dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings.";
return genError("Failed to update the settings"); return genError("Failed to update the settings");
@ -1278,7 +1307,7 @@ private:
int sleep_interval = policy.getErrorSleepInterval(); int sleep_interval = policy.getErrorSleepInterval();
Maybe<void> start_state(genError("Not running yet.")); Maybe<void> start_state(genError("Not running yet."));
while (!(start_state = start()).ok()) { 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( health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY, HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::REGISTRATION, OrchestrationStatusFieldType::REGISTRATION,

View File

@ -66,6 +66,11 @@ public:
EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)).WillOnce( EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)).WillOnce(
WithArg<2>(Invoke(this, &OrchestrationMultitenancyTest::setRestStatus))); WithArg<2>(Invoke(this, &OrchestrationMultitenancyTest::setRestStatus)));
EXPECT_CALL(
rest,
mockRestCall(RestAction::SET, "agent-uninstall", _)
).WillOnce(Return(true));
doEncrypt(); doEncrypt();
orchestration_comp.init(); orchestration_comp.init();
} }
@ -417,7 +422,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
"/etc/cp/conf/settings.json", "/etc/cp/conf/settings.json",
expected_data_types, expected_data_types,
"", "",
"" "",
false
) )
).WillOnce(Return(true)); ).WillOnce(Return(true));
@ -428,7 +434,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
"/etc/cp/conf/tenant_1236_profile_2611_settings.json", "/etc/cp/conf/tenant_1236_profile_2611_settings.json",
expected_data_types, expected_data_types,
"1236", "1236",
"2611" "2611",
false
) )
).WillOnce(Return(true)); ).WillOnce(Return(true));
@ -439,7 +446,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
"/etc/cp/conf/tenant_1235_profile_2311_settings.json", "/etc/cp/conf/tenant_1235_profile_2311_settings.json",
expected_data_types, expected_data_types,
"1235", "1235",
"2311" "2311",
true
) )
).WillOnce(Return(true)); ).WillOnce(Return(true));

View File

@ -79,6 +79,11 @@ public:
WithArg<2>(Invoke(this, &OrchestrationTest::setRestStatus)) WithArg<2>(Invoke(this, &OrchestrationTest::setRestStatus))
); );
EXPECT_CALL(
rest,
mockRestCall(RestAction::SET, "agent-uninstall", _)
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandlerAgentUninstall)));
string message_body; string message_body;
EXPECT_CALL(mock_message, mockSendPersistentMessage( EXPECT_CALL(mock_message, mockSendPersistentMessage(
false, false,
@ -101,6 +106,12 @@ public:
return true; return true;
} }
bool
restHandlerAgentUninstall(const unique_ptr<RestInit> &p)
{
agent_uninstall = p->getRest();
return true;
}
void void
doEncrypt() doEncrypt()
@ -249,6 +260,7 @@ public:
} }
unique_ptr<ServerRest> rest_handler; unique_ptr<ServerRest> rest_handler;
unique_ptr<ServerRest> agent_uninstall;
unique_ptr<ServerRest> declare_variable; unique_ptr<ServerRest> declare_variable;
StrictMock<MockMainLoop> mock_ml; StrictMock<MockMainLoop> mock_ml;
NiceMock<MockTimeGet> mock_time_get; NiceMock<MockTimeGet> mock_time_get;
@ -295,8 +307,36 @@ private:
I_MainLoop::Routine status_routine; 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) TEST_F(OrchestrationTest, register_config)
@ -530,12 +570,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
vector<string> expected_data_types = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).WillOnce(Return(true));
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, mock_service_controller,
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "") updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _)
).WillOnce(Return(true)); ).WillOnce(Return(true));
EXPECT_CALL( EXPECT_CALL(
@ -633,7 +673,7 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures)
vector<string> expected_data_types = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(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 = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).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 = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).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 = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(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( EXPECT_CALL(
mock_service_controller, 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>())) EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
@ -1183,7 +1223,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
vector<string> expected_data_types = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).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 = {}; vector<string> expected_data_types = {};
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, 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)); ).WillOnce(Return(true));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>())) EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
@ -1582,13 +1622,13 @@ TEST_F(OrchestrationTest, dataUpdate)
vector<string> expected_empty_data_types = {}; vector<string> expected_empty_data_types = {};
ExpectationSet expectation_set = EXPECT_CALL( ExpectationSet expectation_set = EXPECT_CALL(
mock_service_controller, 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)); ).WillOnce(Return(true));
vector<string> expected_ips_data_types = { "ips" }; vector<string> expected_ips_data_types = { "ips" };
EXPECT_CALL( EXPECT_CALL(
mock_service_controller, mock_service_controller,
updateServiceConfiguration("", "", expected_ips_data_types, "", "") updateServiceConfiguration("", "", expected_ips_data_types, "", "", _)
).After(expectation_set).WillOnce(Return(true)); ).After(expectation_set).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesDirectoryExist("/etc/cp/conf/data")).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesDirectoryExist("/etc/cp/conf/data")).WillOnce(Return(true));

View File

@ -272,7 +272,8 @@ public:
const string &new_settings_path, const string &new_settings_path,
const vector<string> &new_data_files, const vector<string> &new_data_files,
const string &tenant_id, const string &tenant_id,
const string &profile_id const string &profile_id,
const bool last_iteration
) override; ) override;
bool isServiceInstalled(const string &service_name) override; bool isServiceInstalled(const string &service_name) override;
@ -325,6 +326,7 @@ private:
map<int, string> services_reconf_names; map<int, string> services_reconf_names;
map<int, string> services_reconf_ids; map<int, string> services_reconf_ids;
string filesystem_prefix; string filesystem_prefix;
bool is_multi_tenant_env = false;
}; };
class GetServicesPorts : public ServerRest class GetServicesPorts : public ServerRest
@ -412,6 +414,11 @@ ServiceController::Impl::init()
filesystem_prefix = getFilesystemPathConfig(); filesystem_prefix = getFilesystemPathConfig();
loadRegisteredServicesFromFile(); loadRegisteredServicesFromFile();
auto agent_type = getSetting<string>("agentType");
if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) {
is_multi_tenant_env = true;
}
} }
void void
@ -592,7 +599,8 @@ ServiceController::Impl::updateServiceConfiguration(
const string &new_settings_path, const string &new_settings_path,
const vector<string> &new_data_files, const vector<string> &new_data_files,
const string &tenant_id, const string &tenant_id,
const string &profile_id) const string &profile_id,
const bool last_iteration)
{ {
dbgFlow(D_ORCHESTRATOR) dbgFlow(D_ORCHESTRATOR)
<< "new_policy_path: " << "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"); 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; dbgError(D_ORCHESTRATOR) << "Service reconfiguration monitor received illegal id :" << id;
return; return;
} }
dbgTrace(D_ORCHESTRATOR)
<< "Updating reconf status for reconfiguration ID "
<< id
<< ". Status: "
<< static_cast<int>(status);
services_reconf_status[id] = status; services_reconf_status[id] = status;
} }
@ -975,6 +991,15 @@ ServiceController::Impl::startReconfStatus(
const string &service_name, const string &service_name,
const string &service_id) 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_status.emplace(id, status);
services_reconf_names.emplace(id, service_name); services_reconf_names.emplace(id, service_name);
services_reconf_ids.emplace(id, service_id); services_reconf_ids.emplace(id, service_id);

View File

@ -122,9 +122,9 @@ LocalCommunication::getUpdate(CheckUpdateRequest &request)
} }
Maybe<string> 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>(); I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<LocalCommunication>();
if (file_name.compare("policy") == 0) { 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; dbgError(D_ORCHESTRATOR) << "Unknown resource file name " << file_name;
return genError("Failed to detect resourse file name " + file_name); return genError("Failed to detect resource file name " + file_name);
} }
void void

View File

@ -191,7 +191,7 @@ protected:
dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i; dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i;
mainloop->yield(true); 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; max_send_obj_retries;
return false; return false;
} }
@ -245,7 +245,7 @@ protected:
dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i; dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i;
mainloop->yield(true); 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; max_send_obj_retries;
return false; return false;
} }

View File

@ -129,17 +129,29 @@ SourceReputationFeaturesAgg::addHeaders(const ReputationFeaturesEntry &entry)
} }
const auto &referer_header_itr = headers.find("referer"); 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++; m_referer_count.na++;
} else { } else {
const string &uri = referer_header_itr->second; const string &uri = referer_header_itr->second;
size_t scheme_end_pos = uri.find("://") + 3; size_t scheme_end_pos = uri.find("://");
size_t authority_end_pos = uri.find("/", scheme_end_pos + 1); if (scheme_end_pos != string::npos) {
string authority = uri.substr(scheme_end_pos + 1, authority_end_pos); string authority;
if (authority.find(entry.getHost()) != string::npos) { scheme_end_pos = scheme_end_pos + 3;
m_referer_count.external_host++; size_t authority_end_pos = uri.find("/", scheme_end_pos);
if (authority_end_pos == string::npos) {
authority = uri.substr(scheme_end_pos);
} else { } 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++; m_referer_count.internal_host++;
} else {
m_referer_count.external_host++;
}
} else {
m_referer_count.external_host++;
dbgTrace(D_WAAP_REPUTATION) << "No scheme found in referer header: " << uri;
} }
} }

View File

@ -82,6 +82,7 @@ add_library(waap_clib
SyncLearningNotification.cc SyncLearningNotification.cc
LogGenWrapper.cc LogGenWrapper.cc
WaapSampleValue.cc WaapSampleValue.cc
ParserGql.cc
) )
add_definitions("-Wno-unused-function") add_definitions("-Wno-unused-function")

View File

@ -17,6 +17,7 @@
#include "ParserUrlEncode.h" #include "ParserUrlEncode.h"
#include "PHPSerializedDataParser.h" #include "PHPSerializedDataParser.h"
#include "ParserJson.h" #include "ParserJson.h"
#include "ParserGql.h"
#include "ParserConfluence.h" #include "ParserConfluence.h"
#include "ParserXML.h" #include "ParserXML.h"
#include "ParserHTML.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; bool base64ParamFound = false;
dbgTrace(D_WAAP_DEEP_PARSER) << " ===Processing potential base64==="; 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_variants base64_status = Waap::Util::b64Test (cur_val,
base64_key, key,
base64_decoded_val); decoded_val);
dbgTrace(D_WAAP_DEEP_PARSER) << " status = " << base64_status dbgTrace(D_WAAP_DEEP_PARSER)
<< " key = " << base64_key << " status = "
<< " value = " << base64_decoded_val; << base64_status
<< " key = "
<< key
<< " value = "
<< decoded_val;
switch (base64_status) { switch (base64_status) {
case SINGLE_B64_CHUNK_CONVERT: case SINGLE_B64_CHUNK_CONVERT:
cur_val = base64_decoded_val; cur_val = decoded_val;
base64ParamFound = true; base64ParamFound = true;
break; break;
case KEY_VALUE_B64_PAIR: case KEY_VALUE_B64_PAIR:
// going deep with new pair in case value is not empty // going deep with new pair in case value is not empty
if (base64_decoded_val.size() > 0) { if (decoded_val.size() > 0) {
cur_val = base64_decoded_val; cur_val = decoded_val;
base64ParamFound = true; 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; dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc;
if (rc != CONTINUE_PARSING) { if (rc != CONTINUE_PARSING) {
return rc; 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 // Parse buffer
// Note: API report does not include output of "PIPE" and similar extracted stuff. // 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; 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--; m_depth--;
// Send key/value pair to the Signature scanner // 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"; dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse phpSerializedData";
m_parsersDeque.push_front(std::make_shared<BufferedParser<PHPSerializedDataParser>>(*this)); 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] == '{')) else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{'))
{ {
boost::smatch confulence_match; boost::smatch confulence_match;

View File

@ -25,7 +25,8 @@ IndicatorsFiltersManager::IndicatorsFiltersManager(const std::string& remotePath
: :
SerializeToFileBase(pWaapAssetState->getWaapDataDir() + "/6.data"), SerializeToFileBase(pWaapAssetState->getWaapDataDir() + "/6.data"),
m_ignoreSources(pWaapAssetState->getWaapDataDir(), remotePath, assetId), m_ignoreSources(pWaapAssetState->getWaapDataDir(), remotePath, assetId),
m_tuning(remotePath) m_tuning(remotePath),
m_matchedOverrideKeywords()
{ {
restore(); restore();
m_keywordsFreqFilter = std::make_unique<KeywordIndicatorFilter>( m_keywordsFreqFilter = std::make_unique<KeywordIndicatorFilter>(
@ -88,6 +89,12 @@ bool IndicatorsFiltersManager::shouldFilterKeyword(const std::string &key, const
shouldFilter |= m_keywordsFreqFilter->shouldFilterKeyword(type, keyword); 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; return shouldFilter;
} }
@ -315,3 +322,8 @@ void IndicatorsFiltersManager::pushSample(
} }
m_typeFilter->registerKeywords(key, sample, pTransaction); m_typeFilter->registerKeywords(key, sample, pTransaction);
} }
std::set<std::string> & IndicatorsFiltersManager::getMatchedOverrideKeywords(void)
{
return m_matchedOverrideKeywords;
}

View File

@ -42,6 +42,7 @@ public:
virtual bool shouldFilterKeyword(const std::string &key, const std::string &keyword) const; virtual bool shouldFilterKeyword(const std::string &key, const std::string &keyword) const;
virtual void filterKeywords(const std::string &key, Waap::Keywords::KeywordsSet& keywords, virtual void filterKeywords(const std::string &key, Waap::Keywords::KeywordsSet& keywords,
std::vector<std::string>& filteredKeywords); std::vector<std::string>& filteredKeywords);
std::set<std::string> &getMatchedOverrideKeywords(void);
void pushSample(const std::string& key, const std::string& sample, IWaf2Transaction* pTransaction); 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; std::shared_ptr<Waap::TrustedSources::TrustedSourcesParameter> m_trustedSrcParams;
ScannerDetector m_ignoreSources; ScannerDetector m_ignoreSources;
TuningDecision m_tuning; TuningDecision m_tuning;
std::set<std::string> m_matchedOverrideKeywords;
}; };

View File

@ -43,6 +43,7 @@ struct IParserReceiver2 {
virtual void onEndMap() = 0; virtual void onEndMap() = 0;
virtual void onStartArray() = 0; virtual void onStartArray() = 0;
virtual void onEndArray() = 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 // Interface for receiver classes that can accept not only full key/value pairs, but also partial content

View 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());
}

View 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

View File

@ -270,6 +270,10 @@ size_t ParserJson::push(const char* buf, size_t len) {
m_state = s_error; m_state = s_error;
} }
if (m_receiver2) {
m_receiver2->onEndOfData();
}
return 0; return 0;
} }

View File

@ -44,18 +44,19 @@ static const string defaultSharedStorageHost = "appsec-shared-storage-svc";
#define LEARNING_HOST_ENV_NAME "LEARNING_HOST" #define LEARNING_HOST_ENV_NAME "LEARNING_HOST"
static bool static bool
isGZipped(const std::string &stream) isGZipped(const string &stream)
{ {
if (stream.size() < 2) return false; if (stream.size() < 2) return false;
auto unsinged_stream = reinterpret_cast<const u_char *>(stream.data()); auto unsinged_stream = reinterpret_cast<const u_char *>(stream.data());
return unsinged_stream[0] == 0x1f && unsinged_stream[1] == 0x8b; 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; json_str = json;
if (isGZipped(json_str) == 0) if (!isGZipped(json_str))
{ {
return ClientRest::loadJson(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())); reinterpret_cast<const unsigned char *>(json_str.c_str()));
if (res.ok){ 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); if (res.output) free(res.output);
res.output = nullptr; res.output = nullptr;
res.num_output_bytes = 0; res.num_output_bytes = 0;
@ -76,12 +77,12 @@ bool RestGetFile::loadJson(const std::string& json)
return ClientRest::loadJson(json_str); 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()) if (json.ok())
{ {
std::string data = json.unpack(); string data = json.unpack();
auto compression_stream = initCompressionStream(); auto compression_stream = initCompressionStream();
CompressionResult res = compressData( CompressionResult res = compressData(
compression_stream, compression_stream,
@ -94,7 +95,7 @@ Maybe<std::string> RestGetFile::genJson() const
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "Failed to gzip data"; dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "Failed to gzip data";
return genError("Failed to compress 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; json = data;
@ -104,7 +105,7 @@ Maybe<std::string> RestGetFile::genJson() const
} }
return json; return json;
} }
SerializeToFilePeriodically::SerializeToFilePeriodically(std::chrono::seconds pollingIntervals, std::string filePath) : SerializeToFilePeriodically::SerializeToFilePeriodically(ch::seconds pollingIntervals, string filePath) :
SerializeToFileBase(filePath), SerializeToFileBase(filePath),
m_lastSerialization(0), m_lastSerialization(0),
m_interval(pollingIntervals) 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) 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 dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "SerializeToFileBase::SerializeToFileBase() fname='" << m_filePath
<< "'"; << "'";
@ -163,12 +164,12 @@ SerializeToFileBase::~SerializeToFileBase()
void SerializeToFileBase::saveData() void SerializeToFileBase::saveData()
{ {
std::fstream filestream; fstream filestream;
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "saving to file: " << m_filePath; 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) { if (filestream.is_open() == false) {
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << m_filePath << " Error: " dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << m_filePath << " Error: "
@ -182,12 +183,12 @@ void SerializeToFileBase::saveData()
filestream.close(); filestream.close();
} }
void SerializeToFileBase::loadFromFile(std::string filePath) void SerializeToFileBase::loadFromFile(string filePath)
{ {
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "loadFromFile() file: " << 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) { if (filestream.is_open() == false) {
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << filePath << " Error: " << 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 // 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. // that might exist in previous run where instance awareness didn't exits.
I_InstanceAwareness* instanceAwareness = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>(); I_InstanceAwareness* instanceAwareness = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>();
Maybe<std::string> id = instanceAwareness->getUniqueID(); Maybe<string> id = instanceAwareness->getUniqueID();
if (!id.ok()) if (!id.ok())
{ {
return; return;
} }
std::string idStr = "/" + id.unpack() + "/"; string idStr = "/" + id.unpack() + "/";
size_t idPosition = filePath.find(idStr); size_t idPosition = filePath.find(idStr);
if (idPosition != std::string::npos) if (idPosition != string::npos)
{ {
filePath.erase(idPosition, idStr.length() - 1); filePath.erase(idPosition, idStr.length() - 1);
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "retry to load file from : " << filePath; 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; dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "loading from file: " << filePath;
int length; 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) length = filestream.tellg(); // report location (this is the length)
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "file length: " << length; dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "file length: " << length;
assert(length >= 0); // length -1 really happens if filePath is a directory (!) 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 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 if (!filestream.read(buffer, length)) // read the whole file into the buffer
{ {
filestream.close(); filestream.close();
@ -234,18 +235,18 @@ void SerializeToFileBase::loadFromFile(std::string filePath)
} }
filestream.close(); filestream.close();
std::string dataObfuscated(buffer, length); string dataObfuscated(buffer, length);
delete[] buffer; delete[] buffer;
std::stringstream ss(dataObfuscated); stringstream ss(dataObfuscated);
try try
{ {
deserialize(ss); deserialize(ss);
} }
catch (std::runtime_error & e) { catch (runtime_error & e) {
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to deserialize file: " << m_filePath << ", error: " << dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to deserialize file: " << m_filePath << ", error: " <<
e.what(); e.what();
} }
@ -263,7 +264,7 @@ RemoteFilesList::RemoteFilesList() : files(), filesPathsList()
// parses xml instead of json // parses xml instead of json
// extracts a file list in <Contents><Key> // 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 xmlDocPtr doc; // the resulting document tree
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "XML input: " << xml; 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"; dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Contents element";
xmlNodePtr contents_node = node->children; xmlNodePtr contents_node = node->children;
std::string file; string file;
std::string lastModified; string lastModified;
while (contents_node != NULL) while (contents_node != NULL)
{ {
if (xmlStrEqual(key_name, contents_node->name) == 1) if (xmlStrEqual(key_name, contents_node->name) == 1)
{ {
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Key element"; dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Key element";
xmlChar* xml_file = xmlNodeGetContent(contents_node); 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); xmlFree(xml_file);
} }
if (xmlStrEqual(last_modified_name, contents_node->name) == 1) if (xmlStrEqual(last_modified_name, contents_node->name) == 1)
{ {
dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the LastModified element"; dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the LastModified element";
xmlChar* xml_file = xmlNodeGetContent(contents_node); 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); xmlFree(xml_file);
} }
if (!file.empty() && !lastModified.empty()) if (!file.empty() && !lastModified.empty())
@ -333,24 +334,24 @@ bool RemoteFilesList::loadJson(const std::string& xml)
return true; return true;
} }
const std::vector<std::string>& RemoteFilesList::getFilesList() const const vector<string>& RemoteFilesList::getFilesList() const
{ {
return filesPathsList; return filesPathsList;
} }
const std::vector<FileMetaData>& RemoteFilesList::getFilesMetadataList() const const vector<FileMetaData>& RemoteFilesList::getFilesMetadataList() const
{ {
return files.get(); return files.get();
} }
SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase( SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
std::chrono::minutes interval, ch::minutes interval,
std::chrono::seconds waitForSync, ch::seconds waitForSync,
const std::string& filePath, const string& filePath,
const std::string& remotePath, const string& remotePath,
const std::string& assetId, const string& assetId,
const std::string& owner) const string& owner)
: :
SerializeToFileBase(filePath), SerializeToFileBase(filePath),
m_remotePath(remotePath), m_remotePath(remotePath),
@ -400,7 +401,7 @@ SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
if (parts[0].empty()) { if (parts[0].empty()) {
offset = 1; offset = 1;
} }
std::string type = ""; string type = "";
for (size_t i = offset + 2; i < parts.size(); i++) for (size_t i = offset + 2; i < parts.size(); i++)
{ {
type += type.empty() ? parts[i] : "/" + parts[i]; type += type.empty() ? parts[i] : "/" + parts[i];
@ -417,7 +418,7 @@ bool SerializeToLocalAndRemoteSyncBase::isBase()
return m_remotePath == ""; return m_remotePath == "";
} }
std::string SerializeToLocalAndRemoteSyncBase::getUri() string SerializeToLocalAndRemoteSyncBase::getUri()
{ {
static const string hybridModeUri = "/api"; static const string hybridModeUri = "/api";
static const string onlineModeUri = "/storage/waap"; 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>()) if (Singleton::exists<I_InstanceAwareness>())
{ {
I_InstanceAwareness* instance = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>(); I_InstanceAwareness* instance = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>();
Maybe<std::string> uniqueId = instance->getUniqueID(); Maybe<string> uniqueId = instance->getUniqueID();
if (uniqueId.ok()) if (uniqueId.ok())
{ {
agentId += "/" + uniqueId.unpack(); agentId += "/" + uniqueId.unpack();
} }
} }
std::string windowId = getWindowId(); string windowId = getWindowId();
return getUri() + "/" + m_remotePath + "/" + windowId + "/" + agentId + "/data.data"; return getUri() + "/" + m_remotePath + "/" + windowId + "/" + agentId + "/data.data";
} }
void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled) void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled)
@ -462,7 +463,7 @@ void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled)
m_remoteSyncEnabled = 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 " << dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "setInterval: from " << m_interval.count() << " to " <<
newInterval.count() << " seconds. assetId='" << m_assetId << "', owner='" << m_owner << "'"; 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 slicesCount = m_interval / assetSyncTimeSliceLength;
size_t sliceIndex = 0; size_t sliceIndex = 0;
if (slicesCount != 0 && m_assetId != "") { if (slicesCount != 0 && m_assetId != "") {
sliceIndex = std::hash<std::string>{}(m_assetId) % slicesCount; sliceIndex = hash<string>{}(m_assetId) % slicesCount;
} }
ch::seconds sliceOffset = assetSyncTimeSliceLength * sliceIndex; ch::seconds sliceOffset = assetSyncTimeSliceLength * sliceIndex;
@ -572,7 +573,7 @@ bool SerializeToLocalAndRemoteSyncBase::localSyncAndProcess()
return true; return true;
} }
std::chrono::seconds SerializeToLocalAndRemoteSyncBase::getIntervalDuration() const ch::seconds SerializeToLocalAndRemoteSyncBase::getIntervalDuration() const
{ {
return m_interval; return m_interval;
} }
@ -581,14 +582,14 @@ void SerializeToLocalAndRemoteSyncBase::updateStateFromRemoteService()
{ {
for (int i = 0; i < remoteSyncMaxPollingAttempts; i++) for (int i = 0; i < remoteSyncMaxPollingAttempts; i++)
{ {
m_pMainLoop->yield(std::chrono::seconds(60)); m_pMainLoop->yield(ch::seconds(60));
RemoteFilesList remoteFiles = getRemoteProcessedFilesList(); RemoteFilesList remoteFiles = getRemoteProcessedFilesList();
if (remoteFiles.getFilesMetadataList().empty()) if (remoteFiles.getFilesMetadataList().empty())
{ {
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "no files generated by the remote service were found"; dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "no files generated by the remote service were found";
continue; continue;
} }
std::string lastModified = remoteFiles.getFilesMetadataList().begin()->modified; string lastModified = remoteFiles.getFilesMetadataList().begin()->modified;
if (lastModified != m_lastProcessedModified) if (lastModified != m_lastProcessedModified)
{ {
m_lastProcessedModified = lastModified; m_lastProcessedModified = lastModified;
@ -618,7 +619,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker()
<< "Did not synchronize the data. Remote URL: " << "Did not synchronize the data. Remote URL: "
<< m_remotePath << m_remotePath
<< " is enabled: " << " is enabled: "
<< std::to_string(m_remoteSyncEnabled); << to_string(m_remoteSyncEnabled);
processData(); processData();
saveData(); saveData();
return; return;
@ -659,7 +660,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker()
Flags<MessageConnConfig> conn_flags; Flags<MessageConnConfig> conn_flags;
conn_flags.setFlag(MessageConnConfig::EXTERNAL); 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, bool ok = messaging->sendNoReplyObject(syncObj,
I_Messaging::Method::POST, I_Messaging::Method::POST,
getLearningHost(), getLearningHost(),
@ -735,7 +736,7 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList()
if (!processedFilesList.getFilesList().empty()) if (!processedFilesList.getFilesList().empty())
{ {
const std::vector<FileMetaData>& filesMD = processedFilesList.getFilesMetadataList(); const vector<FileMetaData>& filesMD = processedFilesList.getFilesMetadataList();
if (filesMD.size() > 1) { if (filesMD.size() > 1) {
dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "got more than 1 expected processed file"; dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "got more than 1 expected processed file";
} }
@ -764,7 +765,7 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList()
return processedFilesList; return processedFilesList;
} }
// backward compatibility - try to get backup file with the buggy prefix tenantID/assetID/instanceID/ // 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('/'); size_t pos = bcRemotePath.find('/');
pos = bcRemotePath.find('/', pos + 1); pos = bcRemotePath.find('/', pos + 1);
if (!Singleton::exists<I_InstanceAwareness>()) if (!Singleton::exists<I_InstanceAwareness>())
@ -774,14 +775,14 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList()
return processedFilesList; return processedFilesList;
} }
I_InstanceAwareness* instanceAwareness = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>(); I_InstanceAwareness* instanceAwareness = Singleton::Consume<I_InstanceAwareness>::by<WaapComponent>();
Maybe<std::string> id = instanceAwareness->getUniqueID(); Maybe<string> id = instanceAwareness->getUniqueID();
if (!id.ok()) if (!id.ok())
{ {
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to get instance id err: " << id.getErr() << dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to get instance id err: " << id.getErr() <<
". can't check backward compatibility"; ". can't check backward compatibility";
return processedFilesList; return processedFilesList;
} }
std::string idStr = id.unpack(); string idStr = id.unpack();
bcRemotePath.insert(pos + 1, idStr + "/"); bcRemotePath.insert(pos + 1, idStr + "/");
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "List of files is empty - trying to get the file from " << dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "List of files is empty - trying to get the file from " <<
bcRemotePath; bcRemotePath;

View File

@ -65,7 +65,8 @@ bool TypeIndicatorFilter::shouldFilterKeyword(const std::string &key, const std:
key.compare(key.size() - htmlParam.size(), htmlParam.size(), htmlParam) == 0); key.compare(key.size() - htmlParam.size(), htmlParam.size(), htmlParam) == 0);
for (auto keyType : keyTypes) 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; return true;
} }

View File

@ -1993,7 +1993,7 @@ void WaapAssetState::filterKeywordsByParameters(
} }
else 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";
} }
} }

View File

@ -23,6 +23,15 @@ set<string> WaapConfigApplication::assets_ids{};
set<string> WaapConfigApplication::assets_ids_aggregation{}; set<string> WaapConfigApplication::assets_ids_aggregation{};
bool WaapConfigApplication::getWaapSiteConfig(WaapConfigApplication& ngenSiteConfig) { 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>( auto &maybe_ngen_config = getConfiguration<WaapConfigApplication>(
"WAAP", "WAAP",
"WebApplicationSecurity" "WebApplicationSecurity"

View File

@ -19,9 +19,13 @@
#include "WaapConfigBase.h" #include "WaapConfigBase.h"
#include "log_generator.h" #include "log_generator.h"
#include "i_environment.h"
#include "debug.h" #include "debug.h"
class WaapConfigApplication : public WaapConfigBase class WaapConfigApplication
:
public WaapConfigBase,
Singleton::Consume<I_Environment>
{ {
public: public:
WaapConfigApplication(); WaapConfigApplication();

View File

@ -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); std::string param_name = IndicatorsFiltersManager::generateKey(res.location, res.param_name, m_transaction);
dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name; dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name;
m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction); m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction);
m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords); m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords);
if (m_transaction->getSiteConfig() != nullptr) 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); m_transaction->getAssetState()->filterKeywordsByParameters(res.param_name, keywordsSet);
// The keywords are only removed in production, they are still used while building scores // The keywords are only removed in production, they are still used while building scores
if (!m_transaction->get_ignoreScore()) { if (!m_transaction->get_ignoreScore()) {
m_transaction->getAssetState()->removeKeywords(keywordsSet); 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::sort(res.keyword_matches.begin(), res.keyword_matches.end());
std::string keywords_string; std::string keywords_string;
std::vector<std::string> strippedKeywords;
for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) { for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) {
// Add spaces between the items, but not before the first one // Add spaces between the items, but not before the first one
if (pKeyword != keywordsSet.begin()) { if (pKeyword != keywordsSet.begin()) {
@ -75,15 +78,21 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
std::string k = *pKeyword; std::string k = *pKeyword;
stripSpaces(k); stripSpaces(k);
keywords_string += k; keywords_string += k;
strippedKeywords.push_back(k);
} }
std::vector<std::string> newKeywords; std::vector<std::string> newKeywords;
for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) { for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) {
std::string k = *pKeyword; std::string k = *pKeyword;
stripSpaces(k); stripSpaces(k);
// if keyword_string.count(key) < 2: new_keywords.append(key)
if (countSubstrings(keywords_string, k) < 2) { if (countSubstrings(keywords_string, k) < 2) {
newKeywords.push_back(k); 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.location = location;
res.param_name = param_name; // remember the param name (analyzer needs it for reporting) 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 // Select scores pool by location
std::string poolName = Waap::Scores::getScorePoolNameByLocation(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 << dbgTrace(D_WAAP_SCANNER) << "Ignoring parameter key/value " << res.param_name <<
" due to ignore action in override"; " due to ignore action in override";
m_bIgnoreOverride = true; m_bIgnoreOverride = true;

View File

@ -67,8 +67,6 @@ using namespace ReportIS;
// Score threshold below which the match won't be considered // Score threshold below which the match won't be considered
#define SCORE_THRESHOLD (1.4f) #define SCORE_THRESHOLD (1.4f)
static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE);
void Waf2Transaction::learnScore(ScoreBuilderData& data, const std::string &poolName) void Waf2Transaction::learnScore(ScoreBuilderData& data, const std::string &poolName)
{ {
m_pWaapAssetState->scoreBuilder.analyzeFalseTruePositive(data, poolName, !m_ignoreScore); m_pWaapAssetState->scoreBuilder.analyzeFalseTruePositive(data, poolName, !m_ignoreScore);
@ -1554,6 +1552,8 @@ void Waf2Transaction::appendCommonLogFields(LogGen& waapLog,
const std::string& incidentType) const const std::string& incidentType) const
{ {
auto env = Singleton::Consume<I_Environment>::by<WaapComponent>(); 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); auto proxy_ip = env->get<std::string>(HttpTransactionData::proxy_ip_ctx);
if (proxy_ip.ok() && m_remote_addr != proxy_ip.unpack()) 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"); auto exceptions = getConfiguration<ParameterException>("rulebase", "exception");
if (!exceptions.ok()) return false; 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; 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["url"].insert(getUriStr());
exceptions_dict["hostName"].insert(m_hostStr); 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. // 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) { for (auto const &behavior : behaviors) {
if (behavior == action_ignore) { 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(); std::string overrideId = behavior.getId();
if (!overrideId.empty()) { if (!overrideId.empty()) {
m_matchedOverrideIds.insert(overrideId); m_matchedOverrideIds.insert(overrideId);

View File

@ -41,6 +41,7 @@ using namespace std;
USE_DEBUG_FLAG(D_WAAP); USE_DEBUG_FLAG(D_WAAP);
USE_DEBUG_FLAG(D_WAAP_EVASIONS); USE_DEBUG_FLAG(D_WAAP_EVASIONS);
USE_DEBUG_FLAG(D_WAAP_BASE64); USE_DEBUG_FLAG(D_WAAP_BASE64);
USE_DEBUG_FLAG(D_WAAP_JSON);
#define MIN_HEX_LENGTH 6 #define MIN_HEX_LENGTH 6
#define charToDigit(c) (c - '0') #define charToDigit(c) (c - '0')
@ -1144,6 +1145,8 @@ namespace Util {
#define B64_TRAILERCHAR '=' #define B64_TRAILERCHAR '='
static bool err = false; 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( static const SingleRegex invalid_hex_evasion_re(
"%([g-zG-Z][0-9a-zA-Z]|[0-9a-zA-Z][g-zG-Z])", "%([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" "csp_report_policy"
); );
static const SingleRegex base64_key_value_detector_re( static const SingleRegex base64_key_value_detector_re(
"^[^<>;&\\?|=\\s]+={1}\\s*.+", "^[^<>{};,&\\?|=\\s]+={1}\\s*.+",
err, err,
"base64_key_value"); "base64_key_value");
static const SingleRegex json_key_value_detector_re(
"^[^<>{};,&\\?|=\\s]+={.+:.+}\\z",
err,
"json_key_value");
static const SingleRegex base64_key_detector_re( static const SingleRegex base64_key_detector_re(
"^[^<>;&\\?|=\\s]+={1}", "^[^<>{};,&\\?|=\\s]+={1}",
err, err,
"base64_key"); "base64_key");
static const SingleRegex base64_prefix_detector_re( static const SingleRegex base64_prefix_detector_re(
@ -1173,6 +1180,44 @@ static const SingleRegex base64_prefix_detector_re(
err, err,
"base64_prefix"); "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, static void b64TestChunk(const string &s,
string::const_iterator chunkStart, string::const_iterator chunkStart,
string::const_iterator chunkEnd, string::const_iterator chunkEnd,
@ -2115,6 +2160,8 @@ string convertParamTypeToStr(ParamType type)
return "urls"; return "urls";
case FREE_TEXT_PARAM_TYPE: case FREE_TEXT_PARAM_TYPE:
return "free_text"; return "free_text";
case FREE_TEXT_FRENCH_PARAM_TYPE:
return "free_text_french";
case PIPE_PARAM_TYPE: case PIPE_PARAM_TYPE:
return "pipes"; return "pipes";
case LONG_RANDOM_TEXT_PARAM_TYPE: case LONG_RANDOM_TEXT_PARAM_TYPE:
@ -2148,6 +2195,7 @@ ParamType convertTypeStrToEnum(const string& typeStr)
{"administration_config", ParamType::ADMINISTRATOR_CONFIG_PARAM_TYPE}, {"administration_config", ParamType::ADMINISTRATOR_CONFIG_PARAM_TYPE},
{"base64", ParamType::BASE64_PARAM_TYPE }, {"base64", ParamType::BASE64_PARAM_TYPE },
{"free_text", ParamType::FREE_TEXT_PARAM_TYPE}, {"free_text", ParamType::FREE_TEXT_PARAM_TYPE},
{"free_text_french", ParamType::FREE_TEXT_FRENCH_PARAM_TYPE},
{"html_input", ParamType::HTML_PARAM_TYPE}, {"html_input", ParamType::HTML_PARAM_TYPE},
{"long_random_text", ParamType::LONG_RANDOM_TEXT_PARAM_TYPE}, {"long_random_text", ParamType::LONG_RANDOM_TEXT_PARAM_TYPE},
{"pipes", ParamType::PIPE_PARAM_TYPE}, {"pipes", ParamType::PIPE_PARAM_TYPE},

View File

@ -858,6 +858,10 @@ namespace Util {
std::string::const_iterator e, std::string::const_iterator e,
std::string &repl); std::string &repl);
bool detectJSONasParameter(const std::string &s,
std::string &key,
std::string &value);
void b64Decode( void b64Decode(
const std::string &s, const std::string &s,
RegexSubCallback_f cb, RegexSubCallback_f cb,

View File

@ -1,2 +1,3 @@
add_subdirectory(http_transaction_data)
add_subdirectory(ip_utilities) add_subdirectory(ip_utilities)
add_subdirectory(pm) add_subdirectory(pm)

View File

@ -14,6 +14,7 @@
#include "config.h" #include "config.h"
#include "config_component.h" #include "config_component.h"
#include <dirent.h>
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
#include <boost/regex.hpp> #include <boost/regex.hpp>
@ -66,11 +67,24 @@ public:
void void
doCall() override 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); 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; 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) { if (!finished) {
error_message = "Reload already in progress - can't start another one"; error_message = "Reload already in progress - can't start another one";
} }
@ -669,8 +683,8 @@ ConfigComponent::Impl::clearOldTenants()
bool bool
ConfigComponent::Impl::areTenantAndProfileActive(const TenantProfilePair &tenant_profile) const ConfigComponent::Impl::areTenantAndProfileActive(const TenantProfilePair &tenant_profile) const
{ {
return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getPfofileId() == default_profile_id) return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getProfileId() == default_profile_id)
|| tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getPfofileId()); || tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getProfileId());
} }
void void
@ -723,12 +737,21 @@ ConfigComponent::Impl::loadConfiguration(vector<shared_ptr<JSONInputArchive>> &f
string curr_profile = default_profile_id; string curr_profile = default_profile_id;
try { try {
(*archive)(cereal::make_nvp("tenantID", curr_tenant)); (*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)); (*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); TenantProfilePair tenant_profile(curr_tenant, curr_profile);
for (auto &config : expected_configs) { for (auto &config : expected_configs) {
auto loaded = config->loadConfiguration(*archive); auto loaded = config->loadConfiguration(*archive);
@ -800,6 +823,7 @@ ConfigComponent::Impl::commitFailure(const string &error)
bool bool
ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_async) ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_async)
{ {
dbgFlow(D_CONFIG) << "Reloading configuration";
auto env = Singleton::Consume<I_Environment>::by<ConfigComponent>(); auto env = Singleton::Consume<I_Environment>::by<ConfigComponent>();
env->registerValue<string>("New Policy Version", version); env->registerValue<string>("New Policy Version", version);
auto cleanup = make_scope_exit([env] () { env->unregisterKey<string>("New Policy 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>(); 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 &config_file : expected_configuration_files) {
for (const auto &type : config_file.second) { for (const auto &type : config_file.second) {
if (type == ConfigFileType::RawData) continue; if (type == ConfigFileType::RawData) continue;
@ -835,7 +861,9 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
const vector<string> &profile_ids = const vector<string> &profile_ids =
tenant_mananger ? tenant_mananger->fetchProfileIds(tenant) : vector<string>(); tenant_mananger ? tenant_mananger->fetchProfileIds(tenant) : vector<string>();
for (auto &profile_id : profile_ids) { 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)); 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; vector<shared_ptr<JSONInputArchive>> archives;
for (const auto &file : files) { for (const auto &file : files) {
if (file.second->is_open()) { 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)); archives.push_back(make_shared<JSONInputArchive>(*file.second));
} else { } else {
dbgDebug(D_CONFIG) << "Could not open configuration file. Path: " << file.first; dbgTrace(D_CONFIG) << "Could not open configuration file. Path: " << file.first;
} }
} }

View File

@ -161,26 +161,6 @@ IPAddr::createIPAddr(const string &ip_text)
bool IPAddr::isValidIPAddr(const string &ip_text) { return createIPAddr(ip_text).ok(); } 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"; const string ConnKey::network_key = "NetworkKey";
template<typename Num> template<typename Num>

View File

@ -24,6 +24,7 @@
#include "i_socket_is.h" #include "i_socket_is.h"
#include "component.h" #include "component.h"
#include "i_agent_details.h" #include "i_agent_details.h"
#include "i_shell_cmd.h"
class LoggingComp class LoggingComp
: :
@ -35,7 +36,8 @@ class LoggingComp
Singleton::Consume<I_TimeGet>, Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Logging>, Singleton::Consume<I_Logging>,
Singleton::Consume<I_Socket>, Singleton::Consume<I_Socket>,
Singleton::Consume<I_AgentDetails> Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_ShellCmd>
{ {
public: public:
LoggingComp(); LoggingComp();

View File

@ -79,7 +79,7 @@ public:
} }
std::string std::string
getPfofileId() const getProfileId() const
{ {
return profile_id; return profile_id;
} }

View File

@ -25,7 +25,11 @@ public:
using GeneralModifier = std::function<void(LogBulkRest &)>; using GeneralModifier = std::function<void(LogBulkRest &)>;
virtual bool addStream(ReportIS::StreamType type) = 0; 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 bool delStream(ReportIS::StreamType type) = 0;
virtual void sendLog(const Report &msg) = 0; virtual void sendLog(const Report &msg) = 0;

View File

@ -41,6 +41,8 @@ public:
virtual std::chrono::microseconds getTimeoutVal() const = 0; virtual std::chrono::microseconds getTimeoutVal() const = 0;
virtual std::string getProfileId(const std::string &tenant_id, const std::string &region) const = 0;
private: private:
friend class LoadNewTenants; friend class LoadNewTenants;
friend class LoadNewTenantsAndProfiles; friend class LoadNewTenantsAndProfiles;

View File

@ -10,7 +10,7 @@ class MockLogging : public Singleton::Provide<I_Logging>::From<MockProvider<I_Lo
public: public:
MOCK_METHOD1(sendLog, void (const Report &)); MOCK_METHOD1(sendLog, void (const Report &));
MOCK_METHOD1(addStream, bool (ReportIS::StreamType)); 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_METHOD1(delStream, bool (ReportIS::StreamType));
MOCK_METHOD0(getCurrentLogId, uint64_t ()); MOCK_METHOD0(getCurrentLogId, uint64_t ());
MOCK_METHOD1(addGeneralModifier, void (const GeneralModifier &)); MOCK_METHOD1(addGeneralModifier, void (const GeneralModifier &));

View File

@ -25,6 +25,7 @@ public:
MOCK_CONST_METHOD2(areTenantAndProfileActive, bool(const std::string &, const std::string &)); MOCK_CONST_METHOD2(areTenantAndProfileActive, bool(const std::string &, const std::string &));
MOCK_METHOD2(addActiveTenantAndProfile, void(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_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()); MOCK_CONST_METHOD0(getTimeoutVal, std::chrono::microseconds());

View File

@ -74,6 +74,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_WAAP_SCANNER, D_WAAP) DEFINE_FLAG(D_WAAP_SCANNER, D_WAAP)
DEFINE_FLAG(D_WAAP_DEEP_PARSER, D_WAAP) DEFINE_FLAG(D_WAAP_DEEP_PARSER, D_WAAP)
DEFINE_FLAG(D_WAAP_BASE64, 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_BOT_PROTECTION, D_WAAP)
DEFINE_FLAG(D_WAAP_PARSER, D_WAAP) DEFINE_FLAG(D_WAAP_PARSER, D_WAAP)
DEFINE_FLAG(D_WAAP_PARSER_XML, D_WAAP_PARSER) 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_HEALTH_CHECK, D_ORCHESTRATOR)
DEFINE_FLAG(D_AGENT_DETAILS, D_ORCHESTRATOR) DEFINE_FLAG(D_AGENT_DETAILS, D_ORCHESTRATOR)
DEFINE_FLAG(D_K8S_POLICY, 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_GRADUAL_DEPLOYMENT, D_COMPONENT)
DEFINE_FLAG(D_C8_CONTROLLER, D_COMPONENT) DEFINE_FLAG(D_C8_CONTROLLER, D_COMPONENT)

View File

@ -23,6 +23,7 @@ enum class StreamType {
JSON_DEBUG, JSON_DEBUG,
JSON_FOG, JSON_FOG,
JSON_LOG_FILE, JSON_LOG_FILE,
JSON_K8S_SVC,
SYSLOG, SYSLOG,
CEF, CEF,
@ -55,6 +56,7 @@ enum class Tags {
HTTP_GEO_FILTER, HTTP_GEO_FILTER,
FILE_UPLOAD, FILE_UPLOAD,
IDENTITY_AWARENESS, IDENTITY_AWARENESS,
RATE_LIMIT,
COUNT COUNT
}; };

View File

@ -199,21 +199,6 @@ private:
RangeType end; 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 // Specialization of std::hash<> for IPAddr
namespace std namespace std
{ {

View File

@ -33,7 +33,7 @@ public:
Maybe<string> instance_id = checkIfValueIsConfigured("id"); Maybe<string> instance_id = checkIfValueIsConfigured("id");
if (instance_id.ok()) return instance_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> Maybe<string>
@ -42,14 +42,14 @@ public:
Maybe<string> family_id = checkIfValueIsConfigured("family"); Maybe<string> family_id = checkIfValueIsConfigured("family");
if (family_id.ok()) return family_id; 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> Maybe<string>
getUniqueID() override getUniqueID() override
{ {
Maybe<string> instance_id(getInstanceID()); 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()); Maybe<string> family_id(getFamilyID());
if (!family_id.ok()) return *instance_id; if (!family_id.ok()) return *instance_id;

View File

@ -43,9 +43,12 @@ TEST_F(InstanceAwarenessTest, emptyInit)
init(args); 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(), IsError("Family ID isn't active")); EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found"));
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, badFamilyID) TEST_F(InstanceAwarenessTest, badFamilyID)
@ -55,7 +58,7 @@ TEST_F(InstanceAwarenessTest, badFamilyID)
init(args); init(args);
EXPECT_THAT(getInstanceID(), 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: Illegal flag: family"));
EXPECT_THAT(getUniqueID(), IsValue("9")); EXPECT_THAT(getUniqueID(), IsValue("9"));
} }
@ -65,9 +68,12 @@ TEST_F(InstanceAwarenessTest, badInstanceID)
init(args); 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(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) TEST_F(InstanceAwarenessTest, emptyInstanceID)
@ -76,9 +82,12 @@ TEST_F(InstanceAwarenessTest, emptyInstanceID)
init(args); 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(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) TEST_F(InstanceAwarenessTest, noInstanceID)
@ -87,9 +96,12 @@ TEST_F(InstanceAwarenessTest, noInstanceID)
init(args); 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(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) TEST_F(InstanceAwarenessTest, init)
@ -111,7 +123,7 @@ TEST_F(InstanceAwarenessTest, initIDOnly)
EXPECT_THAT(getUniqueID(), IsValue("9")); EXPECT_THAT(getUniqueID(), IsValue("9"));
EXPECT_THAT(getInstanceID(), 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) TEST_F(InstanceAwarenessTest, defaultValues)

View File

@ -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) add_subdirectory(logging_ut)

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <arpa/inet.h>
#include "logging_comp.h" #include "logging_comp.h"
#include "log_streams.h" #include "log_streams.h"
@ -19,11 +21,16 @@ using namespace cereal;
USE_DEBUG_FLAG(D_REPORT); 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>()), i_socket(Singleton::Consume<I_Socket>::by<LoggingComp>()),
ip_address(_ip_address), address(_address),
port(_port) port(_port),
protocol(_protocol)
{ {
connect(); connect();
if (!socket.ok()) { if (!socket.ok()) {
@ -65,17 +72,57 @@ CefStream::sendLog(const Report &log)
void void
CefStream::connect() 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"); auto cef_port = getProfileAgentSettingWithDefault<uint>(port, "agent.config.log.cefServer.port");
if (cef_ip_address.empty()) { if (cef_address.empty()) {
dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP is not configured."; dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP/Domain is not configured.";
return; 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( socket = i_socket->genSocket(
I_Socket::SocketType::UDP, protocol,
false, false,
false, false,
cef_ip_address + ":" + to_string(cef_port) cef_address + ":" + to_string(cef_port)
); );
} }

View 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";
}
}

View File

@ -80,10 +80,24 @@ private:
I_Messaging *i_msg = nullptr; 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 class SyslogStream : public Stream
{ {
public: public:
SyslogStream(const std::string &_ip_address, int _port); SyslogStream(const std::string &_address, int _port, I_Socket::SocketType protocol);
~SyslogStream(); ~SyslogStream();
void sendLog(const Report &log) override; void sendLog(const Report &log) override;
@ -93,8 +107,9 @@ private:
I_Socket *i_socket = nullptr; I_Socket *i_socket = nullptr;
I_MainLoop *mainloop = nullptr; I_MainLoop *mainloop = nullptr;
std::string ip_address; std::string address;
int port; int port;
I_Socket::SocketType protocol = I_Socket::SocketType::UDP;
I_MainLoop::RoutineID log_send_routine = -1; I_MainLoop::RoutineID log_send_routine = -1;
Maybe<I_Socket::socketFd> socket = genError("Not set yet"); Maybe<I_Socket::socketFd> socket = genError("Not set yet");
}; };
@ -102,7 +117,7 @@ private:
class CefStream : public Stream class CefStream : public Stream
{ {
public: public:
CefStream(const std::string &_ip_address, int _port); CefStream(const std::string &_address, int _port, I_Socket::SocketType _protocol);
~CefStream(); ~CefStream();
void sendLog(const Report &log) override; void sendLog(const Report &log) override;
@ -111,8 +126,9 @@ private:
void connect(); void connect();
I_Socket *i_socket = nullptr; I_Socket *i_socket = nullptr;
std::string ip_address; std::string address;
int port; int port;
I_Socket::SocketType protocol = I_Socket::SocketType::UDP;
Maybe<I_Socket::socketFd> socket = genError("Not set yet"); Maybe<I_Socket::socketFd> socket = genError("Not set yet");
}; };

View File

@ -111,7 +111,11 @@ public:
} }
bool 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); string log_type = TagAndEnumManagement::convertToString(type);
if (streams_preperation.find(type) != streams_preperation.end()) { 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 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()); string port = log_server_url.substr(log_server_url.find(':') + 1, log_server_url.length());
int port_num = stoi(port); 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) dbgInfo(D_REPORT)
<< "Successfully added log stream. Stream type: " << "Successfully added log stream. Stream type: "
<< log_type << log_type
@ -265,6 +270,7 @@ private:
case StreamType::JSON_DEBUG: return make_shared<DebugStream>(); case StreamType::JSON_DEBUG: return make_shared<DebugStream>();
case StreamType::JSON_FOG: return make_shared<FogStream>(); case StreamType::JSON_FOG: return make_shared<FogStream>();
case StreamType::JSON_LOG_FILE: return make_shared<LogFileStream>(); 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::SYSLOG: return nullptr;
case StreamType::CEF: return nullptr; case StreamType::CEF: return nullptr;
case StreamType::NONE: return nullptr; case StreamType::NONE: return nullptr;
@ -275,12 +281,11 @@ private:
} }
shared_ptr<Stream> 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) { switch (type) {
case StreamType::SYSLOG: case StreamType::SYSLOG: return make_shared<SyslogStream>(ip, port, protocol);
return make_shared<SyslogStream>(ip, port); case StreamType::CEF: return make_shared<CefStream>(ip, port, protocol);
case StreamType::CEF: return make_shared<CefStream>(ip, port);
default: default:
dbgWarning(D_REPORT) << "Invalid stream type with url"; dbgWarning(D_REPORT) << "Invalid stream type with url";
return NULL; return NULL;

View File

@ -21,6 +21,7 @@
#include "mock/mock_encryptor.h" #include "mock/mock_encryptor.h"
#include "mock/mock_agent_details.h" #include "mock/mock_agent_details.h"
#include "metric/all_metric_event.h" #include "metric/all_metric_event.h"
#include "mock/mock_shell_cmd.h"
#include "version.h" #include "version.h"
using namespace testing; using namespace testing;
@ -33,6 +34,7 @@ class TestEnd {};
static bool should_fail = false; static bool should_fail = false;
static bool should_load_file_stream = false; static bool should_load_file_stream = false;
static bool should_load_k8s_stream = false;
class fakeConfig : Singleton::Consume<I_Logging> class fakeConfig : Singleton::Consume<I_Logging>
{ {
@ -57,19 +59,45 @@ public:
} }
void void
load(cereal::JSONInputArchive &) load(cereal::JSONInputArchive &ar)
{ {
if (should_fail) throw cereal::Exception("Should fail load"); if (should_fail) throw cereal::Exception("Should fail load");
if (should_load_file_stream) { if (should_load_file_stream) {
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_LOG_FILE); Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_LOG_FILE);
return; 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_DEBUG);
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_FOG); 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> class LogTest : public testing::TestWithParam<bool>
@ -81,8 +109,10 @@ public:
i_agent_details(Singleton::Consume<I_AgentDetails>::from(agent_details)), i_agent_details(Singleton::Consume<I_AgentDetails>::from(agent_details)),
logger(Singleton::Consume<I_Logging>::from(log_comp)) logger(Singleton::Consume<I_Logging>::from(log_comp))
{ {
is_domain = false;
should_fail = false; should_fail = false;
should_load_file_stream = false; should_load_file_stream = false;
should_load_k8s_stream = false;
env.preload(); env.preload();
log_comp.preload(); log_comp.preload();
env.init(); env.init();
@ -143,8 +173,10 @@ public:
~LogTest() ~LogTest()
{ {
is_domain = false;
should_fail = false; should_fail = false;
should_load_file_stream = false; should_load_file_stream = false;
should_load_k8s_stream = false;
env.fini(); env.fini();
log_comp.fini(); log_comp.fini();
Debug::setUnitTestFlag(D_REPORT, Debug::DebugLevel::INFO); Debug::setUnitTestFlag(D_REPORT, Debug::DebugLevel::INFO);
@ -208,15 +240,23 @@ public:
} }
bool 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_enable_bulks = enable_bulk ? "true" : "false";
string is_domain = domain ? "true" : "false";
fakeConfig::preload(); fakeConfig::preload();
output_filename = log_file_name == "" ? file.fname : log_file_name; output_filename = log_file_name == "" ? file.fname : log_file_name;
stringstream str_stream; stringstream str_stream;
str_stream str_stream
<< "{\"fake config\": [{}], \"Logging\": {\"Log file name\": [{\"value\": \"" << "{\"fake config\": [{\"IsDomain\": "
<< is_domain
<< "}],"
<< "\"Logging\": {\"Log file name\": [{\"value\": \""
<< output_filename << output_filename
<< "\"}]," << "\"}],"
<< "\"Enable bulk of logs\": [{\"value\": " << "\"Enable bulk of logs\": [{\"value\": "
@ -247,6 +287,8 @@ public:
ConfigComponent config; ConfigComponent config;
vector<string> capture_syslog_cef_data; vector<string> capture_syslog_cef_data;
I_MainLoop::Routine sysog_routine = nullptr; I_MainLoop::Routine sysog_routine = nullptr;
StrictMock<MockShellCmd> mock_shell_cmd;
bool is_domain;
private: private:
string body; string body;
@ -259,6 +301,16 @@ TEST_F(LogTest, load_policy)
EXPECT_TRUE(loadFakeConfiguration(false)); 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) TEST_F(LogTest, loadPolicyFailure)
{ {
should_fail = true; should_fail = true;
@ -690,9 +742,117 @@ TEST_F(LogTest, FogBulkLogs)
EXPECT_EQ(local_body, str1); 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) TEST_P(LogTest, metrics_check)
{ {
loadFakeConfiguration(true, "", 3); loadFakeConfiguration(true, false, "", 3);
Tags tag1 = Tags::POLICY_INSTALLATION; Tags tag1 = Tags::POLICY_INSTALLATION;
Tags tag2 = Tags::ACCESS_CONTROL; Tags tag2 = Tags::ACCESS_CONTROL;
@ -837,7 +997,7 @@ TEST_F(LogTest, ShouldRetryAfterFailedWriteToFile)
EXPECT_TRUE(logger->delStream(ReportIS::StreamType::JSON_LOG_FILE)); EXPECT_TRUE(logger->delStream(ReportIS::StreamType::JSON_LOG_FILE));
static const string invalid_file_path = "/proc/gibberish"; static const string invalid_file_path = "/proc/gibberish";
loadFakeConfiguration(false, invalid_file_path, -1); loadFakeConfiguration(false, false, invalid_file_path, -1);
LogGen( LogGen(
"Install policy", "Install policy",

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <arpa/inet.h>
#include "log_streams.h" #include "log_streams.h"
#include "logging_comp.h" #include "logging_comp.h"
@ -18,12 +20,17 @@ using namespace std;
USE_DEBUG_FLAG(D_REPORT); 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>()), i_socket(Singleton::Consume<I_Socket>::by<LoggingComp>()),
mainloop(Singleton::Consume<I_MainLoop>::by<LoggingComp>()), mainloop(Singleton::Consume<I_MainLoop>::by<LoggingComp>()),
ip_address(_ip_address), address(_address),
port(_port) port(_port),
protocol(_protocol)
{ {
connect(); connect();
if (!socket.ok()) { if (!socket.ok()) {
@ -42,6 +49,12 @@ SyslogStream::~SyslogStream()
void void
SyslogStream::sendLog(const Report &log) SyslogStream::sendLog(const Report &log)
{
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()) { if (!socket.ok()) {
connect(); connect();
@ -52,12 +65,6 @@ SyslogStream::sendLog(const Report &log)
dbgTrace(D_REPORT) << "Successfully connect to the syslog server"; 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] ()
{
int tries = 1; int tries = 1;
for (; tries <=3; tries++) { for (; tries <=3; tries++) {
if (i_socket->writeData(socket.unpack(), data)) { if (i_socket->writeData(socket.unpack(), data)) {
@ -75,18 +82,57 @@ SyslogStream::sendLog(const Report &log)
void void
SyslogStream::connect() 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"); auto syslog_port = getProfileAgentSettingWithDefault<uint>(port, "agent.config.log.syslogServer.port");
if (syslog_ip_address.empty()) { if (syslog_address.empty()) {
dbgWarning(D_REPORT) << "Cannot connect to Syslog server, IP is not configured."; dbgWarning(D_REPORT) << "Cannot connect to Syslog server, Address IP/Domain not configured.";
return; 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( socket = i_socket->genSocket(
I_Socket::SocketType::UDP, protocol,
false, false,
false, false,
syslog_ip_address + ":" + to_string(syslog_port) syslog_address + ":" + to_string(syslog_port)
); );
} }

View File

@ -98,7 +98,8 @@ TagAndEnumManagement::convertStringToTag(const string &tag)
{"Reverse Proxy", ReportIS::Tags::REVERSE_PROXY}, {"Reverse Proxy", ReportIS::Tags::REVERSE_PROXY},
{"Http Geo Filter", ReportIS::Tags::HTTP_GEO_FILTER}, {"Http Geo Filter", ReportIS::Tags::HTTP_GEO_FILTER},
{"File Upload", ReportIS::Tags::FILE_UPLOAD}, {"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); 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_DEBUG: return "JSON Debug stream";
case StreamType::JSON_FOG: return "JSON FOG stream"; case StreamType::JSON_FOG: return "JSON FOG stream";
case StreamType::JSON_LOG_FILE: return "JSON File 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::SYSLOG: return "Syslog stream";
case StreamType::CEF: return "CEF stream"; case StreamType::CEF: return "CEF stream";
@ -307,7 +309,8 @@ EnumArray<Tags, string> TagAndEnumManagement::tags_translation_arr {
"Reverse Proxy", "Reverse Proxy",
"Http Geo Filter", "Http Geo Filter",
"File Upload", "File Upload",
"Identity Awareness" "Identity Awareness",
"Rate Limit"
}; };
EnumArray<AudienceTeam, string> TagAndEnumManagement::audience_team_translation { EnumArray<AudienceTeam, string> TagAndEnumManagement::audience_team_translation {

View File

@ -49,6 +49,8 @@ public:
chrono::microseconds getTimeoutVal() const override; chrono::microseconds getTimeoutVal() const override;
string getProfileId(const string &tenant_id, const string &region) const override;
void void
addInstance(const string &tenant_id, const string &profile_id, const string &instace_id) 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>(); auto rest = Singleton::Consume<I_RestApi>::by<TenantManager>();
rest->addRestCall<LoadNewTenants>(RestAction::SET, "tenant-id"); rest->addRestCall<LoadNewTenants>(RestAction::SET, "tenant-id");
rest->addRestCall<FetchActiveTenants>(RestAction::SHOW, "active-tenants"); 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) { if (type == TenantManagerType::CLIENT) {
@ -307,14 +309,14 @@ TenantManager::Impl::getAllTenants() const
} }
vector<string> 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( auto res = i_messaging->sendObject(
profile_id, tenant_id,
I_Messaging::Method::POST, I_Messaging::Method::POST,
"127.0.0.1", "127.0.0.1",
7777, 7777,
@ -324,7 +326,7 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const
if (!res) { if (!res) {
i_messaging->sendObject( i_messaging->sendObject(
profile_id, tenant_id,
I_Messaging::Method::POST, I_Messaging::Method::POST,
"127.0.0.1", "127.0.0.1",
7778, 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 &region) 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 void
@ -351,7 +399,16 @@ TenantManager::Impl::areTenantAndProfileActive(const string &tenant_id, const st
void void
TenantManager::Impl::addActiveTenantAndProfile(const string &tenant_id, const string &profile_id) 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); 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); active_tenants.createEntry(tenant_profile);
if (type == TenantManagerType::CLIENT) { if (type == TenantManagerType::CLIENT) {
sendTenantAndProfile(tenant_id, profile_id); 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++) { for (auto iter = begin(active_tenants); iter != end(active_tenants); iter++) {
if (iter->first.getTenantId() == tenant_id) { 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; return tenant_profile_ids;
@ -419,7 +477,7 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const
vector<string> vector<string>
TenantManager::Impl::fetchProfileIds(const string &tenant_id) const 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); return (type == TenantManagerType::CLIENT) ? getProfileIds(tenant_id) : fetchAllProfileIds(tenant_id);
} }
@ -462,4 +520,5 @@ TenantManager::preload()
{ {
registerExpectedConfiguration<uint32_t>("Tenant Manager", "Tenant timeout"); registerExpectedConfiguration<uint32_t>("Tenant Manager", "Tenant timeout");
registerExpectedConfiguration<string>("Tenant Manager", "Tenant manager type"); registerExpectedConfiguration<string>("Tenant Manager", "Tenant manager type");
registerExpectedSetting<string>("region");
} }

View File

@ -1,2 +1,3 @@
add_subdirectory(graphqlparser)
add_subdirectory(yajl) add_subdirectory(yajl)
add_subdirectory(yq) add_subdirectory(yq)

326
external/graphqlparser/.clang-tidy vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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.

View 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
View 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
View 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
View 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
View 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.

View 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