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
* GMock
* cURL
* Python2
An example of installing the packages on Alpine:
```bash
$ apk update
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev python2
```
## Compiling and packaging the agent code

View File

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

View File

@ -149,6 +149,7 @@ public:
{
dbgFlow(D_NGINX_ATTACHMENT) << "Initializing NGINX attachment";
i_env = Singleton::Consume<I_Environment>::by<NginxAttachment>();
timer = Singleton::Consume<I_TimeGet>::by<NginxAttachment>();
i_socket = Singleton::Consume<I_Socket>::by<NginxAttachment>();
mainloop = Singleton::Consume<I_MainLoop>::by<NginxAttachment>();
@ -156,6 +157,30 @@ public:
i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
inst_awareness = Singleton::Consume<I_InstanceAwareness>::by<NginxAttachment>();
auto agent_type = getSetting<string>("agentType");
bool is_nsaas_env = false;
if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) {
is_nsaas_env = true;
}
if (is_nsaas_env && inst_awareness->getFamilyID().ok()) {
mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::Offline,
[this] ()
{
while (true) {
if (!setActiveTenantAndProfile()) {
mainloop->yield(std::chrono::seconds(2));
} else {
break;
}
}
},
"Setting active tenant and profile for an NGINX based security app",
false
);
}
metric_report_interval = chrono::seconds(
getConfigurationWithDefault<uint>(
METRIC_PERIODIC_TIMEOUT,
@ -237,6 +262,73 @@ public:
dbgInfo(D_NGINX_ATTACHMENT) << "Successfully initialized NGINX Attachment";
}
bool
setActiveTenantAndProfile()
{
string container_id = inst_awareness->getFamilyID().unpack();
dbgTrace(D_NGINX_ATTACHMENT) << "Found a family ID: " << container_id;
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<NginxAttachment>();
string cmd =
"docker inspect --format='{{.Name}}' " + container_id +
" | awk -F'cp_nginx_gaia' '{print substr($2, index($2, \" \"))}'";
auto maybe_tenant_id = shell_cmd->getExecOutput(cmd, 1000, false);
if (maybe_tenant_id.ok()) {
string tenant_id = *maybe_tenant_id;
tenant_id.erase(remove(tenant_id.begin(), tenant_id.end(), '\n'), tenant_id.end());
dbgTrace(D_NGINX_ATTACHMENT) << "The tenant ID found is :" << tenant_id;
static string region;
if (region.empty()) {
const char *env_region = getenv("CP_NSAAS_REGION");
if (env_region) {
region = env_region;
} else {
region = getProfileAgentSettingWithDefault<string>("eu-west-1", "accessControl.region");
}
dbgInfo(D_NGINX_ATTACHMENT) << "Resolved region is " << region;
}
string profile_id = Singleton::Consume<I_TenantManager>::by<NginxAttachment>()->getProfileId(
tenant_id,
region
);
if (!profile_id.empty()) {
i_env->setActiveTenantAndProfile(tenant_id, profile_id);
dbgTrace(D_NGINX_ATTACHMENT)
<< "NGINX attachment setting active context. Tenant ID: "
<< tenant_id
<< ", Profile ID: "
<< profile_id
<< ", Region: "
<< region;
return true;
} else {
dbgWarning(D_NGINX_ATTACHMENT)
<< "Received an empty profile ID. Tenant ID: "
<< tenant_id
<< ", Region: "
<< region;
return false;
}
} else {
dbgWarning(D_NGINX_ATTACHMENT)
<< "Failed getting the tenant ID: "
<< cmd
<< ". Error :"
<< maybe_tenant_id.getErr();
return false;
}
return true;
}
void
fini()
{
@ -1714,6 +1806,7 @@ private:
I_Socket *i_socket = nullptr;
I_TimeGet *timer = nullptr;
I_MainLoop *mainloop = nullptr;
I_Environment *i_env = nullptr;
I_HttpManager *http_manager = nullptr;
I_InstanceAwareness *inst_awareness = nullptr;
I_TableSpecific<SessionID> *i_transaction_table = nullptr;
@ -1750,6 +1843,7 @@ void
NginxAttachment::preload()
{
pimpl->preload();
registerExpectedSetting<string>("agentType");
registerExpectedConfiguration<bool>("HTTP manager", "Container mode");
registerExpectedConfiguration<uint>("HTTP manager", "Shared memory segment size in KB");
registerExpectedConfiguration<string>("HTTP manager", "Nginx permission");

View File

@ -22,6 +22,8 @@
using namespace std;
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
string AssetMatcher::ctx_key = "asset_id";
AssetMatcher::AssetMatcher(const vector<string> &params)
@ -36,5 +38,15 @@ AssetMatcher::evalVariable() const
I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>();
auto bc_asset_id_ctx = env->get<GenericConfigId>(AssetMatcher::ctx_key);
if (bc_asset_id_ctx.ok()) {
dbgTrace(D_RULEBASE_CONFIG)
<< "Asset ID: "
<< asset_id
<< "; Current set assetId context: "
<< *bc_asset_id_ctx;
} else {
dbgTrace(D_RULEBASE_CONFIG) << "Asset ID: " << asset_id << ". Empty context";
}
return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id;
}

View File

@ -95,6 +95,8 @@ MatchQuery::load(cereal::JSONInputArchive &archive_in)
is_specific_label = false;
}
}
is_ignore_keyword = (key == "indicator");
if (condition_type != Conditions::Exist) {
archive_in(cereal::make_nvp("value", value));
for(const auto &val: value) {
@ -221,23 +223,34 @@ MatchQuery::getAllKeys() const
}
bool
MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_pairs) const
MatchQuery::matchAttributes(
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords ) const
{
if (type == MatchType::Condition) {
auto key_value_pair = key_value_pairs.find(key);
if (key_value_pair == key_value_pairs.end()) {
dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key;
return false;
}
return matchAttributes(key_value_pair->second);
return matchAttributes(key_value_pair->second, matched_override_keywords);
} else if (type == MatchType::Operator && operator_type == Operators::And) {
for (const MatchQuery &inner_match: items) {
if (!inner_match.matchAttributes(key_value_pairs)) return false;
if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords)) {
return false;
}
}
return true;
} else if (type == MatchType::Operator && operator_type == Operators::Or) {
// With 'or' condition, evaluate matched override keywords first and add the ones that were fully matched
set<string> inner_override_keywords;
for (const MatchQuery &inner_match: items) {
if (inner_match.matchAttributes(key_value_pairs)) return true;
inner_override_keywords.clear();
if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords)) {
matched_override_keywords.insert(inner_override_keywords.begin(), inner_override_keywords.end());
return true;
}
}
return false;
} else {
@ -246,18 +259,39 @@ MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_
return false;
}
MatchQuery::MatchResult
MatchQuery::getMatch( const unordered_map<string, set<string>> &key_value_pairs) const
{
MatchQuery::MatchResult matches;
matches.matched_keywords = make_shared<set<string>>();
matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords);
return matches;
}
bool
MatchQuery::matchAttributes(const set<string> &values) const
MatchQuery::matchAttributes(
const unordered_map<string, set<string>> &key_value_pairs) const
{
return getMatch(key_value_pairs).is_match;
}
bool
MatchQuery::matchAttributes(
const set<string> &values,
set<string> &matched_override_keywords) const
{
auto &type = condition_type;
bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn;
bool match = isRegEx() ? matchAttributesRegEx(values) : matchAttributesString(values);
bool match = isRegEx() ? matchAttributesRegEx(values, matched_override_keywords) : matchAttributesString(values);
return negate ? !match : match;
}
bool
MatchQuery::matchAttributesRegEx(const set<string> &values) const
MatchQuery::matchAttributesRegEx(
const set<string> &values,
set<string> &matched_override_keywords) const
{
bool res = false;
boost::cmatch value_matcher;
for (const boost::regex &val_regex : regex_values) {
for (const string &requested_match_value : values) {
@ -268,11 +302,16 @@ MatchQuery::matchAttributesRegEx(const set<string> &values) const
value_matcher,
val_regex))
{
return true;
res = true;
if (is_ignore_keyword) {
matched_override_keywords.insert(requested_match_value);
} else {
return res;
}
}
}
}
return false;
return res;
}
bool

View File

@ -108,19 +108,50 @@ ParameterException::load(cereal::JSONInputArchive &archive_in)
}
set<ParameterBehavior>
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
ParameterException::getBehavior(
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords) const
{
set<ParameterBehavior> matched_behaviors;
matched_override_keywords.clear();
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
for (const MatchBehaviorPair &match_behavior_pair: match_queries) {
if (match_behavior_pair.match.matchAttributes(key_value_pairs)) {
MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs);
if (match_res.is_match) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches.";
matched_behaviors.insert(match_behavior_pair.behavior);
// When matching indicators with action=ignore, we expect no behavior override.
// Instead, a matched keywords list should be returned which will be later removed from score calculation
if (match_res.matched_keywords->size() > 0 && match_behavior_pair.behavior == action_ignore) {
matched_override_keywords.insert(match_res.matched_keywords->begin(),
match_res.matched_keywords->end());
} else {
matched_behaviors.insert(match_behavior_pair.behavior);
}
}
}
if (match_queries.empty() && match.matchAttributes(key_value_pairs)) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
matched_behaviors.insert(behavior);
if (match_queries.empty()) {
MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs);
if (match_res.is_match) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
// When matching indicators with action=ignore, we expect no behavior override.
// Instead, a matched keywords list should be returned which will be later removed from score calculation
if (match_res.matched_keywords->size() > 0 && behavior == action_ignore) {
matched_override_keywords.insert(match_res.matched_keywords->begin(),
match_res.matched_keywords->end());
} else {
matched_behaviors.insert(behavior);
}
}
}
return matched_behaviors;
}
set<ParameterBehavior>
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
{
set<string> keywords;
return getBehavior(key_value_pairs, keywords);
}

View File

@ -124,16 +124,36 @@ setTriggersFlag(const string &key, cereal::JSONInputArchive &ar, EnumClass flag,
}
static void
setLogConfiguration(const ReportIS::StreamType &log_type, const string &log_server_url = "")
setLogConfiguration(
const ReportIS::StreamType &log_type,
const string &log_server_url = "",
const string &protocol = ""
)
{
dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url;
if (log_server_url != "") {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url);
if (log_server_url != "" && protocol != "") {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url, protocol);
} else {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type);
}
}
static string
parseProtocolWithDefault(
const std::string &default_value,
const std::string &key_name,
cereal::JSONInputArchive &archive_in
)
{
string value;
try {
archive_in(cereal::make_nvp(key_name, value));
} catch (const cereal::Exception &e) {
return default_value;
}
return value;
}
void
LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
{
@ -142,6 +162,9 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
parseJSONKey<string>("verbosity", verbosity, archive_in);
parseJSONKey<string>("urlForSyslog", url_for_syslog, archive_in);
parseJSONKey<string>("urlForCef", url_for_cef, archive_in);
parseJSONKey<string>("syslogProtocol", syslog_protocol, archive_in);
syslog_protocol = parseProtocolWithDefault("UDP", "syslogProtocol", archive_in);
cef_protocol = parseProtocolWithDefault("UDP", "cefProtocol", archive_in);
setTriggersFlag("webBody", archive_in, WebLogFields::webBody, log_web_fields);
setTriggersFlag("webHeaders", archive_in, WebLogFields::webHeaders, log_web_fields);
@ -197,11 +220,14 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
case ReportIS::StreamType::JSON_LOG_FILE:
setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE);
break;
case ReportIS::StreamType::JSON_K8S_SVC:
setLogConfiguration(ReportIS::StreamType::JSON_K8S_SVC);
break;
case ReportIS::StreamType::SYSLOG:
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog());
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog(), syslog_protocol);
break;
case ReportIS::StreamType::CEF:
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef());
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef(), cef_protocol);
break;
case ReportIS::StreamType::NONE: break;
case ReportIS::StreamType::COUNT: break;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,9 @@
#include "i_http_manager.h"
#include "i_static_resources_handler.h"
#include "i_socket_is.h"
#include "i_environment.h"
#include "i_shell_cmd.h"
#include "i_tenant_manager.h"
#include "transaction_table_metric.h"
#include "nginx_attachment_metric.h"
#include "nginx_intaker_metric.h"
@ -38,7 +41,10 @@ class NginxAttachment
Singleton::Consume<I_HttpManager>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Socket>,
Singleton::Consume<I_InstanceAwareness>
Singleton::Consume<I_InstanceAwareness>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_TenantManager>
{
public:
NginxAttachment();

View File

@ -28,15 +28,18 @@ ReportMessaging::~ReportMessaging()
LogRest log_rest(report);
auto messaging = Singleton::Consume<I_Messaging>::by<ReportMessaging>();
messaging->sendObjectWithPersistence(
log_rest,
I_Messaging::Method::POST,
url,
"",
true,
message_type_tag,
is_async_message
);
try {
messaging->sendObjectWithPersistence(
log_rest,
I_Messaging::Method::POST,
url,
"",
true,
message_type_tag,
is_async_message
);
} catch (...) {
}
}
ReportMessaging &

View File

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

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__
#define __APPSEC_PRACTICE_SECTION_H__
#include <list>
#include <cereal/archives/json.hpp>
#include <cereal/types/list.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
@ -28,67 +30,24 @@
#include "trusted_sources_section.h"
USE_DEBUG_FLAG(D_K8S_POLICY);
// LCOV_EXCL_START Reason: no test exist
class AppSecWebBotsURI
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots URI";
parseAppsecJSONKey<std::string>("uri", uri, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getURI() const { return uri; }
const std::string & getURI() const;
private:
std::string uri;
};
std::ostream &
operator<<(std::ostream &os, const AppSecWebBotsURI &obj)
{
os << obj.getURI();
return os;
}
std::ostream &
operator<<(std::ostream &os, const std::vector<AppSecWebBotsURI> &obj)
{
os << "[" << std::endl;
makeSeparatedStr(obj, ",");
os << std::endl << "]";
return os;
}
class AppSecPracticeAntiBot
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots";
parseAppsecJSONKey<std::vector<AppSecWebBotsURI>>("injected-URIs", injected_uris, archive_in);
parseAppsecJSONKey<std::vector<AppSecWebBotsURI>>("validated-URIs", validated_uris, archive_in);
parseAppsecJSONKey<std::string>("override-mode", override_mode, archive_in, "Inactive");
}
void
save(cereal::JSONOutputArchive &out_ar) const
{
std::vector<std::string> injected;
std::vector<std::string> validated;
for (const AppSecWebBotsURI &uri : getInjectedURIs()) injected.push_back(uri.getURI());
for (const AppSecWebBotsURI &uri : getValidatedURIs()) injected.push_back(uri.getURI());
out_ar(
cereal::make_nvp("injected", injected),
cereal::make_nvp("validated", validated)
);
}
const std::vector<AppSecWebBotsURI> & getInjectedURIs() const { return injected_uris; }
const std::vector<AppSecWebBotsURI> & getValidatedURIs() const { return validated_uris; }
const std::string & getOverrideMode() const { return override_mode; }
void load(cereal::JSONInputArchive &archive_in);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string override_mode;
@ -96,61 +55,15 @@ private:
std::vector<AppSecWebBotsURI> validated_uris;
};
std::ostream &
operator<<(std::ostream &os, const AppSecPracticeAntiBot &obj)
{
os
<< "injected-URIs: "
<< obj.getInjectedURIs()
<< " validated-URIs: "
<< obj.getValidatedURIs()
<< ", override_mode: "
<< obj.getOverrideMode();
return os;
}
class AppSecWebAttackProtections
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Attack Protections";
parseAppsecJSONKey<std::string>("csrf-protection", csrf_protection, archive_in, "Inactive");
parseAppsecJSONKey<std::string>("error-disclosure", error_disclosure, archive_in, "Inactive");
parseAppsecJSONKey<std::string>("open-redirect", open_redirect, archive_in, "Inactive");
parseAppsecJSONKey<bool>("non-valid-http-methods", non_valid_http_methods, archive_in, false);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string
getCsrfProtectionMode() const
{
if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) {
dbgError(D_K8S_POLICY)
<< "Failed to find a value for "
<< csrf_protection
<< ". Setting CSRF protection to Inactive";
return "Inactive";
}
return key_to_practices_val.at(csrf_protection);
}
const std::string & getErrorDisclosureMode() const { return error_disclosure; }
bool getNonValidHttpMethods() const { return non_valid_http_methods; }
const std::string
getOpenRedirectMode() const
{
if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) {
dbgError(D_K8S_POLICY)
<< "Failed to find a value for "
<< open_redirect
<< ". Setting Open Redirect mode to Inactive";
return "Inactive";
}
return key_to_practices_val.at(open_redirect);
}
const std::string getCsrfProtectionMode() const;
const std::string & getErrorDisclosureMode() const;
bool getNonValidHttpMethods() const;
const std::string getOpenRedirectMode() const;
private:
std::string csrf_protection;
@ -159,53 +72,18 @@ private:
bool non_valid_http_methods;
};
std::ostream &
operator<<(std::ostream &os, const AppSecWebAttackProtections &obj)
{
os
<< " csrf-protection: "
<< obj.getCsrfProtectionMode()
<< " error-disclosure: "
<< obj.getErrorDisclosureMode()
<< " non-valid-http-methods: "
<< obj.getNonValidHttpMethods()
<< " open-redirect: "
<< obj.getOpenRedirectMode();
return os;
}
class AppSecPracticeWebAttacks
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec";
parseAppsecJSONKey<AppSecWebAttackProtections>("protections", protections, archive_in);
parseAppsecJSONKey<std::string>("minimum-confidence", minimum_confidence, archive_in, "critical");
parseAppsecJSONKey<std::string>("override-mode", mode, archive_in, "Unset");
parseAppsecJSONKey<int>("max-body-size-kb", max_body_size_kb, archive_in, 1000000);
parseAppsecJSONKey<int>("max-header-size-bytes", max_header_size_bytes, archive_in, 102400);
parseAppsecJSONKey<int>("max-object-depth", max_object_depth, archive_in, 40);
parseAppsecJSONKey<int>("max-url-size-bytes", max_url_size_bytes, archive_in, 32768);
}
void load(cereal::JSONInputArchive &archive_in);
int getMaxBodySizeKb() const { return max_body_size_kb; }
int getMaxHeaderSizeBytes() const { return max_header_size_bytes; }
int getMaxObjectDepth() const { return max_object_depth; }
int getMaxUrlSizeBytes() const { return max_url_size_bytes; }
const std::string & getMinimumConfidence() const { return minimum_confidence; }
const AppSecWebAttackProtections & getprotections() const { return protections; }
const std::string &
getMode(const std::string &default_mode = "Inactive") const
{
if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) {
dbgError(D_K8S_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode;
return default_mode;
}
return key_to_practices_val.at(mode);
}
int getMaxBodySizeKb() const;
int getMaxHeaderSizeBytes() const;
int getMaxObjectDepth() const;
int getMaxUrlSizeBytes() const;
const std::string & getMinimumConfidence() const;
const AppSecWebAttackProtections & getprotections() const;
const std::string & getMode(const std::string &default_mode = "Inactive") const;
private:
int max_body_size_kb;
@ -217,114 +95,42 @@ private:
AppSecWebAttackProtections protections;
};
std::ostream &
operator<<(std::ostream &os, const AppSecPracticeWebAttacks &obj)
{
os
<< "mode: "
<< obj.getMode()
<< " max-body-size-kb: "
<< obj.getMaxBodySizeKb()
<< " max-header-size-bytes: "
<< obj.getMaxHeaderSizeBytes()
<< " max-object-depth: "
<< obj.getMaxObjectDepth()
<< " max-url-size-bytes: "
<< obj.getMaxUrlSizeBytes()
<< " minimum-confidence: "
<< obj.getMinimumConfidence()
<< " protections: "
<< obj.getprotections();
return os;
}
class AppSecPracticeSnortSignatures
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Snort Signatures practice";
parseAppsecJSONKey<std::string>("override-mode", override_mode, archive_in, "Inactive");
parseAppsecJSONKey<std::vector<std::string>>("configmap", config_map, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getOverrideMode() const { return override_mode; }
const std::vector<std::string> & getConfigMap() const { return config_map; }
const std::string & getOverrideMode() const;
const std::vector<std::string> & getConfigMap() const;
private:
std::string override_mode;
std::vector<std::string> config_map;
};
std::ostream &
operator<<(std::ostream &os, const AppSecPracticeSnortSignatures &obj)
{
os
<< "override mode: "
<< obj.getOverrideMode()
<< ". Config map: [" << std::endl
<< makeSeparatedStr(obj.getConfigMap(), ",")
<< std::endl << "]";
return os;
}
class AppSecPracticeOpenSchemaAPI
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSecPracticeOpenSchemaAPI practice";
parseAppsecJSONKey<std::string>("override-mode", override_mode, archive_in, "Inactive");
parseAppsecJSONKey<std::vector<std::string>>("configmap", config_map, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getOverrideMode() const { return override_mode; }
const std::vector<std::string> & getConfigMap() const { return config_map; }
const std::string & getOverrideMode() const;
const std::vector<std::string> & getConfigMap() const;
private:
std::string override_mode;
std::vector<std::string> config_map;
};
std::ostream &
operator<<(std::ostream &os, const AppSecPracticeOpenSchemaAPI &obj)
{
os
<< "override mode: "
<< obj.getOverrideMode()
<< ". Config map: [" << std::endl
<< makeSeparatedStr(obj.getConfigMap(), ",")
<< std::endl << "]";
return os;
}
class AppSecPracticeSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec";
parseAppsecJSONKey<AppSecPracticeOpenSchemaAPI>(
"openapi-schema-validation",
openapi_schema_validation,
archive_in
);
parseAppsecJSONKey<AppSecPracticeSnortSignatures>("snort-signatures", snort_signatures, archive_in);
parseAppsecJSONKey<AppSecPracticeWebAttacks>("web-attacks", web_attacks, archive_in);
parseAppsecJSONKey<AppSecPracticeAntiBot>("anti-bot", anti_bot, archive_in);
parseAppsecJSONKey<std::string>("name", practice_name, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const { return openapi_schema_validation; }
const AppSecPracticeSnortSignatures & getSnortSignatures() const { return snort_signatures; }
const AppSecPracticeWebAttacks & getWebAttacks() const { return web_attacks; }
const AppSecPracticeAntiBot & getAntiBot() const { return anti_bot; }
const std::string & getName() const { return practice_name; }
const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const;
const AppSecPracticeSnortSignatures & getSnortSignatures() const;
const AppSecPracticeWebAttacks & getWebAttacks() const;
const AppSecPracticeAntiBot & getAntiBot() const;
const std::string & getName() const;
private:
AppSecPracticeOpenSchemaAPI openapi_schema_validation;
@ -334,24 +140,11 @@ private:
std::string practice_name;
};
std::ostream &
operator<<(std::ostream &os, const AppSecPracticeSpec &obj)
{
os
<< "Open Schema API:" << std::endl
<< obj.getOpenSchemaValidation()
<< std::endl << "Snort Signatures:" << std::endl
<< obj.getOpenSchemaValidation()
<< std::endl << "Web Attacks:" << std::endl
<< obj.getWebAttacks()
<< std::endl << "Web Bots:" << std::endl
<< obj.getAntiBot();
return os;
}
class PracticeAdvancedConfig
{
public:
PracticeAdvancedConfig() {}
PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec)
:
http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()),
@ -361,19 +154,7 @@ public:
url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes())
{}
void
save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("httpHeaderMaxSize", http_header_max_size),
cereal::make_nvp("httpIllegalMethodsAllowed", http_illegal_methods_allowed),
cereal::make_nvp("httpRequestBodyMaxSize", http_request_body_max_size),
cereal::make_nvp("jsonMaxObjectDepth", json_max_object_depth),
cereal::make_nvp("urlMaxSize", url_max_size)
);
}
void setIllegalMethodsAllowed(int val) { http_illegal_methods_allowed = val; };
void save(cereal::JSONOutputArchive &out_ar) const;
private:
int http_header_max_size;
@ -394,16 +175,7 @@ public:
log(log_section)
{}
void
save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("$triggerType", trigger_type),
cereal::make_nvp("id", id),
cereal::make_nvp("name", name),
cereal::make_nvp("log", log)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string trigger_type;
@ -415,23 +187,10 @@ private:
class AppSecOverride
{
public:
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources)
{
std::string source_ident = parsed_trusted_sources.getSourceIdent();
std::map<std::string, std::string> behavior = {{"httpSourceId", source_ident}};
parsed_behavior.push_back(behavior);
parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}};
}
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources);
void save(cereal::JSONOutputArchive &out_ar) const;
void
save(cereal::JSONOutputArchive &out_ar) const
{
std::string parameter_type = "TrustedSource";
out_ar(
cereal::make_nvp("parsedBehavior", parsed_behavior),
cereal::make_nvp("parsedMatch", parsed_match)
);
}
private:
std::vector<std::map<std::string, std::string>> parsed_behavior;
std::map<std::string, std::string> parsed_match;
@ -440,6 +199,8 @@ private:
class WebAppSection
{
public:
WebAppSection() {}
WebAppSection(
const std::string &_application_urls,
const std::string &_asset_id,
@ -451,75 +212,12 @@ public:
const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources)
:
application_urls(_application_urls),
asset_id(_asset_id),
asset_name(_asset_name),
rule_id(_rule_id),
rule_name(_rule_name),
practice_id(_practice_id),
practice_name(_practice_name),
context("practiceId(" + practice_id +")"),
web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()),
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
practice_advanced_config(parsed_appsec_spec),
anti_bots(parsed_appsec_spec.getAntiBot()),
trusted_sources({parsed_trusted_sources})
{
web_attack_mitigation = true;
web_attack_mitigation_action =
web_attack_mitigation_severity == "critical" ? "low" :
web_attack_mitigation_severity == "high" ? "balanced" :
web_attack_mitigation_severity == "medium" ? "high" :
"Error";
const AppSecTrustedSources &parsed_trusted_sources
);
triggers.push_back(TriggersInWaapSection(parsed_log_trigger));
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
overrides.push_back(AppSecOverride(source_ident));
}
}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
std::string disabled_str = "Disabled";
std::string detect_str = "Detect";
std::vector<std::string> empty_list;
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("webAttackMitigation", web_attack_mitigation),
cereal::make_nvp("webAttackMitigationSeverity", web_attack_mitigation_severity),
cereal::make_nvp("webAttackMitigationAction", web_attack_mitigation_action),
cereal::make_nvp("webAttackMitigationMode", web_attack_mitigation_mode),
cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config),
cereal::make_nvp("csrfProtection", disabled_str),
cereal::make_nvp("openRedirect", disabled_str),
cereal::make_nvp("errorDisclosure", disabled_str),
cereal::make_nvp("practiceId", practice_id),
cereal::make_nvp("practiceName", practice_name),
cereal::make_nvp("assetId", asset_id),
cereal::make_nvp("assetName", asset_name),
cereal::make_nvp("ruleId", rule_id),
cereal::make_nvp("ruleName", rule_name),
cereal::make_nvp("triggers", triggers),
cereal::make_nvp("applicationUrls", application_urls),
cereal::make_nvp("overrides", overrides),
cereal::make_nvp("trustedSources", trusted_sources),
cereal::make_nvp("waapParameters", empty_list),
cereal::make_nvp("botProtection", false),
cereal::make_nvp("antiBot", anti_bots),
cereal::make_nvp("botProtection_v2", detect_str)
);
}
const std::string & getPracticeId() const { return practice_id; }
bool
operator<(const WebAppSection &other) const
{
return getPracticeId() < other.getPracticeId();
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getPracticeId() const;
bool operator<(const WebAppSection &other) const;
private:
std::string application_urls;
@ -573,36 +271,9 @@ public:
practice_advanced_config(parsed_appsec_spec)
{}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
std::string disabled_str = "Disabled";
std::vector<std::string> empty_list;
out_ar(
cereal::make_nvp("application_urls", application_urls),
cereal::make_nvp("asset_id", asset_id),
cereal::make_nvp("asset_name", asset_name),
cereal::make_nvp("context", context),
cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config),
cereal::make_nvp("practice_id", practice_id),
cereal::make_nvp("practice_name", practice_name),
cereal::make_nvp("ruleId", rule_id),
cereal::make_nvp("ruleName", rule_name),
cereal::make_nvp("schemaValidation", false),
cereal::make_nvp("schemaValidation_v2", disabled_str),
cereal::make_nvp("web_attack_mitigation", web_attack_mitigation),
cereal::make_nvp("web_attack_mitigation_action", web_attack_mitigation_action),
cereal::make_nvp("web_attack_mitigation_severity", web_attack_mitigation_severity),
cereal::make_nvp("web_attack_mitigation_mode", web_attack_mitigation_mode),
cereal::make_nvp("oas", empty_list),
cereal::make_nvp("trustedSources", empty_list),
cereal::make_nvp("triggers", empty_list),
cereal::make_nvp("waapParameters", empty_list),
cereal::make_nvp("overrides", empty_list)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getPracticeId() const { return practice_id; }
const std::string & getPracticeId() const;
private:
std::string application_urls;
@ -630,14 +301,7 @@ public:
webApplicationPractices(_webApplicationPractices),
webAPIPractices(_webAPIPractices) {}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("WebAPISecurity", webAPIPractices),
cereal::make_nvp("WebApplicationSecurity", webApplicationPractices)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<WebAppSection> webApplicationPractices;
@ -652,54 +316,27 @@ public:
app_sec_rulebase(_app_sec)
{}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(cereal::make_nvp("WAAP", app_sec_rulebase));
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
AppSecRulebase app_sec_rulebase;
};
class ParsedRule
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec ParsedRule";
parseAppsecJSONKey<std::vector<std::string>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("triggers", log_triggers, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("practices", practices, archive_in);
parseAppsecJSONKey<std::string>("mode", mode, archive_in);
parseAppsecJSONKey<std::string>("custom-response", custom_response, archive_in);
parseAppsecJSONKey<std::string>("source-identifiers", source_identifiers, archive_in);
parseAppsecJSONKey<std::string>("trusted-sources", trusted_sources, archive_in);
try {
archive_in(cereal::make_nvp("host", host));
} catch (const cereal::Exception &e)
{} // The default ParsedRule does not hold a host, so no error handling
}
void load(cereal::JSONInputArchive &archive_in);
const std::vector<std::string> & getExceptions() const { return exceptions; }
const std::vector<std::string> & getLogTriggers() const { return log_triggers; }
const std::vector<std::string> & getPractices() const { return practices; }
const std::string & getHost() const { return host; }
const std::string & getMode() const { return mode; }
void setMode(const std::string &_mode) { mode = _mode; };
const std::string & getCustomResponse() const { return custom_response; }
const std::string & getSourceIdentifiers() const { return source_identifiers; }
const std::string & getTrustedSources() const { return trusted_sources; }
const std::vector<std::string> & getExceptions() const;
const std::vector<std::string> & getLogTriggers() const;
const std::vector<std::string> & getPractices() const;
const std::string & getHost() const;
const std::string & getMode() const;
void setHost(const std::string &_host);
void setMode(const std::string &_mode);
const std::string & getCustomResponse() const;
const std::string & getSourceIdentifiers() const;
const std::string & getTrustedSources() const;
private:
std::vector<std::string> exceptions;
@ -712,88 +349,32 @@ private:
std::string trusted_sources;
};
std::ostream &
operator<<(std::ostream &os, const ParsedRule &obj)
{
os
<< "host: "
<< obj.getHost()
<< std::endl << "log trigger: "
<< makeSeparatedStr(obj.getLogTriggers(), ",")
<< std::endl << "mode: "
<< obj.getMode()
<< std::endl << "practices: "
<< makeSeparatedStr(obj.getPractices(), ",")
<< std::endl << "web responce: "
<< obj.getCustomResponse()
<< std::endl << " Exceptions: [" << std::endl
<< makeSeparatedStr(obj.getExceptions(), ",")
<< std::endl << "]";
return os;
}
class AppsecPolicySpec : Singleton::Consume<I_Environment>
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec";
parseAppsecJSONKey<ParsedRule>("default", default_rule, archive_in);
auto default_mode_annot =
Singleton::Consume<I_Environment>::by<AppsecPolicySpec>()->get<std::string>("default mode annotation");
if (default_mode_annot.ok() && !default_mode_annot.unpack().empty() && default_rule.getMode().empty()) {
default_rule.setMode(default_mode_annot.unpack());
}
parseAppsecJSONKey<std::vector<ParsedRule>>("specific-rules", specific_rules, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const ParsedRule & getDefaultRule() const { return default_rule; }
const std::vector<ParsedRule> & getSpecificRules() const { return specific_rules; }
const ParsedRule & getDefaultRule() const;
const std::list<ParsedRule> & getSpecificRules() const;
private:
ParsedRule default_rule;
std::vector<ParsedRule> specific_rules;
std::list<ParsedRule> specific_rules;
};
class AppsecLinuxPolicy : Singleton::Consume<I_Environment>
{
public:
void
serialize(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec";
parseAppsecJSONKey<AppsecPolicySpec>("policies", policies, archive_in);
parseAppsecJSONKey<std::vector<AppSecPracticeSpec>>("practices", practices, archive_in);
parseAppsecJSONKey<std::vector<AppsecTriggerSpec>>("logtriggers", log_triggers, archive_in);
parseAppsecJSONKey<std::vector<AppSecCustomResponseSpec>>("customresponses", custom_responses, archive_in);
parseAppsecJSONKey<std::vector<AppsecExceptionSpec>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<std::vector<TrustedSourcesSpec>>("trustedsources", trusted_sources, archive_in);
parseAppsecJSONKey<std::vector<SourceIdentifierSpecWrapper>>(
"sourceidentifiers",
sources_identifier,
archive_in
);
}
serialize(cereal::JSONInputArchive &archive_in);
const AppsecPolicySpec & getAppsecPolicySpec() const { return policies; }
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const { return practices; }
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const { return log_triggers; }
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const { return custom_responses; }
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const { return exceptions; }
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const { return trusted_sources; }
const std::vector<SourceIdentifierSpecWrapper> &
getAppsecSourceIdentifierSpecs() const
{
return sources_identifier;
}
const AppsecPolicySpec & getAppsecPolicySpec() const;
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const;
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const;
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const;
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
private:
AppsecPolicySpec policies;
@ -805,16 +386,5 @@ private:
std::vector<SourceIdentifierSpecWrapper> sources_identifier;
};
std::ostream &
operator<<(std::ostream &os, const AppsecPolicySpec &obj)
{
os
<< "Default Rule: "
<< obj.getDefaultRule()
<< std::endl <<"Specific Rules: [" << std::endl
<< makeSeparatedStr(obj.getSpecificRules(), ",")
<< std::endl << "]";
return os;
}
// LCOV_EXCL_STOP
#endif // __APPSEC_PRACTICE_SECTION_H__

View File

@ -30,34 +30,22 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AppsecExceptionSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec exception spec";
parseAppsecJSONKey<std::string>("action", action, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("countryCode", country_code, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("countryName", country_name, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("hostName", host_name, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("paramName", param_name, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("paramValue", param_value, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("protectionName", protection_name, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("sourceIdentifier", source_identifier, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("sourceIp", source_ip, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("url", url, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getAction() const { return action; }
const std::vector<std::string> & getCountryCode() const { return country_code; }
const std::vector<std::string> & getCountryName() const { return country_name; }
const std::vector<std::string> & getHostName() const { return host_name; }
const std::vector<std::string> & getParamName() const { return param_name; }
const std::vector<std::string> & getParamValue() const { return param_value; }
const std::vector<std::string> & getProtectionName() const { return protection_name; }
const std::vector<std::string> & getSourceIdentifier() const { return source_identifier; }
const std::vector<std::string> & getSourceIp() const { return source_ip; }
const std::vector<std::string> & getUrl() const { return url; }
const std::string & getName() const;
const std::string & getAction() const;
const std::vector<std::string> & getCountryCode() const;
const std::vector<std::string> & getCountryName() const;
const std::vector<std::string> & getHostName() const;
const std::vector<std::string> & getParamName() const;
const std::vector<std::string> & getParamValue() const;
const std::vector<std::string> & getProtectionName() const;
const std::vector<std::string> & getSourceIdentifier() const;
const std::vector<std::string> & getSourceIp() const;
const std::vector<std::string> & getUrl() const;
private:
std::string name;
std::string action;
std::vector<std::string> country_code;
std::vector<std::string> country_name;
@ -70,71 +58,11 @@ private:
std::vector<std::string> url;
};
std::ostream &
operator<<(std::ostream &os, const AppsecExceptionSpec &obj)
{
os
<< "action: "
<< makeSeparatedStr(obj.getAction(), ",")
<< "countryCode: "
<< makeSeparatedStr(obj.getCountryCode(), ",")
<< "countryName: "
<< makeSeparatedStr(obj.getCountryName(), ",")
<< "hostName: "
<< makeSeparatedStr(obj.getHostName(), ",")
<< "paramName: "
<< makeSeparatedStr(obj.getParamName(), ",")
<< "paramValue: "
<< makeSeparatedStr(obj.getParamValue(), ",")
<< "protectionName: "
<< makeSeparatedStr(obj.getProtectionName(), ",")
<< "sourceIdentifier: "
<< makeSeparatedStr(obj.getSourceIdentifier(), ",")
<< "sourceIp: "
<< makeSeparatedStr(obj.getSourceIp(), ",")
<< "url: "
<< makeSeparatedStr(obj.getUrl(), ",");
return os;
}
class ExceptionMatch
{
public:
ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
:
match_type(MatchType::Operator),
op("and")
{
if (!parsed_exception.getCountryCode().empty()) {
items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode()));
}
if (!parsed_exception.getCountryName().empty()) {
items.push_back(ExceptionMatch("countryName", parsed_exception.getCountryName()));
}
if (!parsed_exception.getHostName().empty()) {
items.push_back(ExceptionMatch("hostName", parsed_exception.getHostName()));
}
if (!parsed_exception.getParamName().empty()) {
items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName()));
}
if (!parsed_exception.getParamValue().empty()) {
items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue()));
}
if (!parsed_exception.getProtectionName().empty()) {
items.push_back(ExceptionMatch("protectionName", parsed_exception.getProtectionName()));
}
if (!parsed_exception.getSourceIdentifier().empty()) {
items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier()));
}
if (!parsed_exception.getSourceIp().empty()) {
items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp()));
}
if (!parsed_exception.getUrl().empty()) {
items.push_back(ExceptionMatch("url", parsed_exception.getUrl()));
}
}
ExceptionMatch() {}
ExceptionMatch(const AppsecExceptionSpec &parsed_exception);
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value)
:
match_type(MatchType::Condition),
@ -143,34 +71,7 @@ public:
value(_value)
{}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
switch (match_type) {
case (MatchType::Condition): {
std::string type_str = "condition";
out_ar(
cereal::make_nvp("key", key),
cereal::make_nvp("op", op),
cereal::make_nvp("type", type_str),
cereal::make_nvp("value", value)
);
break;
}
case (MatchType::Operator): {
std::string type_str = "operator";
out_ar(
cereal::make_nvp("op", op),
cereal::make_nvp("type", type_str),
cereal::make_nvp("items", items)
);
break;
}
default: {
dbgError(D_K8S_POLICY) << "No match for exception match type: " << static_cast<int>(match_type);
}
}
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
MatchType match_type;
@ -183,31 +84,14 @@ private:
class ExceptionBehavior
{
public:
ExceptionBehavior() {}
ExceptionBehavior(
const std::string &_key,
const std::string &_value)
:
key(_key),
value(_value)
{
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what();
}
}
const std::string &_value
);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("key", key),
cereal::make_nvp("value", value),
cereal::make_nvp("id", id)
);
}
const std::string getBehaviorId() const { return id; }
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string getBehaviorId() const;
private:
std::string key;
@ -218,6 +102,7 @@ private:
class InnerException
{
public:
InnerException() {}
InnerException(
ExceptionBehavior _behavior,
ExceptionMatch _match)
@ -225,22 +110,9 @@ public:
behavior(_behavior),
match(_match) {}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("behavior", behavior),
cereal::make_nvp("match", match)
);
}
const std::string getBehaviorId() const { return behavior.getBehaviorId(); }
bool
operator<(const InnerException &other) const
{
return getBehaviorId() < other.getBehaviorId();
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string getBehaviorId() const;
bool operator<(const InnerException &other) const;
private:
ExceptionBehavior behavior;
@ -250,28 +122,8 @@ private:
class ExceptionsRulebase
{
public:
ExceptionsRulebase(
std::vector<InnerException> _exceptions)
:
exceptions(_exceptions)
{
std::string context_id_str = "";
for (const InnerException exception : exceptions) {
std::string curr_id = "parameterId(" + exception.getBehaviorId() + "), ";
context_id_str += curr_id;
}
context_id_str = context_id_str.substr(0, context_id_str.size() - 2);
context = "Any(" + context_id_str + ")";
}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("exceptions", exceptions)
);
}
ExceptionsRulebase(std::vector<InnerException> _exceptions);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string context;
@ -286,11 +138,7 @@ public:
public:
Exception(const std::vector<ExceptionsRulebase> &_exception) : exception(_exception) {}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(cereal::make_nvp("exception", exception));
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<ExceptionsRulebase> exception;
@ -298,13 +146,7 @@ public:
ExceptionsWrapper(const std::vector<ExceptionsRulebase> &_exception) : exception_rulebase(Exception(_exception))
{}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", exception_rulebase)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
Exception exception_rulebase;

View File

@ -21,26 +21,21 @@
#include "debug.h"
#include "rest.h"
#include "cereal/archives/json.hpp"
#include <cereal/types/map.hpp>
#include "k8s_policy_common.h"
USE_DEBUG_FLAG(D_K8S_POLICY);
// LCOV_EXCL_START Reason: no test exist
class IngressMetadata
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "IngressMetadata load";
parseAppsecJSONKey<std::string>("name", name, archive_in);
parseAppsecJSONKey<std::string>("resourceVersion", resourceVersion, archive_in);
parseAppsecJSONKey<std::string>("namespace", namespace_name, archive_in);
parseAppsecJSONKey<std::map<std::string, std::string>>("annotations", annotations, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const { return name; }
const std::string & getResourceVersion() const { return resourceVersion; }
const std::string & getNamespace() const { return namespace_name; }
const std::map<std::string, std::string> & getAnnotations() const { return annotations; }
const std::string & getName() const;
const std::string & getResourceVersion() const;
const std::string & getNamespace() const;
const std::map<std::string, std::string> & getAnnotations() const;
private:
std::string name;
@ -53,19 +48,15 @@ class IngressRulePath
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path";
parseAppsecJSONKey<std::string>("path", path, archive_in);
}
load(cereal::JSONInputArchive &archive_in);
const std::string & getPath() const { return path; }
const std::string & getPath() const;
private:
std::string path;
};
std::ostream &
inline std::ostream &
operator<<(std::ostream &os, const IngressRulePath &obj)
{
os << obj.getPath();
@ -75,14 +66,9 @@ operator<<(std::ostream &os, const IngressRulePath &obj)
class IngressRulePathsWrapper
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path wrapper";
parseAppsecJSONKey<std::vector<IngressRulePath>>("paths", paths, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::vector<IngressRulePath> & getRulePaths() const { return paths; }
const std::vector<IngressRulePath> & getRulePaths() const;
private:
std::vector<IngressRulePath> paths;
@ -91,23 +77,17 @@ private:
class IngressDefinedRule
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule";
parseAppsecJSONKey<std::string>("host", host, archive_in);
parseAppsecJSONKey<IngressRulePathsWrapper>("http", paths_wrapper, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getHost() const { return host; }
const IngressRulePathsWrapper & getPathsWrapper() const { return paths_wrapper; }
const std::string & getHost() const;
const IngressRulePathsWrapper & getPathsWrapper() const;
private:
std::string host;
IngressRulePathsWrapper paths_wrapper;
};
std::ostream &
inline std::ostream &
operator<<(std::ostream &os, const IngressDefinedRule &obj)
{
os
@ -123,13 +103,9 @@ class DefaultBackend
{
public:
void
load(cereal::JSONInputArchive &)
{
dbgTrace(D_K8S_POLICY) << "Loading Default Backend";
is_exists = true;
}
load(cereal::JSONInputArchive &);
bool isExists() const { return is_exists; }
bool isExists() const;
private:
bool is_exists = false;
@ -139,17 +115,11 @@ class IngressSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading single ingress spec";
parseAppsecJSONKey<std::string>("ingressClassName", ingress_class_name, archive_in);
parseAppsecJSONKey<std::vector<IngressDefinedRule>>("rules", rules, archive_in);
parseAppsecJSONKey<DefaultBackend>("defaultBackend", default_backend, archive_in);
}
load(cereal::JSONInputArchive &archive_in);
const std::string & getIngressClassName() const { return ingress_class_name; }
const std::vector<IngressDefinedRule> & getRules() const { return rules; }
bool isDefaultBackendExists() const { return default_backend.isExists(); }
const std::string & getIngressClassName() const;
const std::vector<IngressDefinedRule> & getRules() const;
bool isDefaultBackendExists() const;
private:
std::string ingress_class_name;
@ -157,31 +127,14 @@ private:
DefaultBackend default_backend;
};
std::ostream &
operator<<(std::ostream &os, const IngressSpec &obj)
{
os
<< "Ingress Spec - ingressClassName: "
<< obj.getIngressClassName()
<< ", rules: [" << std::endl
<< makeSeparatedStr(obj.getRules(), ",")
<< std::endl << "]";
return os;
}
class SingleIngressData
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading single ingress data";
parseAppsecJSONKey<IngressMetadata>("metadata", metadata, archive_in);
parseAppsecJSONKey<IngressSpec>("spec", spec, archive_in);
}
load(cereal::JSONInputArchive &archive_in);
const IngressMetadata & getMetadata() const { return metadata; }
const IngressSpec & getSpec() const { return spec; }
const IngressMetadata & getMetadata() const;
const IngressSpec & getSpec() const;
private:
IngressMetadata metadata;
@ -192,29 +145,10 @@ private:
class IngressData : public ClientRest
{
public:
bool
loadJson(const std::string &json)
{
std::string modified_json = json;
modified_json.pop_back();
std::stringstream in;
in.str(modified_json);
dbgTrace(D_K8S_POLICY) << "Loading ingress data";
try {
cereal::JSONInputArchive in_ar(in);
in_ar(
cereal::make_nvp("apiVersion", apiVersion),
cereal::make_nvp("items", items)
);
} catch (cereal::Exception &e) {
dbgError(D_K8S_POLICY) << "Failed to load ingress data JSON. Error: " << e.what();
return false;
}
return true;
}
bool loadJson(const std::string &json);
const std::string & getapiVersion() const { return apiVersion; }
const std::vector<SingleIngressData> & getItems() const { return items; }
const std::string & getapiVersion() const;
const std::vector<SingleIngressData> & getItems() const;
private:
std::string apiVersion;

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
{
public:
AssetUrlParser() {}
static AssetUrlParser parse(const std::string &uri);
std::string query_string, asset_uri, protocol, asset_url, port;
AssetUrlParser()
{}
AssetUrlParser(const std::string &asset)
{
parse(asset);
}
private:
static AssetUrlParser
parse(const std::string &uri)
{
AssetUrlParser result;
using iterator_t = std::string::const_iterator;
if (uri.length() == 0) return result;
iterator_t uri_end = uri.end();
// get query start
iterator_t query_start = std::find(uri.begin(), uri_end, '?');
// protocol
iterator_t protocol_start = uri.begin();
iterator_t protocol_end = std::find(protocol_start, uri_end, ':'); //"://");
if (protocol_end != uri_end) {
std::string http_protocol = &*(protocol_end);
if ((http_protocol.length() > 3) && (http_protocol.substr(0, 3) == "://")) {
result.protocol = std::string(protocol_start, protocol_end);
protocol_end += 3; // ://
} else {
protocol_end = uri.begin(); // no protocol
}
} else {
protocol_end = uri.begin(); // no protocol
}
// URL
iterator_t host_start = protocol_end;
iterator_t path_start = std::find(host_start, uri_end, '/');
iterator_t host_end = std::find(protocol_end, (path_start != uri_end) ? path_start : query_start, ':');
result.asset_url = std::string(host_start, host_end);
// port
if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { // we have a port
host_end++;
iterator_t portEnd = (path_start != uri_end) ? path_start : query_start;
result.port = std::string(host_end, portEnd);
}
// URI
if (path_start != uri_end) result.asset_uri = std::string(path_start, query_start);
// query
if (query_start != uri_end) result.query_string = std::string(query_start, uri.end());
return result;
} // Parse
}; // uri
};
class PracticeSection
{
public:
PracticeSection(const std::string &_id, const std::string &_type, const std::string &_practice_name)
{
auto maybe_type = string_to_practice_type.find(_type);
if (maybe_type == string_to_practice_type.end()) {
dbgError(D_K8S_POLICY) << "Illegal pracrtice type: " << _type;
return;
}
PracticeSection(
const std::string &_id,
const std::string &_type,
const std::string &_practice_name);
type = _type;
name = _practice_name;
id = _id;
}
void save(cereal::JSONOutputArchive &out_ar) const;
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("practiceId", id),
cereal::make_nvp("practiceName", name),
cereal::make_nvp("practiceType", type)
);
}
const std::string & getPracticeId() const { return id; }
const std::string & getPracticeName() const { return name; }
const std::string & getPracticeId() const;
const std::string & getPracticeName() const;
private:
std::string id;
@ -134,30 +58,10 @@ private:
class ParametersSection
{
public:
ParametersSection(
const std::string &_id,
const std::string &_name)
:
name(_name),
id(_id)
{
if (_id.empty() && _name.empty()) {
dbgError(D_K8S_POLICY) << "Illegal Parameter values. Name and ID are empty";
return;
}
}
ParametersSection(const std::string &_id, const std::string &_name);
const std::string & getId() const { return id; }
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("parameterId", id),
cereal::make_nvp("parameterName", name),
cereal::make_nvp("parameterType", type)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getId() const;
private:
std::string name;
@ -171,35 +75,12 @@ public:
RulesTriggerSection(
const std::string &_name,
const std::string &_id,
const std::string &_type)
:
name(_name),
id(_id)
{
if (_name.empty() && _id.empty()) {
dbgError(D_K8S_POLICY) << "Illegal values for trigger. Name and ID are empty";
return;
}
auto maybe_type = string_to_trigger_type.find(_type);
if (maybe_type == string_to_trigger_type.end()) {
dbgError(D_K8S_POLICY) << "Illegal trigger type in rule: " << _type;
return;
}
type = _type;
}
const std::string &_type);
const std::string & getId() const { return id; }
const std::string & getName() const { return id; }
void save(cereal::JSONOutputArchive &out_ar) const;
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("triggerId", id),
cereal::make_nvp("triggerName", name),
cereal::make_nvp("triggerType", type)
);
}
const std::string & getId() const;
const std::string & getName() const;
private:
std::string name;
@ -219,84 +100,19 @@ public:
const std::string &_uri,
std::vector<PracticeSection> _practices,
std::vector<ParametersSection> _parameters,
std::vector<RulesTriggerSection> _triggers)
:
name(_name),
practices(_practices),
parameters(_parameters),
triggers(_triggers)
{
try {
id = _url+_uri;
bool any = _name == "Any" && _url == "Any" && _uri == "Any";
if (_uri != "/") {
context = any ? "All()" : "Any("
"All("
"Any("
"EqualHost(" + _url + ")"
"),"
"EqualListeningPort(80)" +
std::string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
"),"
"All("
"Any("
"EqualHost(" + _url + ")"
"),"
"EqualListeningPort(443)" +
std::string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") +
")"
")";
} else {
context = any ? "All()" : "Any("
"All("
"Any("
"EqualHost(" + _url + ")"
"),"
"EqualListeningPort(80)"
"),"
"All("
"Any("
"EqualHost(" + _url + ")"
"),"
"EqualListeningPort(443)"
")"
")";
}
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate rule UUID. Error: " << e.what();
}
}
std::vector<RulesTriggerSection> _triggers);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
std::string empty_str = "";
out_ar(
cereal::make_nvp("assetId", id),
cereal::make_nvp("assetName", name),
cereal::make_nvp("ruleId", id),
cereal::make_nvp("ruleName", name),
cereal::make_nvp("context", context),
cereal::make_nvp("priority", 1),
cereal::make_nvp("isCleanup", false),
cereal::make_nvp("parameters", parameters),
cereal::make_nvp("practices", practices),
cereal::make_nvp("triggers", triggers),
cereal::make_nvp("zoneId", empty_str),
cereal::make_nvp("zoneName", empty_str)
);
}
const std::string & getRuleId() const { return id; }
const std::string & getAssetName() const { return name; }
const std::string & getRuleName() const { return name; }
const std::string & getAsstId() const { return id; }
const std::string & getPracticeId() const { return practices[0].getPracticeId(); }
const std::string & getPracticeName() const { return practices[0].getPracticeName(); }
const std::vector<PracticeSection> & getPractice() const { return practices; }
const std::vector<ParametersSection> & getParameters() const { return parameters; }
const std::vector<RulesTriggerSection> & getTriggers() const { return triggers; }
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getRuleId() const;
const std::string & getAssetName() const;
const std::string & getRuleName() const;
const std::string & getAssetId() const;
const std::string & getPracticeId() const;
const std::string & getPracticeName() const;
const std::vector<PracticeSection> & getPractice() const;
const std::vector<ParametersSection> & getParameters() const;
const std::vector<RulesTriggerSection> & getTriggers() const;
private:
std::string context;
@ -313,60 +129,13 @@ public:
class RulesConfig
{
public:
RulesConfig(const std::vector<RulesConfigRulebase> &_rules_config)
:
rules_config(_rules_config)
{
sort(rules_config.begin(), rules_config.end(), sortBySpecific);
}
RulesConfig(const std::vector<RulesConfigRulebase> &_rules_config);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulesConfig", rules_config)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
static bool
sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second)
{
return sortBySpecificAux(first.getAssetName(), second.getAssetName());
}
static bool
sortBySpecificAux(const std::string &first, const std::string &second)
{
if (first.empty()) return false;
if (second.empty()) return true;
AssetUrlParser first_parsed = AssetUrlParser(first);
AssetUrlParser second_parsed = AssetUrlParser(second);
// sort by URL
if (first_parsed.asset_url == "*" && second_parsed.asset_url != "*") return false;
if (second_parsed.asset_url == "*" && first_parsed.asset_url != "*") return true;
// sort by port
if (first_parsed.port == "*" && second_parsed.port != "*") return false;
if (second_parsed.port == "*" && first_parsed.port != "*") return true;
// sort by URI
if (first_parsed.asset_uri == "*" && second_parsed.asset_uri != "*") return false;
if (second_parsed.asset_uri == "*" && first_parsed.asset_uri != "*") return true;
if (first_parsed.asset_uri.empty()) return false;
if (second_parsed.asset_uri.empty()) return true;
if (second_parsed.asset_uri.find(first_parsed.asset_uri) != std::string::npos) return false;
if (first_parsed.asset_uri.find(second_parsed.asset_uri) != std::string::npos) return true;
if (first_parsed.asset_url.empty()) return false;
if (second_parsed.asset_url.empty()) return false;
return second < first;
}
static bool sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second);
static bool sortBySpecificAux(const std::string &first, const std::string &second);
std::vector<RulesConfigRulebase> rules_config;
};
@ -376,13 +145,7 @@ public:
rules_config_rulebase(RulesConfig(_rules_config))
{}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", rules_config_rulebase)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
RulesConfig rules_config_rulebase;

View File

@ -28,31 +28,10 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AgentSettingsSection
{
public:
AgentSettingsSection(
const std::string &_key,
const std::string &_value)
:
key(_key),
value(_value)
{
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what();
}
}
AgentSettingsSection(const std::string &_key, const std::string &_value);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("key", key),
cereal::make_nvp("value", value)
);
}
const std::string & getSettingId() const { return id; }
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getSettingId() const;
private:
std::string id;
@ -65,20 +44,7 @@ class SettingsRulebase
public:
SettingsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
std::string profile_type = "Kubernetes";
std::string upgrade_mode = "automatic";
out_ar(
cereal::make_nvp("agentSettings", agentSettings),
cereal::make_nvp("agentType", profile_type),
cereal::make_nvp("allowOnlyDefinedApplications", false),
cereal::make_nvp("anyFog", true),
cereal::make_nvp("maxNumberOfAgents", 10),
cereal::make_nvp("upgradeMode", upgrade_mode)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<AgentSettingsSection> agentSettings;
@ -87,27 +53,9 @@ private:
class SettingsWrapper
{
public:
SettingsWrapper(SettingsRulebase _agent) : agent(_agent)
{
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate Settings Wrapper UUID. Error: " << e.what();
}
}
SettingsWrapper(SettingsRulebase _agent);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("profileType", profileType),
cereal::make_nvp("tokenType", isToken),
cereal::make_nvp("tokenType", tokenType),
cereal::make_nvp("name", name),
cereal::make_nvp("id", id),
cereal::make_nvp("agent", agent)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string profileType = "agent";

View File

@ -27,24 +27,9 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class AgentSettingsSection
{
public:
AgentSettingsSection(std::string _key, std::string _value) : key(_key), value(_value)
{
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what();
}
}
AgentSettingsSection(std::string _key, std::string _value);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("key", key),
cereal::make_nvp("value", value)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string id;
@ -57,20 +42,7 @@ class IpsSnortSigsRulebase
public:
IpsSnortSigsRulebase(std::vector<AgentSettingsSection> _agentSettings) : agentSettings(_agentSettings) {}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
std::string profile_type = "KubernetesProfile";
std::string upgrade_mode = "automatic";
out_ar(
cereal::make_nvp("agentSettings", agentSettings),
cereal::make_nvp("agentType", profile_type),
cereal::make_nvp("allowOnlyDefinedApplications", false),
cereal::make_nvp("anyFog", true),
cereal::make_nvp("maxNumberOfAgents", 10),
cereal::make_nvp("upgradeMode", upgrade_mode)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<AgentSettingsSection> agentSettings;

View File

@ -52,76 +52,14 @@ public:
const std::string &_cefIpAddress,
int _syslogPortNum,
const std::string &_syslogIpAddress,
bool _beautify_logs)
:
name(_name),
verbosity(_verbosity),
extendloggingMinSeverity(_extendloggingMinSeverity),
extendlogging(_extendlogging),
logToAgent(_logToAgent),
logToCef(_logToCef),
logToCloud(_logToCloud),
logToSyslog(_logToSyslog),
responseBody(_responseBody),
tpDetect(_tpDetect),
tpPrevent(_tpPrevent),
webBody(_webBody),
webHeaders(_webHeaders),
webRequests(_webRequests),
webUrlPath(_webUrlPath),
webUrlQuery(_webUrlQuery),
cefPortNum (_cefPortNum),
cefIpAddress (_cefIpAddress),
syslogPortNum (_syslogPortNum),
syslogIpAddress (_syslogIpAddress),
beautify_logs(_beautify_logs)
{
try {
id = to_string(boost::uuids::random_generator()());
context = "triggerId(" + id + ")";
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate log trigger UUID. Error: " << e.what();
}
}
bool _beautify_logs
);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
std::string trigger_type = "log";
std::string urlForSyslog = syslogIpAddress + ":" + std::to_string(syslogPortNum);
std::string urlForCef = cefIpAddress + ":" + std::to_string(cefPortNum);
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("triggerName", name),
cereal::make_nvp("triggerType", trigger_type),
cereal::make_nvp("verbosity", verbosity),
cereal::make_nvp("acAllow", false),
cereal::make_nvp("acDrop", false),
cereal::make_nvp("complianceViolations", false),
cereal::make_nvp("complianceWarnings", false),
cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity),
cereal::make_nvp("extendlogging", extendlogging),
cereal::make_nvp("logToAgent", logToAgent),
cereal::make_nvp("logToCef", logToCef),
cereal::make_nvp("logToCloud", logToCloud),
cereal::make_nvp("logToSyslog", logToSyslog),
cereal::make_nvp("responseBody", responseBody),
cereal::make_nvp("responseCode", false),
cereal::make_nvp("tpDetect", tpDetect),
cereal::make_nvp("tpPrevent", tpPrevent),
cereal::make_nvp("webBody", webBody),
cereal::make_nvp("webHeaders", webHeaders),
cereal::make_nvp("webRequests", webRequests),
cereal::make_nvp("webUrlPath", webUrlPath),
cereal::make_nvp("webUrlQuery", webUrlQuery),
cereal::make_nvp("urlForSyslog", urlForSyslog),
cereal::make_nvp("urlForCef", urlForCef),
cereal::make_nvp("formatLoggingOutput", beautify_logs)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getTriggerId() const { return id; }
const std::string & getTriggerName() const { return name; }
const std::string & getTriggerId() const;
const std::string & getTriggerName() const;
bool operator<(const LogTriggerSection &other) const;
private:
std::string id;
@ -152,43 +90,22 @@ private:
class WebUserResponseTriggerSection
{
public:
WebUserResponseTriggerSection() {}
WebUserResponseTriggerSection(
const std::string &_name,
const std::string &_details_level,
const std::string &_response_body,
int _response_code,
const std::string &_response_title)
:
name(_name),
context(),
details_level(_details_level),
response_body(_response_body),
response_title(_response_title),
response_code(_response_code)
{
try {
id = to_string(boost::uuids::random_generator()());
context = "triggerId(" + id + ")";
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate webUserResponse trigger UUID. Error: " << e.what();
}
}
const std::string &_response_title
);
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("triggerName", name),
cereal::make_nvp("details level", details_level),
cereal::make_nvp("response body", response_body),
cereal::make_nvp("response code", response_code),
cereal::make_nvp("response title", response_title)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getTriggerId() const { return id; }
const std::string & getTriggerName() const { return name; }
const std::string & getTriggerId() const;
const std::string & getTriggerName() const;
bool operator<(const WebUserResponseTriggerSection &other) const;
private:
std::string id;
@ -203,34 +120,13 @@ private:
class AppSecCustomResponseSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec web user response spec";
parseAppsecJSONKey<int>("http-response-code", httpResponseCode, archive_in, 403);
parseAppsecJSONKey<std::string>("mode", mode, archive_in, "block-page");
parseAppsecJSONKey<std::string>("name", name, archive_in);
if (mode == "block-page") {
parseAppsecJSONKey<std::string>(
"message-body",
messageBody,
archive_in,
"Openappsec's <b>Application Security</b> has detected an attack and blocked it."
);
parseAppsecJSONKey<std::string>(
"message-title",
messageTitle,
archive_in,
"Attack blocked by web application protection"
);
}
}
void load(cereal::JSONInputArchive &archive_in);
int getHttpResponseCode() const { return httpResponseCode; }
const std::string & getMessageBody() const { return messageBody; }
const std::string & getMessageTitle() const { return messageTitle; }
const std::string & getMode() const { return mode; }
const std::string & getName() const { return name; }
int getHttpResponseCode() const;
const std::string & getMessageBody() const;
const std::string & getMessageTitle() const;
const std::string & getMode() const;
const std::string & getName() const;
private:
int httpResponseCode;
@ -240,21 +136,6 @@ private:
std::string name;
};
std::ostream &
operator<<(std::ostream &os, const AppSecCustomResponseSpec &obj)
{
os
<< "mode: "
<< obj.getMode()
<< "," << std::endl << "message-title: "
<< obj.getMessageTitle()
<< "," << std::endl << "message-body: "
<< obj.getMessageBody()
<< "," << std::endl << "http-response-code: "
<< obj.getHttpResponseCode();
return os;
}
class TriggersRulebase
{
public:
@ -266,14 +147,7 @@ public:
webUserResponseTriggers(_webUserResponseTriggers) {}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("log", logTriggers),
cereal::make_nvp("webUserResponse", webUserResponseTriggers)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<LogTriggerSection> logTriggers;
@ -283,49 +157,24 @@ private:
class AppsecTriggerAccessControlLogging
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Access Control Logging";
parseAppsecJSONKey<bool>("allow-events", allow_events, archive_in, false);
parseAppsecJSONKey<bool>("drop-events", drop_events, archive_in, false);
}
void load(cereal::JSONInputArchive &archive_in);
bool isAllowEvents() const { return allow_events; }
bool isDropEvents() const { return drop_events; }
bool isAllowEvents() const;
bool isDropEvents() const;
private:
bool allow_events = false;
bool drop_events = false;
};
std::ostream &
operator<<(std::ostream &os, const AppsecTriggerAccessControlLogging &obj)
{
os
<< "AppSec Trigger - Access Control Logging: "
<< "isAllowEvents: "
<< obj.isAllowEvents()
<< " , isDropEvents: "
<< obj.isDropEvents();
return os;
}
class AppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging";
parseAppsecJSONKey<bool>("enabled", enabled, archive_in, true);
parseAppsecJSONKey<bool>("response-body", response_body, archive_in, false);
parseAppsecJSONKey<std::string>("minimum-severity", minimum_severity, archive_in, "high");
}
void load(cereal::JSONInputArchive &archive_in);
bool isEnabled() const { return enabled; }
bool isResponseBody() const { return response_body; }
const std::string & getMinimumSeverity() const { return minimum_severity; }
bool isEnabled() const;
bool isResponseBody() const;
const std::string & getMinimumSeverity() const;
private:
bool enabled = true;
@ -333,37 +182,15 @@ private:
std::string minimum_severity = "high";
};
std::ostream &
operator<<(std::ostream &os, const AppsecTriggerAdditionalSuspiciousEventsLogging &obj)
{
os
<< "AppsecTriggerAdditionalSuspiciousEventsLogging: "
<< "Enabled: "
<< obj.isEnabled()
<< " response_body: "
<< obj.isResponseBody()
<< " minimum_severity: "
<< obj.getMinimumSeverity();
return os;
}
class AppsecTriggerLogging : public ClientRest
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Logging";
parseAppsecJSONKey<bool>("all-web-requests", all_web_requests, archive_in, false);
parseAppsecJSONKey<bool>("detect-events", detect_events, archive_in, false);
parseAppsecJSONKey<bool>("prevent-events", prevent_events, archive_in, true);
}
load(cereal::JSONInputArchive &archive_in);
bool isAllWebRequests() const { return all_web_requests; }
bool isDetectEvents() const { return detect_events; }
bool isPreventEvents() const { return prevent_events; }
bool isAllWebRequests() const;
bool isDetectEvents() const;
bool isPreventEvents() const;
private:
bool all_web_requests = false;
@ -371,37 +198,15 @@ private:
bool prevent_events = true;
};
std::ostream &
operator<<(std::ostream &os, const AppsecTriggerLogging &obj)
{
os
<< "AppsecTriggerLogging: "
<< "all_web_requests: "
<< obj.isAllWebRequests()
<< ", detect_events: "
<< obj.isDetectEvents()
<< ", prevent_events: "
<< obj.isPreventEvents();
return os;
}
class AppsecTriggerExtendedLogging : public ClientRest
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Extended Logging";
parseAppsecJSONKey<bool>("http-headers", http_headers, archive_in, false);
parseAppsecJSONKey<bool>("request-body", request_body, archive_in, false);
parseAppsecJSONKey<bool>("url-path", url_path, archive_in, false);
parseAppsecJSONKey<bool>("url-query", url_query, archive_in, false);
}
void load(cereal::JSONInputArchive &archive_in);
bool isHttpHeaders() const { return http_headers; }
bool isRequestBody() const { return request_body; }
bool isUrlPath() const { return url_path; }
bool isUrlQuery() const { return url_query; }
bool isHttpHeaders() const;
bool isRequestBody() const;
bool isUrlPath() const;
bool isUrlQuery() const;
private:
bool http_headers = false;
@ -410,36 +215,14 @@ private:
bool url_query = false;
};
std::ostream &
operator<<(std::ostream &os, const AppsecTriggerExtendedLogging &obj)
{
os
<< "AppsecTriggerExtendedLogging: "
<< "http_headers: "
<< obj.isHttpHeaders()
<< ", request_body: "
<< obj.isRequestBody()
<< ", url_path: "
<< obj.isUrlPath()
<< ", url_query: "
<< obj.isUrlQuery();
return os;
}
class LoggingService
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
parseAppsecJSONKey<std::string>("address", address, archive_in);
parseAppsecJSONKey<std::string>("proto", proto, archive_in);
parseAppsecJSONKey<int>("port", port, archive_in, 514);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string & getAddress() const { return address; }
const std::string & getProto() const { return proto; }
int getPort() const { return port; }
const std::string & getAddress() const;
const std::string & getProto() const;
int getPort() const;
private:
std::string address;
@ -452,13 +235,8 @@ class StdoutLogging
public:
StdoutLogging() : format("json") {}
void
load(cereal::JSONInputArchive &archive_in)
{
parseAppsecJSONKey<std::string>("format", format, archive_in, "json");
}
const std::string & getFormat() const { return format; }
void load(cereal::JSONInputArchive &archive_in);
const std::string & getFormat() const;
private:
std::string format;
@ -467,35 +245,22 @@ private:
class AppsecTriggerLogDestination : public ClientRest
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger LogDestination";
// TBD: support "file"
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
void load(cereal::JSONInputArchive &archive_in);
StdoutLogging stdout_log;
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);
agent_local = !(stdout_log.getFormat().empty());
beautify_logs = stdout_log.getFormat() == "json-formatted";
parseAppsecJSONKey<LoggingService>("syslog-service", syslog_service, archive_in);
parseAppsecJSONKey<LoggingService>("cef-service", cef_service, archive_in);
}
int getCefServerUdpPort() const;
int getSyslogServerUdpPort() const;
bool isAgentLocal() const;
bool shouldBeautifyLogs() const;
int getCefServerUdpPort() const { return getCefServiceData().getPort(); }
int getSyslogServerUdpPort() const { return getSyslogServiceData().getPort(); }
bool isAgentLocal() const { return agent_local; }
bool shouldBeautifyLogs() const { return beautify_logs; }
bool getCloud() const { return cloud; }
bool isCefNeeded() const { return !getCefServiceData().getAddress().empty(); }
bool isSyslogNeeded() const { return !getSyslogServiceData().getAddress().empty(); }
const std::string & getSyslogServerIpv4Address() const { return getSyslogServiceData().getAddress(); }
const std::string & getCefServerIpv4Address() const { return getCefServiceData().getAddress(); }
bool getCloud() const;
bool isCefNeeded() const;
bool isSyslogNeeded() const;
const std::string & getSyslogServerIpv4Address() const;
const std::string & getCefServerIpv4Address() const;
private:
const LoggingService & getSyslogServiceData() const { return syslog_service; }
const LoggingService & getCefServiceData() const { return cef_service; }
const LoggingService & getSyslogServiceData() const;
const LoggingService & getCefServiceData() const;
bool cloud = false;
bool agent_local = true;
@ -504,90 +269,17 @@ private:
LoggingService cef_service;
};
std::ostream &
operator<<(std::ostream &os, const AppsecTriggerLogDestination &obj)
{
os
<< "AppSec Trigger Log Destination:" << std::endl
<< "agent_local: "
<< obj.isAgentLocal()
<< ", beautify_logs: "
<< obj.shouldBeautifyLogs()
<< ", cef_server_udp_port: "
<< obj.getCefServerUdpPort()
<< ", syslog_server_udp_port: "
<< obj.getSyslogServerUdpPort()
<< ", cef_service: "
<< obj.isCefNeeded()
<< ", cloud: "
<< obj.getCloud()
<< ", syslog: "
<< obj.isSyslogNeeded()
<< ", syslog_server_ipv4_address: "
<< obj.getSyslogServerIpv4Address()
<< ", cef_server_ipv4_address: "
<< obj.getCefServerIpv4Address();
return os;
}
class AppsecTriggerSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading AppSec trigger spec";
parseAppsecJSONKey<AppsecTriggerAccessControlLogging>(
"access-control-logging",
access_control_logging,
archive_in
);
parseAppsecJSONKey<AppsecTriggerAdditionalSuspiciousEventsLogging>(
"additional-suspicious-events-logging",
additional_suspicious_events_logging,
archive_in
);
parseAppsecJSONKey<AppsecTriggerLogging>("appsec-logging", appsec_logging, archive_in);
parseAppsecJSONKey<AppsecTriggerExtendedLogging>("extended-logging", extended_logging, archive_in);
parseAppsecJSONKey<AppsecTriggerLogDestination>("log-destination", log_destination, archive_in);
parseAppsecJSONKey<std::string>("name", name, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const AppsecTriggerAccessControlLogging &
getAppsecTriggerAccessControlLogging() const
{
return access_control_logging;
}
const std::string &
getName() const
{
return name;
}
const AppsecTriggerAdditionalSuspiciousEventsLogging &
getAppsecTriggerAdditionalSuspiciousEventsLogging() const
{
return additional_suspicious_events_logging;
}
const AppsecTriggerLogging &
getAppsecTriggerLogging() const
{
return appsec_logging;
}
const AppsecTriggerExtendedLogging &
getAppsecTriggerExtendedLogging() const
{
return extended_logging;
}
const AppsecTriggerLogDestination &
getAppsecTriggerLogDestination() const
{
return log_destination;
}
const AppsecTriggerAccessControlLogging & getAppsecTriggerAccessControlLogging() const;
const std::string & getName() const;
const AppsecTriggerAdditionalSuspiciousEventsLogging & getAppsecTriggerAdditionalSuspiciousEventsLogging() const;
const AppsecTriggerLogging & getAppsecTriggerLogging() const;
const AppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const;
const AppsecTriggerLogDestination & getAppsecTriggerLogDestination() const;
private:
AppsecTriggerAccessControlLogging access_control_logging;
@ -598,36 +290,13 @@ private:
std::string name;
};
std::ostream &
operator<<(std::ostream &os, const AppsecTriggerSpec &obj)
{
os
<< "AppSec Access Control Logging:" << std::endl
<< obj.getAppsecTriggerAccessControlLogging()
<< std::endl << "AppSec Additional Suspocious Events Logging:" << std::endl
<< obj.getAppsecTriggerAdditionalSuspiciousEventsLogging()
<< std::endl << "AppSec Trigger Logging:" << std::endl
<< obj.getAppsecTriggerLogging()
<< std::endl << "Appsec Trigger Extended Logging:" << std::endl
<< obj.getAppsecTriggerExtendedLogging()
<< std::endl << "AppSec Trigger Log Destination:" << std::endl
<< obj.getAppsecTriggerLogDestination();
return os;
}
class TriggersWrapper
{
public:
TriggersWrapper(const TriggersRulebase &_triggers) : triggers_rulebase(_triggers)
{}
void
serialize(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", triggers_rulebase)
);
}
void save(cereal::JSONOutputArchive &out_ar) const;
private:
TriggersRulebase triggers_rulebase;

View File

@ -29,51 +29,18 @@ USE_DEBUG_FLAG(D_K8S_POLICY);
class TrustedSourcesSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
parseAppsecJSONKey<int>("minNumOfSources", min_num_of_sources, archive_in, 3);
parseAppsecJSONKey<std::vector<std::string>>("sourcesIdentifiers", sources_identifiers, archive_in);
parseAppsecJSONKey<std::string>("name", name, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
int
getMinNumOfSources() const
{
return min_num_of_sources;
}
const std::vector<std::string> &
getSourcesIdentifiers() const
{
return sources_identifiers;
}
const std::string &
getName() const
{
return name;
}
int getMinNumOfSources() const;
const std::vector<std::string> & getSourcesIdentifiers() const;
const std::string & getName() const;
private:
int min_num_of_sources;
int min_num_of_sources = 0;
std::string name;
std::vector<std::string> sources_identifiers;
};
std::ostream &
operator<<(std::ostream &os, const TrustedSourcesSpec &obj)
{
os
<< "Min number of sources: "
<< obj.getMinNumOfSources()
<< ", SourceIdentifiers: ["
<< makeSeparatedStr(obj.getSourcesIdentifiers(), ",")
<< "]";
return os;
}
class SourcesIdentifiers
{
public:
@ -83,20 +50,8 @@ public:
value(_value)
{}
void
save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("sourceIdentifier", source_identifier),
cereal::make_nvp("value", value)
);
}
const std::string &
getSourceIdent() const
{
return source_identifier;
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getSourceIdent() const;
private:
std::string source_identifier;
@ -106,25 +61,10 @@ private:
class SourceIdentifierSpec
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec";
parseAppsecJSONKey<std::string>("sourceIdentifier", source_identifier, archive_in);
parseAppsecJSONKey<std::vector<std::string>>("value", value, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string &
getSourceIdentifier() const
{
return source_identifier;
}
const std::vector<std::string> &
getValues() const
{
return value;
}
const std::string & getSourceIdentifier() const;
const std::vector<std::string> & getValues() const;
private:
std::string source_identifier;
@ -134,43 +74,16 @@ private:
class SourceIdentifierSpecWrapper
{
public:
void
load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_K8S_POLICY) << "Loading Source Identifier Spec Wrapper";
parseAppsecJSONKey<std::vector<SourceIdentifierSpec>>("identifiers", identifiers, archive_in);
parseAppsecJSONKey<std::string>("name", name, archive_in);
}
void load(cereal::JSONInputArchive &archive_in);
const std::string &
getName() const
{
return name;
}
const std::vector<SourceIdentifierSpec> &
getIdentifiers() const
{
return identifiers;
}
const std::string & getName() const;
const std::vector<SourceIdentifierSpec> & getIdentifiers() const;
private:
std::string name;
std::vector<SourceIdentifierSpec> identifiers;
};
std::ostream &
operator<<(std::ostream &os, const SourceIdentifierSpec &obj)
{
os
<< "sourceIdentifier: "
<< obj.getSourceIdentifier()
<< ", values: ["
<< makeSeparatedStr(obj.getValues(), ",")
<< "]";
return os;
}
class AppSecTrustedSources
{
public:
@ -180,42 +93,16 @@ public:
AppSecTrustedSources(
const std::string &_name,
int _num_of_sources,
const std::vector<SourcesIdentifiers> &_sources_identifiers)
:
name(_name),
num_of_sources(_num_of_sources),
sources_identifiers(_sources_identifiers)
{
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_K8S_POLICY) << "Failed to generate Trusted Sources ID. Error: " << e.what();
}
}
const std::vector<SourcesIdentifiers> &_sources_identifiers
);
void
save(cereal::JSONOutputArchive &out_ar) const
{
std::string parameter_type = "TrustedSource";
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("name", name),
cereal::make_nvp("numOfSources", num_of_sources),
cereal::make_nvp("sourcesIdentifiers", sources_identifiers),
cereal::make_nvp("parameterType", parameter_type)
);
}
const std::vector<SourcesIdentifiers> &
getSourcesIdentifiers() const
{
return sources_identifiers;
}
void save(cereal::JSONOutputArchive &out_ar) const;
const std::vector<SourcesIdentifiers> & getSourcesIdentifiers() const;
private:
std::string id;
std::string name;
int num_of_sources;
int num_of_sources = 0;
std::vector<SourcesIdentifiers> sources_identifiers;
};
// LCOV_EXCL_STOP

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

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

View File

@ -124,6 +124,29 @@ private:
map<string, HealthCheckStatus> field_types_status;
};
class setAgentUninstall : public ServerRest
{
public:
void
doCall() override
{
dbgTrace(D_ORCHESTRATOR) << "Send 'agent uninstall process started' log to fog";
setConfiguration(false, "Logging", "Enable bulk of logs");
LogGen log (
"Agent started uninstall process",
Audience::INTERNAL,
Severity::INFO,
Priority::URGENT,
LogField("issuingEngine", "agentUninstallProvider"),
Tags::ORCHESTRATOR
);
notify_uninstall_to_fog = true;
}
private:
S2C_PARAM(bool, notify_uninstall_to_fog);
};
class OrchestrationComp::Impl
{
public:
@ -144,6 +167,7 @@ public:
auto rest = Singleton::Consume<I_RestApi>::by<OrchestrationComp>();
rest->addRestCall<getStatusRest>(RestAction::SHOW, "orchestration-status");
rest->addRestCall<AddProxyRest>(RestAction::ADD, "proxy");
rest->addRestCall<setAgentUninstall>(RestAction::SET, "agent-uninstall");
// Main loop of the Orchestration.
Singleton::Consume<I_MainLoop>::by<OrchestrationComp>()->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime,
@ -982,7 +1006,7 @@ private:
const Maybe<vector<CheckUpdateRequest::Tenants>> &updated_policy_tenants,
const vector<string> &new_data_files)
{
dbgFlow(D_ORCHESTRATOR) << "Hanlding virtual files";
dbgFlow(D_ORCHESTRATOR) << "Handling virtual files";
if (!updated_policy_tenants.ok()) return;
// Sorting files by tenant id;
@ -1053,26 +1077,31 @@ private:
}
}
for (const auto downloade_files: sorted_files) {
auto files = downloade_files.second;
for (auto it = sorted_files.begin(); it != sorted_files.end(); it++) {
const auto &downloaded_files = *it;
auto files = downloaded_files.second;
string policy_file = files[0];
string setting_file = "";
if (files.size() > 1) {
setting_file = files[1];
auto handled_settings = updateSettingsFile(
setting_file,
downloade_files.first.getTenantId(),
downloade_files.first.getPfofileId()
downloaded_files.first.getTenantId(),
downloaded_files.first.getProfileId()
);
if (handled_settings.ok()) setting_file = *handled_settings;
}
bool last_iteration = false;
if (next(it) == sorted_files.end()) last_iteration = true;
Singleton::Consume<I_ServiceController>::by<OrchestrationComp>()->updateServiceConfiguration(
policy_file,
setting_file,
new_data_files,
downloade_files.first.getTenantId(),
downloade_files.first.getPfofileId()
downloaded_files.first.getTenantId(),
downloaded_files.first.getProfileId(),
last_iteration
);
}
}
@ -1087,9 +1116,9 @@ private:
"Conf dir"
) + (tenant_id != "" ? "tenant_" + tenant_id + "_profile_" + profile_id + "_" : "");
dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << conf_dir;
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
string settings_file_path = conf_dir + "settings.json";
dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << settings_file_path;
if (!orchestration_tools->copyFile(new_settings_file, settings_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings.";
return genError("Failed to update the settings");
@ -1278,7 +1307,7 @@ private:
int sleep_interval = policy.getErrorSleepInterval();
Maybe<void> start_state(genError("Not running yet."));
while (!(start_state = start()).ok()) {
dbgError(D_ORCHESTRATOR) << "Failed to start the Orchestration. Error: " << start_state.getErr();
dbgDebug(D_ORCHESTRATOR) << "Orchestration not started yet. Status: " << start_state.getErr();
health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::REGISTRATION,

View File

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

View File

@ -79,6 +79,11 @@ public:
WithArg<2>(Invoke(this, &OrchestrationTest::setRestStatus))
);
EXPECT_CALL(
rest,
mockRestCall(RestAction::SET, "agent-uninstall", _)
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandlerAgentUninstall)));
string message_body;
EXPECT_CALL(mock_message, mockSendPersistentMessage(
false,
@ -101,6 +106,12 @@ public:
return true;
}
bool
restHandlerAgentUninstall(const unique_ptr<RestInit> &p)
{
agent_uninstall = p->getRest();
return true;
}
void
doEncrypt()
@ -249,6 +260,7 @@ public:
}
unique_ptr<ServerRest> rest_handler;
unique_ptr<ServerRest> agent_uninstall;
unique_ptr<ServerRest> declare_variable;
StrictMock<MockMainLoop> mock_ml;
NiceMock<MockTimeGet> mock_time_get;
@ -295,8 +307,36 @@ private:
I_MainLoop::Routine status_routine;
};
TEST_F(OrchestrationTest, doNothing)
TEST_F(OrchestrationTest, testAgentUninstallRest)
{
EXPECT_CALL(
rest,
mockRestCall(RestAction::ADD, "proxy", _)
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler)));
init();
Report report;
EXPECT_CALL(mock_log, sendLog(_)).WillRepeatedly(SaveArg<0>(&report));
stringstream ss("{}");
Maybe<string> maybe_res = agent_uninstall->performRestCall(ss);
EXPECT_TRUE(maybe_res.ok());
EXPECT_EQ(maybe_res.unpack(),
"{\n"
" \"notify_uninstall_to_fog\": true\n"
"}"
);
stringstream report_ss;
{
cereal::JSONOutputArchive ar(report_ss);
report.serialize(ar);
}
string report_str = report_ss.str();
EXPECT_THAT(report_str, HasSubstr("\"eventName\": \"Agent started uninstall process\""));
EXPECT_THAT(report_str, HasSubstr("\"issuingEngine\": \"agentUninstallProvider\""));
}
TEST_F(OrchestrationTest, register_config)
@ -530,12 +570,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "")
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(
@ -633,7 +673,7 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(Return(true));
@ -753,7 +793,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
@ -887,7 +927,7 @@ TEST_F(OrchestrationTest, manifestUpdate)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
@ -1037,7 +1077,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
@ -1118,7 +1158,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "")).WillOnce(Return(false)
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _)).WillOnce(Return(false)
);
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
@ -1183,7 +1223,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
@ -1401,7 +1441,7 @@ TEST_P(OrchestrationTest, orchestrationFirstRun)
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
@ -1582,13 +1622,13 @@ TEST_F(OrchestrationTest, dataUpdate)
vector<string> expected_empty_data_types = {};
ExpectationSet expectation_set = EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "")
updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "", _)
).WillOnce(Return(true));
vector<string> expected_ips_data_types = { "ips" };
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration("", "", expected_ips_data_types, "", "")
updateServiceConfiguration("", "", expected_ips_data_types, "", "", _)
).After(expectation_set).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesDirectoryExist("/etc/cp/conf/data")).WillOnce(Return(true));

View File

@ -272,7 +272,8 @@ public:
const string &new_settings_path,
const vector<string> &new_data_files,
const string &tenant_id,
const string &profile_id
const string &profile_id,
const bool last_iteration
) override;
bool isServiceInstalled(const string &service_name) override;
@ -325,6 +326,7 @@ private:
map<int, string> services_reconf_names;
map<int, string> services_reconf_ids;
string filesystem_prefix;
bool is_multi_tenant_env = false;
};
class GetServicesPorts : public ServerRest
@ -412,6 +414,11 @@ ServiceController::Impl::init()
filesystem_prefix = getFilesystemPathConfig();
loadRegisteredServicesFromFile();
auto agent_type = getSetting<string>("agentType");
if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) {
is_multi_tenant_env = true;
}
}
void
@ -592,7 +599,8 @@ ServiceController::Impl::updateServiceConfiguration(
const string &new_settings_path,
const vector<string> &new_data_files,
const string &tenant_id,
const string &profile_id)
const string &profile_id,
const bool last_iteration)
{
dbgFlow(D_ORCHESTRATOR)
<< "new_policy_path: "
@ -746,7 +754,10 @@ ServiceController::Impl::updateServiceConfiguration(
}
}
was_policy_updated &= sendSignalForServices(nano_services_to_update, version_value);
// In a multi-tenant env, we send the signal to the services only on the last iteration
was_policy_updated &= (is_multi_tenant_env && !last_iteration) ?
true :
sendSignalForServices(nano_services_to_update, version_value);
dbgTrace(D_ORCHESTRATOR) << "was_policy_updated: " << (was_policy_updated ? "true" : "false");
@ -965,6 +976,11 @@ ServiceController::Impl::updateReconfStatus(int id, ReconfStatus status)
dbgError(D_ORCHESTRATOR) << "Service reconfiguration monitor received illegal id :" << id;
return;
}
dbgTrace(D_ORCHESTRATOR)
<< "Updating reconf status for reconfiguration ID "
<< id
<< ". Status: "
<< static_cast<int>(status);
services_reconf_status[id] = status;
}
@ -975,6 +991,15 @@ ServiceController::Impl::startReconfStatus(
const string &service_name,
const string &service_id)
{
dbgTrace(D_ORCHESTRATOR)
<< "Starting reconf status. Configuration ID: "
<< id
<< ", service name: "
<< service_name
<< ", service ID: "
<< service_id
<< ", status: "
<< static_cast<int>(status);
services_reconf_status.emplace(id, status);
services_reconf_names.emplace(id, service_name);
services_reconf_ids.emplace(id, service_id);

View File

@ -122,9 +122,9 @@ LocalCommunication::getUpdate(CheckUpdateRequest &request)
}
Maybe<string>
LocalCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
LocalCommunication::downloadAttributeFile(const GetResourceFile &resource_file)
{
auto file_name = resourse_file.getFileName();
auto file_name = resource_file.getFileName();
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<LocalCommunication>();
if (file_name.compare("policy") == 0) {
@ -163,8 +163,8 @@ LocalCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
));
}
dbgError(D_ORCHESTRATOR) << "Unknown resourse file name " << file_name;
return genError("Failed to detect resourse file name " + file_name);
dbgError(D_ORCHESTRATOR) << "Unknown resource file name " << file_name;
return genError("Failed to detect resource file name " + file_name);
}
void

View File

@ -191,7 +191,7 @@ protected:
dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i;
mainloop->yield(true);
}
dbgError(D_WAAP) << "Failed to send object, reached maximum attempts: " <<
dbgError(D_WAAP) << "Failed to send object to " << uri << ", reached maximum attempts: " <<
max_send_obj_retries;
return false;
}
@ -245,7 +245,7 @@ protected:
dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i;
mainloop->yield(true);
}
dbgError(D_WAAP) << "Failed to send object, reached maximum attempts: " <<
dbgError(D_WAAP) << "Failed to send object to " << uri << ", reached maximum attempts: " <<
max_send_obj_retries;
return false;
}

View File

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

View File

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

View File

@ -17,6 +17,7 @@
#include "ParserUrlEncode.h"
#include "PHPSerializedDataParser.h"
#include "ParserJson.h"
#include "ParserGql.h"
#include "ParserConfluence.h"
#include "ParserXML.h"
#include "ParserHTML.h"
@ -231,26 +232,30 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i
bool base64ParamFound = false;
dbgTrace(D_WAAP_DEEP_PARSER) << " ===Processing potential base64===";
std::string base64_decoded_val, base64_key;
std::string decoded_val, key;
base64_variants base64_status = Waap::Util::b64Test (cur_val,
base64_key,
base64_decoded_val);
key,
decoded_val);
dbgTrace(D_WAAP_DEEP_PARSER) << " status = " << base64_status
<< " key = " << base64_key
<< " value = " << base64_decoded_val;
dbgTrace(D_WAAP_DEEP_PARSER)
<< " status = "
<< base64_status
<< " key = "
<< key
<< " value = "
<< decoded_val;
switch (base64_status) {
case SINGLE_B64_CHUNK_CONVERT:
cur_val = base64_decoded_val;
cur_val = decoded_val;
base64ParamFound = true;
break;
case KEY_VALUE_B64_PAIR:
// going deep with new pair in case value is not empty
if (base64_decoded_val.size() > 0) {
cur_val = base64_decoded_val;
if (decoded_val.size() > 0) {
cur_val = decoded_val;
base64ParamFound = true;
rc = onKv(base64_key.c_str(), base64_key.size(), cur_val.data(), cur_val.size(), flags);
rc = onKv(key.c_str(), key.size(), cur_val.data(), cur_val.size(), flags);
dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc;
if (rc != CONTINUE_PARSING) {
return rc;
@ -323,6 +328,7 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i
}
}
// Parse buffer
// Note: API report does not include output of "PIPE" and similar extracted stuff.
@ -365,6 +371,21 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i
return rc;
}
if (Waap::Util::detectJSONasParameter(cur_val, key, decoded_val)) {
dbgTrace(D_WAAP_DEEP_PARSER)
<< " detectJSONasParameter was true: key = "
<< key
<< " value = "
<< decoded_val;
rc = onKv(key.c_str(), key.size(), decoded_val.data(), decoded_val.size(), flags);
dbgTrace(D_WAAP_DEEP_PARSER) << " After processing potential JSON rc = " << rc;
if (rc != CONTINUE_PARSING) {
return rc;
}
}
m_depth--;
// Send key/value pair to the Signature scanner
@ -878,6 +899,11 @@ void DeepParser::createInternalParser(const char *k, size_t k_len, std::string&
dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse phpSerializedData";
m_parsersDeque.push_front(std::make_shared<BufferedParser<PHPSerializedDataParser>>(*this));
}
else if (isPotentialGqlQuery && cur_val.size() > 0 && !validateJson(cur_val.data(), cur_val.size())) {
// Graphql value detected
dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse graphql";
m_parsersDeque.push_front(std::make_shared<BufferedParser<ParserGql>>(*this));
}
else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{'))
{
boost::smatch confulence_match;

View File

@ -25,7 +25,8 @@ IndicatorsFiltersManager::IndicatorsFiltersManager(const std::string& remotePath
:
SerializeToFileBase(pWaapAssetState->getWaapDataDir() + "/6.data"),
m_ignoreSources(pWaapAssetState->getWaapDataDir(), remotePath, assetId),
m_tuning(remotePath)
m_tuning(remotePath),
m_matchedOverrideKeywords()
{
restore();
m_keywordsFreqFilter = std::make_unique<KeywordIndicatorFilter>(
@ -88,6 +89,12 @@ bool IndicatorsFiltersManager::shouldFilterKeyword(const std::string &key, const
shouldFilter |= m_keywordsFreqFilter->shouldFilterKeyword(type, keyword);
}
}
if (m_matchedOverrideKeywords.size() > 0 &&
m_matchedOverrideKeywords.find(keyword) != m_matchedOverrideKeywords.end())
{
dbgTrace(D_WAAP_OVERRIDE) << "Filtering keyword '" << keyword << "' due to override";
shouldFilter = true;
}
return shouldFilter;
}
@ -315,3 +322,8 @@ void IndicatorsFiltersManager::pushSample(
}
m_typeFilter->registerKeywords(key, sample, pTransaction);
}
std::set<std::string> & IndicatorsFiltersManager::getMatchedOverrideKeywords(void)
{
return m_matchedOverrideKeywords;
}

View File

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

View File

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

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;
}
if (m_receiver2) {
m_receiver2->onEndOfData();
}
return 0;
}

View File

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

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

View File

@ -1993,7 +1993,7 @@ void WaapAssetState::filterKeywordsByParameters(
}
else
{
dbgTrace(D_WAAP_ASSET_STATE) << "No keywords need to be filter for this parameter";
dbgTrace(D_WAAP_ASSET_STATE) << "No keywords need to be filtered for this parameter";
}
}

View File

@ -23,6 +23,15 @@ set<string> WaapConfigApplication::assets_ids{};
set<string> WaapConfigApplication::assets_ids_aggregation{};
bool WaapConfigApplication::getWaapSiteConfig(WaapConfigApplication& ngenSiteConfig) {
auto maybe_tenant_id = Singleton::Consume<I_Environment>::by<WaapConfigApplication>()->get<string>(
"ActiveTenantId"
);
auto maybe_profile_id = Singleton::Consume<I_Environment>::by<WaapConfigApplication>()->get<string>(
"ActiveProfileId"
);
string tenant_id = (maybe_tenant_id.ok() ? *maybe_tenant_id : "not found");
string profile_id = (maybe_profile_id.ok() ? *maybe_profile_id : "not found");
dbgTrace(D_WAAP) << "Tenant ID: " << tenant_id << ", Profile ID: " << profile_id;
auto &maybe_ngen_config = getConfiguration<WaapConfigApplication>(
"WAAP",
"WebApplicationSecurity"

View File

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

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);
dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name;
m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction);
m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords);
if (m_transaction->getSiteConfig() != nullptr)
{
@ -41,6 +42,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
}
m_transaction->getAssetState()->filterKeywordsByParameters(res.param_name, keywordsSet);
// The keywords are only removed in production, they are still used while building scores
if (!m_transaction->get_ignoreScore()) {
m_transaction->getAssetState()->removeKeywords(keywordsSet);
@ -66,6 +68,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
std::sort(res.keyword_matches.begin(), res.keyword_matches.end());
std::string keywords_string;
std::vector<std::string> strippedKeywords;
for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) {
// Add spaces between the items, but not before the first one
if (pKeyword != keywordsSet.begin()) {
@ -75,15 +78,21 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
std::string k = *pKeyword;
stripSpaces(k);
keywords_string += k;
strippedKeywords.push_back(k);
}
std::vector<std::string> newKeywords;
for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) {
std::string k = *pKeyword;
stripSpaces(k);
// if keyword_string.count(key) < 2: new_keywords.append(key)
if (countSubstrings(keywords_string, k) < 2) {
newKeywords.push_back(k);
} else {
if ((std::count(strippedKeywords.begin(), strippedKeywords.end(), k) > 1) ) {
if ((std::count(newKeywords.begin(), newKeywords.end(), k) < 1)) {
newKeywords.push_back(k);
}
}
}
}
@ -127,6 +136,10 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp,
res.location = location;
res.param_name = param_name; // remember the param name (analyzer needs it for reporting)
// call shouldIgnoreOverride prior to score calculation, so that matched override keywords will be filtered
// when an ignore override action is detected
bool ignoreOverride = m_transaction->shouldIgnoreOverride(res);
// Select scores pool by location
std::string poolName = Waap::Scores::getScorePoolNameByLocation(location);
@ -145,7 +158,7 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp,
);
}
if (isKeyCspReport(key, res, dp) || m_transaction->shouldIgnoreOverride(res)) {
if (isKeyCspReport(key, res, dp) || ignoreOverride) {
dbgTrace(D_WAAP_SCANNER) << "Ignoring parameter key/value " << res.param_name <<
" due to ignore action in override";
m_bIgnoreOverride = true;

View File

@ -67,8 +67,6 @@ using namespace ReportIS;
// Score threshold below which the match won't be considered
#define SCORE_THRESHOLD (1.4f)
static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE);
void Waf2Transaction::learnScore(ScoreBuilderData& data, const std::string &poolName)
{
m_pWaapAssetState->scoreBuilder.analyzeFalseTruePositive(data, poolName, !m_ignoreScore);
@ -1372,7 +1370,7 @@ Waf2Transaction::checkShouldInject()
std::string uri = m_uriPath;
std::string low_method = m_methodStr;
std::transform(low_method.begin(), low_method.end(), low_method.begin(), ::tolower);
auto csrfPolicy = m_siteConfig ? m_siteConfig->get_CsrfPolicy() : NULL;
bool csrf = false;
dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): received the relevant Application configuration "
@ -1384,7 +1382,7 @@ Waf2Transaction::checkShouldInject()
{
dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): Should not inject CSRF scripts.";
}
if(csrf) {
dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): Should inject CSRF script";
m_responseInjectReasons.setCsrf(true);
@ -1554,6 +1552,8 @@ void Waf2Transaction::appendCommonLogFields(LogGen& waapLog,
const std::string& incidentType) const
{
auto env = Singleton::Consume<I_Environment>::by<WaapComponent>();
auto active_id = env->get<std::string>("ActiveTenantId");
if (active_id.ok()) waapLog.addToOrigin(LogField("tenantId", *active_id));
auto proxy_ip = env->get<std::string>(HttpTransactionData::proxy_ip_ctx);
if (proxy_ip.ok() && m_remote_addr != proxy_ip.unpack())
{
@ -2155,7 +2155,7 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
auto exceptions = getConfiguration<ParameterException>("rulebase", "exception");
if (!exceptions.ok()) return false;
dbgTrace(D_WAAP) << "matching exceptions";
dbgTrace(D_WAAP_OVERRIDE) << "matching exceptions";
std::unordered_map<std::string, std::set<std::string>> exceptions_dict;
@ -2184,11 +2184,16 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
exceptions_dict["url"].insert(getUriStr());
exceptions_dict["hostName"].insert(m_hostStr);
for (auto &keyword : res.keyword_matches) {
exceptions_dict["indicator"].insert(keyword);
}
// calling behavior and check if there is a behavior that match to this specific param name.
auto behaviors = exceptions.unpack().getBehavior(exceptions_dict);
auto behaviors = exceptions.unpack().getBehavior(exceptions_dict,
getAssetState()->m_filtersMngr->getMatchedOverrideKeywords());
for (auto const &behavior : behaviors) {
if (behavior == action_ignore) {
dbgTrace(D_WAAP) << "matched exceptions for " << res.param_name << " should ignore.";
dbgTrace(D_WAAP_OVERRIDE) << "matched exceptions for " << res.param_name << " should ignore.";
std::string overrideId = behavior.getId();
if (!overrideId.empty()) {
m_matchedOverrideIds.insert(overrideId);

View File

@ -41,6 +41,7 @@ using namespace std;
USE_DEBUG_FLAG(D_WAAP);
USE_DEBUG_FLAG(D_WAAP_EVASIONS);
USE_DEBUG_FLAG(D_WAAP_BASE64);
USE_DEBUG_FLAG(D_WAAP_JSON);
#define MIN_HEX_LENGTH 6
#define charToDigit(c) (c - '0')
@ -1144,6 +1145,8 @@ namespace Util {
#define B64_TRAILERCHAR '='
static bool err = false;
// based on malicious JSON "{1:\x00}"
static const int minimal_legal_json_size = 8;
static const SingleRegex invalid_hex_evasion_re(
"%([g-zG-Z][0-9a-zA-Z]|[0-9a-zA-Z][g-zG-Z])",
@ -1161,11 +1164,15 @@ static const SingleRegex csp_report_policy_re(
"csp_report_policy"
);
static const SingleRegex base64_key_value_detector_re(
"^[^<>;&\\?|=\\s]+={1}\\s*.+",
"^[^<>{};,&\\?|=\\s]+={1}\\s*.+",
err,
"base64_key_value");
static const SingleRegex json_key_value_detector_re(
"^[^<>{};,&\\?|=\\s]+={.+:.+}\\z",
err,
"json_key_value");
static const SingleRegex base64_key_detector_re(
"^[^<>;&\\?|=\\s]+={1}",
"^[^<>{};,&\\?|=\\s]+={1}",
err,
"base64_key");
static const SingleRegex base64_prefix_detector_re(
@ -1173,6 +1180,44 @@ static const SingleRegex base64_prefix_detector_re(
err,
"base64_prefix");
// looks for combination <param>={<some text>*:<some text>*}
//used to allow parsing param=JSON to reduce false positives
bool detectJSONasParameter(const string &string_buffer,
string &key,
string &value)
{
key.clear();
value.clear();
bool is_json_candidate_detected = json_key_value_detector_re.hasMatch(string_buffer);
if (is_json_candidate_detected) {
dbgTrace(D_WAAP_JSON) << "===JSONdetect===: json_key_value_detector_re test passed - looking for key";
string::const_iterator it = string_buffer.begin();
for (; it != string_buffer.end(); ++it) {
if (*it != '{') {
continue;
}
// candidate should have size 8 or more - minimum for JSON with attack
if ((string_buffer.end() - it) < minimal_legal_json_size) {
dbgTrace(D_WAAP_JSON)
<< "===JSONdetect===: candidate is shorter then the length"
"of the shortest known json attack which is: " << minimal_legal_json_size;
return false;
}
key = std::string(string_buffer.begin(), it-1);
value = std::string(it, string_buffer.end());
break;
}
}
dbgTrace(D_WAAP_JSON)
<< "===JSONdetect===: key = '"
<< key
<< "', value = '"
<< value <<"'";
return is_json_candidate_detected;
}
static void b64TestChunk(const string &s,
string::const_iterator chunkStart,
string::const_iterator chunkEnd,
@ -2115,6 +2160,8 @@ string convertParamTypeToStr(ParamType type)
return "urls";
case FREE_TEXT_PARAM_TYPE:
return "free_text";
case FREE_TEXT_FRENCH_PARAM_TYPE:
return "free_text_french";
case PIPE_PARAM_TYPE:
return "pipes";
case LONG_RANDOM_TEXT_PARAM_TYPE:
@ -2148,6 +2195,7 @@ ParamType convertTypeStrToEnum(const string& typeStr)
{"administration_config", ParamType::ADMINISTRATOR_CONFIG_PARAM_TYPE},
{"base64", ParamType::BASE64_PARAM_TYPE },
{"free_text", ParamType::FREE_TEXT_PARAM_TYPE},
{"free_text_french", ParamType::FREE_TEXT_FRENCH_PARAM_TYPE},
{"html_input", ParamType::HTML_PARAM_TYPE},
{"long_random_text", ParamType::LONG_RANDOM_TEXT_PARAM_TYPE},
{"pipes", ParamType::PIPE_PARAM_TYPE},

View File

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

View File

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

View File

@ -14,6 +14,7 @@
#include "config.h"
#include "config_component.h"
#include <dirent.h>
#include <algorithm>
#include <fstream>
#include <boost/regex.hpp>
@ -66,11 +67,24 @@ public:
void
doCall() override
{
auto i_config = Singleton::Consume<I_Config>::from<ConfigComponent>();
static const map<I_Config::AsyncLoadConfigStatus, string> status_map {
{I_Config::AsyncLoadConfigStatus::Success, "Success"},
{I_Config::AsyncLoadConfigStatus::InProgress, "In Progress"},
{I_Config::AsyncLoadConfigStatus::Error, "Error"}
};
auto i_config = Singleton::Consume<I_Config>::from<ConfigComponent>();
I_Config::AsyncLoadConfigStatus load_config_staus = i_config->reloadConfiguration(policy_version, true, id);
finished = load_config_staus == I_Config::AsyncLoadConfigStatus::InProgress;
finished = load_config_staus != I_Config::AsyncLoadConfigStatus::InProgress;
error = load_config_staus == I_Config::AsyncLoadConfigStatus::Error;
if (error) {
dbgWarning(D_CONFIG) << "Configuration reload status: " << status_map.at(load_config_staus);
} else {
dbgDebug(D_CONFIG) << "Configuration reload status: " << status_map.at(load_config_staus);
}
if (!finished) {
error_message = "Reload already in progress - can't start another one";
}
@ -669,8 +683,8 @@ ConfigComponent::Impl::clearOldTenants()
bool
ConfigComponent::Impl::areTenantAndProfileActive(const TenantProfilePair &tenant_profile) const
{
return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getPfofileId() == default_profile_id)
|| tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getPfofileId());
return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getProfileId() == default_profile_id)
|| tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getProfileId());
}
void
@ -723,12 +737,21 @@ ConfigComponent::Impl::loadConfiguration(vector<shared_ptr<JSONInputArchive>> &f
string curr_profile = default_profile_id;
try {
(*archive)(cereal::make_nvp("tenantID", curr_tenant));
dbgTrace(D_CONFIG) << "Found a tenant ID in the file: " << curr_tenant;
} catch (cereal::Exception &e) {}
try {
(*archive)(cereal::make_nvp("profileID", curr_profile));
} catch (cereal::Exception &e) {
}
dbgTrace(D_CONFIG) << "Found a profile ID in the file " << curr_profile;
} catch (cereal::Exception &e) {}
dbgTrace(D_CONFIG)
<< "Loading configuration for tenant: "
<< curr_tenant
<< " and profile: "
<< curr_profile
<< ", for the archive: "
<< (*archive).getNodeName();
dbgTrace(D_CONFIG) <<
"Loading configuration for tenant: " << curr_tenant << " and profile: " << curr_profile;
TenantProfilePair tenant_profile(curr_tenant, curr_profile);
for (auto &config : expected_configs) {
auto loaded = config->loadConfiguration(*archive);
@ -800,6 +823,7 @@ ConfigComponent::Impl::commitFailure(const string &error)
bool
ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_async)
{
dbgFlow(D_CONFIG) << "Reloading configuration";
auto env = Singleton::Consume<I_Environment>::by<ConfigComponent>();
env->registerValue<string>("New Policy Version", version);
auto cleanup = make_scope_exit([env] () { env->unregisterKey<string>("New Policy Version"); } );
@ -812,6 +836,8 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
const auto &active_tenants = tenant_mananger ? tenant_mananger->fetchAllActiveTenants() : vector<string>();
dbgTrace(D_CONFIG) << "Number of active tenants found while reloading configuration: " << active_tenants.size();
for (const auto &config_file : expected_configuration_files) {
for (const auto &type : config_file.second) {
if (type == ConfigFileType::RawData) continue;
@ -835,7 +861,9 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
const vector<string> &profile_ids =
tenant_mananger ? tenant_mananger->fetchProfileIds(tenant) : vector<string>();
for (auto &profile_id : profile_ids) {
string settings_path = config_directory_path + "tenant_" + tenant + "_" + profile_id + "_settings.json";
string settings_path =
config_directory_path + "tenant_" + tenant + "_profile_"+ profile_id + "_settings.json";
dbgTrace(D_CONFIG) << "Inserting a settings path: " << settings_path;
files.emplace(settings_path, make_shared<ifstream>(settings_path));
}
}
@ -843,10 +871,10 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as
vector<shared_ptr<JSONInputArchive>> archives;
for (const auto &file : files) {
if (file.second->is_open()) {
dbgDebug(D_CONFIG) << "Succesfully opened configuration file. File: " << file.first;
dbgTrace(D_CONFIG) << "Succesfully opened configuration file. File: " << file.first;
archives.push_back(make_shared<JSONInputArchive>(*file.second));
} else {
dbgDebug(D_CONFIG) << "Could not open configuration file. Path: " << file.first;
dbgTrace(D_CONFIG) << "Could not open configuration file. Path: " << file.first;
}
}

View File

@ -161,26 +161,6 @@ IPAddr::createIPAddr(const string &ip_text)
bool IPAddr::isValidIPAddr(const string &ip_text) { return createIPAddr(ip_text).ok(); }
IPAddressConfig::IPAddressConfig(const string &ip_string)
{
auto maybe_address = IPAddr::createIPAddr(ip_string);
if (maybe_address.ok()) address = maybe_address.unpack();
}
void
IPAddressConfig::load(cereal::JSONInputArchive &ar)
{
string ip_string;
ar(cereal::make_nvp("IPAddress", ip_string));
auto ip_address = IPAddr::createIPAddr(ip_string);
if (!ip_address.ok()) {
throw Config::ConfigException(
"Failed to create an IP address from " + ip_string + ": " + ip_address.getErr()
);
}
address = ip_address.unpack();
}
const string ConnKey::network_key = "NetworkKey";
template<typename Num>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,6 +25,7 @@ public:
MOCK_CONST_METHOD2(areTenantAndProfileActive, bool(const std::string &, const std::string &));
MOCK_METHOD2(addActiveTenantAndProfile, void(const std::string &, const std::string &));
MOCK_METHOD2(deactivateTenant, void(const std::string &, const std::string &));
MOCK_CONST_METHOD2(getProfileId, std::string(const std::string &, const std::string &));
MOCK_CONST_METHOD0(getTimeoutVal, std::chrono::microseconds());

View File

@ -74,6 +74,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_WAAP_SCANNER, D_WAAP)
DEFINE_FLAG(D_WAAP_DEEP_PARSER, D_WAAP)
DEFINE_FLAG(D_WAAP_BASE64, D_WAAP)
DEFINE_FLAG(D_WAAP_JSON, D_WAAP)
DEFINE_FLAG(D_WAAP_BOT_PROTECTION, D_WAAP)
DEFINE_FLAG(D_WAAP_PARSER, D_WAAP)
DEFINE_FLAG(D_WAAP_PARSER_XML, D_WAAP_PARSER)
@ -122,6 +123,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_HEALTH_CHECK, D_ORCHESTRATOR)
DEFINE_FLAG(D_AGENT_DETAILS, D_ORCHESTRATOR)
DEFINE_FLAG(D_K8S_POLICY, D_ORCHESTRATOR)
DEFINE_FLAG(D_NGINX_POLICY, D_ORCHESTRATOR)
DEFINE_FLAG(D_GRADUAL_DEPLOYMENT, D_COMPONENT)
DEFINE_FLAG(D_C8_CONTROLLER, D_COMPONENT)

View File

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

View File

@ -199,21 +199,6 @@ private:
RangeType end;
};
class IPAddressConfig
{
public:
IPAddressConfig() = default;
IPAddressConfig(const std::string &ip_string);
void load(cereal::JSONInputArchive &ar);
const IPAddr & getAddress() const { return address; }
operator IPAddr() const { return address; }
private:
IPAddr address;
};
// Specialization of std::hash<> for IPAddr
namespace std
{

View File

@ -33,7 +33,7 @@ public:
Maybe<string> instance_id = checkIfValueIsConfigured("id");
if (instance_id.ok()) return instance_id;
return genError("Instance Awareness isn't active");
return genError("Instance Awareness isn't active, Error: " + instance_id.getErr());
}
Maybe<string>
@ -42,14 +42,14 @@ public:
Maybe<string> family_id = checkIfValueIsConfigured("family");
if (family_id.ok()) return family_id;
return genError("Family ID isn't active");
return genError("Family ID isn't active, Error: " + family_id.getErr());
}
Maybe<string>
getUniqueID() override
{
Maybe<string> instance_id(getInstanceID());
if (!instance_id.ok()) return genError("Instance Awareness isn't active");
if (!instance_id.ok()) return genError("Can't get instance ID, Error: " + instance_id.getErr());
Maybe<string> family_id(getFamilyID());
if (!family_id.ok()) return *instance_id;

View File

@ -43,9 +43,12 @@ TEST_F(InstanceAwarenessTest, emptyInit)
init(args);
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active"));
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found"));
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found"));
EXPECT_THAT(
getUniqueID(),
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found")
);
}
TEST_F(InstanceAwarenessTest, badFamilyID)
@ -55,7 +58,7 @@ TEST_F(InstanceAwarenessTest, badFamilyID)
init(args);
EXPECT_THAT(getInstanceID(), IsValue("9"));
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active"));
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Illegal flag: family"));
EXPECT_THAT(getUniqueID(), IsValue("9"));
}
@ -65,9 +68,12 @@ TEST_F(InstanceAwarenessTest, badInstanceID)
init(args);
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Illegal flag: id"));
EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5"));
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(
getUniqueID(),
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Illegal flag: id")
);
}
TEST_F(InstanceAwarenessTest, emptyInstanceID)
@ -76,9 +82,12 @@ TEST_F(InstanceAwarenessTest, emptyInstanceID)
init(args);
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found"));
EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5"));
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(
getUniqueID(),
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found")
);
}
TEST_F(InstanceAwarenessTest, noInstanceID)
@ -87,9 +96,12 @@ TEST_F(InstanceAwarenessTest, noInstanceID)
init(args);
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found"));
EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5"));
EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active"));
EXPECT_THAT(
getUniqueID(),
IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found")
);
}
TEST_F(InstanceAwarenessTest, init)
@ -111,7 +123,7 @@ TEST_F(InstanceAwarenessTest, initIDOnly)
EXPECT_THAT(getUniqueID(), IsValue("9"));
EXPECT_THAT(getInstanceID(), IsValue("9"));
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active"));
EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found"));
}
TEST_F(InstanceAwarenessTest, defaultValues)

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)

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <arpa/inet.h>
#include "logging_comp.h"
#include "log_streams.h"
@ -19,11 +21,16 @@ using namespace cereal;
USE_DEBUG_FLAG(D_REPORT);
CefStream::CefStream(const string &_ip_address, int _port)
static string lookup_cmd = "nslookup ";
static string line_selection_cmd = "| grep Address | sed -n 2p";
static string parsing_cmd = "| cut -f2 -d' ' | tr -d '\n'";
CefStream::CefStream(const string &_address, int _port, I_Socket::SocketType _protocol)
:
i_socket(Singleton::Consume<I_Socket>::by<LoggingComp>()),
ip_address(_ip_address),
port(_port)
address(_address),
port(_port),
protocol(_protocol)
{
connect();
if (!socket.ok()) {
@ -65,17 +72,57 @@ CefStream::sendLog(const Report &log)
void
CefStream::connect()
{
auto cef_ip_address = getProfileAgentSettingWithDefault<string>(ip_address, "agent.config.log.cefServer.IP");
auto cef_address = getProfileAgentSettingWithDefault<string>(address, "agent.config.log.cefServer.IP");
auto cef_port = getProfileAgentSettingWithDefault<uint>(port, "agent.config.log.cefServer.port");
if (cef_ip_address.empty()) {
dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP is not configured.";
if (cef_address.empty()) {
dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP/Domain is not configured.";
return;
}
struct in_addr addr;
if (inet_pton(AF_INET, cef_address.data(), &addr) != 1) {
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<LoggingComp>();
string host_cmd = lookup_cmd + cef_address + line_selection_cmd + parsing_cmd;
Maybe<string> res = shell_cmd->getExecOutput(host_cmd, 500);
if (!res.ok()) {
dbgWarning(D_REPORT)
<< "Failed to execute domain lookup command. "
<< "CEF Domain: "
<< cef_address
<< "Error: "
<< res.getErr();
return;
}
if (res.unpack().empty()) {
dbgWarning(D_REPORT)
<< "Got en empty ip address from lookup command. "
<< "CEF Domain: "
<< cef_address
<< "Got bad ip address: "
<< res.unpack();
return;
}
dbgDebug(D_REPORT) << "CEF Domain lookup result: " << res.unpack();
if (inet_pton(AF_INET, res.unpack().data(), &addr) != 1) {
dbgWarning(D_REPORT)
<< "Got a faulty ip address from lookup command. "
<< "CEF Domain: "
<< cef_address
<< "Got bad ip address: "
<< res.unpack();
return;
}
cef_address = res.unpack();
}
socket = i_socket->genSocket(
I_Socket::SocketType::UDP,
protocol,
false,
false,
cef_ip_address + ":" + to_string(cef_port)
cef_address + ":" + to_string(cef_port)
);
}

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

View File

@ -111,7 +111,11 @@ public:
}
bool
addStream(ReportIS::StreamType type, const string &log_server_url) override
addStream(
ReportIS::StreamType type,
const string &log_server_url,
const string &_protocol
) override
{
string log_type = TagAndEnumManagement::convertToString(type);
if (streams_preperation.find(type) != streams_preperation.end()) {
@ -124,8 +128,9 @@ public:
string ip = log_server_url.substr(0, log_server_url.find(':'));
string port = log_server_url.substr(log_server_url.find(':') + 1, log_server_url.length());
int port_num = stoi(port);
auto protocol = (_protocol == "TCP") ? I_Socket::SocketType::TCP : I_Socket::SocketType::UDP;
streams_preperation[type] = makeStream(type, ip, port_num);
streams_preperation[type] = makeStream(type, ip, port_num, protocol);
dbgInfo(D_REPORT)
<< "Successfully added log stream. Stream type: "
<< log_type
@ -265,6 +270,7 @@ private:
case StreamType::JSON_DEBUG: return make_shared<DebugStream>();
case StreamType::JSON_FOG: return make_shared<FogStream>();
case StreamType::JSON_LOG_FILE: return make_shared<LogFileStream>();
case StreamType::JSON_K8S_SVC: return make_shared<K8sSvcStream>();
case StreamType::SYSLOG: return nullptr;
case StreamType::CEF: return nullptr;
case StreamType::NONE: return nullptr;
@ -275,12 +281,11 @@ private:
}
shared_ptr<Stream>
makeStream(StreamType type, const string &ip, int port)
makeStream(StreamType type, const string &ip, int port, I_Socket::SocketType protocol)
{
switch (type) {
case StreamType::SYSLOG:
return make_shared<SyslogStream>(ip, port);
case StreamType::CEF: return make_shared<CefStream>(ip, port);
case StreamType::SYSLOG: return make_shared<SyslogStream>(ip, port, protocol);
case StreamType::CEF: return make_shared<CefStream>(ip, port, protocol);
default:
dbgWarning(D_REPORT) << "Invalid stream type with url";
return NULL;

View File

@ -21,6 +21,7 @@
#include "mock/mock_encryptor.h"
#include "mock/mock_agent_details.h"
#include "metric/all_metric_event.h"
#include "mock/mock_shell_cmd.h"
#include "version.h"
using namespace testing;
@ -33,6 +34,7 @@ class TestEnd {};
static bool should_fail = false;
static bool should_load_file_stream = false;
static bool should_load_k8s_stream = false;
class fakeConfig : Singleton::Consume<I_Logging>
{
@ -57,19 +59,45 @@ public:
}
void
load(cereal::JSONInputArchive &)
load(cereal::JSONInputArchive &ar)
{
if (should_fail) throw cereal::Exception("Should fail load");
if (should_load_file_stream) {
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_LOG_FILE);
return;
}
if (should_load_k8s_stream) {
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_K8S_SVC);
return;
}
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_DEBUG);
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::JSON_FOG);
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::CEF, "1.3.3.0:123");
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(ReportIS::StreamType::SYSLOG, "1.2.3.4:567");
}
bool is_domain;
ar(cereal::make_nvp("IsDomain", is_domain));
if (is_domain) {
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
ReportIS::StreamType::CEF,
"www.youtube.com:123",
"UDP"
);
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
ReportIS::StreamType::SYSLOG,
"www.google.com:567",
"UDP"
);
} else {
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
ReportIS::StreamType::CEF,
"1.3.3.0:123", "UDP"
);
Singleton::Consume<I_Logging>::by<fakeConfig>()->addStream(
ReportIS::StreamType::SYSLOG,
"1.2.3.4:567",
"UDP"
);
}
}
};
class LogTest : public testing::TestWithParam<bool>
@ -81,8 +109,10 @@ public:
i_agent_details(Singleton::Consume<I_AgentDetails>::from(agent_details)),
logger(Singleton::Consume<I_Logging>::from(log_comp))
{
is_domain = false;
should_fail = false;
should_load_file_stream = false;
should_load_k8s_stream = false;
env.preload();
log_comp.preload();
env.init();
@ -143,8 +173,10 @@ public:
~LogTest()
{
is_domain = false;
should_fail = false;
should_load_file_stream = false;
should_load_k8s_stream = false;
env.fini();
log_comp.fini();
Debug::setUnitTestFlag(D_REPORT, Debug::DebugLevel::INFO);
@ -208,15 +240,23 @@ public:
}
bool
loadFakeConfiguration(const bool &enable_bulk, const string &log_file_name = "", int bulks_size = -1)
loadFakeConfiguration(
bool enable_bulk,
bool domain = false,
const string &log_file_name = "",
int bulks_size = -1)
{
string is_enable_bulks = enable_bulk ? "true" : "false";
string is_domain = domain ? "true" : "false";
fakeConfig::preload();
output_filename = log_file_name == "" ? file.fname : log_file_name;
stringstream str_stream;
str_stream
<< "{\"fake config\": [{}], \"Logging\": {\"Log file name\": [{\"value\": \""
<< "{\"fake config\": [{\"IsDomain\": "
<< is_domain
<< "}],"
<< "\"Logging\": {\"Log file name\": [{\"value\": \""
<< output_filename
<< "\"}],"
<< "\"Enable bulk of logs\": [{\"value\": "
@ -247,6 +287,8 @@ public:
ConfigComponent config;
vector<string> capture_syslog_cef_data;
I_MainLoop::Routine sysog_routine = nullptr;
StrictMock<MockShellCmd> mock_shell_cmd;
bool is_domain;
private:
string body;
@ -259,6 +301,16 @@ TEST_F(LogTest, load_policy)
EXPECT_TRUE(loadFakeConfiguration(false));
}
TEST_F(LogTest, loadPolicyDomain)
{
is_domain = true;
string result = "172.28.1.6";
EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillRepeatedly(Return(result));
EXPECT_TRUE(loadFakeConfiguration(false, true));
string failed_str = "Failed to connect to the CEF server";
EXPECT_THAT(getMessages(), Not(HasSubstr(failed_str)));
}
TEST_F(LogTest, loadPolicyFailure)
{
should_fail = true;
@ -690,9 +742,117 @@ TEST_F(LogTest, FogBulkLogs)
EXPECT_EQ(local_body, str1);
}
TEST_F(LogTest, OfflineK8sSvcTest)
{
i_agent_details->setOrchestrationMode(OrchestrationMode::HYBRID);
should_load_k8s_stream = true;
loadFakeConfiguration(false);
Tags tag1 = Tags::POLICY_INSTALLATION;
Tags tag2 = Tags::ACCESS_CONTROL;
string local_body;
string res("[{\"id\": 1, \"code\": 400, \"message\": \"yes\"}]");
EXPECT_CALL(
mock_fog_msg,
sendMessage(_, _, _, "open-appsec-tuning-svc", _, _, "/api/v1/agents/events", _, _, MessageTypeTag::LOG)
).WillRepeatedly(DoAll(SaveArg<1>(&local_body), Return(res)));
string str1(
"{\n"
" \"log\": {\n"
" \"eventTime\": \"0:0:0\",\n"
" \"eventName\": \"Install policy\",\n"
" \"eventSeverity\": \"Info\",\n"
" \"eventPriority\": \"Low\",\n"
" \"eventType\": \"Event Driven\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"Access Control\",\n"
" \"Policy Installation\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"Unnamed Nano Service\"\n"
" },\n"
" \"eventData\": {\n"
" \"logIndex\": 1\n"
" }\n"
" }\n"
"}"
);
LogGen("Install policy", Audience::INTERNAL, Severity::INFO, Priority::LOW, tag1, tag2);
EXPECT_EQ(local_body, str1);
}
TEST_F(LogTest, OfflineK8sSvcBulkLogs)
{
i_agent_details->setOrchestrationMode(OrchestrationMode::HYBRID);
should_load_k8s_stream = true;
loadFakeConfiguration(true);
string local_body;
string res("[{\"id\": 1, \"code\": 400, \"message\": \"yes\"}]");
EXPECT_CALL(
mock_fog_msg,
sendMessage(_, _, _, "open-appsec-tuning-svc", _, _, "/api/v1/agents/events/bulk", _, _, MessageTypeTag::LOG)
).WillRepeatedly(DoAll(SaveArg<1>(&local_body), Return(res)));
Tags tag1 = Tags::POLICY_INSTALLATION;
Tags tag2 = Tags::ACCESS_CONTROL;
string str1(
"{\n"
" \"logs\": [\n"
" {\n"
" \"id\": 1,\n"
" \"log\": {\n"
" \"eventTime\": \"0:0:0\",\n"
" \"eventName\": \"Install policy\",\n"
" \"eventSeverity\": \"Info\",\n"
" \"eventPriority\": \"Low\",\n"
" \"eventType\": \"Event Driven\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"Access Control\",\n"
" \"Policy Installation\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"Unnamed Nano Service\"\n"
" },\n"
" \"eventData\": {\n"
" \"logIndex\": 1\n"
" }\n"
" }\n"
" }\n"
" ]\n"
"}"
);
{
LogGen("Install policy", Audience::INTERNAL, Severity::INFO, Priority::LOW, tag1, tag2);
}
bulk_routine();
EXPECT_EQ(local_body, str1);
}
TEST_P(LogTest, metrics_check)
{
loadFakeConfiguration(true, "", 3);
loadFakeConfiguration(true, false, "", 3);
Tags tag1 = Tags::POLICY_INSTALLATION;
Tags tag2 = Tags::ACCESS_CONTROL;
@ -837,7 +997,7 @@ TEST_F(LogTest, ShouldRetryAfterFailedWriteToFile)
EXPECT_TRUE(logger->delStream(ReportIS::StreamType::JSON_LOG_FILE));
static const string invalid_file_path = "/proc/gibberish";
loadFakeConfiguration(false, invalid_file_path, -1);
loadFakeConfiguration(false, false, invalid_file_path, -1);
LogGen(
"Install policy",

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <arpa/inet.h>
#include "log_streams.h"
#include "logging_comp.h"
@ -18,12 +20,17 @@ using namespace std;
USE_DEBUG_FLAG(D_REPORT);
SyslogStream::SyslogStream(const string &_ip_address, int _port)
static string lookup_cmd = "nslookup ";
static string line_selection_cmd = "| grep Address | sed -n 2p";
static string parsing_cmd = "| cut -f2 -d' ' | tr -d '\n'";
SyslogStream::SyslogStream(const string &_address, int _port, I_Socket::SocketType _protocol)
:
i_socket(Singleton::Consume<I_Socket>::by<LoggingComp>()),
mainloop(Singleton::Consume<I_MainLoop>::by<LoggingComp>()),
ip_address(_ip_address),
port(_port)
address(_address),
port(_port),
protocol(_protocol)
{
connect();
if (!socket.ok()) {
@ -43,21 +50,21 @@ SyslogStream::~SyslogStream()
void
SyslogStream::sendLog(const Report &log)
{
if (!socket.ok()) {
connect();
if (!socket.ok()) {
dbgWarning(D_REPORT) << "Failed to connect to the syslog server, Log will not be sent.";
return;
}
dbgTrace(D_REPORT) << "Successfully connect to the syslog server";
}
string syslog_report = log.getSyslog();
vector<char> data(syslog_report.begin(), syslog_report.end());
mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::Offline,
[this, data] ()
{
if (!socket.ok()) {
connect();
if (!socket.ok()) {
dbgWarning(D_REPORT) << "Failed to connect to the syslog server, Log will not be sent.";
return;
}
dbgTrace(D_REPORT) << "Successfully connect to the syslog server";
}
int tries = 1;
for (; tries <=3; tries++) {
if (i_socket->writeData(socket.unpack(), data)) {
@ -75,18 +82,57 @@ SyslogStream::sendLog(const Report &log)
void
SyslogStream::connect()
{
auto syslog_ip_address = getProfileAgentSettingWithDefault<string>(ip_address, "agent.config.log.syslogServer.IP");
auto syslog_address = getProfileAgentSettingWithDefault<string>(address, "agent.config.log.syslogServer.IP");
auto syslog_port = getProfileAgentSettingWithDefault<uint>(port, "agent.config.log.syslogServer.port");
if (syslog_ip_address.empty()) {
dbgWarning(D_REPORT) << "Cannot connect to Syslog server, IP is not configured.";
if (syslog_address.empty()) {
dbgWarning(D_REPORT) << "Cannot connect to Syslog server, Address IP/Domain not configured.";
return;
}
struct in_addr addr;
if (inet_pton(AF_INET, syslog_address.data(), &addr) != 1) {
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<LoggingComp>();
string host_cmd = lookup_cmd + syslog_address + line_selection_cmd + parsing_cmd;
Maybe<string> res = shell_cmd->getExecOutput(host_cmd, 500);
if (!res.ok()) {
dbgWarning(D_REPORT)
<< "Failed to execute domain lookup command. "
<< "SYSLOG Domain: "
<< syslog_address
<< "Error: "
<< res.getErr();
return;
}
if (res.unpack().empty()) {
dbgWarning(D_REPORT)
<< "Got en empty ip address from lookup command. "
<< "SYSLOG Domain: "
<< syslog_address
<< "Got bad ip address: "
<< res.unpack();
return;
}
dbgDebug(D_REPORT) << "SYSLOG Domain lookup result: " << res.unpack();
if (inet_pton(AF_INET, res.unpack().data(), &addr) != 1) {
dbgWarning(D_REPORT)
<< "Got a faulty ip address from lookup command. "
<< "SYSLOG Domain: "
<< syslog_address
<< "Got bad ip address: "
<< res.unpack();
return;
}
syslog_address = res.unpack();
}
socket = i_socket->genSocket(
I_Socket::SocketType::UDP,
protocol,
false,
false,
syslog_ip_address + ":" + to_string(syslog_port)
syslog_address + ":" + to_string(syslog_port)
);
}

View File

@ -98,7 +98,8 @@ TagAndEnumManagement::convertStringToTag(const string &tag)
{"Reverse Proxy", ReportIS::Tags::REVERSE_PROXY},
{"Http Geo Filter", ReportIS::Tags::HTTP_GEO_FILTER},
{"File Upload", ReportIS::Tags::FILE_UPLOAD},
{"Identity Awareness", ReportIS::Tags::IDENTITY_AWARENESS}
{"Identity Awareness", ReportIS::Tags::IDENTITY_AWARENESS},
{"Rate Limit", ReportIS::Tags::RATE_LIMIT}
};
auto report_is_tag = strings_to_tags.find(tag);
@ -135,6 +136,7 @@ TagAndEnumManagement::convertToString(const StreamType &stream_type)
case StreamType::JSON_DEBUG: return "JSON Debug stream";
case StreamType::JSON_FOG: return "JSON FOG stream";
case StreamType::JSON_LOG_FILE: return "JSON File stream";
case StreamType::JSON_K8S_SVC: return "JSON K8S service stream";
case StreamType::SYSLOG: return "Syslog stream";
case StreamType::CEF: return "CEF stream";
@ -307,7 +309,8 @@ EnumArray<Tags, string> TagAndEnumManagement::tags_translation_arr {
"Reverse Proxy",
"Http Geo Filter",
"File Upload",
"Identity Awareness"
"Identity Awareness",
"Rate Limit"
};
EnumArray<AudienceTeam, string> TagAndEnumManagement::audience_team_translation {

View File

@ -49,6 +49,8 @@ public:
chrono::microseconds getTimeoutVal() const override;
string getProfileId(const string &tenant_id, const string &region) const override;
void
addInstance(const string &tenant_id, const string &profile_id, const string &instace_id)
{
@ -183,7 +185,7 @@ TenantManager::Impl::init()
auto rest = Singleton::Consume<I_RestApi>::by<TenantManager>();
rest->addRestCall<LoadNewTenants>(RestAction::SET, "tenant-id");
rest->addRestCall<FetchActiveTenants>(RestAction::SHOW, "active-tenants");
rest->addRestCall<FetchActiveTenants>(RestAction::SHOW, "profile-ids");
rest->addRestCall<FetchProfileIds>(RestAction::SHOW, "profile-ids");
}
if (type == TenantManagerType::CLIENT) {
@ -307,14 +309,14 @@ TenantManager::Impl::getAllTenants() const
}
vector<string>
TenantManager::Impl::getProfileIds(const string &tenant_id) const
TenantManager::Impl::getProfileIds(const string &_tenant_id) const
{
dbgFlow(D_TENANT_MANAGER) << "Tenant Manager is a client. Requesting the active tenants";
dbgFlow(D_TENANT_MANAGER) << "Tenant Manager is a client. Requesting the active profiles";
GetProfileIds profile_id(tenant_id);
GetProfileIds tenant_id(_tenant_id);
auto res = i_messaging->sendObject(
profile_id,
tenant_id,
I_Messaging::Method::POST,
"127.0.0.1",
7777,
@ -324,7 +326,7 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const
if (!res) {
i_messaging->sendObject(
profile_id,
tenant_id,
I_Messaging::Method::POST,
"127.0.0.1",
7778,
@ -333,7 +335,53 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const
);
}
return profile_id.profile_ids.get();
return tenant_id.profile_ids.get();
}
string
TenantManager::Impl::getProfileId(const string &tenant_id, const string &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
@ -351,7 +399,16 @@ TenantManager::Impl::areTenantAndProfileActive(const string &tenant_id, const st
void
TenantManager::Impl::addActiveTenantAndProfile(const string &tenant_id, const string &profile_id)
{
if (tenant_id.empty() || profile_id.empty()) {
dbgWarning(D_TENANT_MANAGER) << "Tenant ID and Profile ID should not be empty.";
return;
}
auto tenant_profile = TenantProfilePair(tenant_id, profile_id);
dbgTrace(D_TENANT_MANAGER)
<< "Adding an active tenant and profile. Tenant ID: "
<< tenant_id
<< ", Profile ID: "
<< profile_id;
active_tenants.createEntry(tenant_profile);
if (type == TenantManagerType::CLIENT) {
sendTenantAndProfile(tenant_id, profile_id);
@ -410,7 +467,8 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const
for (auto iter = begin(active_tenants); iter != end(active_tenants); iter++) {
if (iter->first.getTenantId() == tenant_id) {
tenant_profile_ids.push_back(iter->first.getPfofileId());
dbgTrace(D_TENANT_MANAGER) << "Returning a fetched profile ID: " << iter->first.getProfileId();
tenant_profile_ids.push_back(iter->first.getProfileId());
}
}
return tenant_profile_ids;
@ -419,7 +477,7 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const
vector<string>
TenantManager::Impl::fetchProfileIds(const string &tenant_id) const
{
dbgFlow(D_TENANT_MANAGER) << "Fetching all profile ids for tenant " << tenant_id;
dbgFlow(D_TENANT_MANAGER) << "Fetching all profile IDs for tenant " << tenant_id;
return (type == TenantManagerType::CLIENT) ? getProfileIds(tenant_id) : fetchAllProfileIds(tenant_id);
}
@ -462,4 +520,5 @@ TenantManager::preload()
{
registerExpectedConfiguration<uint32_t>("Tenant Manager", "Tenant timeout");
registerExpectedConfiguration<string>("Tenant Manager", "Tenant manager type");
registerExpectedSetting<string>("region");
}

View File

@ -1,2 +1,3 @@
add_subdirectory(graphqlparser)
add_subdirectory(yajl)
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