diff --git a/components/attachment-intakers/nginx_attachment/nginx_attachment.cc b/components/attachment-intakers/nginx_attachment/nginx_attachment.cc index 8df0049..438970c 100755 --- a/components/attachment-intakers/nginx_attachment/nginx_attachment.cc +++ b/components/attachment-intakers/nginx_attachment/nginx_attachment.cc @@ -1762,8 +1762,8 @@ private: &did_fail_on_purpose )) { return genError( - "Failed to read the attachment's User ID or Group ID" + - did_fail_on_purpose ? "[Intentional Failure]" : "" + string("Failed to read the attachment's User ID or Group ID") + + (did_fail_on_purpose ? "[Intentional Failure]" : "") ); } diff --git a/components/generic_rulebase/zone.cc b/components/generic_rulebase/zone.cc index b8266b7..c9f902c 100755 --- a/components/generic_rulebase/zone.cc +++ b/components/generic_rulebase/zone.cc @@ -156,7 +156,7 @@ Zone::contains(const Asset &asset) { QueryRequest request; - for (const pair &main_attr : asset.getAttrs()) { + for (const auto &main_attr : asset.getAttrs()) { request.addCondition(Condition::EQUALS, contextKeyToString(main_attr.first), main_attr.second); } diff --git a/components/health_check_manager/health_check_manager.cc b/components/health_check_manager/health_check_manager.cc index 519ea63..41d852a 100755 --- a/components/health_check_manager/health_check_manager.cc +++ b/components/health_check_manager/health_check_manager.cc @@ -83,13 +83,13 @@ public: : status(raw_status) { - for (const pair &single_stat : descriptions) { + for (const auto &single_stat : descriptions) { if (single_stat.second.getStatus() == HealthCheckStatus::HEALTHY) { dbgTrace(D_HEALTH_CHECK_MANAGER) << "Ignoring healthy status reply. Comp name: " << single_stat.first; continue; } - for (const pair &status : single_stat.second.getExtendedStatus()) { + for (const auto &status : single_stat.second.getExtendedStatus()) { errors.push_back(HealthCheckError(single_stat.first + " " + status.first, status.second)); } } @@ -190,7 +190,7 @@ private: { general_health_aggregated_status = HealthCheckStatus::HEALTHY; - for (const pair &reply : all_comps_health_status) { + for (const auto &reply : all_comps_health_status) { HealthCheckStatus status = reply.second.getStatus(); dbgTrace(D_HEALTH_CHECK_MANAGER) diff --git a/components/http_manager/http_manager_opaque.cc b/components/http_manager/http_manager_opaque.cc index ed1f312..7be0e25 100644 --- a/components/http_manager/http_manager_opaque.cc +++ b/components/http_manager/http_manager_opaque.cc @@ -48,7 +48,7 @@ HttpManagerOpaque::getCurrVerdict() const uint accepted_apps = 0; ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT; - for (const pair &app_verdic_pair : applications_verdicts) { + for (const auto &app_verdic_pair : applications_verdicts) { switch (app_verdic_pair.second) { case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP: return app_verdic_pair.second; diff --git a/components/include/generic_rulebase/triggers_config.h b/components/include/generic_rulebase/triggers_config.h index bea59df..13b5b6d 100755 --- a/components/include/generic_rulebase/triggers_config.h +++ b/components/include/generic_rulebase/triggers_config.h @@ -11,52 +11,108 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// \file triggers_config.h +/// \brief Declaration of classes WebTriggerConf and LogTriggerConf, and related functions. +/// \author Check Point Software Technologies Ltd. +/// \date 2022 + #ifndef __TRIGGERS_CONFIG_H__ #define __TRIGGERS_CONFIG_H__ -#include #include +#include -#include "environment/evaluator_templates.h" +#include "cereal/archives/json.hpp" #include "cereal/types/string.hpp" #include "cereal/types/vector.hpp" -#include "cereal/archives/json.hpp" +#include "config.h" +#include "environment/evaluator_templates.h" +#include "generic_rulebase_utils.h" #include "i_environment.h" #include "i_logging.h" -#include "singleton.h" -#include "maybe_res.h" -#include "config.h" #include "log_generator.h" -#include "generic_rulebase_utils.h" +#include "maybe_res.h" +#include "singleton.h" +/// \class WebTriggerConf +/// \brief Represents the configuration for a web trigger. class WebTriggerConf { public: + /// \brief Default constructor for WebTriggerConf. WebTriggerConf(); + + /// \brief Constructor for WebTriggerConf. + /// \param title The title of the trigger. + /// \param body The body of the trigger. + /// \param code The response code for the trigger. WebTriggerConf(const std::string &title, const std::string &body, uint code); + /// \brief Preload function to register expected configuration. static void preload() { registerExpectedConfiguration("rulebase", "webUserResponse"); } + /// \brief Load function to deserialize configuration from JSONInputArchive. + /// \param archive_in The JSON input archive. void load(cereal::JSONInputArchive &archive_in); + /// \brief Equality operator for WebTriggerConf. + /// \param other The WebTriggerConf to compare. + /// \return True if the two WebTriggerConf objects are equal, otherwise false. bool operator==(const WebTriggerConf &other) const; - uint getResponseCode() const { return response_code; } + /// \brief Get the response code for the trigger. + /// \return The response code. + uint + getResponseCode() const + { + return response_code; + } - const std::string & getResponseTitle() const { return response_title; } + /// \brief Get the response title for the trigger. + /// \return The response title. + const std::string & + getResponseTitle() const + { + return response_title; + } - const std::string & getResponseBody() const { return response_body; } + /// \brief Get the response body for the trigger. + /// \return The response body. + const std::string & + getResponseBody() const + { + return response_body; + } - const std::string & getDetailsLevel() const { return details_level; } + /// \brief Get the details level for the trigger. + /// \return The details level. + const std::string & + getDetailsLevel() const + { + return details_level; + } - const std::string & getRedirectURL() const { return redirect_url; } + /// \brief Get the redirect URL for the trigger. + /// \return The redirect URL. + const std::string & + getRedirectURL() const + { + return redirect_url; + } - bool getAddEventId() const { return add_event_id_to_header; } + /// \brief Check if the trigger should add an event ID to the header. + /// \return True if the trigger should add an event ID, otherwise false. + bool + getAddEventId() const + { + return add_event_id_to_header; + } + /// \brief Default trigger configuration for WebTriggerConf. static WebTriggerConf default_trigger_conf; private: @@ -64,17 +120,38 @@ private: std::string details_level; std::string response_body; std::string redirect_url; - uint response_code; - bool add_event_id_to_header = false; + uint response_code; + bool add_event_id_to_header = false; }; +/// \class LogTriggerConf +/// \brief Represents the configuration for a log trigger. class LogTriggerConf : Singleton::Consume { public: - enum class SecurityType { AccessControl, ThreatPrevention, Compliance, COUNT }; - enum class extendLoggingSeverity { None, High, Critical }; + /// \enum SecurityType + /// \brief Enumerates the security types for LogTriggerConf. + enum class SecurityType + { + AccessControl, + ThreatPrevention, + Compliance, + COUNT + }; - enum class WebLogFields { + /// \enum extendLoggingSeverity + /// \brief Enumerates the extended logging severity for LogTriggerConf. + enum class extendLoggingSeverity + { + None, + High, + Critical + }; + + /// \enum WebLogFields + /// \brief Enumerates the web log fields for LogTriggerConf. + enum class WebLogFields + { webBody, webHeaders, webRequests, @@ -85,17 +162,31 @@ public: COUNT }; + /// \brief Default constructor for LogTriggerConf. LogTriggerConf() {} + /// \brief Constructor for LogTriggerConf. + /// \param trigger_name The name of the trigger. + /// \param log_detect Flag indicating whether to log on detect. + /// \param log_prevent Flag indicating whether to log on prevent. LogTriggerConf(std::string trigger_name, bool log_detect, bool log_prevent); + /// \brief Preload function to register expected configuration. static void preload() { registerExpectedConfiguration("rulebase", "log"); } - template + /// \brief LogGen operator for LogTriggerConf. + /// \param title The title of the log. + /// \param security The security type of the log. + /// \param severity The severity of the log. + /// \param priority The priority of the log. + /// \param is_action_drop_or_prevent Flag indicating if the action is drop or prevent. + /// \param tags Tags for the log. + /// \return The LogGen object. + template LogGen operator()( const std::string &title, @@ -103,7 +194,8 @@ public: ReportIS::Severity severity, ReportIS::Priority priority, bool is_action_drop_or_prevent, - Tags ...tags) const + Tags... tags + ) const { return LogGen( title, @@ -117,11 +209,17 @@ public: ); } - template + /// \brief LogGen operator for LogTriggerConf. + /// \param title The title of the log. + /// \param security The security type of the log. + /// \param is_action_drop_or_prevent Flag indicating if the action is drop or prevent. + /// \param tags Tags for the log. + /// \return The LogGen object. + template LogGen - operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags ...tags) const + operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags... tags) const { - return (*this)( + return operator()( title, security, getSeverity(is_action_drop_or_prevent), @@ -131,30 +229,98 @@ public: ); } + /// \brief Load function to deserialize configuration from JSONInputArchive. + /// \param archive_in The JSON input archive. void load(cereal::JSONInputArchive &archive_in); - bool isWebLogFieldActive(WebLogFields log_field) const { return log_web_fields.isSet(log_field); } + /// \brief Check if the web log field is active for the trigger. + /// \param log_field The web log field to check. + /// \return True if the web log field is active, otherwise false. + bool + isWebLogFieldActive(WebLogFields log_field) const + { + return log_web_fields.isSet(log_field); + } - bool isLogStreamActive(ReportIS::StreamType stream_type) const { return active_streams.isSet(stream_type); } + /// \brief Check if the log stream is active for the trigger. + /// \param stream_type The log stream type to check. + /// \return True if the log stream is active, otherwise false. + bool + isLogStreamActive(ReportIS::StreamType stream_type) const + { + return active_streams.isSet(stream_type); + } - bool isPreventLogActive(SecurityType security_type) const { return should_log_on_prevent.isSet(security_type); } + /// \brief Check if the log is active on prevent for the given security type. + /// \param security_type The security type to check. + /// \return True if the log is active on prevent, otherwise false. + bool + isPreventLogActive(SecurityType security_type) const + { + return should_log_on_prevent.isSet(security_type); + } - bool isDetectLogActive(SecurityType security_type) const { return should_log_on_detect.isSet(security_type); } + /// \brief Check if the log is active on detect for the given security type. + /// \param security_type The security type to check. + /// \return True if the log is active on detect, otherwise false. + bool + isDetectLogActive(SecurityType security_type) const + { + return should_log_on_detect.isSet(security_type); + } - bool isLogGeoLocationActive(SecurityType security_type) const { return log_geo_location.isSet(security_type); } + /// \brief Check if the geo-location log is active for the given security type. + /// \param security_type The security type to check. + /// \return True if the geo-location log is active, otherwise false. + bool + isLogGeoLocationActive(SecurityType security_type) const + { + return log_geo_location.isSet(security_type); + } - extendLoggingSeverity getExtendLoggingSeverity() const { return extend_logging_severity; } + /// \brief Get the extended logging severity. + /// \return The extended logging severity. + extendLoggingSeverity + getExtendLoggingSeverity() const + { + return extend_logging_severity; + } - const std::string & getVerbosity() const { return verbosity; } - const std::string & getName() const { return name; } + /// \brief Get the verbosity. + /// \return The verbosity. + const std::string & + getVerbosity() const + { + return verbosity; + } - const std::string & getUrlForSyslog() const { return url_for_syslog; } - const std::string & getUrlForCef() const { return url_for_cef; } + /// \brief Get the name. + /// \return The name. + const std::string & + getName() const + { + return name; + } + + /// \brief Get the URL for syslog. + /// \return The URL for syslog. + const std::string & + getUrlForSyslog() const + { + return url_for_syslog; + } + + /// \brief Get the URL for CEF. + /// \return The URL for CEF. + const std::string & + getUrlForCef() const + { + return url_for_cef; + } private: ReportIS::Severity getSeverity(bool is_action_drop_or_prevent) const; ReportIS::Priority getPriority(bool is_action_drop_or_prevent) const; - Flags getStreams(SecurityType security_type, bool is_action_drop_or_prevent) const; Flags getEnrechments(SecurityType security_type) const; diff --git a/components/include/health_checker.h b/components/include/health_checker.h index e62f841..af8b3e4 100755 --- a/components/include/health_checker.h +++ b/components/include/health_checker.h @@ -18,6 +18,7 @@ #include "i_mainloop.h" #include "i_socket_is.h" #include "i_health_check_manager.h" +#include "i_shell_cmd.h" #include "component.h" class HealthChecker @@ -25,7 +26,8 @@ class HealthChecker public Component, Singleton::Consume, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume { public: HealthChecker(); diff --git a/components/include/i_orchestration_tools.h b/components/include/i_orchestration_tools.h index 630ce88..18da6c9 100755 --- a/components/include/i_orchestration_tools.h +++ b/components/include/i_orchestration_tools.h @@ -109,6 +109,11 @@ public: virtual Maybe readFile(const std::string &path) const = 0; virtual bool writeFile(const std::string &text, const std::string &path) const = 0; virtual bool removeFile(const std::string &path) const = 0; + virtual bool removeDirectory(const std::string &path, bool delete_content) const = 0; + virtual void deleteVirtualTenantProfileFiles( + const std::string &tenant_id, + const std::string &profile_id, + const std::string &conf_path) const = 0; virtual bool copyFile(const std::string &src_path, const std::string &dst_path) const = 0; virtual bool doesFileExist(const std::string &file_path) const = 0; virtual void fillKeyInJson( @@ -118,6 +123,7 @@ public: virtual bool createDirectory(const std::string &directory_path) const = 0; virtual bool doesDirectoryExist(const std::string &dir_path) const = 0; virtual bool executeCmd(const std::string &cmd) const = 0; + virtual void loadTenantsFromDir(const std::string &dir_path) const = 0; virtual std::string base64Encode(const std::string &input) const = 0; virtual std::string base64Decode(const std::string &input) const = 0; diff --git a/components/include/i_service_controller.h b/components/include/i_service_controller.h index e32786c..d1f9872 100755 --- a/components/include/i_service_controller.h +++ b/components/include/i_service_controller.h @@ -19,6 +19,7 @@ #include #include "connkey.h" +#include "maybe_res.h" #include "rest.h" enum class ReconfStatus { SUCCEEDED, IN_PROGRESS, FAILED, INACTIVE }; @@ -27,6 +28,7 @@ class I_ServiceController { public: virtual void refreshPendingServices() = 0; + virtual const std::string & getPolicyVersions() const = 0; virtual const std::string & getPolicyVersion() const = 0; virtual const std::string & getUpdatePolicyVersion() const = 0; virtual void updateReconfStatus(int id, ReconfStatus status) = 0; @@ -37,13 +39,13 @@ public: const std::string &service_id ) = 0; - virtual bool + virtual Maybe updateServiceConfiguration( const std::string &new_policy_path, const std::string &new_settings_path, const std::vector &new_data_files = {}, - const std::string &tenant_id = "", - const std::string &profile_id = "", + const std::string &child_tenant_id = "", + const std::string &child_profile_id = "", const bool last_iteration = false ) = 0; diff --git a/components/include/i_update_communication.h b/components/include/i_update_communication.h index 65bf4c4..b31d8fd 100755 --- a/components/include/i_update_communication.h +++ b/components/include/i_update_communication.h @@ -26,9 +26,12 @@ using OrchData = Maybe; class I_UpdateCommunication { public: + virtual Maybe sendPolicyVersion( + const std::string &policy_version, + const std::string &policy_versions + ) const = 0; virtual Maybe authenticateAgent() = 0; virtual Maybe getUpdate(CheckUpdateRequest &request) = 0; - virtual Maybe sendPolicyVersion(const std::string &policy_version) const = 0; virtual Maybe downloadAttributeFile(const GetResourceFile &resourse_file) = 0; virtual void setAddressExtenesion(const std::string &extension) = 0; }; diff --git a/components/include/orchestration_tools.h b/components/include/orchestration_tools.h index 0e26d3e..caa851c 100755 --- a/components/include/orchestration_tools.h +++ b/components/include/orchestration_tools.h @@ -17,9 +17,16 @@ #include #include "i_orchestration_tools.h" +#include "i_shell_cmd.h" +#include "i_tenant_manager.h" #include "component.h" -class OrchestrationTools : public Component, Singleton::Provide +class OrchestrationTools + : + public Component, + Singleton::Provide, + Singleton::Consume, + Singleton::Consume { public: OrchestrationTools(); diff --git a/components/include/orchestrator/rest_api/orchestration_check_update.h b/components/include/orchestrator/rest_api/orchestration_check_update.h index 1306d07..2304ecd 100644 --- a/components/include/orchestrator/rest_api/orchestration_check_update.h +++ b/components/include/orchestrator/rest_api/orchestration_check_update.h @@ -106,6 +106,42 @@ public: BOTH_LABEL_OPTIONAL_PARAM(TenantError, error, "error"); }; + class UpgradeSchedule : public ClientRest + { + public: + UpgradeSchedule() = default; + + void init(const std::string &_upgrade_mode) { mode = _upgrade_mode; } + + void + init( + const std::string &_upgrade_mode, + const std::string &_upgrade_time, + const uint &_upgrade_duration_hours) + { + init(_upgrade_mode); + time = _upgrade_time; + duration_hours = _upgrade_duration_hours; + } + + void + init( + const std::string &_upgrade_mode, + const std::string &_upgrade_time, + const uint &_upgrade_duration_hours, + const std::vector &_upgrade_days) + { + init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours); + days = _upgrade_days; + } + + private: + C2S_LABEL_PARAM(std::string, mode, "upgradeMode"); + C2S_LABEL_OPTIONAL_PARAM(std::string, time, "upgradeTime"); + C2S_LABEL_OPTIONAL_PARAM(uint, duration_hours, "upgradeDurationHours"); + C2S_LABEL_OPTIONAL_PARAM(std::vector, days, "upgradeDay"); + }; + CheckUpdateRequest( const std::string &_manifest, const std::string &_policy, @@ -185,6 +221,28 @@ public: void setGreedyMode() { check_all_tenants = true; } + void + setUpgradeFields(const std::string &_upgrade_mode) + { + upgrade_schedule.setActive(true); + upgrade_schedule.get().init(_upgrade_mode); + } + + void + setUpgradeFields( + const std::string &_upgrade_mode, + const std::string &_upgrade_time, + const uint &_upgrade_duration_hours, + const std::vector &_upgrade_days) + { + upgrade_schedule.setActive(true); + if (!_upgrade_days.empty()) { + upgrade_schedule.get().init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days); + return; + } + upgrade_schedule.get().init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours); + } + private: class VirtualConfig : public ClientRest { @@ -239,6 +297,8 @@ private: C2S_LABEL_PARAM(std::string, checksum_type, "checksum-type"); C2S_LABEL_PARAM(std::string, policy_version, "policyVersion"); + C2S_LABEL_OPTIONAL_PARAM(UpgradeSchedule, upgrade_schedule, "upgradeSchedule"); + S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_policy, "virtualPolicy"); S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_settings, "virtualSettings"); }; diff --git a/components/security_apps/ips/include/ips_signatures.h b/components/security_apps/ips/include/ips_signatures.h index 9b9bb1d..f6347b2 100644 --- a/components/security_apps/ips/include/ips_signatures.h +++ b/components/security_apps/ips/include/ips_signatures.h @@ -1,54 +1,176 @@ +// 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. + +/// \file ips_signatures.h +/// \brief Declaration of classes IPSSignatureSubTypes, IPSSignaturesPerContext, IPSSignatures, SnortSignatures, and +/// related functions. \author Check Point Software Technologies Ltd. \date 2022 + #ifndef __IPS_SIGNATURES_H__ #define __IPS_SIGNATURES_H__ #include #include "config.h" -#include "parsed_context.h" -#include "log_generator.h" -#include "pm_hook.h" -#include "ips_enums.h" -#include "ips_entry.h" #include "i_first_tier_agg.h" +#include "ips_entry.h" +#include "ips_enums.h" +#include "log_generator.h" +#include "parsed_context.h" +#include "pm_hook.h" +/// \namespace IPSSignatureSubTypes +/// \brief Namespace containing subtypes for IPS signatures. namespace IPSSignatureSubTypes { using ActionResults = std::tuple>; +/// \class BaseSignature +/// \brief Represents the base signature class. class BaseSignature { public: - enum class MatchType { NO_MATCH, CACHE_MATCH, MATCH }; + /// \enum MatchType + /// \brief Enumerates the types of matches for BaseSignature. + enum class MatchType + { + NO_MATCH, + CACHE_MATCH, + MATCH + }; - virtual const std::string & getSigId() const = 0; + /// \brief Get the ID of the signature. + virtual const std::string &getSigId() const = 0; + + /// \brief Get the match type for the signature. + /// \param matched The set of patterns that matched. virtual MatchType getMatch(const std::set &matched) const = 0; + + /// \brief Get the set of patterns in the signature. virtual std::set patternsInSignature() const = 0; - virtual const std::vector & getContext() const = 0; + + /// \brief Get the context of the signature. + virtual const std::vector &getContext() const = 0; }; +/// \class IPSSignatureMetaData +/// \brief Represents the metadata for an IPS signature. class IPSSignatureMetaData { public: + /// \brief Load the metadata from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); + + /// \brief Set the indicators for the metadata. + /// \param source The source indicator. + /// \param version The version indicator. void setIndicators(const std::string &source, const std::string &version); - const std::string & getId() const { return protection_id; } - const std::string & getName() const { return sig_name; } - const std::string & getUpdateVersion() const { return update; } - const std::string & getLogTitle() const { return event_log; } - const std::string & getSource() const { return source; } - const std::string & getFeedVersion() const { return version; } - const std::vector & getCveList() const { return cve_list; } - IPSLevel getSeverity() const { return severity; } - std::string getSeverityString() const; - IPSLevel getConfidence() const { return confidence; } - std::string getConfidenceString() const; - IPSLevel getPerformance() const { return performance; } - std::string getPerformanceString() const; - bool isSilent() const { return is_silent; } - std::string getIncidentType() const; - bool isYearAtLeast(const Maybe &year) const; - Maybe getYear() const; + /// \brief Get the ID of the signature. + const std::string & + getId() const + { + return protection_id; + } + + /// \brief Get the name of the signature. + const std::string & + getName() const + { + return sig_name; + } + + /// \brief Get the update version of the signature. + const std::string & + getUpdateVersion() const + { + return update; + } + + /// \brief Get the log title of the signature. + const std::string & + getLogTitle() const + { + return event_log; + } + + /// \brief Get the source indicator of the signature. + const std::string & + getSource() const + { + return source; + } + + /// \brief Get the feed version of the signature. + const std::string & + getFeedVersion() const + { + return version; + } + + /// \brief Get the CVE list of the signature. + const std::vector & + getCveList() const + { + return cve_list; + } + + /// \brief Get the severity level of the signature. + IPSLevel + getSeverity() const + { + return severity; + } + + /// \brief Get the severity level as a string of the signature. + std::string getSeverityString() const; + + /// \brief Get the confidence level of the signature. + IPSLevel + getConfidence() const + { + return confidence; + } + + /// \brief Get the confidence level as a string of the signature. + std::string getConfidenceString() const; + + /// \brief Get the performance level of the signature. + IPSLevel + getPerformance() const + { + return performance; + } + + /// \brief Get the performance level as a string of the signature. + std::string getPerformanceString() const; + + /// \brief Check if the signature is silent. + bool + isSilent() const + { + return is_silent; + } + + /// \brief Get the incident type of the signature. + std::string getIncidentType() const; + + /// \brief Check if the signature is from a specific year or later. + /// \param year The year to compare with. + bool isYearAtLeast(const Maybe &year) const; + + /// \brief Get the year of the signature. + Maybe getYear() const; private: std::string protection_id; @@ -65,69 +187,224 @@ private: bool is_silent = false; }; +/// \class CompleteSignature +/// \brief Represents a complete signature. class CompleteSignature { public: + /// \brief Load the complete signature from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); + + /// \brief Get the match type for the signature. + /// \param matches The set of patterns that matched. BaseSignature::MatchType getMatch(const std::set &matches) const; + + /// \brief Get the set of patterns in the signature. std::set patternsInSignature() const; + + /// \brief Set the indicators for the complete signature. + /// \param source The source indicator. + /// \param version The version indicator. void setIndicators(const std::string &source, const std::string &version); - const std::vector & getContext() const { return rule->getContext(); } - const std::string & getId() const { return metadata.getId(); } - const std::string & getLogTitle() const { return metadata.getLogTitle(); } - const std::string & getName() const { return metadata.getName(); } - const std::string & getUpdateVersion() const { return metadata.getUpdateVersion(); } - const std::string & getSource() const { return metadata.getSource(); } - const std::string & getFeedVersion() const { return metadata.getFeedVersion(); } - const std::vector & getCveList() const { return metadata.getCveList(); } - IPSLevel getSeverity() const { return metadata.getSeverity(); } - std::string getSeverityString() const { return metadata.getSeverityString(); } - IPSLevel getConfidence() const { return metadata.getConfidence(); } - std::string getConfidenceString() const { return metadata.getConfidenceString(); } - IPSLevel getPerformance() const { return metadata.getPerformance(); } - std::string getPerformanceString() const { return metadata.getPerformanceString(); } - bool isSilent() const { return metadata.isSilent(); } - std::string getIncidentType() const { return metadata.getIncidentType(); } + /// \brief Get the context of the signature. + const std::vector & + getContext() const + { + return rule->getContext(); + } - bool isYearAtLeast(const Maybe &year) const { return metadata.isYearAtLeast(year); } - Maybe getYear() const { return metadata.getYear(); } + /// \brief Get the ID of the signature. + const std::string & + getId() const + { + return metadata.getId(); + } + + /// \brief Get the log title of the signature. + const std::string & + getLogTitle() const + { + return metadata.getLogTitle(); + } + + /// \brief Get the name of the signature. + const std::string & + getName() const + { + return metadata.getName(); + } + + /// \brief Get the update version of the signature. + const std::string & + getUpdateVersion() const + { + return metadata.getUpdateVersion(); + } + + /// \brief Get the source indicator of the signature. + const std::string & + getSource() const + { + return metadata.getSource(); + } + + /// \brief Get the feed version of the signature. + const std::string & + getFeedVersion() const + { + return metadata.getFeedVersion(); + } + + /// \brief Get the CVE list of the signature. + const std::vector & + getCveList() const + { + return metadata.getCveList(); + } + + /// \brief Get the severity level of the signature. + IPSLevel + getSeverity() const + { + return metadata.getSeverity(); + } + + /// \brief Get the severity level as a string of the signature. + std::string + getSeverityString() const + { + return metadata.getSeverityString(); + } + + /// \brief Get the confidence level of the signature. + IPSLevel + getConfidence() const + { + return metadata.getConfidence(); + } + + /// \brief Get the confidence level as a string of the signature. + std::string + getConfidenceString() const + { + return metadata.getConfidenceString(); + } + + /// \brief Get the performance level of the signature. + IPSLevel + getPerformance() const + { + return metadata.getPerformance(); + } + + /// \brief Get the performance level as a string of the signature. + std::string + getPerformanceString() const + { + return metadata.getPerformanceString(); + } + + /// \brief Check if the signature is silent. + bool + isSilent() const + { + return metadata.isSilent(); + } + + /// \brief Get the incident type of the signature. + std::string + getIncidentType() const + { + return metadata.getIncidentType(); + } + + /// \brief Check if the signature is from a specific year or later. + /// \param year The year to compare with. + bool + isYearAtLeast(const Maybe &year) const + { + return metadata.isYearAtLeast(year); + } + + /// \brief Get the year of the signature. + Maybe + getYear() const + { + return metadata.getYear(); + } private: IPSSignatureMetaData metadata; std::shared_ptr rule; }; +/// \class SignatureAndAction +/// \brief Represents a signature and its associated action. class SignatureAndAction { public: - SignatureAndAction(std::shared_ptr _signature, SignatureAction _action) - : - signature(_signature), - action(_action) + /// \brief Construct a SignatureAndAction object. + /// \param _signature The complete signature. + /// \param _action The signature action. + SignatureAndAction(std::shared_ptr _signature, SignatureAction _action) : + signature(_signature), action(_action) + {} + + /// \brief Check if the signature is matched for prevention. + /// \param context_buffer The context buffer. + /// \param pattern The set of patterns to match. + bool isMatchedPrevent(const Buffer &context_buffer, const std::set &pattern) const; + + /// \brief Check if the signature is matched silently. + /// \param context_buffer The context buffer. + bool matchSilent(const Buffer &context_buffer) const; + + /// \brief Get the set of patterns in the signature. + std::set + patternsInSignature() const { + return signature->patternsInSignature(); } - bool isMatchedPrevent(const Buffer &context_buffer, const std::set &pattern) const; - bool matchSilent(const Buffer &context_buffer) const; - std::set patternsInSignature() const { return signature->patternsInSignature(); } - const std::vector & getContext() const { return signature->getContext(); } + /// \brief Get the context of the signature. + const std::vector & + getContext() const + { + return signature->getContext(); + } private: + /// \brief Get the action results for the IPS state. + /// \param ips_state The IPS entry. ActionResults getAction(const IPSEntry &ips_state) const; + std::shared_ptr signature; SignatureAction action; }; -} // IPSSignatureSubTypes +} // namespace IPSSignatureSubTypes +/// \class IPSSignaturesPerContext +/// \brief Represents IPS signatures per context. class IPSSignaturesPerContext : public Singleton::Consume { public: + /// \brief Add a signature to the context. + /// \param sig The signature and its associated action. void addSignature(const IPSSignatureSubTypes::SignatureAndAction &sig); + + /// \brief Check if the context is matched for prevention. + /// \param context_buffer The context buffer. bool isMatchedPrevent(const Buffer &context_buffer) const; + + /// \brief Calculate the first tier for the given context name. + /// \param ctx_name The context name. void calcFirstTier(const std::string &ctx_name); private: + /// \brief Get the first tier matches for the buffer. + /// \param buffer The buffer to match. std::set getFirstTierMatches(const Buffer &buffer) const; std::map> signatures_per_lss; @@ -135,11 +412,17 @@ private: std::shared_ptr first_tier; }; +/// \class IPSSignaturesResource +/// \brief Represents IPS signatures resource. class IPSSignaturesResource { public: + /// \brief Load the IPS signatures resource from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); + /// \brief Get all the signatures. + /// \return A vector of shared pointers to CompleteSignature. const std::vector> & getSignatures() const { @@ -150,11 +433,26 @@ private: std::vector> all_signatures; }; +/// \class SnortSignaturesResourceFile +/// \brief Represents Snort signatures resource file. class SnortSignaturesResourceFile { public: + /// \brief Load the Snort signatures resource file from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); - bool isFile(const std::string &file_name) const { return file_name == name; } + + /// \brief Check if the file name matches. + /// \param file_name The name of the file. + /// \return True if the file name matches, otherwise false. + bool + isFile(const std::string &file_name) const + { + return file_name == name; + } + + /// \brief Get all the signatures. + /// \return A vector of shared pointers to CompleteSignature. const std::vector> & getSignatures() const { @@ -166,11 +464,18 @@ private: std::vector> all_signatures; }; +/// \class SnortSignaturesResource +/// \brief Represents Snort signatures resource. class SnortSignaturesResource { public: + /// \brief Load the Snort signatures resource from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); + /// \brief Get all the signatures for the given file name. + /// \param file_name The name of the file. + /// \return A vector of shared pointers to CompleteSignature. const std::vector> & getSignatures(const std::string &file_name) const { @@ -185,21 +490,74 @@ private: std::vector files; }; +/// \class IPSSignatures +/// \brief Represents IPS signatures. class IPSSignatures { std::set getFirstTier(const ParsedContext &context); public: + /// \brief Load the IPS signatures from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); + + /// \brief Check if the context is matched for prevention. + /// \param context_name The name of the context. + /// \param context_buffer The context buffer. bool isMatchedPrevent(const std::string &context_name, const Buffer &context_buffer) const; - bool isEmpty() const { return signatures_per_context.empty(); } + + /// \brief Check if the IPS signatures are empty. + /// \return True if the signatures are empty, otherwise false. + bool + isEmpty() const + { + return signatures_per_context.empty(); + } + + /// \brief Check if the IPS signatures for the given context are empty. + /// \param context The name of the context. + /// \return True if the signatures for the context are empty, otherwise false. bool isEmpty(const std::string &context) const; - const std::string & getAsset() const { return asset_name; } - const std::string & getAssetId() const { return asset_id; } - const std::string & getPractice() const { return practice_name; } - const std::string & getPracticeId() const { return practice_id; } - const std::string & getSourceIdentifier() const { return source_id; } + /// \brief Get the asset name. + /// \return The asset name. + const std::string & + getAsset() const + { + return asset_name; + } + + /// \brief Get the asset ID. + /// \return The asset ID. + const std::string & + getAssetId() const + { + return asset_id; + } + + /// \brief Get the practice name. + /// \return The practice name. + const std::string & + getPractice() const + { + return practice_name; + } + + /// \brief Get the practice ID. + /// \return The practice ID. + const std::string & + getPracticeId() const + { + return practice_id; + } + + /// \brief Get the source identifier. + /// \return The source identifier. + const std::string & + getSourceIdentifier() const + { + return source_id; + } private: std::map signatures_per_context; @@ -210,21 +568,74 @@ private: std::string source_id; }; +/// \class SnortSignatures +/// \brief Represents Snort signatures. class SnortSignatures { std::set getFirstTier(const ParsedContext &context); public: + /// \brief Load the Snort signatures from a JSON archive. + /// \param ar The JSON input archive. void load(cereal::JSONInputArchive &ar); + + /// \brief Check if the context is matched for prevention. + /// \param context_name The name of the context. + /// \param context_buffer The context buffer. bool isMatchedPrevent(const std::string &context_name, const Buffer &context_buffer) const; - bool isEmpty() const { return signatures_per_context.empty(); } + + /// \brief Check if the Snort signatures are empty. + /// \return True if the signatures are empty, otherwise false. + bool + isEmpty() const + { + return signatures_per_context.empty(); + } + + /// \brief Check if the Snort signatures for the given context are empty. + /// \param context The name of the context. + /// \return True if the signatures for the context are empty, otherwise false. bool isEmpty(const std::string &context) const; - const std::string & getAsset() const { return asset_name; } - const std::string & getAssetId() const { return asset_id; } - const std::string & getPractice() const { return practice_name; } - const std::string & getPracticeId() const { return practice_id; } - const std::string & getSourceIdentifier() const { return source_id; } + /// \brief Get the asset name. + /// \return The asset name. + const std::string & + getAsset() const + { + return asset_name; + } + + /// \brief Get the asset ID. + /// \return The asset ID. + const std::string & + getAssetId() const + { + return asset_id; + } + + /// \brief Get the practice name. + /// \return The practice name. + const std::string & + getPractice() const + { + return practice_name; + } + + /// \brief Get the practice ID. + /// \return The practice ID. + const std::string & + getPracticeId() const + { + return practice_id; + } + + /// \brief Get the source identifier. + /// \return The source identifier. + const std::string & + getSourceIdentifier() const + { + return source_id; + } private: std::map signatures_per_context; diff --git a/components/security_apps/ips/ips_signatures.cc b/components/security_apps/ips/ips_signatures.cc index 65b21cc..0412a60 100644 --- a/components/security_apps/ips/ips_signatures.cc +++ b/components/security_apps/ips/ips_signatures.cc @@ -23,6 +23,8 @@ using namespace ReportIS; using namespace std; using MatchType = BaseSignature::MatchType; +static const LogTriggerConf default_triger; + static const map severities = { { IPSLevel::CRITICAL, Severity::CRITICAL }, { IPSLevel::HIGH, Severity::HIGH }, @@ -396,7 +398,7 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT; auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL; diff --git a/components/security_apps/orchestration/details_resolver/details_resolver.cc b/components/security_apps/orchestration/details_resolver/details_resolver.cc index 82c12d1..b9452b9 100644 --- a/components/security_apps/orchestration/details_resolver/details_resolver.cc +++ b/components/security_apps/orchestration/details_resolver/details_resolver.cc @@ -131,7 +131,7 @@ DetailsResolver::Impl::isReverseProxy() return is_reverse_proxy.unpack().front() == '1'; } #endif - return false; + return getenv("DOCKER_RPM_ENABLED") && getenv("DOCKER_RPM_ENABLED") == string("true"); } bool diff --git a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h index 37014fb..97958c1 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h +++ b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h @@ -125,44 +125,54 @@ getMgmtObjName(shared_ptr file_stream) } Maybe -getGWIPAddress(shared_ptr file_stream) +getGWHardware(const string &command_output) { - return getMgmtObjAttr(file_stream, "ipaddr "); -} - -Maybe -getGWHardware(shared_ptr file_stream) -{ - Maybe val = getMgmtObjAttr(file_stream, "appliance_type "); - if(val.ok()) { - if (val == string("software")) return string("Open server"); - if (val == string("Maestro Gateway")) return string("Maestro"); + if (!command_output.empty()) { + if (command_output == "software") return string("Open server"); + if (command_output == "Maestro Gateway") return string("Maestro"); + return string(command_output); } - return val; + return genError("GW Hardware was not found"); } Maybe -getGWApplicationControlBlade(shared_ptr file_stream) +getAttr(const string &command_output, const string &error) { - return getMgmtObjAttr(file_stream, "application_firewall_blade "); + if (!command_output.empty()) { + return string(command_output); + } + + return genError(error); } Maybe -getGWURLFilteringBlade(shared_ptr file_stream) +getGWApplicationControlBlade(const string &command_output) { - return getMgmtObjAttr(file_stream, "advanced_uf_blade "); + return getAttr(command_output, "Application Control Blade was not found"); } Maybe -getGWIPSecVPNBlade(shared_ptr file_stream) +getGWURLFilteringBlade(const string &command_output) { - return getMgmtObjAttr(file_stream, "VPN_1 "); + return getAttr(command_output, "URL Filtering Blade was not found"); } Maybe -getGWVersion(shared_ptr file_stream) +getGWIPSecVPNBlade(const string &command_output) { - return getMgmtObjAttr(file_stream, "svn_version_name "); + return getAttr(command_output, "IPSec VPN Blade was not found"); +} + +Maybe +getGWIPAddress(const string &command_output) +{ + return getAttr(command_output, "IP Address was not found"); +} + +Maybe +getGWVersion(const string &command_output) +{ + return getAttr(command_output, "GW Version was not found"); } Maybe @@ -190,6 +200,33 @@ getSmbObjectName(const string &command_output) return getMgmtObjAttr(ifs, "name "); } +Maybe +getSmbBlade(const string &command_output, const string &error) +{ + if (command_output.front() == '1') return string("installed"); + if (command_output.front() == '0') return string("not-installed"); + + return genError(error); +} + +Maybe +getSmbGWApplicationControlBlade(const string &command_output) +{ + return getSmbBlade(command_output, "Application Control Blade was not found"); +} + +Maybe +getSmbGWURLFilteringBlade(const string &command_output) +{ + return getSmbBlade(command_output, "URL Filterin Blade was not found"); +} + +Maybe +getSmbGWIPSecVPNBlade(const string &command_output) +{ + return getSmbBlade(command_output, "IPSec VPN Blade was not found"); +} + Maybe getMgmtParentObjAttr(shared_ptr file_stream, const string &parent_obj, const string &attr) { diff --git a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h index 111da0c..e979501 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h +++ b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h @@ -31,16 +31,50 @@ #if defined(gaia) || defined(smb) SHELL_CMD_HANDLER("cpProductIntegrationMgmtObjectType", "cpprod_util CPPROD_IsMgmtMachine", getMgmtObjType) SHELL_CMD_HANDLER("hasSDWan", "[ -f $FWDIR/bin/sdwan_steering ] && echo '1' || echo '0'", checkHasSDWan) -SHELL_CMD_HANDLER("canUpdateSDWanData", "cpsdwan get_data | jq -r .can_update_sdwan_data", checkCanUpdateSDWanData) +SHELL_CMD_HANDLER( + "canUpdateSDWanData", + "CPSDWAN_NOLOGS=1 cpsdwan get_data -f can_update_sdwan_data | jq -r .can_update_sdwan_data", + checkCanUpdateSDWanData +) SHELL_CMD_HANDLER( "isSdwanRunning", "[ -v $(pidof cp-nano-sdwan) ] && echo 'false' || echo 'true'", checkIfSdwanRunning) +SHELL_CMD_HANDLER( + "IP Address", + "cpsdwan get_data | jq -r .main_ip", + getGWIPAddress +) +SHELL_CMD_HANDLER( + "Version", + "cat /etc/cp-release | grep -oE 'R[0-9]+(\\.[0-9]+)?'", + getGWVersion +) #endif //gaia || smb #if defined(gaia) SHELL_CMD_HANDLER("hasSupportedBlade", "enabled_blades", checkHasSupportedBlade) SHELL_CMD_HANDLER("hasSamlPortal", "mpclient status saml-vpn", checkSamlPortal) +SHELL_CMD_HANDLER( + "Hardware", + "cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:appliance_type/ {print $3}' | head -n 1", + getGWHardware +) +SHELL_CMD_HANDLER( + "Application Control", + "cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:application_firewall_blade/ {print $3}' | head -n 1", + getGWApplicationControlBlade +) +SHELL_CMD_HANDLER( + "URL Filtering", + "cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:advanced_uf_blade/ {print $3}' | head -n 1", + getGWURLFilteringBlade +) +SHELL_CMD_HANDLER( + "IPSec VPN", + "cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:VPN_1/ {print $3}' | head -n 1", + getGWIPSecVPNBlade +) #endif //gaia #if defined(smb) @@ -59,6 +93,21 @@ SHELL_CMD_HANDLER( "cpprod_util FwIsLocalMgmt", getSmbObjectName ) +SHELL_CMD_HANDLER( + "Application Control", + "cat $FWDIR/conf/active_blades.txt | grep -o 'APCL [01]' | cut -d ' ' -f2", + getSmbGWApplicationControlBlade +) +SHELL_CMD_HANDLER( + "URL Filtering", + "cat $FWDIR/conf/active_blades.txt | grep -o 'URLF [01]' | cut -d ' ' -f2", + getSmbGWURLFilteringBlade +) +SHELL_CMD_HANDLER( + "IPSec VPN", + "cat $FWDIR/conf/active_blades.txt | grep -o 'IPS [01]' | cut -d ' ' -f2", + getSmbGWIPSecVPNBlade +) #endif//smb SHELL_CMD_OUTPUT("kernel_version", "uname -r") @@ -73,17 +122,6 @@ SHELL_CMD_OUTPUT("helloWorld", "cat /tmp/agentHelloWorld 2>/dev/null") #if defined(gaia) FILE_CONTENT_HANDLER("hasIdpConfigured", "/opt/CPSamlPortal/phpincs/spPortal/idpPolicy.xml", checkIDP) - -FILE_CONTENT_HANDLER( - "cpProductIntegrationMgmtParentObjectUid", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getMgmtParentObjUid -) -FILE_CONTENT_HANDLER( - "cpProductIntegrationMgmtParentObjectName", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getMgmtParentObjName -) FILE_CONTENT_HANDLER( "cpProductIntegrationMgmtObjectName", (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C", @@ -101,37 +139,6 @@ FILE_CONTENT_HANDLER( (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C", getMgmtObjUid ) -FILE_CONTENT_HANDLER( - "IP Address", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getGWIPAddress -) -FILE_CONTENT_HANDLER( - "Hardware", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getGWHardware -) -FILE_CONTENT_HANDLER( - "Application Control", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getGWApplicationControlBlade -) -FILE_CONTENT_HANDLER( - "URL Filtering", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getGWURLFilteringBlade -) -FILE_CONTENT_HANDLER( - "IPSec VPN", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getGWIPSecVPNBlade -) -FILE_CONTENT_HANDLER( - "Version", - (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myself_objects.C", - getGWVersion -) - #else // !(gaia || smb) FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease) #endif // gaia || smb diff --git a/components/security_apps/orchestration/downloader/http_client.cc b/components/security_apps/orchestration/downloader/http_client.cc index eb25ffd..7447515 100755 --- a/components/security_apps/orchestration/downloader/http_client.cc +++ b/components/security_apps/orchestration/downloader/http_client.cc @@ -179,14 +179,13 @@ private: Maybe HTTPClient::getFile(const URLParser &url, ofstream &out_file, bool auth_required) { - auto message = Singleton::Consume::by(); - auto load_env_proxy = message->loadProxy(); + auto proxy_config = Singleton::Consume::by(); + auto load_env_proxy = proxy_config->loadProxy(); if (!load_env_proxy.ok()) return load_env_proxy; string token = ""; if (auth_required) { - auto message = Singleton::Consume::by(); - token = message->getAccessToken(); + token = Singleton::Consume::by()->getAccessToken(); } if (url.isOverSSL()) { @@ -214,15 +213,15 @@ Maybe HTTPClient::curlGetFileOverHttp(const URLParser &url, ofstream &out_file, const string &token) { try { - auto message = Singleton::Consume::by(); + auto proxy_config = Singleton::Consume::by(); HttpCurl http_curl_client( url, out_file, token, - message->getProxyDomain(ProxyProtocol::HTTPS), - message->getProxyPort(ProxyProtocol::HTTPS), - message->getProxyCredentials(ProxyProtocol::HTTPS)); + proxy_config->getProxyDomain(ProxyProtocol::HTTPS), + proxy_config->getProxyPort(ProxyProtocol::HTTPS), + proxy_config->getProxyCredentials(ProxyProtocol::HTTPS)); http_curl_client.setCurlOpts(); bool connection_ok = http_curl_client.connect(); @@ -247,12 +246,12 @@ Maybe HTTPClient::getFileHttp(const URLParser &url, ofstream &out_file, const string &token) { try { - auto message = Singleton::Consume::by(); + auto proxy_config = Singleton::Consume::by(); ClientConnection client_connection( url, - message->getProxyDomain(ProxyProtocol::HTTP), - message->getProxyPort(ProxyProtocol::HTTP), - message->getProxyCredentials(ProxyProtocol::HTTP), + proxy_config->getProxyDomain(ProxyProtocol::HTTP), + proxy_config->getProxyPort(ProxyProtocol::HTTP), + proxy_config->getProxyCredentials(ProxyProtocol::HTTP), token ); auto handle_connect_res = client_connection.handleConnect(); diff --git a/components/security_apps/orchestration/downloader/http_client.h b/components/security_apps/orchestration/downloader/http_client.h index c25c5f9..ae725f9 100755 --- a/components/security_apps/orchestration/downloader/http_client.h +++ b/components/security_apps/orchestration/downloader/http_client.h @@ -18,9 +18,15 @@ #include "maybe_res.h" #include "url_parser.h" #include "i_messaging.h" +#include "i_agent_details.h" +#include "i_proxy_configuration.h" // LCOV_EXCL_START Reason: Depends on real download server. -class HTTPClient : public Singleton::Consume +class HTTPClient + : + public Singleton::Consume, + public Singleton::Consume, + public Singleton::Consume { public: HTTPClient() = default; diff --git a/components/security_apps/orchestration/downloader/https_client.cc b/components/security_apps/orchestration/downloader/https_client.cc index d892a73..33d9031 100755 --- a/components/security_apps/orchestration/downloader/https_client.cc +++ b/components/security_apps/orchestration/downloader/https_client.cc @@ -535,16 +535,16 @@ HTTPClient::getFileSSL(const URLParser &url, ofstream &out_file, const string &t } } boost::asio::io_service io_service; - auto message = Singleton::Consume::by(); + auto proxy_config = Singleton::Consume::by(); Client client( out_file, io_service, ctx, url, - message->getProxyDomain(ProxyProtocol::HTTPS), - message->getProxyPort(ProxyProtocol::HTTPS), - message->getProxyCredentials(ProxyProtocol::HTTPS), + proxy_config->getProxyDomain(ProxyProtocol::HTTPS), + proxy_config->getProxyPort(ProxyProtocol::HTTPS), + proxy_config->getProxyCredentials(ProxyProtocol::HTTPS), token ); @@ -581,15 +581,15 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s ); } - auto message = Singleton::Consume::by(); + auto proxy_config = Singleton::Consume::by(); HttpsCurl ssl_curl_client( url, out_file, token, - message->getProxyDomain(ProxyProtocol::HTTPS), - message->getProxyPort(ProxyProtocol::HTTPS), - message->getProxyCredentials(ProxyProtocol::HTTPS), + proxy_config->getProxyDomain(ProxyProtocol::HTTPS), + proxy_config->getProxyPort(ProxyProtocol::HTTPS), + proxy_config->getProxyCredentials(ProxyProtocol::HTTPS), cert_file_path); ssl_curl_client.setCurlOpts(); diff --git a/components/security_apps/orchestration/health_check/health_check.cc b/components/security_apps/orchestration/health_check/health_check.cc index c034de4..96a43f0 100755 --- a/components/security_apps/orchestration/health_check/health_check.cc +++ b/components/security_apps/orchestration/health_check/health_check.cc @@ -247,6 +247,33 @@ private: ); } + bool + nginxContainerIsRunning() + { + static const string nginx_container_name = "cp_nginx_gaia"; + static const string cmd_running = + "docker ps --filter name=" + nginx_container_name + " --filter status=running"; + dbgTrace(D_HEALTH_CHECK) << "Checking if the container is running with the commmand: " << cmd_running; + + auto maybe_result = Singleton::Consume::by()->getExecOutput(cmd_running); + if (!maybe_result.ok()) { + dbgWarning(D_HEALTH_CHECK) + << "Unable to get status of nginx container. return false and failing health check."; + return false; + } + + return (*maybe_result).find(nginx_container_name) != string::npos; + + } + + void + closeCurrentSocket(I_Socket::socketFd fd, I_MainLoop::RoutineID curr_routine) { + dbgDebug(D_HEALTH_CHECK) << "Connection with client closed, client fd: " << fd; + open_connections_counter--; + i_socket->closeSocket(fd); + client_sockets_routines.erase(curr_routine); + } + void handleConnection() { @@ -254,7 +281,7 @@ private: dbgDebug(D_HEALTH_CHECK) << "Cannot serve new client, reached maximun open connections bound which is:" << open_connections_counter - << "maximun allowed: " + << "maximum allowed: " << max_connections; return; } @@ -276,21 +303,48 @@ private: dbgDebug(D_HEALTH_CHECK) << "Successfully accepted client, client fd: " << new_client_socket; open_connections_counter++; - auto curr_routine = i_mainloop->addFileRoutine( + auto curr_routine = i_mainloop->addOneTimeRoutine( I_MainLoop::RoutineType::RealTime, - new_client_socket, [this] () { auto curr_routine_id = i_mainloop->getCurrentRoutineId().unpack(); auto curr_client_socket = client_sockets_routines[curr_routine_id]; auto data_recieved = i_socket->receiveData(curr_client_socket, sizeof(uint8_t), false); if (!data_recieved.ok()) { - dbgDebug(D_HEALTH_CHECK) << "Connection with client closed, client fd: " << curr_client_socket; - open_connections_counter--; - i_socket->closeSocket(curr_client_socket); - client_sockets_routines.erase(curr_routine_id); + closeCurrentSocket(curr_client_socket, curr_routine_id); i_mainloop->stop(); } + + static const string success_response = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 25\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "health check successful\r\n"; + static const vector success_response_buffer(success_response.begin(), success_response.end()); + + static const string failure_response = + "HTTP/1.1 500 Internal Server Error\r\n" + "Content-Length: 21\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "health check failed\r\n"; + static const vector failure_response_buffer(failure_response.begin(), failure_response.end()); + + if (nginxContainerIsRunning()) { + dbgDebug(D_HEALTH_CHECK) + << "nginx conatiner is running, returning the following response: " + << success_response; + i_socket->writeData(curr_client_socket, success_response_buffer); + closeCurrentSocket(curr_client_socket, curr_routine_id); + return; + } + + dbgDebug(D_HEALTH_CHECK) + << "nginx conatiner is not running, returning the following response: " + << failure_response; + i_socket->writeData(curr_client_socket, failure_response_buffer); + closeCurrentSocket(curr_client_socket, curr_routine_id); }, "Health check probe connection handler", true diff --git a/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc b/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc index 9a7c952..e6b4a69 100755 --- a/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc +++ b/components/security_apps/orchestration/health_check/health_check_ut/health_check_ut.cc @@ -6,6 +6,7 @@ #include "mock/mock_time_get.h" #include "mock/mock_socket_is.h" #include "mock/mock_mainloop.h" +#include "mock/mock_shell_cmd.h" #include "health_check_manager.h" #include "config.h" @@ -18,6 +19,22 @@ using namespace testing; USE_DEBUG_FLAG(D_HEALTH_CHECK); +static const string response = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 25\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "health check successful\r\n"; +static const vector response_buffer(response.begin(), response.end()); + +static const string failure_response = + "HTTP/1.1 500 Internal Server Error\r\n" + "Content-Length: 21\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "health check failed\r\n"; +static const vector failure_response_buffer(failure_response.begin(), failure_response.end()); + class HealthCheckerTest : public testing::Test { public: @@ -47,6 +64,7 @@ public: NiceMock mock_log; AgentDetails agent_details; StrictMock mock_socket; + NiceMock mock_shell_cmd; I_Socket::socketFd server_socket = -1; Context ctx; ConfigComponent config; @@ -82,7 +100,7 @@ TEST_F(HealthCheckerTest, clientConnection) EXPECT_CALL( mock_mainloop, - addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false) + addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe listener startup", false) ).WillOnce(DoAll(SaveArg<1>(&handle_probe_routine), Return(0))); EXPECT_CALL( @@ -95,11 +113,19 @@ TEST_F(HealthCheckerTest, clientConnection) addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true) ).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0))); + EXPECT_CALL( + mock_mainloop, + addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true) + ).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0))); + int socket = 1; EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket)); EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0)); EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector())); + EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillRepeatedly(Return(string("cp_nginx_gaia"))); + EXPECT_CALL(mock_socket, writeData(_, response_buffer)).WillOnce(Return(true)); EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2); + health_checker.init(); handle_probe_routine(); connection_handler_routine(); @@ -194,10 +220,17 @@ TEST_F(HealthCheckerTest, disablingAfterEnabled) addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true) ).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0))); + EXPECT_CALL( + mock_mainloop, + addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true) + ).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0))); + int socket = 1; EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket)); EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0)); EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector())); + EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillOnce(Return(string("cp_nginx_gaia"))); + EXPECT_CALL(mock_socket, writeData(_, response_buffer)).WillOnce(Return(true)); EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2); health_checker.init(); handle_probe_routine(); @@ -242,11 +275,20 @@ TEST_F(HealthCheckerTest, changePortIpConfig) addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true) ).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0))); + EXPECT_CALL( + mock_mainloop, + addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true) + ).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0))); + int socket = 1; + int socket2 = 0; EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket)); EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0)); EXPECT_CALL(mock_socket, receiveData(_, 1, false)).Times(2).WillRepeatedly(Return(vector())); + EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).Times(2).WillRepeatedly(Return(string("cp_nginx_gaia"))); + EXPECT_CALL(mock_socket, writeData(_, response_buffer)).Times(2).WillRepeatedly(Return(true)); EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2); + EXPECT_CALL(mock_socket, closeSocket(socket2)); health_checker.init(); handle_probe_routine(); connection_handler_routine(); @@ -258,3 +300,44 @@ TEST_F(HealthCheckerTest, changePortIpConfig) setConfiguration(new_port, "Health Check", "Probe port"); connection_handler_routine(); } + +TEST_F(HealthCheckerTest, FailedHealthCheck) +{ + string ip = "1.2.3.4"; + setConfiguration(ip, "Health Check", "Probe IP"); + uint port = 11600; + setConfiguration(port, "Health Check", "Probe port"); + + EXPECT_CALL( + mock_mainloop, + addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false) + ).WillOnce(DoAll(SaveArg<1>(&handle_probe_routine), Return(0))); + + EXPECT_CALL( + mock_socket, + genSocket(I_Socket::SocketType::TCP, false, true, _) + ).WillRepeatedly(Return(1)); + + EXPECT_CALL( + mock_mainloop, + addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true) + ).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0))); + + EXPECT_CALL( + mock_mainloop, + addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true) + ).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0))); + + int socket = 1; + EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket)); + EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0)); + EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector())); + EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillOnce(Return(string(""))); + EXPECT_CALL(mock_socket, writeData(_, failure_response_buffer)).WillOnce(Return(true)); + EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2); + health_checker.init(); + handle_probe_routine(); + connection_handler_routine(); + connection_handler_routine(); + setConfiguration(false, "Health Check", "Probe enabled"); +} diff --git a/components/security_apps/orchestration/hybrid_mode_telemetry.cc b/components/security_apps/orchestration/hybrid_mode_telemetry.cc index 52cc834..b49ecb1 100755 --- a/components/security_apps/orchestration/hybrid_mode_telemetry.cc +++ b/components/security_apps/orchestration/hybrid_mode_telemetry.cc @@ -24,8 +24,8 @@ USE_DEBUG_FLAG(D_ORCHESTRATOR); static inline string & trim(string &in) { - in.erase(in.begin(), find_if(in.begin(), in.end(), not1(ptr_fun(isspace)))); - in.erase(find_if(in.rbegin(), in.rend(), not1(ptr_fun(isspace))).base(), in.end()); + in.erase(in.begin(), find_if(in.begin(), in.end(), [] (char c) { return !isspace(c); })); + in.erase(find_if(in.rbegin(), in.rend(), [] (char c) { return !isspace(c); }).base(), in.end()); return in; } diff --git a/components/security_apps/orchestration/include/fog_authenticator.h b/components/security_apps/orchestration/include/fog_authenticator.h index d07c224..1bdc3f6 100755 --- a/components/security_apps/orchestration/include/fog_authenticator.h +++ b/components/security_apps/orchestration/include/fog_authenticator.h @@ -266,17 +266,25 @@ private: S2C_PARAM(std::string, agentId); }; -class PolicyVersionPatchRequest : public ClientRest +class PolicyVersionPatchRequest { public: - PolicyVersionPatchRequest(const std::string &_policy_version) + PolicyVersionPatchRequest(const std::string &_policy_version, const std::string &_policy_versions) : - policy_version(_policy_version) + policy_version(_policy_version), + policy_versions(_policy_versions) { } + Maybe + genJson() const + { + return "{ \"policyVersion\" :\"" + policy_version + "\", \"versions\": " + policy_versions + "}"; + } + private: - C2S_LABEL_PARAM(std::string, policy_version, "policyVersion"); + std::string policy_version; + std::string policy_versions; }; class TokenRequest : public ClientRest diff --git a/components/security_apps/orchestration/include/fog_communication.h b/components/security_apps/orchestration/include/fog_communication.h index d41768b..3c27003 100755 --- a/components/security_apps/orchestration/include/fog_communication.h +++ b/components/security_apps/orchestration/include/fog_communication.h @@ -41,7 +41,10 @@ public: void init() override; Maybe getUpdate(CheckUpdateRequest &request) override; Maybe downloadAttributeFile(const GetResourceFile &resourse_file) override; - Maybe sendPolicyVersion(const std::string &policy_version) const override; + Maybe sendPolicyVersion( + const std::string &policy_version, + const std::string &policy_versions + ) const override; private: DeclarativePolicyUtils declarative_policy_utils; diff --git a/components/security_apps/orchestration/include/hybrid_communication.h b/components/security_apps/orchestration/include/hybrid_communication.h index 6e85345..84648fc 100755 --- a/components/security_apps/orchestration/include/hybrid_communication.h +++ b/components/security_apps/orchestration/include/hybrid_communication.h @@ -46,7 +46,10 @@ public: void init() override; Maybe getUpdate(CheckUpdateRequest &request) override; Maybe downloadAttributeFile(const GetResourceFile &resourse_file) override; - Maybe sendPolicyVersion(const std::string &policy_version) const override; + Maybe sendPolicyVersion( + const std::string &policy_version, + const std::string &policy_versions + ) const override; private: Maybe getNewVersion(); diff --git a/components/security_apps/orchestration/include/local_communication.h b/components/security_apps/orchestration/include/local_communication.h index d7f625a..f6dcb9f 100755 --- a/components/security_apps/orchestration/include/local_communication.h +++ b/components/security_apps/orchestration/include/local_communication.h @@ -33,7 +33,10 @@ public: Maybe downloadAttributeFile(const GetResourceFile &resourse_file) override; void setAddressExtenesion(const std::string &extension) override; - Maybe sendPolicyVersion(const std::string &policy_version) const override; + Maybe sendPolicyVersion( + const std::string &policy_version, + const std::string &policy_versions + ) const override; private: std::string getChecksum(const std::string &file_path); diff --git a/components/security_apps/orchestration/include/mock/mock_orchestration_tools.h b/components/security_apps/orchestration/include/mock/mock_orchestration_tools.h index 47c5fe3..9f89c89 100755 --- a/components/security_apps/orchestration/include/mock/mock_orchestration_tools.h +++ b/components/security_apps/orchestration/include/mock/mock_orchestration_tools.h @@ -55,5 +55,11 @@ public: MOCK_CONST_METHOD1(executeCmd, bool(const std::string &)); MOCK_CONST_METHOD1(base64Encode, std::string(const std::string &)); MOCK_CONST_METHOD1(base64Decode, std::string(const std::string &)); + MOCK_CONST_METHOD2(removeDirectory, bool(const std::string &, bool delete_content)); + MOCK_CONST_METHOD1(loadTenantsFromDir, void(const std::string &)); + MOCK_CONST_METHOD3( + deleteVirtualTenantProfileFiles, + void(const std::string &tenant_id, const std::string &profile_id, const std::string &conf_path) + ); }; #endif // __MOCK_ORCHESTRATION_TOOLS_H__ diff --git a/components/security_apps/orchestration/include/mock/mock_service_controller.h b/components/security_apps/orchestration/include/mock/mock_service_controller.h index e425d0b..23f8d16 100755 --- a/components/security_apps/orchestration/include/mock/mock_service_controller.h +++ b/components/security_apps/orchestration/include/mock/mock_service_controller.h @@ -38,14 +38,16 @@ public: MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &()); + MOCK_CONST_METHOD0(getPolicyVersions, const std::string &()); + MOCK_METHOD6( updateServiceConfiguration, - bool( + Maybe( const std::string &new_policy_path, const std::string &new_settings_path, const std::vector &new_data_files, - const std::string &tenant_id, - const std::string &profile_id, + const std::string &child_tenant_id, + const std::string &child_profile_id, const bool last_iteration ) ); diff --git a/components/security_apps/orchestration/include/mock/mock_update_communication.h b/components/security_apps/orchestration/include/mock/mock_update_communication.h index 3557c70..12960f4 100755 --- a/components/security_apps/orchestration/include/mock/mock_update_communication.h +++ b/components/security_apps/orchestration/include/mock/mock_update_communication.h @@ -31,7 +31,7 @@ public: MOCK_METHOD1(getUpdate, Maybe(CheckUpdateRequest &)); MOCK_METHOD1(downloadAttributeFile, Maybe(const GetResourceFile &)); MOCK_METHOD1(setAddressExtenesion, void(const std::string &)); - MOCK_CONST_METHOD1(sendPolicyVersion, Maybe(const std::string &)); + MOCK_CONST_METHOD2(sendPolicyVersion, Maybe(const std::string &, const std::string &)); }; #endif // __MOCK_UPDATE_COMMUNICATION_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt b/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt index 34db07a..08b99a7 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt @@ -1,3 +1,3 @@ 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 k8s_policy_utils.cc namespace_data.cc) +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 k8s_policy_utils.cc namespace_data.cc new_appsec_linux_policy.cc new_appsec_policy_crd_parser.cc new_custom_response.cc new_exceptions.cc new_log_trigger.cc new_practice.cc new_trusted_sources.cc access_control_practice.cc) diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/access_control_practice.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/access_control_practice.cc new file mode 100644 index 0000000..329a4b6 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/access_control_practice.cc @@ -0,0 +1,245 @@ +// 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 "access_control_practice.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"prevent", "detect", "inactive"}; +static const set valid_units = {"minute", "second"}; + +static const std::unordered_map key_to_mode_val = { + { "prevent-learn", "Prevent"}, + { "detect-learn", "Detect"}, + { "prevent", "Prevent"}, + { "detect", "Detect"}, + { "inactive", "Inactive"} +}; + +static const std::unordered_map key_to_units_val = { + { "second", "Second"}, + { "minute", "Minute"} +}; + +void +RateLimitRulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("name", name), + cereal::make_nvp("type", type) + ); +} + +const string & +RateLimitRulesTriggerSection::getName() const +{ + return name; +} + +void +RateLimitRulesSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("URI", uri), + cereal::make_nvp("scope", key_to_units_val.at(scope)), + cereal::make_nvp("triggers", triggers), + cereal::make_nvp("limit", limit) + ); +} + +RateLimitSection::RateLimitSection( + const string &asset_name, + const string &url, + const string &uri, + const std::string &_mode, + const std::string &_practice_id, + const std::string &_name, + const std::vector &_rules) + : + mode(_mode), + practice_id(_practice_id), + name(_name), + rules(_rules) +{ + bool any = asset_name == "Any" && url == "Any" && uri == "Any"; + string asset_id = any ? "Any" : url+uri; + context = "assetId(" + asset_id + ")"; +} + +void +RateLimitSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("mode", key_to_mode_val.at(mode)), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("name", name), + cereal::make_nvp("rules", rules) + ); +} + +const string & +RateLimitSection::getId() const +{ + return practice_id; +} + +const string & +RateLimitSection::getName() const +{ + return name; +} + +const string & +RateLimitSection::getMode() const +{ + return mode; +} + +void +AccessControlRulebaseSection::save(cereal::JSONOutputArchive &out_ar) const +{ + vector empty; + out_ar( + cereal::make_nvp("accessControl", empty), + cereal::make_nvp("traditionalFirewall", empty), + cereal::make_nvp("l4firewall", empty), + cereal::make_nvp("rateLimit", rate_limit) + ); +} + +void +AccessControlRulebaseWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", rule_base) + ); +} + +void +AccessControlRateLimiteRules::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limite rules"; + parseAppsecJSONKey("limit", limit, archive_in); + parseAppsecJSONKey("uri", uri, archive_in); + parseAppsecJSONKey("unit", unit, archive_in); + if (valid_units.count(unit) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "Access control rate limite rules units invalid: " + << unit; + } + parseAppsecJSONKey("comment", comment, archive_in); + parseAppsecJSONKey>("triggers", triggers, archive_in); +} + +const vector +AccessControlRateLimiteRules::getTriggers() const +{ + return triggers; +} + +RateLimitRulesSection +AccessControlRateLimiteRules::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const +{ + string id = ""; + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_LOCAL_POLICY) << "Failed to create random id"; + } + vector triggers_section; + string trigger_name = trigger.getName().substr(trigger.getName().find("/") + 1); + if (find(triggers.begin(), triggers.end(), trigger_name) != triggers.end()) { + triggers_section.push_back(trigger); + } + return RateLimitRulesSection( + limit, + id, + uri, + unit, + triggers_section + ); +} + +void +AccessControlRateLimit::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limit"; + parseAppsecJSONKey("overrideMode", mode, archive_in, "Inactive"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec access control rate limit override mode invalid: " << mode; + } + parseAppsecJSONKey>("rules", rules, archive_in); +} + +vector +AccessControlRateLimit::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const +{ + vector rules_section; + for (const AccessControlRateLimiteRules &rule : rules) { + rules_section.push_back(rule.createRateLimitRulesSection(trigger)); + } + return rules_section; +} + +const vector & +AccessControlRateLimit::getRules() const +{ + return rules; +} + +const string & +AccessControlRateLimit::getMode() const +{ + return mode; +} + +void +AccessControlPracticeSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec"; + + parseAppsecJSONKey("name", practice_name, archive_in); + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("rateLimit", rate_limit, archive_in); +} + +void +AccessControlPracticeSpec::setName(const string &_name) +{ + practice_name = _name; +} + +const AccessControlRateLimit & +AccessControlPracticeSpec::geRateLimit() const +{ + return rate_limit; +} + +const string & +AccessControlPracticeSpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +AccessControlPracticeSpec::getName() const +{ + return practice_name; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc index ab8b09f..043e168 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc @@ -34,6 +34,26 @@ AppSecWebBotsURI::getURI() const return uri; } +std::vector +AppSecPracticeAntiBot::getIjectedUris() const +{ + vector injected; + for (const AppSecWebBotsURI &uri : injected_uris) { + injected.push_back(uri.getURI()); + } + return injected; +} + +std::vector +AppSecPracticeAntiBot::getValidatedUris() const +{ + vector validated; + for (const AppSecWebBotsURI &uri : validated_uris) { + validated.push_back(uri.getURI()); + } + return validated; +} + void AppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in) { @@ -52,7 +72,7 @@ AppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const vector injected; vector validated; for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); - for (const AppSecWebBotsURI &uri : validated_uris) injected.push_back(uri.getURI()); + for (const AppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI()); out_ar( cereal::make_nvp("injected", injected), cereal::make_nvp("validated", validated) @@ -313,6 +333,16 @@ AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const ); } +void +AppsecPracticeAntiBotSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("injected", injected_uris), + cereal::make_nvp("validated", validated_uris) + ); +} + +// LCOV_EXCL_START Reason: no test exist WebAppSection::WebAppSection( const string &_application_urls, const string &_asset_id, @@ -321,6 +351,7 @@ WebAppSection::WebAppSection( const string &_rule_name, const string &_practice_id, const string &_practice_name, + const string &_context, const AppSecPracticeSpec &parsed_appsec_spec, const LogTriggerSection &parsed_log_trigger, const string &default_mode, @@ -333,7 +364,7 @@ WebAppSection::WebAppSection( rule_name(_rule_name), practice_id(_practice_id), practice_name(_practice_name), - context("practiceId(" + practice_id +")"), + context(_context), 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), @@ -353,6 +384,50 @@ WebAppSection::WebAppSection( } } +WebAppSection::WebAppSection( + const std::string &_application_urls, + const std::string &_asset_id, + const std::string &_asset_name, + const std::string &_rule_id, + const std::string &_rule_name, + const std::string &_practice_id, + const std::string &_practice_name, + const string &_context, + const std::string &_web_attack_mitigation_severity, + const std::string &_web_attack_mitigation_mode, + const PracticeAdvancedConfig &_practice_advanced_config, + const AppsecPracticeAntiBotSection &_anti_bots, + const LogTriggerSection &parsed_log_trigger, + 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(_context), + web_attack_mitigation_severity(_web_attack_mitigation_severity), + web_attack_mitigation_mode(_web_attack_mitigation_mode), + practice_advanced_config(_practice_advanced_config), + anti_bots(_anti_bots), + 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)); + } +} +// LCOV_EXCL_STOP + void WebAppSection::save(cereal::JSONOutputArchive &out_ar) const { diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc index 6b6afdb..c9af836 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc @@ -147,6 +147,40 @@ ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception) } } +ExceptionMatch::ExceptionMatch(const NewAppsecException &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 { diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/access_control_practice.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/access_control_practice.h new file mode 100644 index 0000000..b8c263a --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/access_control_practice.h @@ -0,0 +1,192 @@ +// 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 __ACCESS_CONTROL_PRACTICE_H__ +#define __ACCESS_CONTROL_PRACTICE_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class RateLimitRulesTriggerSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + RateLimitRulesTriggerSection() {}; + + RateLimitRulesTriggerSection( + const std::string &_id, + const std::string &_name, + const std::string &_type + ) + : + id(_id), + name(_name), + type(_type) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getName() const; + +private: + std::string id; + std::string name; + std::string type;; +}; + +class RateLimitRulesSection +{ +public: + RateLimitRulesSection() {}; + + // LCOV_EXCL_START Reason: no test exist + RateLimitRulesSection( + const int _limit, + const std::string &_id, + const std::string &_uri, + const std::string &_scope, + const std::vector &_triggers + ) + : + limit(_limit), + id(_id), + uri(_uri), + scope(_scope), + triggers(_triggers) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int limit; + std::string id; + std::string uri; + std::string scope; + std::vector triggers; +}; + +class RateLimitSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + RateLimitSection() {}; + // LCOV_EXCL_STOP + + RateLimitSection( + const std::string &asset_name, + const std::string &url, + const std::string &uri, + const std::string &_mode, + const std::string &_practice_id, + const std::string &_name, + const std::vector &_rules); + + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getId() const; + const std::string & getName() const; + const std::string & getMode() const; + +private: + std::string context; + std::string mode; + std::string practice_id; + std::string name; + std::vector rules; +}; + +class AccessControlRulebaseSection +{ +public: + AccessControlRulebaseSection() {}; + + AccessControlRulebaseSection(const std::vector &_rate_limit) : rate_limit(_rate_limit) {}; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector rate_limit; +}; + +class AccessControlRulebaseWrapper +{ +public: + AccessControlRulebaseWrapper() {}; + + AccessControlRulebaseWrapper( + const std::vector &rate_limits + ) + : + rule_base(AccessControlRulebaseSection(rate_limits)) + {}; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + AccessControlRulebaseSection rule_base; +}; + +class AccessControlRateLimiteRules +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::vector getTriggers() const; + RateLimitRulesSection createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const; + +private: + int limit; + std::string uri; + std::string unit; + std::string comment; + std::vector triggers; +}; + +class AccessControlRateLimit +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::vector & getRules() const; + const std::string & getMode() const; + std::vector createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const; + +private: + std::string mode; + std::vector rules; +}; + +class AccessControlPracticeSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const AccessControlRateLimit & geRateLimit() const; + const std::string & getAppSecClassName() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + AccessControlRateLimit rate_limit; + std::string appsec_class_name; + std::string practice_name; +}; + +#endif // __ACCESS_CONTROL_PRACTICE_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h index d9e7c2b..312f7de 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h @@ -28,6 +28,7 @@ #include "triggers_section.h" #include "exceptions_section.h" #include "trusted_sources_section.h" +#include "new_practice.h" class AppSecWebBotsURI { @@ -43,6 +44,9 @@ private: class AppSecPracticeAntiBot { public: + std::vector getIjectedUris() const; + std::vector getValidatedUris() const; + void load(cereal::JSONInputArchive &archive_in); void save(cereal::JSONOutputArchive &out_ar) const; @@ -152,6 +156,22 @@ public: url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes()) {} + // LCOV_EXCL_START Reason: no test exist + PracticeAdvancedConfig( + int _http_header_max_size, + int _http_request_body_max_size, + int _json_max_object_depth, + int _url_max_size) + : + http_header_max_size(_http_header_max_size), + http_illegal_methods_allowed(0), + http_request_body_max_size(_http_request_body_max_size), + json_max_object_depth(_json_max_object_depth), + url_max_size(_url_max_size) + {} + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; private: @@ -194,6 +214,29 @@ private: std::map parsed_match; }; +class AppsecPracticeAntiBotSection +{ +public: + AppsecPracticeAntiBotSection() {}; + // LCOV_EXCL_START Reason: no test exist + AppsecPracticeAntiBotSection(const NewAppSecPracticeAntiBot &anti_bot) : + injected_uris(anti_bot.getIjectedUris()), + validated_uris(anti_bot.getValidatedUris()) + {}; + // LCOV_EXCL_STOP + + AppsecPracticeAntiBotSection(const AppSecPracticeAntiBot &anti_bot) : + injected_uris(anti_bot.getIjectedUris()), + validated_uris(anti_bot.getValidatedUris()) + {}; + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector injected_uris; + std::vector validated_uris; +}; + class WebAppSection { public: @@ -207,12 +250,29 @@ public: const std::string &_rule_name, const std::string &_practice_id, const std::string &_practice_name, + const std::string &_context, const AppSecPracticeSpec &parsed_appsec_spec, const LogTriggerSection &parsed_log_trigger, const std::string &default_mode, const AppSecTrustedSources &parsed_trusted_sources ); + WebAppSection( + const std::string &_application_urls, + const std::string &_asset_id, + const std::string &_asset_name, + const std::string &_rule_id, + const std::string &_rule_name, + const std::string &_practice_id, + const std::string &_practice_name, + const std::string &_context, + const std::string &_web_attack_mitigation_severity, + const std::string &_web_attack_mitigation_mode, + const PracticeAdvancedConfig &_practice_advanced_config, + const AppsecPracticeAntiBotSection &_anti_bots, + const LogTriggerSection &parsed_log_trigger, + const AppSecTrustedSources &parsed_trusted_sources); + void save(cereal::JSONOutputArchive &out_ar) const; private: @@ -230,7 +290,7 @@ private: bool web_attack_mitigation; std::vector triggers; PracticeAdvancedConfig practice_advanced_config; - AppSecPracticeAntiBot anti_bots; + AppsecPracticeAntiBotSection anti_bots; std::vector trusted_sources; std::vector overrides; }; @@ -250,7 +310,7 @@ public: const std::string &_web_attack_mitigation_severity, const std::string &_web_attack_mitigation_mode, bool _web_attack_mitigation, - const AppSecPracticeSpec &parsed_appsec_spec) + const PracticeAdvancedConfig &_practice_advanced_config) : application_urls(_application_urls), asset_id(_asset_id), @@ -264,7 +324,7 @@ public: web_attack_mitigation_severity(_web_attack_mitigation_severity), web_attack_mitigation_mode(_web_attack_mitigation_mode), web_attack_mitigation(_web_attack_mitigation), - practice_advanced_config(parsed_appsec_spec) + practice_advanced_config(_practice_advanced_config) {} void save(cereal::JSONOutputArchive &out_ar) const; @@ -302,6 +362,7 @@ private: std::vector webAPIPractices; }; + class AppSecWrapper { public: diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h index 329bb4b..b07b0bb 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h @@ -24,6 +24,7 @@ #include "debug.h" #include "rest.h" #include "local_policy_common.h" +#include "new_exceptions.h" class AppsecExceptionSpec { @@ -62,6 +63,7 @@ class ExceptionMatch public: ExceptionMatch() {} ExceptionMatch(const AppsecExceptionSpec &parsed_exception); + ExceptionMatch(const NewAppsecException &parsed_exception); ExceptionMatch(const std::string &_key, const std::vector &_value) : match_type(MatchType::Condition), diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/k8s_policy_utils.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/k8s_policy_utils.h index a63a7ea..7c5764d 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/k8s_policy_utils.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/k8s_policy_utils.h @@ -28,6 +28,7 @@ #include "i_env_details.h" #include "i_agent_details.h" #include "appsec_practice_section.h" +#include "new_appsec_linux_policy.h" #include "policy_maker_utils.h" enum class AnnotationKeys { PolicyKey, OpenAppsecIo, SyslogAddressKey, SyslogPortKey, ModeKey }; @@ -44,7 +45,8 @@ class K8sPolicyUtils public: void init(); - std::map createAppsecPoliciesFromIngresses(); + std::tuple, std::map> + createAppsecPoliciesFromIngresses(); bool getClusterId() const; private: @@ -60,13 +62,41 @@ private: const ParsedRule &default_rule ) const; + std::map> extractElementsNamesV1beta2( + const std::vector &specific_rules, + const NewParsedRule &default_rule + ) const; + template std::vector extractElementsFromCluster( const std::string &crd_plural, const std::unordered_set &elements_names ) const; - Maybe createAppsecPolicyK8s( + template + std::vector extractV1Beta2ElementsFromCluster( + const std::string &crd_plural, + const std::unordered_set &elements_names + ) const; + + Maybe createAppsecPolicyK8sFromV1beta1Crds( + const AppsecSpecParser &appsec_policy_spe, + const std::string &ingress_mode + ) const; + + Maybe createAppsecPolicyK8sFromV1beta2Crds( + const AppsecSpecParser &appsec_policy_spe, + const std::string &ingress_mode + ) const; + + template + void createPolicy( + T &appsec_policy, + std::map &policies, + std::map &annotations_values, + const SingleIngressData &item) const; + + std::tuple, Maybe> createAppsecPolicyK8s( const std::string &policy_name, const std::string &ingress_mode ) const; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/local_policy_common.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/local_policy_common.h index 9ee5819..2ef8b31 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/local_policy_common.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/local_policy_common.h @@ -22,10 +22,13 @@ #include "config.h" #include "debug.h" #include "rest.h" +#include "cereal/archives/json.hpp" +#include +#include "customized_cereal_map.h" USE_DEBUG_FLAG(D_LOCAL_POLICY); -enum class PracticeType { WebApplication, WebAPI }; +enum class PracticeType { WebApplication, WebAPI, RateLimit }; enum class TriggerType { Log, WebUserResponse }; enum class MatchType { Condition, Operator }; @@ -36,7 +39,8 @@ static const std::unordered_map string_to_match_type = { static const std::unordered_map string_to_practice_type = { { "WebApplication", PracticeType::WebApplication }, - { "WebAPI", PracticeType::WebAPI } + { "WebAPI", PracticeType::WebAPI }, + { "RateLimit", PracticeType::RateLimit } }; static const std::unordered_map string_to_trigger_type = { @@ -73,6 +77,26 @@ parseAppsecJSONKey( } } +class AppsecSpecParserMetaData +{ +public: + void + load(cereal::JSONInputArchive &archive_in) + { + dbgTrace(D_LOCAL_POLICY) << "AppsecSpecParserMetaData load"; + parseAppsecJSONKey>("annotations", annotations, archive_in); + } + + const std::map & + getAnnotations() const + { + return annotations; + } + +private: + std::map annotations; +}; + template class AppsecSpecParser : public ClientRest { @@ -90,6 +114,7 @@ public: try { cereal::JSONInputArchive in_ar(ss); in_ar(cereal::make_nvp("spec", spec)); + in_ar(cereal::make_nvp("metadata", meta_data)); } catch (cereal::Exception &e) { dbgWarning(D_LOCAL_POLICY) << "Failed to load spec JSON. Error: " << e.what(); return false; @@ -103,10 +128,17 @@ public: spec.setName(_name); } + const AppsecSpecParserMetaData & + getMetaData() const + { + return meta_data; + } + const T & getSpec() const { return spec; } private: T spec; + AppsecSpecParserMetaData meta_data; }; #endif // __LOCAL_POLICY_COMMON_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_appsec_linux_policy.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_appsec_linux_policy.h new file mode 100644 index 0000000..d52c224 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_appsec_linux_policy.h @@ -0,0 +1,84 @@ +// 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 __NEW_APPSEC_LINUX_POLICY_H__ +#define __NEW_APPSEC_LINUX_POLICY_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "customized_cereal_map.h" +#include "new_appsec_policy_crd_parser.h" +#include "new_custom_response.h" +#include "new_exceptions.h" +#include "new_log_trigger.h" +#include "new_practice.h" +#include "access_control_practice.h" +#include "new_trusted_sources.h" + + +class V1beta2AppsecLinuxPolicy : Singleton::Consume +{ +public: + // LCOV_EXCL_START Reason: no test exist + V1beta2AppsecLinuxPolicy() {} + + V1beta2AppsecLinuxPolicy( + const NewAppsecPolicySpec &_policies, + const std::vector &_threat_prevention_practices, + const std::vector &_access_control_practices, + const std::vector &_log_triggers, + const std::vector &_custom_responses, + const std::vector &_exceptions, + const std::vector &_trusted_sources, + const std::vector &_sources_identifiers) + : + policies(_policies), + threat_prevection_practices(_threat_prevention_practices), + access_control_practices(_access_control_practices), + log_triggers(_log_triggers), + custom_responses(_custom_responses), + exceptions(_exceptions), + trusted_sources(_trusted_sources), + sources_identifiers(_sources_identifiers) {} + // LCOV_EXCL_STOP + + const NewAppsecPolicySpec & getAppsecPolicySpec() const; + const std::vector & getAppSecPracticeSpecs() const; + const std::vector & getAccessControlPracticeSpecs() const; + const std::vector & getAppsecTriggerSpecs() const; + const std::vector & getAppSecCustomResponseSpecs() const; + const std::vector & getAppsecExceptionSpecs() const; + const std::vector & getAppsecTrustedSourceSpecs() const; + const std::vector & getAppsecSourceIdentifierSpecs() const; + void addSpecificRule(const NewParsedRule &_rule); + +private: + NewAppsecPolicySpec policies; + std::vector threat_prevection_practices; + std::vector access_control_practices; + std::vector log_triggers; + std::vector custom_responses; + std::vector exceptions; + std::vector trusted_sources; + std::vector sources_identifiers; +}; + +#endif // __NEW_APPSEC_LINUX_POLICY_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h new file mode 100644 index 0000000..db80891 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_appsec_policy_crd_parser.h @@ -0,0 +1,82 @@ +// 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 __NEW_APPSEC_POLICY_CRD_PARSER_H__ +#define __NEW_APPSEC_POLICY_CRD_PARSER_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "local_policy_common.h" + +// LCOV_EXCL_START Reason: no test exist + +class NewParsedRule +{ +public: + NewParsedRule() {} + NewParsedRule(const std::string &_host) : host(_host) {} + + void load(cereal::JSONInputArchive &archive_in); + + const std::vector & getLogTriggers() const; + const std::vector & getExceptions() const; + const std::vector & getPractices() const; + const std::vector & getAccessControlPractices() const; + const std::string & getSourceIdentifiers() const; + const std::string & getCustomResponse() const; + const std::string & getTrustedSources() const; + const std::string & getHost() const; + const std::string & getMode() const; + + void setHost(const std::string &_host); + void setMode(const std::string &_mode); + +private: + std::vector log_triggers; + std::vector exceptions; + std::vector threat_prevention_practices; + std::vector access_control_practices; + std::string source_identifiers; + std::string custom_response; + std::string trusted_sources; + std::string host; + std::string mode; +}; + +class NewAppsecPolicySpec : Singleton::Consume +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const NewParsedRule & getDefaultRule() const; + const std::vector & getSpecificRules() const; + const std::string & getAppSecClassName() const; + bool isAssetHostExist(const std::string &full_url) const; + void addSpecificRule(const NewParsedRule &_rule); + +private: + std::string appsec_class_name; + NewParsedRule default_rule; + std::vector specific_rules; +}; + + +#endif // __NEW_APPSEC_POLICY_CRD_PARSER_H__ +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_custom_response.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_custom_response.h new file mode 100644 index 0000000..2902f5c --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_custom_response.h @@ -0,0 +1,51 @@ +// 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 __NEW_CUSTOM_RESPONSE_H__ +#define __NEW_CUSTOM_RESPONSE_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class NewAppSecCustomResponse +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getHttpResponseCode() const; + const std::string & getMessageBody() const; + const std::string & getMessageTitle() const; + const std::string & getAppSecClassName() const; + const std::string & getMode() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + bool redirect_add_x_event_id; + int http_response_code; + std::string appsec_class_name; + std::string redirect_url; + std::string message_title; + std::string message_body; + std::string mode; + std::string name; +}; + +#endif // __NEW_CUSTOM_RESPONSE_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_exceptions.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_exceptions.h new file mode 100644 index 0000000..9cc22db --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_exceptions.h @@ -0,0 +1,67 @@ +// 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 __NEW_EXCEPTIONS_H__ +#define __NEW_EXCEPTIONS_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "rest.h" +#include "local_policy_common.h" + +class NewAppsecExceptionCondition +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getKey() const; + const std::string & getvalue() const; + +private: + std::string key; + std::string value; +}; + +class NewAppsecException +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::string & getAction() const; + const std::string & getAppSecClassName() const; + const std::vector getCountryCode() const; + const std::vector getCountryName() const; + const std::vector getHostName() const; + const std::vector getParamName() const; + const std::vector getParamValue() const; + const std::vector getProtectionName() const; + const std::vector getSourceIdentifier() const; + const std::vector getSourceIp() const; + const std::vector getUrl() const; + void setName(const std::string &_name); + +private: + std::string appsec_class_name; + std::string name; + std::string action; + std::vector conditions; +}; + +#endif // __NEW_EXCEPTIONS_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_log_trigger.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_log_trigger.h new file mode 100644 index 0000000..8e36138 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_log_trigger.h @@ -0,0 +1,172 @@ +// 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 __NEW_LOG_TRIGGERS_H__ +#define __NEW_LOG_TRIGGERS_H__ + +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" +#include "i_agent_details.h" +#include "i_env_details.h" + +class NewAppsecTriggerAccessControlLogging +{ +public: + void load(cereal::JSONInputArchive &archive_in); + +private: + bool allow_events = false; + bool drop_events = false; +}; + +class NewAppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + bool isEnabled() const; + bool isResponseBody() const; + const std::string & getMinimumSeverity() const; + +private: + bool enabled = true; + bool response_body = false; + bool response_code = false; + std::string minimum_severity = "high"; +}; + +class NewAppsecTriggerLogging : public ClientRest +{ +public: + void + load(cereal::JSONInputArchive &archive_in); + + bool isAllWebRequests() const; + bool isDetectEvents() const; + bool isPreventEvents() const; + +private: + bool all_web_requests = false; + bool detect_events = false; + bool prevent_events = true; +}; + +class NewAppsecTriggerExtendedLogging : public ClientRest +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + bool isHttpHeaders() const; + bool isRequestBody() const; + bool isUrlPath() const; + bool isUrlQuery() const; + +private: + bool http_headers = false; + bool request_body = false; + bool url_path = false; + bool url_query = false; +}; + +class NewLoggingService +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getAddress() const; + int getPort() const; + +private: + std::string address; + std::string proto; + int port = 514; +}; + +class NewStdoutLogging +{ +public: + // LCOV_EXCL_START Reason: no test exist + NewStdoutLogging() : format("json") {} + // LCOV_EXCL_STOP + + void load(cereal::JSONInputArchive &archive_in); + const std::string & getFormat() const; + +private: + std::string format; +}; + +class NewAppsecTriggerLogDestination + : + public ClientRest, + Singleton::Consume, + Singleton::Consume +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getCefServerUdpPort() const; + int getSyslogServerUdpPort() const; + bool isAgentLocal() const; + bool shouldBeautifyLogs() const; + + bool getCloud() const; + bool isK8SNeeded() const; + bool isCefNeeded() const; + bool isSyslogNeeded() const; + const std::string & getSyslogServerIpv4Address() const; + const std::string & getCefServerIpv4Address() const; + +private: + const NewLoggingService & getSyslogServiceData() const; + const NewLoggingService & getCefServiceData() const; + + bool cloud = false; + bool k8s_service = false; + bool agent_local = true; + bool beautify_logs = true; + NewLoggingService syslog_service; + NewLoggingService cef_service; +}; + +class NewAppsecLogTrigger +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::string & getAppSecClassName() const; + void setName(const std::string &_name); + const NewAppsecTriggerAdditionalSuspiciousEventsLogging & + getAppsecTriggerAdditionalSuspiciousEventsLogging() const; + const NewAppsecTriggerLogging & getAppsecTriggerLogging() const; + const NewAppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const; + const NewAppsecTriggerLogDestination & getAppsecTriggerLogDestination() const; + +private: + NewAppsecTriggerAccessControlLogging access_control_logging; + NewAppsecTriggerAdditionalSuspiciousEventsLogging additional_suspicious_events_logging; + NewAppsecTriggerLogging appsec_logging; + NewAppsecTriggerExtendedLogging extended_logging; + NewAppsecTriggerLogDestination log_destination; + std::string name; + std::string appsec_class_name; +}; + +#endif // __NEW_LOG_TRIGGERS_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_practice.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_practice.h new file mode 100644 index 0000000..553fb06 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_practice.h @@ -0,0 +1,395 @@ +// 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 __NEW_PRACTICE_H__ +#define __NEW_PRACTICE_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class IpsProtectionsRulesSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + IpsProtectionsRulesSection() {}; + + IpsProtectionsRulesSection( + const int _protections_from_year, + const std::string &_action, + const std::string &_confidence_level, + const std::string &_performance_impact, + const std::string &_source_identifier, + const std::string &_severity_level + ) + : + protections_from_year(_protections_from_year), + action(_action), + confidence_level(_confidence_level), + performance_impact(_performance_impact), + source_identifier(_source_identifier), + severity_level(_severity_level) + {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int protections_from_year; + std::string action; + std::string confidence_level; + std::string performance_impact; + std::string source_identifier; + std::string severity_level; +}; + +class IpsProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + IpsProtectionsSection() {}; + // LCOV_EXCL_STOP + + IpsProtectionsSection( + const std::string &_context, + const std::string &asset_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_source_identifier, + const std::string &_mode, + const std::vector &_rules); + + std::string & getMode(); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string context; + std::string name; + std::string asset_id; + std::string practice_name; + std::string practice_id; + std::string source_identifier; + std::string mode; + std::vector rules; +}; + +class IPSSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + IPSSection() {}; + + IPSSection(const std::vector &_ips) : ips(_ips) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector ips; +}; + +class IntrusionPreventionWrapper +{ +public: + // LCOV_EXCL_START Reason: no test exist + IntrusionPreventionWrapper() {}; + + IntrusionPreventionWrapper(const std::vector &_ips) : ips(IPSSection(_ips)) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + IPSSection ips; +}; + +class NewIntrusionPrevention +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + std::vector createIpsRules() const; + const std::string & getMode() const; + +private: + std::string override_mode; + std::string max_performance_impact; + std::string min_severity_level; + std::string high_confidence_event_action; + std::string medium_confidence_event_action; + std::string low_confidence_event_action; + int min_cve_Year; +}; + +class FileSecurityProtectionsSection +{ +public: + // LCOV_EXCL_START Reason: no test exist + FileSecurityProtectionsSection() {}; + // LCOV_EXCL_STOP + + FileSecurityProtectionsSection( + int file_size_limit, + int archive_file_size_limit, + bool allow_files_without_name, + bool required_file_size_limit, + bool required_archive_extraction, + const std::string &context, + const std::string &name, + const std::string &asset_id, + const std::string &practice_name, + const std::string &practice_id, + const std::string &action, + const std::string &files_without_name_action, + const std::string &high_confidence_action, + const std::string &medium_confidence_action, + const std::string &low_confidence_action, + const std::string &severity_level, + const std::string &fileSize_limit_action, + const std::string &multi_level_archive_action, + const std::string &unopened_archive_actio + ); + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + int file_size_limit; + int archive_file_size_limit; + bool allow_files_without_name; + bool required_file_size_limit; + bool required_archive_extraction; + std::string context; + std::string name; + std::string asset_id; + std::string practice_name; + std::string practice_id; + std::string action; + std::string files_without_name_action; + std::string high_confidence_action; + std::string medium_confidence_action; + std::string low_confidence_action; + std::string severity_level; + std::string file_size_limit_action; + std::string file_size_limit_unit; + std::string scan_max_file_size_unit; + std::string multi_level_archive_action; + std::string unopened_archive_action; +}; + +class FileSecuritySection +{ +public: + // LCOV_EXCL_START Reason: no test exist + FileSecuritySection() {}; + + FileSecuritySection(const std::vector &_file_security) + : + file_security(_file_security) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::vector file_security; +}; + +class FileSecurityWrapper +{ +public: + // LCOV_EXCL_START Reason: no test exist + FileSecurityWrapper() {}; + + FileSecurityWrapper(const std::vector &_file_security) + : + file_security(FileSecuritySection(_file_security)) {}; + // LCOV_EXCL_STOP + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + FileSecuritySection file_security; +}; + +class NewFileSecurityArchiveInspection +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getArchiveFileSizeLimit() const; + bool getrequiredArchiveExtraction() const; + const std::string & getMultiLevelArchiveAction() const; + const std::string & getUnopenedArchiveAction() const; + +private: + int scan_max_file_size; + bool extract_archive_files; + std::string scan_max_file_size_unit; + std::string archived_files_within_archived_files; + std::string archived_files_where_content_extraction_failed; +}; + +class NewFileSecurityLargeFileInspection +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getFileSizeLimit() const; + const std::string & getFileSizeLimitAction() const; + +private: + int file_size_limit; + std::string file_size_limit_unit; + std::string files_exceeding_size_limit_action; +}; + +class NewFileSecurity +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const NewFileSecurityArchiveInspection & getArchiveInspection() const; + const NewFileSecurityLargeFileInspection & getLargeFileInspection() const; + FileSecurityProtectionsSection createFileSecurityProtectionsSection( + const std::string &context, + const std::string &asset_name, + const std::string &asset_id, + const std::string &practice_name, + const std::string &practice_id + ) const; + +private: + bool threat_emulation_enabled; + std::string override_mode; + std::string min_severity_level; + std::string high_confidence_event_action; + std::string medium_confidence_event_action; + std::string low_confidence_event_action; + std::string unnamed_files_action; + NewFileSecurityArchiveInspection archive_inspection; + NewFileSecurityLargeFileInspection large_file_inspection; +}; + +class NewSnortSignaturesAndOpenSchemaAPI +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getOverrideMode() const; + const std::vector & getConfigMap() const; + +private: + std::string override_mode; + std::vector config_map; +}; + +class NewAppSecWebBotsURI +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getURI() const; + +private: + std::string uri; +}; + +class NewAppSecPracticeAntiBot +{ +public: + std::vector getIjectedUris() const; + std::vector getValidatedUris() const; + + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + std::string override_mode; + std::vector injected_uris; + std::vector validated_uris; +}; + +class NewAppSecWebAttackProtections +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string getCsrfProtectionMode() const; + const std::string & getErrorDisclosureMode() const; + bool getNonValidHttpMethods() const; + const std::string getOpenRedirectMode() const; + +private: + std::string csrf_protection; + std::string open_redirect; + std::string error_disclosure; + bool non_valid_http_methods; +}; + +class NewAppSecPracticeWebAttacks +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getMaxBodySizeKb() const; + int getMaxHeaderSizeBytes() const; + int getMaxObjectDepth() const; + int getMaxUrlSizeBytes() const; + const std::string & getMinimumConfidence() const; + const NewAppSecWebAttackProtections & getprotections() const; + const std::string & getMode(const std::string &default_mode = "Inactive") const; + +private: + int max_body_size_kb; + int max_header_size_bytes; + int max_object_depth; + int max_url_size_bytes; + std::string mode; + std::string minimum_confidence; + NewAppSecWebAttackProtections protections; +}; + +class NewAppSecPracticeSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const NewSnortSignaturesAndOpenSchemaAPI & getOpenSchemaValidation() const; + const NewSnortSignaturesAndOpenSchemaAPI & getSnortSignatures() const; + const NewAppSecPracticeWebAttacks & getWebAttacks() const; + const NewAppSecPracticeAntiBot & getAntiBot() const; + const NewIntrusionPrevention & getIntrusionPrevention() const; + const NewFileSecurity & getFileSecurity() const; + const std::string & getAppSecClassName() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + NewFileSecurity file_security; + NewIntrusionPrevention intrusion_prevention; + NewSnortSignaturesAndOpenSchemaAPI openapi_schema_validation; + NewSnortSignaturesAndOpenSchemaAPI snort_signatures; + NewAppSecPracticeWebAttacks web_attacks; + NewAppSecPracticeAntiBot anti_bot; + std::string appsec_class_name; + std::string practice_name; +}; + +#endif // __NEW_PRACTICE_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_trusted_sources.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_trusted_sources.h new file mode 100644 index 0000000..9566ced --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/new_trusted_sources.h @@ -0,0 +1,74 @@ +// 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 __NEW_TRUSTED_SOURCES_H__ +#define __NEW_TRUSTED_SOURCES_H__ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "local_policy_common.h" + +class NewTrustedSourcesSpec +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + int getMinNumOfSources() const; + const std::vector & getSourcesIdentifiers() const; + const std::string & getAppSecClassName() const; + const std::string & getName() const; + void setName(const std::string &_name); + +private: + int min_num_of_sources = 0; + std::string name; + std::vector sources_identifiers; + std::string appsec_class_name; +}; + +class Identifier +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getIdentifier() const; + const std::vector & getValues() const; + +private: + std::string identifier; + std::vector value; +}; + +class NewSourcesIdentifiers +{ +public: + void load(cereal::JSONInputArchive &archive_in); + + const std::string & getName() const; + const std::string & getAppSecClassName() const; + const std::vector & getSourcesIdentifiers() const; + void setName(const std::string &_name); + +private: + std::string name; + std::string appsec_class_name; + std::vector sources_identifiers; +}; + +#endif // __NEW_TRUSTED_SOURCES_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h index 4cae78e..1e8b9b1 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h @@ -38,9 +38,13 @@ #include "exceptions_section.h" #include "rules_config_section.h" #include "trusted_sources_section.h" +#include "new_appsec_linux_policy.h" +#include "access_control_practice.h" enum class AnnotationTypes { PRACTICE, + THREAT_PREVENTION_PRACTICE, + ACCESS_CONTROL_PRACTICE, TRIGGER, EXCEPTION, WEB_USER_RES, @@ -56,12 +60,18 @@ public: const AppSecWrapper &_waap, const TriggersWrapper &_trrigers, const RulesConfigWrapper &_rules, + const IntrusionPreventionWrapper &_ips, + const AccessControlRulebaseWrapper &_rate_limit, + const FileSecurityWrapper &_file_security, const ExceptionsWrapper &_exceptions, const std::string &_policy_version) : waap(_waap), trrigers(_trrigers), rules(_rules), + ips(_ips), + rate_limit(_rate_limit), + file_security(_file_security), exceptions(_exceptions), policy_version(_policy_version) {} @@ -71,6 +81,9 @@ private: AppSecWrapper waap; TriggersWrapper trrigers; RulesConfigWrapper rules; + IntrusionPreventionWrapper ips; + AccessControlRulebaseWrapper rate_limit; + FileSecurityWrapper file_security; ExceptionsWrapper exceptions; std::string policy_version; }; @@ -106,8 +119,9 @@ public: const std::string &local_appsec_policy_path ); + template std::string proccesMultipleAppsecPolicies( - const std::map &appsec_policies, + const std::map &appsec_policies, const std::string &policy_version, const std::string &local_appsec_policy_path ); @@ -129,29 +143,104 @@ private: PolicyWrapper combineElementsToPolicy(const std::string &policy_version); + void + createIpsSections( + const std::string &asset_id, + const std::string &asset_name, + const std::string &practice_id, + const std::string &practice_name, + const std::string &source_identifier, + const std::string & context, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void + createFileSecuritySections( + const std::string &asset_id, + const std::string &asset_name, + const std::string &practice_id, + const std::string &practice_name, + const std::string & context, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void + createRateLimitSection( + const std::string &asset_name, + const std::string &url, + const std::string &uri, + const std::string &trigger_id, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + void createWebAppSection( + const V1beta2AppsecLinuxPolicy &policy, + const RulesConfigRulebase& rule_config, + const std::string &practice_id, const std::string &full_url, + const std::string &default_mode, + std::map &rule_annotations + ); + + void + createThreatPreventionPracticeSections( + const std::string &asset_name, + const std::string &url, + const std::string &uri, + const std::string &default_mode, + const V1beta2AppsecLinuxPolicy &policy, + std::map &rule_annotations + ); + + template void createPolicyElementsByRule( - const ParsedRule &rule, - const ParsedRule &default_rule, - const AppsecLinuxPolicy &policy, + const R &rule, + const R &default_rule, + const T &policy, const std::string &policy_name ); + template void createPolicyElements( - const std::vector &rules, - const ParsedRule &default_rule, - const AppsecLinuxPolicy &policy, + const std::vector &rules, + const R &default_rule, + const T &policy, const std::string &policy_name ); - void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const AppsecLinuxPolicy &appsec_policy); + template + void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const T &appsec_policy); std::map log_triggers; std::map web_user_res_triggers; std::map inner_exceptions; std::map web_apps; std::map rules_config; + std::map ips; + std::map file_security; + std::map rate_limit; std::map users_identifiers; std::map trusted_sources; }; +template +std::string +PolicyMakerUtils::proccesMultipleAppsecPolicies( + const std::map &appsec_policies, + const std::string &policy_version, + const std::string &local_appsec_policy_path) +{ + for (const auto &appsec_policy : appsec_policies) { + createAgentPolicyFromAppsecPolicy(appsec_policy.first, appsec_policy.second); + } + + PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version); + return dumpPolicyToFile( + policy_wrapper, + local_appsec_policy_path + ); +} + #endif // __POLICY_MAKER_UTILS_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h index 16e9507..189cff4 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h @@ -121,6 +121,8 @@ public: std::vector _identifier_values ); + const std::string & getIdentifier() const; + void save(cereal::JSONOutputArchive &out_ar) const; private: @@ -141,6 +143,8 @@ public: const std::vector &_source_identifiers ); + const std::string & getIdentifier() const; + void save(cereal::JSONOutputArchive &out_ar) const; private: diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/k8s_policy_utils.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/k8s_policy_utils.cc index f8860e3..fe88182 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/k8s_policy_utils.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/k8s_policy_utils.cc @@ -52,7 +52,7 @@ map K8sPolicyUtils::parseIngressAnnotations(const map &annotations) const { map annotations_values; - for (const pair &annotation : annotations) { + for (const auto &annotation : annotations) { string annotation_key = annotation.first; string annotation_val = annotation.second; if (annotation_key.find(convertAnnotationKeysTostring(AnnotationKeys::OpenAppsecIo)) != string::npos) { @@ -134,6 +134,56 @@ K8sPolicyUtils::extractElementsNames(const vector &specific_rules, c return policy_elements_names; } +// LCOV_EXCL_START Reason: no test exist +void +extractElementsFromNewRule( + const NewParsedRule &rule, + map> &policy_elements_names) +{ + policy_elements_names[AnnotationTypes::EXCEPTION].insert( + rule.getExceptions().begin(), + rule.getExceptions().end() + ); + policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE].insert( + rule.getPractices().begin(), + rule.getPractices().end() + ); + policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE].insert( + rule.getAccessControlPractices().begin(), + rule.getAccessControlPractices().end() + ); + policy_elements_names[AnnotationTypes::TRIGGER].insert( + rule.getLogTriggers().begin(), + rule.getLogTriggers().end() + ); + policy_elements_names[AnnotationTypes::WEB_USER_RES].insert(rule.getCustomResponse()); + policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS].insert(rule.getSourceIdentifiers()); + policy_elements_names[AnnotationTypes::TRUSTED_SOURCES].insert(rule.getTrustedSources()); +} + +map> +K8sPolicyUtils::extractElementsNamesV1beta2( + const vector &specific_rules, + const NewParsedRule &default_rule) const +{ + map> policy_elements_names; + for (const NewParsedRule &specific_rule : specific_rules) { + extractElementsFromNewRule(specific_rule, policy_elements_names); + } + extractElementsFromNewRule(default_rule, policy_elements_names); + + return policy_elements_names; +} + +string +getAppSecClassNameFromCluster() +{ + auto env_res = getenv("appsecClassName"); + if (env_res != nullptr) return env_res; + return ""; +} +// LCOV_EXCL_STOP + template vector K8sPolicyUtils::extractElementsFromCluster( @@ -168,19 +218,52 @@ K8sPolicyUtils::extractElementsFromCluster( return elements; } -Maybe -K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const +// LCOV_EXCL_START Reason: no test exist +template +vector +K8sPolicyUtils::extractV1Beta2ElementsFromCluster( + const string &crd_plural, + const unordered_set &elements_names) const { - auto maybe_appsec_policy_spec = getObjectFromCluster>( - "/apis/openappsec.io/v1beta1/policies/" + policy_name - ); - if (!maybe_appsec_policy_spec.ok()) { - dbgWarning(D_LOCAL_POLICY) - << "Failed to retrieve AppSec policy. Error: " - << maybe_appsec_policy_spec.getErr(); - return genError("Failed to retrieve AppSec policy. Error: " + maybe_appsec_policy_spec.getErr()); + dbgTrace(D_LOCAL_POLICY) << "Retrieve AppSec elements. type: " << crd_plural; + vector elements; + for (const string &element_name : elements_names) { + dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name; + auto maybe_appsec_element = getObjectFromCluster>( + "/apis/openappsec.io/v1beta2/" + crd_plural + "/" + element_name + ); + + if (!maybe_appsec_element.ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve AppSec element. type: " + << crd_plural + << ", name: " + << element_name + << ". Error: " + << maybe_appsec_element.getErr(); + continue; + } + + AppsecSpecParser appsec_element = maybe_appsec_element.unpack(); + if (getAppSecClassNameFromCluster() != "" && + appsec_element.getSpec().getAppSecClassName() != getAppSecClassNameFromCluster()) { + continue; + } + + if (appsec_element.getSpec().getName() == "") { + appsec_element.setName(element_name); + } + elements.push_back(appsec_element.getSpec()); } - AppsecSpecParser appsec_policy_spec = maybe_appsec_policy_spec.unpack(); + return elements; +} +// LCOV_EXCL_STOP + +Maybe +K8sPolicyUtils::createAppsecPolicyK8sFromV1beta1Crds( + const AppsecSpecParser &appsec_policy_spec, + const string &ingress_mode) const +{ ParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule(); vector specific_rules = appsec_policy_spec.getSpec().getSpecificRules(); @@ -236,11 +319,160 @@ K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &i return appsec_policy; } -map +// LCOV_EXCL_START Reason: no test exist +Maybe +K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds( + const AppsecSpecParser &appsec_policy_spec, + const string &ingress_mode) const +{ + NewParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule(); + vector specific_rules = appsec_policy_spec.getSpec().getSpecificRules(); + string appsec_class_name = appsec_policy_spec.getSpec().getAppSecClassName(); + + if (getAppSecClassNameFromCluster() != "" && + appsec_class_name != getAppSecClassNameFromCluster()) { + return genError("Unmached appsec class name!"); + } + + if (default_rule.getMode().empty() && !ingress_mode.empty()) { + default_rule.setMode(ingress_mode); + } + + map> policy_elements_names = extractElementsNamesV1beta2( + specific_rules, + default_rule + ); + + vector threat_prevention_practices = + extractV1Beta2ElementsFromCluster( + "threatpreventionpractices", + policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE] + ); + + vector access_control_practices = + extractV1Beta2ElementsFromCluster( + "accesscontrolpractice", + policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE] + ); + + vector log_triggers = extractV1Beta2ElementsFromCluster( + "logtriggers", + policy_elements_names[AnnotationTypes::TRIGGER] + ); + + vector web_user_responses = extractV1Beta2ElementsFromCluster( + "customresponses", + policy_elements_names[AnnotationTypes::WEB_USER_RES] + ); + + vector exceptions = extractV1Beta2ElementsFromCluster( + "exceptions", + policy_elements_names[AnnotationTypes::EXCEPTION] + ); + + vector source_identifiers = extractV1Beta2ElementsFromCluster( + "sourcesidentifiers", + policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS] + ); + + vector trusted_sources = extractV1Beta2ElementsFromCluster( + "trustedsources", + policy_elements_names[AnnotationTypes::TRUSTED_SOURCES] + ); + + V1beta2AppsecLinuxPolicy appsec_policy = V1beta2AppsecLinuxPolicy( + appsec_policy_spec.getSpec(), + threat_prevention_practices, + access_control_practices, + log_triggers, + web_user_responses, + exceptions, + trusted_sources, + source_identifiers + ); + return appsec_policy; +} +// LCOV_EXCL_STOP + +bool +doesVersionExist(const map &annotations, const string &version) +{ + for (auto annotation : annotations) { + if(annotation.second.find(version) != std::string::npos) { + return true; + } + } + return false; +} +//need to refactor don't forget that +std::tuple, Maybe> +K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const +{ + auto maybe_appsec_policy_spec = getObjectFromCluster>( + "/apis/openappsec.io/v1beta1/policies/" + policy_name + ); + + if (!maybe_appsec_policy_spec.ok() || + !doesVersionExist(maybe_appsec_policy_spec.unpack().getMetaData().getAnnotations(), "v1beta1") + ) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve Appsec policy with crds version: v1beta1, Trying version: v1beta2"; + auto maybe_v1beta2_appsec_policy_spec = getObjectFromCluster>( + "/apis/openappsec.io/v1beta2/policies/" + policy_name + ); + if(!maybe_v1beta2_appsec_policy_spec.ok()) { + dbgWarning(D_LOCAL_POLICY) + << "Failed to retrieve AppSec policy. Error: " + << maybe_v1beta2_appsec_policy_spec.getErr(); + return std::make_tuple( + genError("Failed to retrieve AppSec v1beta1 policy. Error: " + maybe_appsec_policy_spec.getErr()), + genError( + "Failed to retrieve AppSec v1beta2 policy. Error: " + maybe_v1beta2_appsec_policy_spec.getErr())); + } + return std::make_tuple( + genError("There is no v1beta1 policy"), + createAppsecPolicyK8sFromV1beta2Crds(maybe_v1beta2_appsec_policy_spec.unpack(), ingress_mode)); + } + + return std::make_tuple( + createAppsecPolicyK8sFromV1beta1Crds(maybe_appsec_policy_spec.unpack(), ingress_mode), + genError("There is no v1beta2 policy")); +} + +template +void +K8sPolicyUtils::createPolicy( + T &appsec_policy, + map &policies, + map &annotations_values, + const SingleIngressData &item) const +{ + for (const IngressDefinedRule &rule : item.getSpec().getRules()) { + string url = rule.getHost(); + for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) { + if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) { + dbgTrace(D_LOCAL_POLICY) + << "Inserting Host data to the specific asset set:" + << "URL: '" + << url + << "' uri: '" + << uri.getPath() + << "'"; + K ingress_rule = K(url + uri.getPath()); + appsec_policy.addSpecificRule(ingress_rule); + } + } + } + policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy; +} + + +std::tuple, map> K8sPolicyUtils::createAppsecPoliciesFromIngresses() { dbgFlow(D_LOCAL_POLICY) << "Getting all policy object from Ingresses"; - map policies; + map v1bet1_policies; + map v1bet2_policies; auto maybe_ingress = getObjectFromCluster("/apis/networking.k8s.io/v1/ingresses"); if (!maybe_ingress.ok()) { @@ -248,9 +480,10 @@ K8sPolicyUtils::createAppsecPoliciesFromIngresses() dbgWarning(D_LOCAL_POLICY) << "Failed to retrieve K8S Ingress configurations. Error: " << maybe_ingress.getErr(); - return policies; + return make_tuple(v1bet1_policies, v1bet2_policies); } + IngressData ingress = maybe_ingress.unpack(); for (const SingleIngressData &item : ingress.getItems()) { map annotations_values = parseIngressAnnotations( @@ -262,37 +495,34 @@ K8sPolicyUtils::createAppsecPoliciesFromIngresses() continue; } - Maybe maybe_appsec_policy = createAppsecPolicyK8s( + auto maybe_appsec_policy = createAppsecPolicyK8s( annotations_values[AnnotationKeys::PolicyKey], annotations_values[AnnotationKeys::ModeKey] ); - if (!maybe_appsec_policy.ok()) { + if (!std::get<0>(maybe_appsec_policy).ok() && !std::get<1>(maybe_appsec_policy).ok()) { dbgWarning(D_LOCAL_POLICY) << "Failed to create appsec policy. Error: " - << maybe_appsec_policy.getErr(); + << std::get<1>(maybe_appsec_policy).getErr(); continue; } - AppsecLinuxPolicy appsec_policy = maybe_appsec_policy.unpack(); - for (const IngressDefinedRule &rule : item.getSpec().getRules()) { - string url = rule.getHost(); - for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) { - if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) { - dbgTrace(D_LOCAL_POLICY) - << "Inserting Host data to the specific asset set:" - << "URL: '" - << url - << "' uri: '" - << uri.getPath() - << "'"; - ParsedRule ingress_rule = ParsedRule(url + uri.getPath()); - appsec_policy.addSpecificRule(ingress_rule); - } - } + if (!std::get<0>(maybe_appsec_policy).ok()) { + auto appsec_policy=std::get<1>(maybe_appsec_policy).unpack(); + createPolicy( + appsec_policy, + v1bet2_policies, + annotations_values, + item); + } else { + auto appsec_policy=std::get<0>(maybe_appsec_policy).unpack(); + createPolicy( + appsec_policy, + v1bet1_policies, + annotations_values, + item); } - policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy; } - return policies; + return make_tuple(v1bet1_policies, v1bet2_policies); } bool diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc index d6f36fa..1016d94 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc @@ -104,9 +104,16 @@ public: { dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - K8S environment"; - map appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses(); - return policy_maker_utils.proccesMultipleAppsecPolicies( - appsec_policies, + auto appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses(); + if (!std::get<0>(appsec_policies).empty()) { + return policy_maker_utils.proccesMultipleAppsecPolicies( + std::get<0>(appsec_policies), + policy_version, + default_local_appsec_policy_path + ); + } + return policy_maker_utils.proccesMultipleAppsecPolicies( + std::get<1>(appsec_policies), policy_version, default_local_appsec_policy_path ); diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_appsec_linux_policy.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_appsec_linux_policy.cc new file mode 100644 index 0000000..34d6b16 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_appsec_linux_policy.cc @@ -0,0 +1,72 @@ +// 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 "new_appsec_linux_policy.h" +// LCOV_EXCL_START Reason: no test exist + +using namespace std; + +const NewAppsecPolicySpec & +V1beta2AppsecLinuxPolicy::getAppsecPolicySpec() const +{ + return policies; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppSecPracticeSpecs() const +{ + return threat_prevection_practices; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAccessControlPracticeSpecs() const +{ + return access_control_practices; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecTriggerSpecs() const +{ + return log_triggers; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const +{ + return custom_responses; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecExceptionSpecs() const +{ + return exceptions; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const +{ + return trusted_sources; +} + +const vector & +V1beta2AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const +{ + return sources_identifiers; +} + +void +V1beta2AppsecLinuxPolicy::addSpecificRule(const NewParsedRule &_rule) +{ + policies.addSpecificRule(_rule); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc new file mode 100644 index 0000000..4fdc0ef --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_appsec_policy_crd_parser.cc @@ -0,0 +1,154 @@ +// 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 "new_appsec_policy_crd_parser.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"prevent-learn", "detect-learn", "prevent", "detect", "inactive"}; + +void +NewParsedRule::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec NewParsedRule"; + parseAppsecJSONKey>("exceptions", exceptions, archive_in); + parseAppsecJSONKey>("triggers", log_triggers, archive_in); + parseAppsecJSONKey>("threatPreventionPractices", threat_prevention_practices, archive_in); + parseAppsecJSONKey>("accessControlPractices", access_control_practices, archive_in); + parseAppsecJSONKey("mode", mode, archive_in); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec New Parsed Rule mode invalid: " << mode; + } + parseAppsecJSONKey("customResponse", custom_response, archive_in); + parseAppsecJSONKey("sourceIdentifiers", source_identifiers, archive_in); + parseAppsecJSONKey("trustedSources", trusted_sources, archive_in); + try { + archive_in(cereal::make_nvp("host", host)); + } catch (const cereal::Exception &e) + { + // The default NewParsedRule does not hold a host, so by default it will be * + host = "*"; + } +} + +const vector & +NewParsedRule::getLogTriggers() const +{ + return log_triggers; +} +const vector & + +NewParsedRule::getExceptions() const +{ + return exceptions; +} + +const vector & +NewParsedRule::getPractices() const +{ + return threat_prevention_practices; +} + +const vector & +NewParsedRule::getAccessControlPractices() const +{ + return access_control_practices; +} + +const string & +NewParsedRule::getSourceIdentifiers() const +{ + return source_identifiers; +} + +const string & +NewParsedRule::getCustomResponse() const +{ + return custom_response; +} + +const string & +NewParsedRule::getTrustedSources() const +{ + return trusted_sources; +} + +const string & +NewParsedRule::getHost() const +{ + return host; +} + +const string & +NewParsedRule::getMode() const +{ + return mode; +} + +void +NewParsedRule::setHost(const string &_host) +{ + host = _host; +} + +void +NewParsedRule::setMode(const string &_mode) +{ + mode = _mode; +} + +void +NewAppsecPolicySpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec policy spec"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("default", default_rule, archive_in); + parseAppsecJSONKey>("specificRules", specific_rules, archive_in); +} + +const NewParsedRule & +NewAppsecPolicySpec::getDefaultRule() const +{ + return default_rule; +} + +const vector & +NewAppsecPolicySpec::getSpecificRules() const +{ + return specific_rules; +} + +const string & +NewAppsecPolicySpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +bool +NewAppsecPolicySpec::isAssetHostExist(const std::string &full_url) const +{ + for (const NewParsedRule &rule : specific_rules) { + if (rule.getHost() == full_url) return true; + } + return false; +} + +void +NewAppsecPolicySpec::addSpecificRule(const NewParsedRule &_rule) +{ + specific_rules.push_back(_rule); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_custom_response.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_custom_response.cc new file mode 100644 index 0000000..d8f815b --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_custom_response.cc @@ -0,0 +1,99 @@ +// 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 "new_custom_response.h" + +#define MIN_RESPONSE_CODE 100 +#define MAX_RESPOMSE_CODE 599 + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_modes = {"block-page", "response-code-only", "redirect"}; + +void +NewAppSecCustomResponse::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec web user response spec"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("httpResponseCode", http_response_code, archive_in, 403); + if (http_response_code < MIN_RESPONSE_CODE || http_response_code > MAX_RESPOMSE_CODE) { + dbgWarning(D_LOCAL_POLICY) << "AppSec web user response code invalid: " << http_response_code; + } + parseAppsecJSONKey("mode", mode, archive_in, "block-page"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec web user response mode invalid: " << mode; + } + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("redirectUrl", redirect_url, archive_in); + parseAppsecJSONKey("redirectAddXEventId", redirect_add_x_event_id, archive_in); + if (mode == "block-page") { + parseAppsecJSONKey( + "messageBody", + message_body, + archive_in, + "Openappsec's Application Security has detected an attack and blocked it." + ); + parseAppsecJSONKey( + "messageTitle", + message_title, + archive_in, + "Attack blocked by web application protection" + ); + } +} + +void +NewAppSecCustomResponse::setName(const string &_name) +{ + name = _name; +} + +int +NewAppSecCustomResponse::getHttpResponseCode() const +{ + return http_response_code; +} + +const string & +NewAppSecCustomResponse::getMessageBody() const +{ + return message_body; +} + +const string & +NewAppSecCustomResponse::getMessageTitle() const +{ + return message_title; +} + +const string & +NewAppSecCustomResponse::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +NewAppSecCustomResponse::getMode() const +{ + return mode; +} + +const string & +NewAppSecCustomResponse::getName() const +{ + return name; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_exceptions.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_exceptions.cc new file mode 100644 index 0000000..115a781 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_exceptions.cc @@ -0,0 +1,187 @@ +// 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 "new_exceptions.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); + +// LCOV_EXCL_START Reason: no test exist +static const set valid_actions = {"skip", "accept", "drop", "suppressLog"}; + +void +NewAppsecExceptionCondition::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception condition"; + parseAppsecJSONKey("key", key, archive_in); + parseAppsecJSONKey("value", value, archive_in); +} + +const string & +NewAppsecExceptionCondition::getKey() const +{ + return key; +} + +const string & +NewAppsecExceptionCondition::getvalue() const +{ + return value; +} + +void +NewAppsecException::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception"; + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("action", action, archive_in); + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + if (valid_actions.count(action) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action; + } + parseAppsecJSONKey>("condition", conditions, archive_in); +} + +void +NewAppsecException::setName(const string &_name) +{ + name = _name; +} + +const string & +NewAppsecException::getName() const +{ + return name; +} + +const string & +NewAppsecException::getAction() const +{ + return action; +} + +const string & +NewAppsecException::getAppSecClassName() const +{ + return appsec_class_name; +} + +const vector +NewAppsecException::getCountryCode() const +{ + vector country_codes; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "countryCode") { + country_codes.push_back(condition.getvalue()); + } + } + return country_codes; +} + +const vector +NewAppsecException::getCountryName() const +{ + vector country_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "countryName") { + country_names.push_back(condition.getvalue()); + } + } + return country_names; +} + +const vector +NewAppsecException::getHostName() const +{ + vector host_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "hostName") { + host_names.push_back(condition.getvalue()); + } + } + return host_names; +} + +const vector +NewAppsecException::getParamName() const +{ + vector param_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "paramName") { + param_names.push_back(condition.getvalue()); + } + } + return param_names; +} + +const vector +NewAppsecException::getParamValue() const +{ + vector param_values; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "paramValue") { + param_values.push_back(condition.getvalue()); + } + } + return param_values; +} + +const vector +NewAppsecException::getProtectionName() const +{ + vector protection_names; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "protectionName") { + protection_names.push_back(condition.getvalue()); + } + } + return protection_names; +} + +const vector +NewAppsecException::getSourceIdentifier() const +{ + vector source_identifiers; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "sourceIdentifier") { + source_identifiers.push_back(condition.getvalue()); + } + } + return source_identifiers; +} + +const vector +NewAppsecException::getSourceIp() const +{ + vector source_ips; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "sourceIp") { + source_ips.push_back(condition.getvalue()); + } + } + return source_ips; +} + +const vector +NewAppsecException::getUrl() const +{ + vector urls; + for (const NewAppsecExceptionCondition &condition : conditions) { + if (condition.getKey() == "url") { + urls.push_back(condition.getvalue()); + } + } + return urls; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_log_trigger.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_log_trigger.cc new file mode 100644 index 0000000..13dded3 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_log_trigger.cc @@ -0,0 +1,321 @@ +// 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 "new_log_trigger.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_severities = {"high", "critical"}; +static const set valid_protocols = {"tcp", "udp"}; +static const set valid_formats = {"json", "json-formatted"}; + +void +NewAppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging"; + parseAppsecJSONKey("allowEvents", allow_events, archive_in, false); + parseAppsecJSONKey("dropEvents", drop_events, archive_in, false); +} + +void +NewAppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging"; + parseAppsecJSONKey("enabled", enabled, archive_in, true); + parseAppsecJSONKey("responseBody", response_body, archive_in, false); + //the old code didn't parse the responsecode so ask Noam what is the currenct default value for it + parseAppsecJSONKey("responseCode", response_code, archive_in, false); + parseAppsecJSONKey("minSeverity", minimum_severity, archive_in, "high"); + if (valid_severities.count(minimum_severity) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec AppSec Trigger - Additional Suspicious Events Logging minimum severity invalid: " + << minimum_severity; + } +} + +bool +NewAppsecTriggerAdditionalSuspiciousEventsLogging::isEnabled() const +{ + return enabled; +} + +bool +NewAppsecTriggerAdditionalSuspiciousEventsLogging::isResponseBody() const +{ + return response_body; +} + +const string & +NewAppsecTriggerAdditionalSuspiciousEventsLogging::getMinimumSeverity() const +{ + return minimum_severity; +} + +void +NewAppsecTriggerLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Logging"; + parseAppsecJSONKey("detectEvents", detect_events, archive_in, false); + parseAppsecJSONKey("preventEvents", prevent_events, archive_in, true); + parseAppsecJSONKey("allWebRequests", all_web_requests, archive_in, false); +} + +bool +NewAppsecTriggerLogging::isAllWebRequests() const +{ + return all_web_requests; +} + +bool +NewAppsecTriggerLogging::isDetectEvents() const +{ + return detect_events; +} + +bool +NewAppsecTriggerLogging::isPreventEvents() const +{ + return prevent_events; +} + +void +NewAppsecTriggerExtendedLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger Extended Logging"; + parseAppsecJSONKey("httpHeaders", http_headers, archive_in, false); + parseAppsecJSONKey("requestBody", request_body, archive_in, false); + parseAppsecJSONKey("urlPath", url_path, archive_in, false); + parseAppsecJSONKey("urlQuery", url_query, archive_in, false); +} + +bool +NewAppsecTriggerExtendedLogging::isHttpHeaders() const +{ + return http_headers; +} + +bool +NewAppsecTriggerExtendedLogging::isRequestBody() const +{ + return request_body; +} + +bool +NewAppsecTriggerExtendedLogging::isUrlPath() const +{ + return url_path; +} + +bool +NewAppsecTriggerExtendedLogging::isUrlQuery() const +{ + return url_query; +} + +void +NewLoggingService::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("address", address, archive_in); + parseAppsecJSONKey("proto", proto, archive_in); + if (valid_protocols.count(proto) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Logging Service - proto invalid: " << proto; + } + + parseAppsecJSONKey("port", port, archive_in, 514); +} + +const string & +NewLoggingService::getAddress() const +{ + return address; +} + +int +NewLoggingService::getPort() const +{ + return port; +} + + +void +NewStdoutLogging::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("format", format, archive_in, "json"); + if (valid_formats.count(format) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Stdout Logging - format invalid: " << format; + } +} + +const string & +NewStdoutLogging::getFormat() const +{ + return format; +} + +void +NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination"; + // TBD: support "file" + parseAppsecJSONKey("cloud", cloud, archive_in, false); + auto mode = Singleton::Consume::by()->getOrchestrationMode(); + auto env_type = Singleton::Consume::by()->getEnvType(); + bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S); + parseAppsecJSONKey("k8s-service", k8s_service, archive_in, k8s_service_default); + + NewStdoutLogging stdout_log; + parseAppsecJSONKey("stdout", stdout_log, archive_in); + agent_local = !(stdout_log.getFormat().empty()); + beautify_logs = stdout_log.getFormat() == "json-formatted"; + parseAppsecJSONKey("syslogService", syslog_service, archive_in); + parseAppsecJSONKey("cefService", cef_service, archive_in); +} + +int +NewAppsecTriggerLogDestination::getCefServerUdpPort() const +{ + return getCefServiceData().getPort(); +} + +int +NewAppsecTriggerLogDestination::getSyslogServerUdpPort() const +{ + return getSyslogServiceData().getPort(); +} + +bool +NewAppsecTriggerLogDestination::isAgentLocal() const +{ + return agent_local; +} + +bool +NewAppsecTriggerLogDestination::shouldBeautifyLogs() const +{ + return beautify_logs; +} + +bool +NewAppsecTriggerLogDestination::getCloud() const +{ + return cloud; +} + +bool +NewAppsecTriggerLogDestination::isK8SNeeded() const +{ + return k8s_service; +} + +bool +NewAppsecTriggerLogDestination::isCefNeeded() const +{ + return !getCefServiceData().getAddress().empty(); +} + +bool +NewAppsecTriggerLogDestination::isSyslogNeeded() const +{ + return !getSyslogServiceData().getAddress().empty(); +} + +const +string & NewAppsecTriggerLogDestination::getSyslogServerIpv4Address() const +{ + return getSyslogServiceData().getAddress(); +} + +const string & +NewAppsecTriggerLogDestination::getCefServerIpv4Address() const +{ + return getCefServiceData().getAddress(); +} + +const NewLoggingService & +NewAppsecTriggerLogDestination::getSyslogServiceData() const +{ + return syslog_service; +} + +const NewLoggingService & +NewAppsecTriggerLogDestination::getCefServiceData() const +{ + return cef_service; +} + +void +NewAppsecLogTrigger::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec log trigger"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey( + "accessControlLogging", + access_control_logging, + archive_in + ); + parseAppsecJSONKey( + "additionalSuspiciousEventsLogging", + additional_suspicious_events_logging, + archive_in + ); + parseAppsecJSONKey("appsecLogging", appsec_logging, archive_in); + parseAppsecJSONKey("extendedLogging", extended_logging, archive_in); + parseAppsecJSONKey("logDestination", log_destination, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +NewAppsecLogTrigger::setName(const string &_name) +{ + name = _name; +} + +const string & +NewAppsecLogTrigger::getName() const +{ + return name; +} + +const string & +NewAppsecLogTrigger::getAppSecClassName() const +{ + return appsec_class_name; +} + +const NewAppsecTriggerAdditionalSuspiciousEventsLogging & +NewAppsecLogTrigger::getAppsecTriggerAdditionalSuspiciousEventsLogging() const +{ + return additional_suspicious_events_logging; +} + +const NewAppsecTriggerLogging & +NewAppsecLogTrigger::getAppsecTriggerLogging() const +{ + return appsec_logging; +} + +const NewAppsecTriggerExtendedLogging & +NewAppsecLogTrigger::getAppsecTriggerExtendedLogging() const +{ + return extended_logging; +} + +const NewAppsecTriggerLogDestination & +NewAppsecLogTrigger::getAppsecTriggerLogDestination() const +{ + return log_destination; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_practice.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_practice.cc new file mode 100644 index 0000000..9ae3141 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_practice.cc @@ -0,0 +1,751 @@ +// 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 "new_practice.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set performance_impacts = {"low", "medium", "high"}; +static const set severity_levels = {"low", "medium", "high", "critical"}; +static const set size_unit = {"bytes", "KB", "MB", "GB"}; +static const set confidences_actions = {"prevent", "detect", "inactive"}; +static const set valid_modes = {"prevent", "detect", "inactive", "prevent-learn", "detect-learn"}; +static const set valid_confidences = {"medium", "high", "critical"}; +static const std::unordered_map key_to_performance_impact_val = { + { "low", "Low or lower"}, + { "medium", "Medium or lower"}, + { "high", "High or lower"} +}; +static const std::unordered_map key_to_severity_level_val = { + { "low", "Low or above"}, + { "medium", "Medium or above"}, + { "high", "High or above"}, + { "critical", "Critical"} +}; +static const std::unordered_map key_to_mode_val = { + { "prevent-learn", "Prevent"}, + { "detect-learn", "Detect"}, + { "prevent", "Prevent"}, + { "detect", "Detect"}, + { "inactive", "Inactive"} +}; +static const std::unordered_map unit_to_int = { + { "bytes", 1}, + { "KB", 1024}, + { "MB", 1048576}, + { "GB", 1073741824} +}; + +void +NewAppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots URI"; + parseAppsecJSONKey("uri", uri, archive_in); +} + +const string & +NewAppSecWebBotsURI::getURI() const +{ + return uri; +} + +std::vector +NewAppSecPracticeAntiBot::getIjectedUris() const +{ + vector injected; + for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); + return injected; +} + +std::vector +NewAppSecPracticeAntiBot::getValidatedUris() const +{ + vector validated; + for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI()); + return validated; +} + +void +NewAppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots"; + parseAppsecJSONKey>("injectedUris", injected_uris, archive_in); + parseAppsecJSONKey>("validatedUris", validated_uris, archive_in); + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "Inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Web Bots override mode invalid: " << override_mode; + } +} + +void +NewAppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const +{ + vector injected; + vector validated; + for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); + for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI()); + out_ar( + cereal::make_nvp("injected", injected), + cereal::make_nvp("validated", validated) + ); +} + +void +NewAppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Attack Protections"; + parseAppsecJSONKey("csrfEnabled", csrf_protection, archive_in, "inactive"); + parseAppsecJSONKey("errorDisclosureEnabled", error_disclosure, archive_in, "inactive"); + parseAppsecJSONKey("openRedirectEnabled", open_redirect, archive_in, "inactive"); + parseAppsecJSONKey("nonValidHttpMethods", non_valid_http_methods, archive_in, false); +} + +const string +NewAppSecWebAttackProtections::getCsrfProtectionMode() const +{ + if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) { + dbgError(D_LOCAL_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 & +NewAppSecWebAttackProtections::getErrorDisclosureMode() const +{ + return error_disclosure; +} + +bool +NewAppSecWebAttackProtections::getNonValidHttpMethods() const +{ + return non_valid_http_methods; +} + +const string +NewAppSecWebAttackProtections::getOpenRedirectMode() const +{ + if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) { + dbgError(D_LOCAL_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 +NewAppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice web attacks spec"; + parseAppsecJSONKey("protections", protections, archive_in); + parseAppsecJSONKey("overrideMode", mode, archive_in, "Unset"); + if (valid_modes.count(mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec practice override mode invalid: " << mode; + } + + if (getMode() == "Prevent") { + parseAppsecJSONKey("minimumConfidence", minimum_confidence, archive_in, "critical"); + if (valid_confidences.count(minimum_confidence) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec practice override minimum confidence invalid: " + << minimum_confidence; + } + } else { + minimum_confidence = "Transparent"; + } + parseAppsecJSONKey("maxBodySizeKb", max_body_size_kb, archive_in, 1000000); + parseAppsecJSONKey("maxHeaderSizeBytes", max_header_size_bytes, archive_in, 102400); + parseAppsecJSONKey("maxObjectDepth", max_object_depth, archive_in, 40); + parseAppsecJSONKey("maxUrlSizeBytes", max_url_size_bytes, archive_in, 32768); +} + +int +NewAppSecPracticeWebAttacks::getMaxBodySizeKb() const +{ + return max_body_size_kb; +} + +int +NewAppSecPracticeWebAttacks::getMaxHeaderSizeBytes() const +{ + return max_header_size_bytes; +} + +int +NewAppSecPracticeWebAttacks::getMaxObjectDepth() const +{ + return max_object_depth; +} + +int +NewAppSecPracticeWebAttacks::getMaxUrlSizeBytes() const +{ + return max_url_size_bytes; +} + +const string & +NewAppSecPracticeWebAttacks::getMinimumConfidence() const +{ + return minimum_confidence; +} + +const string & +NewAppSecPracticeWebAttacks::getMode(const string &default_mode) const +{ + if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) { + dbgError(D_LOCAL_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode; + return default_mode; + } + return key_to_practices_val.at(mode); +} + +void +NewSnortSignaturesAndOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Snort Signatures practice"; + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "Inactive"); + parseAppsecJSONKey>("configmap", config_map, archive_in); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Snort Signatures override mode invalid: " << override_mode; + } +} + +const string & +NewSnortSignaturesAndOpenSchemaAPI::getOverrideMode() const +{ + return override_mode; +} + +const vector & +NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const +{ + return config_map; +} + +void +IpsProtectionsRulesSection::save(cereal::JSONOutputArchive &out_ar) const +{ + vector protections; + out_ar( + cereal::make_nvp("action", key_to_mode_val.at(action)), + cereal::make_nvp("confidenceLevel", confidence_level), + cereal::make_nvp("clientProtections", true), + cereal::make_nvp("serverProtections", true), + cereal::make_nvp("protectionTags", protections), + cereal::make_nvp("protectionIds", protections), + cereal::make_nvp("performanceImpact", key_to_performance_impact_val.at(performance_impact)), + cereal::make_nvp("severityLevel", key_to_severity_level_val.at(severity_level)), + cereal::make_nvp("protectionsFromYear", protections_from_year) + ); +} + +IpsProtectionsSection::IpsProtectionsSection( + const string &_context, + const string &asset_name, + const string &_asset_id, + const string &_practice_name, + const string &_practice_id, + const string &_source_identifier, + const string &_mode, + const vector &_rules) + : + context(_context), + name(asset_name), + asset_id(_asset_id), + practice_name(_practice_name), + practice_id(_practice_id), + source_identifier(_source_identifier), + mode(_mode), + rules(_rules) +{ +} + +std::string & +IpsProtectionsSection::getMode() +{ + return mode; +} + +void +IpsProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("ruleName", name), + cereal::make_nvp("assetName", name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("sourceIdentifier", source_identifier), + cereal::make_nvp("defaultAction", key_to_mode_val.at(mode)), + cereal::make_nvp("rules", rules) + ); +} + +void +IPSSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("IpsProtections", ips) + ); +} + +void +IntrusionPreventionWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("IPS", ips) + ); +} + +void +NewIntrusionPrevention::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Intrusion Prevention practice"; + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "Inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec Intrusion Prevention override mode invalid: " << override_mode; + } + parseAppsecJSONKey("maxPerformanceImpact", max_performance_impact, archive_in, "low"); + if (performance_impacts.count(max_performance_impact) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention max performance impact invalid: " + << max_performance_impact; + } + parseAppsecJSONKey("minSeverityLevel", min_severity_level, archive_in, "low"); + if (severity_levels.count(min_severity_level) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention min severity level invalid: " + << min_severity_level; + } + parseAppsecJSONKey("highConfidenceEventAction", high_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(high_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention high confidence event invalid: " + << high_confidence_event_action; + } + parseAppsecJSONKey("mediumConfidenceEventAction", medium_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(medium_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention medium confidence event invalid: " + << medium_confidence_event_action; + } + parseAppsecJSONKey("lowConfidenceEventAction", low_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(low_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec Intrusion Prevention low confidence event action invalid: " + << low_confidence_event_action; + } + parseAppsecJSONKey("minCveYear", min_cve_Year, archive_in); +} + +vector +NewIntrusionPrevention::createIpsRules() const +{ + vector ips_rules; + IpsProtectionsRulesSection high_rule( + min_cve_Year, + high_confidence_event_action, + string("High"), + max_performance_impact, + string(""), + min_severity_level + ); + ips_rules.push_back(high_rule); + + IpsProtectionsRulesSection med_rule( + min_cve_Year, + medium_confidence_event_action, + string("Medium"), + max_performance_impact, + string(""), + min_severity_level + ); + ips_rules.push_back(med_rule); + + IpsProtectionsRulesSection low_rule( + min_cve_Year, + low_confidence_event_action, + string("Low"), + max_performance_impact, + string(""), + min_severity_level + ); + ips_rules.push_back(low_rule); + + return ips_rules; +} + +const std::string & +NewIntrusionPrevention::getMode() const +{ + return override_mode; +} + +FileSecurityProtectionsSection::FileSecurityProtectionsSection( + int _file_size_limit, + int _archive_file_size_limit, + bool _allow_files_without_name, + bool _required_file_size_limit, + bool _required_archive_extraction, + const std::string &_context, + const std::string &_name, + const std::string &_asset_id, + const std::string &_practice_name, + const std::string &_practice_id, + const std::string &_action, + const std::string &_files_without_name_action, + const std::string &_high_confidence_action, + const std::string &_medium_confidence_action, + const std::string &_low_confidence_action, + const std::string &_severity_level, + const std::string &_file_size_limit_action, + const std::string &_multi_level_archive_action, + const std::string &_unopened_archive_action) + : + file_size_limit(_file_size_limit), + archive_file_size_limit(_archive_file_size_limit), + allow_files_without_name(_allow_files_without_name), + required_file_size_limit(_required_file_size_limit), + required_archive_extraction(_required_archive_extraction), + context(_context), + name(_name), + asset_id(_asset_id), + practice_name(_practice_name), + practice_id(_practice_id), + action(_action), + files_without_name_action(_files_without_name_action), + high_confidence_action(_high_confidence_action), + medium_confidence_action(_medium_confidence_action), + low_confidence_action(_low_confidence_action), + severity_level(_severity_level), + file_size_limit_action(_file_size_limit_action), + multi_level_archive_action(_multi_level_archive_action), + unopened_archive_action(_unopened_archive_action) +{} + +void +FileSecurityProtectionsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("ruleName", name), + cereal::make_nvp("assetName", name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("action", key_to_mode_val.at(action)), + cereal::make_nvp("filesWithoutNameAction", key_to_mode_val.at(files_without_name_action)), + cereal::make_nvp("allowFilesWithoutName", allow_files_without_name), + cereal::make_nvp("highConfidence", key_to_mode_val.at(high_confidence_action)), + cereal::make_nvp("mediumConfidence", key_to_mode_val.at(medium_confidence_action)), + cereal::make_nvp("lowConfidence", key_to_mode_val.at(low_confidence_action)), + cereal::make_nvp("severityLevel", key_to_severity_level_val.at(severity_level)), + cereal::make_nvp("fileSizeLimitAction", key_to_mode_val.at(file_size_limit_action)), + cereal::make_nvp("fileSizeLimit", file_size_limit), + cereal::make_nvp("requiredFileSizeLimit", required_file_size_limit), + cereal::make_nvp("requiredArchiveExtraction", required_archive_extraction), + cereal::make_nvp("archiveFileSizeLimit", archive_file_size_limit), + cereal::make_nvp("MultiLevelArchiveAction", key_to_mode_val.at(multi_level_archive_action)), + cereal::make_nvp("UnopenedArchiveAction", key_to_mode_val.at(unopened_archive_action)) + ); +} + +void +FileSecuritySection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("FileSecurityProtections", file_security) + ); +} + +void +FileSecurityWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("FileSecurity", file_security) + ); +} + +void +NewFileSecurityArchiveInspection::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security Archive Inspection practice"; + parseAppsecJSONKey("extractArchiveFiles", extract_archive_files, archive_in); + parseAppsecJSONKey("scanMaxFileSize", scan_max_file_size, archive_in, 0); + parseAppsecJSONKey("scanMaxFileSizeUnit", scan_max_file_size_unit, archive_in, "bytes"); + if (size_unit.count(scan_max_file_size_unit) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection scan max file size unit invalid: " + << scan_max_file_size_unit; + } + parseAppsecJSONKey( + "archivedFilesWithinArchivedFiles", + archived_files_within_archived_files, + archive_in, + "inactive"); + if (confidences_actions.count(archived_files_within_archived_files) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection archived files within archived files invalid: " + << archived_files_within_archived_files; + } + parseAppsecJSONKey( + "archivedFilesWhereContentExtractionFailed", + archived_files_where_content_extraction_failed, + archive_in, + "inactive"); + if (confidences_actions.count(archived_files_where_content_extraction_failed) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection archived files within archived file invalid: " + << archived_files_where_content_extraction_failed; + } +} + +int +NewFileSecurityArchiveInspection::getArchiveFileSizeLimit() const +{ + if (unit_to_int.find(scan_max_file_size_unit) == unit_to_int.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << scan_max_file_size_unit + << ". Setting scan max file size unit to 0"; + return 0; + } + return (scan_max_file_size * unit_to_int.at(scan_max_file_size_unit)); +} + +bool +NewFileSecurityArchiveInspection::getrequiredArchiveExtraction() const +{ + return extract_archive_files; +} + +const std::string & +NewFileSecurityArchiveInspection::getMultiLevelArchiveAction() const +{ + return archived_files_within_archived_files; +} + +const std::string & +NewFileSecurityArchiveInspection::getUnopenedArchiveAction() const +{ + return archived_files_where_content_extraction_failed; +} + +void +NewFileSecurityLargeFileInspection::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security large File Inspection practice"; + parseAppsecJSONKey("fileSizeLimit", file_size_limit, archive_in); + parseAppsecJSONKey("fileSizeLimitUnit", file_size_limit_unit, archive_in, "bytes"); + if (size_unit.count(file_size_limit_unit) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security large File Inspection file size limit unit invalid: " + << file_size_limit_unit; + } + parseAppsecJSONKey( + "filesExceedingSizeLimitAction", + files_exceeding_size_limit_action, + archive_in, + "inactive"); + if (confidences_actions.count(files_exceeding_size_limit_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security Archive Inspection archived files within archived files invalid: " + << files_exceeding_size_limit_action; + } +} + +int +NewFileSecurityLargeFileInspection::getFileSizeLimit() const +{ + if (unit_to_int.find(file_size_limit_unit) == unit_to_int.end()) { + dbgError(D_LOCAL_POLICY) + << "Failed to find a value for " + << file_size_limit_unit + << ". Setting file size limit unit to 0"; + return 0; + } + return (file_size_limit * unit_to_int.at(file_size_limit_unit)); +} + +const std::string & +NewFileSecurityLargeFileInspection::getFileSizeLimitAction() const +{ + return files_exceeding_size_limit_action; +} + +void +NewFileSecurity::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec File Security practice"; + parseAppsecJSONKey("overrideMode", override_mode, archive_in, "Inactive"); + if (valid_modes.count(override_mode) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec File Security override mode invalid: " << override_mode; + } + parseAppsecJSONKey("minSeverityLevel", min_severity_level, archive_in, "low"); + if (severity_levels.count(min_severity_level) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec File Security min severity level invalid: " << min_severity_level; + } + parseAppsecJSONKey("highConfidenceEventAction", high_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(high_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security high confidence event invalid: " + << high_confidence_event_action; + } + parseAppsecJSONKey("mediumConfidenceEventAction", medium_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(medium_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security medium confidence event invalid: " + << medium_confidence_event_action; + } + parseAppsecJSONKey("lowConfidenceEventAction", low_confidence_event_action, archive_in, "inactive"); + if (confidences_actions.count(low_confidence_event_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security low confidence event action invalid: " + << low_confidence_event_action; + } + parseAppsecJSONKey("unnamedFilesAction", unnamed_files_action, archive_in, "inactive"); + if (confidences_actions.count(unnamed_files_action) == 0) { + dbgWarning(D_LOCAL_POLICY) + << "AppSec File Security low unnamed files action invalid: " + << unnamed_files_action; + } + parseAppsecJSONKey("threatEmulationEnabled", threat_emulation_enabled, archive_in); + parseAppsecJSONKey("archiveInspection", archive_inspection, archive_in); + parseAppsecJSONKey("largeFileInspection", large_file_inspection, archive_in); +} + + +const NewFileSecurityArchiveInspection & +NewFileSecurity::getArchiveInspection() const +{ + return archive_inspection; +} + +const NewFileSecurityLargeFileInspection & +NewFileSecurity::getLargeFileInspection() const +{ + return large_file_inspection; +} + +FileSecurityProtectionsSection +NewFileSecurity::createFileSecurityProtectionsSection( + const string &context, + const string &asset_name, + const string &asset_id, + const string &practice_name, + const string &practice_id) const +{ + return FileSecurityProtectionsSection( + getLargeFileInspection().getFileSizeLimit(), + getArchiveInspection().getArchiveFileSizeLimit(), + unnamed_files_action == "prevent" ? true : false, + getLargeFileInspection().getFileSizeLimitAction() == "prevent" ? true : false, + getArchiveInspection().getrequiredArchiveExtraction(), + context, + asset_name, + asset_id, + practice_name, + practice_id, + override_mode, + unnamed_files_action, + high_confidence_event_action, + medium_confidence_event_action, + low_confidence_event_action, + min_severity_level, + getLargeFileInspection().getFileSizeLimitAction(), + getArchiveInspection().getMultiLevelArchiveAction(), + getArchiveInspection().getUnopenedArchiveAction() + ); +} + +void +NewAppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec"; + parseAppsecJSONKey( + "openapi-schema-validation", + openapi_schema_validation, + archive_in + ); + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("fileSecurity", file_security, archive_in); + parseAppsecJSONKey("intrusionPrevention", intrusion_prevention, archive_in); + parseAppsecJSONKey("snortSignatures", snort_signatures, archive_in); + parseAppsecJSONKey("webAttacks", web_attacks, archive_in); + parseAppsecJSONKey("antiBot", anti_bot, archive_in); + parseAppsecJSONKey("name", practice_name, archive_in); +} + +void +NewAppSecPracticeSpec::setName(const string &_name) +{ + practice_name = _name; +} + +const NewSnortSignaturesAndOpenSchemaAPI & +NewAppSecPracticeSpec::getOpenSchemaValidation() const +{ + return openapi_schema_validation; +} + +const NewSnortSignaturesAndOpenSchemaAPI & +NewAppSecPracticeSpec::getSnortSignatures() const +{ + return snort_signatures; +} + +const NewAppSecPracticeWebAttacks & +NewAppSecPracticeSpec::getWebAttacks() const +{ + return web_attacks; +} + +const NewAppSecPracticeAntiBot & +NewAppSecPracticeSpec::getAntiBot() const +{ + return anti_bot; +} + +const NewIntrusionPrevention & +NewAppSecPracticeSpec::getIntrusionPrevention() const +{ + return intrusion_prevention; +} + +const NewFileSecurity & +NewAppSecPracticeSpec::getFileSecurity() const +{ + return file_security; +} + +const string & +NewAppSecPracticeSpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +NewAppSecPracticeSpec::getName() const +{ + return practice_name; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/new_trusted_sources.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/new_trusted_sources.cc new file mode 100644 index 0000000..ecff3b7 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/new_trusted_sources.cc @@ -0,0 +1,118 @@ +// 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 "new_trusted_sources.h" + +using namespace std; + +USE_DEBUG_FLAG(D_LOCAL_POLICY); +// LCOV_EXCL_START Reason: no test exist + +static const set valid_identifiers = {"headerkey", "JWTKey", "cookie", "sourceip", "x-forwarded-for"}; + +void +NewTrustedSourcesSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading trusted sources spec"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey("minNumOfSources", min_num_of_sources, archive_in, 3); + parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +NewTrustedSourcesSpec::setName(const string &_name) +{ + name = _name; +} + +int +NewTrustedSourcesSpec::getMinNumOfSources() const +{ + return min_num_of_sources; +} + +const vector & +NewTrustedSourcesSpec::getSourcesIdentifiers() const +{ + return sources_identifiers; +} + +const string & +NewTrustedSourcesSpec::getAppSecClassName() const +{ + return appsec_class_name; +} + +const string & +NewTrustedSourcesSpec::getName() const +{ + return name; +} + +void +Identifier::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading source identifiers spec"; + parseAppsecJSONKey("sourceIdentifier", identifier, archive_in); + if (valid_identifiers.count(identifier) == 0) { + dbgWarning(D_LOCAL_POLICY) << "AppSec identifier invalid: " << identifier; + } + parseAppsecJSONKey>("value", value, archive_in); +} + +const string & +Identifier::getIdentifier() const +{ + return identifier; +} + +const vector & +Identifier::getValues() const +{ + return value; +} + +void +NewSourcesIdentifiers::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_LOCAL_POLICY) << "Loading Sources Identifiers"; + parseAppsecJSONKey("appsecClassName", appsec_class_name, archive_in); + parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +void +NewSourcesIdentifiers::setName(const string &_name) +{ + name = _name; +} + +const string & +NewSourcesIdentifiers::getName() const +{ + return name; +} + +const string & +NewSourcesIdentifiers::getAppSecClassName() const +{ + return appsec_class_name; +} + +const vector & +NewSourcesIdentifiers::getSourcesIdentifiers() const +{ + return sources_identifiers; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc index 0c1df95..11fa9fc 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc @@ -21,11 +21,14 @@ 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) + cereal::make_nvp("accessControlV2", rate_limit), + cereal::make_nvp("waap", waap), + cereal::make_nvp("triggers", trrigers), + cereal::make_nvp("rules", rules), + cereal::make_nvp("ips", ips), + cereal::make_nvp("exceptions", exceptions), + cereal::make_nvp("fileSecurity", file_security), + cereal::make_nvp("version", policy_version) ); } @@ -156,10 +159,11 @@ PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &po return policy_str; } +template map extractAnnotationsNames( - const ParsedRule &parsed_rule, - const ParsedRule &default_rule, + const R &parsed_rule, + const R &default_rule, const string &policy_name) { map rule_annotation; @@ -228,6 +232,94 @@ extractAnnotationsNames( return rule_annotation; } +// LCOV_EXCL_START Reason: no test exist +template<> +map +extractAnnotationsNames( + const NewParsedRule &parsed_rule, + const NewParsedRule &default_rule, + const string &policy_name) +{ + map 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 access_control_practice_name; + // TBD: support multiple practices + if (!parsed_rule.getAccessControlPractices().empty() && !parsed_rule.getAccessControlPractices()[0].empty()) { + access_control_practice_name = parsed_rule.getAccessControlPractices()[0]; + } else if ( !default_rule.getAccessControlPractices().empty() && + !default_rule.getAccessControlPractices()[0].empty()) { + access_control_practice_name = default_rule.getAccessControlPractices()[0]; + } + + if (!access_control_practice_name.empty()) { + rule_annotation[AnnotationTypes::ACCESS_CONTROL_PRACTICE] = policy_name + "/" + access_control_practice_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; +} +// LCOV_EXCL_STOP + template container_it extractElement(container_it begin, container_it end, const string &element_name) @@ -259,47 +351,72 @@ convertMapToVector(map map) return vec; } -AppSecPracticeSpec -getAppsecPracticeSpec(const string &practice_annotation_name, const AppsecLinuxPolicy &policy) +template +R +getAppsecPracticeSpec(const string &practice_annotation_name, const T &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 R(); } return *practice_it; } -AppsecTriggerSpec -getAppsecTriggerSpec(const string &trigger_annotation_name, const AppsecLinuxPolicy &policy) +// LCOV_EXCL_START Reason: no test exist +AccessControlPracticeSpec +getAccessControlPracticeSpec() +{ + return AccessControlPracticeSpec(); +} + +AccessControlPracticeSpec +getAccessControlPracticeSpec(const string &practice_annotation_name, const V1beta2AppsecLinuxPolicy &policy) +{ + auto practices_vec = policy.getAccessControlPracticeSpecs(); + 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 Access control practice"; + return AccessControlPracticeSpec(); + } + return *practice_it; +} +// LCOV_EXCL_STOP + +template +R +getAppsecTriggerSpec(const string &trigger_annotation_name, const T &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 R(); } return *trigger_it; } -AppsecExceptionSpec -getAppsecExceptionSpec(const string &exception_annotation_name, const AppsecLinuxPolicy &policy) +template +R +getAppsecExceptionSpec(const string &exception_annotation_name, const T &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 R(); } return *exception_it; } -AppSecCustomResponseSpec -getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const AppsecLinuxPolicy &policy) +template +R +getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const T &policy) { auto custom_response_vec = policy.getAppSecCustomResponseSpecs(); auto custom_response_it = extractElement( @@ -309,13 +426,14 @@ getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const if (custom_response_it == custom_response_vec.end()) { dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec custom response"; - return AppSecCustomResponseSpec(); + return R(); } return *custom_response_it; } -SourceIdentifierSpecWrapper -getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const AppsecLinuxPolicy &policy) +template +R +getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const T &policy) { auto source_identifiers_vec = policy.getAppsecSourceIdentifierSpecs(); auto source_identifier_it = extractElement( @@ -325,13 +443,14 @@ getAppsecSourceIdentifierSpecs(const string &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 R(); } return *source_identifier_it; } -TrustedSourcesSpec -getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const AppsecLinuxPolicy &policy) +template +R +getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const T &policy) { auto trusted_sources_vec = policy.getAppsecTrustedSourceSpecs(); auto trusted_sources_it = extractElement( @@ -341,18 +460,14 @@ getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const if (trusted_sources_it == trusted_sources_vec.end()) { dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trusted source"; - return TrustedSourcesSpec(); + return R(); } return *trusted_sources_it; } +template LogTriggerSection -createLogTriggerSection( - const string &trigger_annotation_name, - const AppsecLinuxPolicy &policy) -{ - AppsecTriggerSpec trigger_spec = getAppsecTriggerSpec(trigger_annotation_name, policy); - +extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_spec){ string verbosity = "Standard"; string extendLoggingMinSeverity = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().getMinimumSeverity(); @@ -410,12 +525,35 @@ createLogTriggerSection( return log; } -WebUserResponseTriggerSection -createWebUserResponseTriggerSection( - const string &web_user_res_annotation_name, - const AppsecLinuxPolicy &policy) +// LCOV_EXCL_START Reason: no test exist +template +LogTriggerSection +createLogTriggerSection( + const string &trigger_annotation_name, + const T &policy) +{ + auto trigger_spec = getAppsecTriggerSpec(trigger_annotation_name, policy); + return extractLogTriggerData(trigger_annotation_name, trigger_spec); +} + +template<> +LogTriggerSection +createLogTriggerSection( + const string &trigger_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + auto trigger_spec = + getAppsecTriggerSpec(trigger_annotation_name, policy); + return extractLogTriggerData(trigger_annotation_name, trigger_spec); +} + +template +WebUserResponseTriggerSection +extractWebUserResponseTriggerSectionrData +( + const string &web_user_res_annotation_name, + const T &web_user_res_spec) { - 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(); @@ -432,20 +570,63 @@ createWebUserResponseTriggerSection( return web_user_res; } +template +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const T &policy) +{ + auto web_user_res_spec = + getAppsecCustomResponseSpec(web_user_res_annotation_name, policy); + return extractLogTriggerData(web_user_res_annotation_name, web_user_res_spec); +} + +template<> +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const AppsecLinuxPolicy &policy) +{ + auto web_user_res_spec = + getAppsecCustomResponseSpec(web_user_res_annotation_name, policy); + return extractWebUserResponseTriggerSectionrData( + web_user_res_annotation_name, + web_user_res_spec + ); +} + +template<> +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + auto web_user_res_spec = + getAppsecCustomResponseSpec( + web_user_res_annotation_name, + policy + ); + return extractWebUserResponseTriggerSectionrData( + web_user_res_annotation_name, + web_user_res_spec + ); +} + vector addSourceIdentifiersToTrustedSource( const string &source_identifeir_from_trust, - const SourceIdentifierSpec &src_ident + const vector &values, + const string &source_identifer ) { vector generated_trusted_json; - if (src_ident.getValues().empty()) { + if (values.empty()) { generated_trusted_json.push_back( - SourcesIdentifiers(src_ident.getSourceIdentifier(), source_identifeir_from_trust) + SourcesIdentifiers(source_identifer, source_identifeir_from_trust) ); } else { - for (const string &val : src_ident.getValues()) { - string src_key = src_ident.getSourceIdentifier() + ":" + val; + for (const string &val : values) { + string src_key = source_identifer + ":" + val; generated_trusted_json.push_back(SourcesIdentifiers(src_key, source_identifeir_from_trust)); } } @@ -453,24 +634,28 @@ addSourceIdentifiersToTrustedSource( return generated_trusted_json; } +template AppSecTrustedSources createTrustedSourcesSection( const string &treusted_sources_annotation_name, const string &source_identifier_annotation_name, - const AppsecLinuxPolicy &policy) + const T &policy) { - TrustedSourcesSpec treusted_sources_spec = getAppsecTrustedSourceSpecs(treusted_sources_annotation_name, policy); - SourceIdentifierSpecWrapper source_identifiers_spec = getAppsecSourceIdentifierSpecs( - source_identifier_annotation_name, - policy - ); + TrustedSourcesSpec treusted_sources_spec = + getAppsecTrustedSourceSpecs(treusted_sources_annotation_name, policy); + SourceIdentifierSpecWrapper source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); vector generated_trusted_json; for (const SourceIdentifierSpec &src_ident : source_identifiers_spec.getIdentifiers()) { for (const string &source_identifeir_from_trust : treusted_sources_spec.getSourcesIdentifiers()) { vector tmp_trusted = addSourceIdentifiersToTrustedSource( source_identifeir_from_trust, - src_ident + src_ident.getValues(), + src_ident.getSourceIdentifier() ); generated_trusted_json.insert(generated_trusted_json.end(), tmp_trusted.begin(), tmp_trusted.end()); } @@ -485,12 +670,53 @@ createTrustedSourcesSection( return treusted_sources; } +template<> +AppSecTrustedSources +createTrustedSourcesSection( + const string &treusted_sources_annotation_name, + const string &source_identifier_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + NewTrustedSourcesSpec treusted_sources_spec = + getAppsecTrustedSourceSpecs( + treusted_sources_annotation_name, + policy + ); + NewSourcesIdentifiers source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); + + vector generated_trusted_json; + for (const Identifier &src_ident : source_identifiers_spec.getSourcesIdentifiers()) { + for (const string &source_identifeir_from_trust : treusted_sources_spec.getSourcesIdentifiers()) { + vector tmp_trusted = addSourceIdentifiersToTrustedSource( + source_identifeir_from_trust, + src_ident.getValues(), + src_ident.getIdentifier() + ); + generated_trusted_json.insert(generated_trusted_json.end(), tmp_trusted.begin(), tmp_trusted.end()); + } + } + + AppSecTrustedSources treusted_sources( + treusted_sources_spec.getName(), + treusted_sources_spec.getMinNumOfSources(), + generated_trusted_json + ); + + return treusted_sources; +} + +template InnerException createExceptionSection( const string &exception_annotation_name, - const AppsecLinuxPolicy &policy) + const T &policy) { - AppsecExceptionSpec exception_spec = getAppsecExceptionSpec(exception_annotation_name, policy); + AppsecExceptionSpec exception_spec = + getAppsecExceptionSpec(exception_annotation_name, policy); ExceptionMatch exception_match(exception_spec); string behavior = exception_spec.getAction() == "skip" ? @@ -502,20 +728,41 @@ createExceptionSection( return inner_exception; } +template<> +InnerException +createExceptionSection( + const string &exception_annotation_name, + const V1beta2AppsecLinuxPolicy &policy) +{ + NewAppsecException 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; +} + +template UsersIdentifiersRulebase -createUserIdentifiers ( +createUserIdentifiers( const string &source_identifier_annotation_name, - const AppsecLinuxPolicy &policy, + const T &policy, const string &context ) { string jwt_identifier = ""; vector jwt_identifier_values; vector user_ident_vec; - SourceIdentifierSpecWrapper source_identifiers_spec = getAppsecSourceIdentifierSpecs( - source_identifier_annotation_name, - policy - ); + SourceIdentifierSpecWrapper source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); for (const SourceIdentifierSpec &src_ident : source_identifiers_spec.getIdentifiers()) { if (src_ident.getSourceIdentifier() == "JWTKey") { @@ -540,6 +787,46 @@ createUserIdentifiers ( return users_ident; } +template<> +UsersIdentifiersRulebase +createUserIdentifiers( + const string &source_identifier_annotation_name, + const V1beta2AppsecLinuxPolicy &policy, + const string &context +) +{ + string jwt_identifier = ""; + vector jwt_identifier_values; + vector user_ident_vec; + NewSourcesIdentifiers source_identifiers_spec = + getAppsecSourceIdentifierSpecs( + source_identifier_annotation_name, + policy + ); + + for (const Identifier &src_ident : source_identifiers_spec.getSourcesIdentifiers()) { + if (src_ident.getIdentifier() == "JWTKey") { + jwt_identifier = "JWTKey"; + jwt_identifier_values.insert( + jwt_identifier_values.end(), + src_ident.getValues().begin(), + src_ident.getValues().end() + ); + user_ident_vec.push_back(UsersIdentifier("authorization", src_ident.getValues())); + } else { + user_ident_vec.push_back(UsersIdentifier(src_ident.getIdentifier(), src_ident.getValues())); + } + } + UsersIdentifiersRulebase users_ident = UsersIdentifiersRulebase( + context, + jwt_identifier, + jwt_identifier_values, + user_ident_vec + ); + + return users_ident; +} + RulesConfigRulebase createMultiRulesSections( const string &url, @@ -584,6 +871,272 @@ createMultiRulesSections( return rules_config; } +RulesConfigRulebase +createMultiRulesSections( + const string &url, + const string &uri, + const string &practice_id, + const string &practice_name, + const string &practice_type, + const string &rate_limit_practice_id, + const string &rate_limit_practice_name, + const string &rate_limit_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) +{ + ParametersSection exception_param = ParametersSection(exception_id, exception_name); + + vector practices; + if (!practice_id.empty()) { + practices.push_back(PracticeSection(practice_id, practice_type, practice_name)); + } + if (!rate_limit_practice_id.empty()) { + practices.push_back( + PracticeSection(rate_limit_practice_id, rate_limit_practice_type, rate_limit_practice_name) + ); + } + + vector 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, + practices, + {exception_param}, + triggers + ); + + return rules_config; +} + +void +PolicyMakerUtils::createIpsSections( + const string &asset_id, + const string &asset_name, + const string &practice_id, + const string &practice_name, + const string &source_identifier, + const string & context, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + auto apssec_practice = getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy); + IpsProtectionsSection ips_section = IpsProtectionsSection( + context, + asset_name, + asset_id, + practice_name, + practice_id, + source_identifier, + apssec_practice.getIntrusionPrevention().getMode(), + apssec_practice.getIntrusionPrevention().createIpsRules() + ); + + ips[asset_name] = ips_section; +} + +void +PolicyMakerUtils::createFileSecuritySections( + const string &asset_id, + const string &asset_name, + const string &practice_id, + const string &practice_name, + const string &context, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + auto apssec_practice = getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy); + auto file_security_section = apssec_practice.getFileSecurity().createFileSecurityProtectionsSection( + context, + asset_name, + asset_id, + practice_name, + practice_id + ); + + file_security[asset_name] = file_security_section; +} + +void +PolicyMakerUtils::createRateLimitSection( + const string &asset_name, + const string &url, + const string &uri, + const string &trigger_id, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + if (rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE].empty()) { + return; + } + + string practice_id = ""; + try { + practice_id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgFlow(D_LOCAL_POLICY) << "Couldn't generate random id for rate limit practice"; + } + auto access_control_practice = getAccessControlPracticeSpec( + rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE], + policy); + + RateLimitRulesTriggerSection trigger; + if (!trigger_id.empty()) { + string trigger_name = rule_annotations[AnnotationTypes::TRIGGER]; + trigger = RateLimitRulesTriggerSection(trigger_id, trigger_name, "Trigger"); + } + + auto rules = access_control_practice.geRateLimit().createRateLimitRulesSection(trigger); + + rate_limit[rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE]] = RateLimitSection( + asset_name, + url, + uri, + access_control_practice.geRateLimit().getMode(), + practice_id, + rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE], + rules + ); +} + +void +PolicyMakerUtils::createWebAppSection( + const V1beta2AppsecLinuxPolicy &policy, + const RulesConfigRulebase& rule_config, + const string &practice_id, const string &full_url, + const string &default_mode, + map &rule_annotations) +{ + auto apssec_practice = + getAppsecPracticeSpec( + rule_annotations[AnnotationTypes::PRACTICE], + policy + ); + PracticeAdvancedConfig practice_advance_config( + apssec_practice.getWebAttacks().getMaxHeaderSizeBytes(), + apssec_practice.getWebAttacks().getMaxBodySizeKb(), + apssec_practice.getWebAttacks().getMaxObjectDepth(), + apssec_practice.getWebAttacks().getMaxUrlSizeBytes() + ); + 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], + rule_config.getContext(), + apssec_practice.getWebAttacks().getMinimumConfidence(), + apssec_practice.getWebAttacks().getMode(default_mode), + practice_advance_config, + apssec_practice.getAntiBot(), + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]], + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] + ); + web_apps[rule_config.getAssetName()] = web_app; +} + +void +PolicyMakerUtils::createThreatPreventionPracticeSections( + const string &asset_name, + const string &url, + const string &uri, + const string &default_mode, + const V1beta2AppsecLinuxPolicy &policy, + map &rule_annotations) +{ + if (rule_annotations[AnnotationTypes::PRACTICE].empty()) { + return; + } + string practice_id = ""; + try { + practice_id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgFlow(D_LOCAL_POLICY) << "Couldn't generate random id for threat prevention practice"; + } + + RulesConfigRulebase rule_config = createMultiRulesSections( + url, + uri, + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + "WebApplication", + rate_limit[rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE]].getId(), + rate_limit[rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE]].getName(), + "RateLimit", + 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", + asset_name, + rule_annotations[AnnotationTypes::EXCEPTION], + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]].getBehaviorId() + ); + rules_config[rule_config.getAssetName()] = rule_config; + + string current_identifier; + if (!rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty()) { + UsersIdentifiersRulebase user_identifiers = createUserIdentifiers( + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy, + rule_config.getContext() + ); + users_identifiers[rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS]] = user_identifiers; + current_identifier = user_identifiers.getIdentifier(); + } + + createIpsSections( + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + current_identifier, + rule_config.getContext(), + policy, + rule_annotations + ); + + createFileSecuritySections( + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + "assetId(" + rule_config.getAssetId() + ")", + policy, + rule_annotations + ); + + if (!web_apps.count(rule_config.getAssetName())) { + createWebAppSection(policy, rule_config, practice_id, asset_name, default_mode, rule_annotations); + } + +} + SettingsWrapper createProfilesSection() { @@ -594,6 +1147,7 @@ createProfilesSection() SettingsRulebase settings_rulebase_1 = SettingsRulebase({agent_setting_1}); return SettingsWrapper(settings_rulebase_1); } +// LCOV_EXCL_STOP PolicyWrapper PolicyMakerUtils::combineElementsToPolicy(const string &policy_version) @@ -609,10 +1163,16 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version) AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {})); RulesConfigWrapper rules_config_section(convertMapToVector(rules_config), convertMapToVector(users_identifiers)); + IntrusionPreventionWrapper ips_section(convertMapToVector(ips)); + FileSecurityWrapper file_security_section(convertMapToVector(file_security)); + AccessControlRulebaseWrapper rate_limit_section(convertMapToVector(rate_limit)); SecurityAppsWrapper security_app_section = SecurityAppsWrapper( appses_section, triggers_section, rules_config_section, + ips_section, + rate_limit_section, + file_security_section, exceptions_section, policy_version ); @@ -623,11 +1183,12 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version) return policy_wrapper; } +template void PolicyMakerUtils::createPolicyElementsByRule( - const ParsedRule &rule, - const ParsedRule &default_rule, - const AppsecLinuxPolicy &policy, + const R &rule, + const R &default_rule, + const T &policy, const string &policy_name) { map rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name); @@ -636,7 +1197,7 @@ PolicyMakerUtils::createPolicyElementsByRule( !log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER]) ) { log_triggers[rule_annotations[AnnotationTypes::TRIGGER]] = - createLogTriggerSection( + createLogTriggerSection( rule_annotations[AnnotationTypes::TRIGGER], policy ); @@ -647,7 +1208,7 @@ PolicyMakerUtils::createPolicyElementsByRule( !web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES]) ) { web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]] = - createWebUserResponseTriggerSection( + createWebUserResponseTriggerSection( rule_annotations[AnnotationTypes::WEB_USER_RES], policy ); @@ -658,7 +1219,7 @@ PolicyMakerUtils::createPolicyElementsByRule( !inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION]) ) { inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] = - createExceptionSection( + createExceptionSection( rule_annotations[AnnotationTypes::EXCEPTION], policy ); @@ -670,7 +1231,7 @@ PolicyMakerUtils::createPolicyElementsByRule( !trusted_sources.count(rule_annotations[AnnotationTypes::TRUSTED_SOURCES]) ) { trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = - createTrustedSourcesSection( + createTrustedSourcesSection( rule_annotations[AnnotationTypes::TRUSTED_SOURCES], rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], policy @@ -682,7 +1243,7 @@ PolicyMakerUtils::createPolicyElementsByRule( !web_apps.count(rule_annotations[AnnotationTypes::PRACTICE]) ) { trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = - createTrustedSourcesSection( + createTrustedSourcesSection( rule_annotations[AnnotationTypes::TRUSTED_SOURCES], rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], policy @@ -729,7 +1290,7 @@ PolicyMakerUtils::createPolicyElementsByRule( users_identifiers[rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS]] = user_identifiers; } - if (!web_apps.count(rule_annotations[AnnotationTypes::PRACTICE])) { + if (!web_apps.count(rule_config.getAssetName())) { WebAppSection web_app = WebAppSection( full_url == "Any" ? "" : full_url, rule_config.getAssetId(), @@ -738,42 +1299,169 @@ PolicyMakerUtils::createPolicyElementsByRule( rule_config.getAssetName(), practice_id, rule_annotations[AnnotationTypes::PRACTICE], - getAppsecPracticeSpec(rule_annotations[AnnotationTypes::PRACTICE], policy), + rule_config.getContext(), + getAppsecPracticeSpec(rule_annotations[AnnotationTypes::PRACTICE], policy), log_triggers[rule_annotations[AnnotationTypes::TRIGGER]], rule.getMode(), trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] ); - web_apps[rule_annotations[AnnotationTypes::PRACTICE]] = web_app; + web_apps[rule_config.getAssetName()] = web_app; } } } +// LCOV_EXCL_START Reason: no test exist +template<> void -PolicyMakerUtils::createPolicyElements( - const vector &rules, - const ParsedRule &default_rule, - const AppsecLinuxPolicy &policy, +PolicyMakerUtils::createPolicyElementsByRule( + const NewParsedRule &rule, + const NewParsedRule &default_rule, + const V1beta2AppsecLinuxPolicy &policy, const string &policy_name) { - for (const ParsedRule &rule : rules) { - createPolicyElementsByRule(rule, default_rule, policy, policy_name); + dbgTrace(D_LOCAL_POLICY) << "Creating policy elements from version V1beta2"; + map 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::TRUSTED_SOURCES].empty() && + !rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS].empty() && + !trusted_sources.count(rule_annotations[AnnotationTypes::TRUSTED_SOURCES]) + ) { + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = + createTrustedSourcesSection( + rule_annotations[AnnotationTypes::TRUSTED_SOURCES], + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::PRACTICE].empty() && + !web_apps.count(rule_annotations[AnnotationTypes::PRACTICE]) + ) { + trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]] = + createTrustedSourcesSection( + rule_annotations[AnnotationTypes::TRUSTED_SOURCES], + rule_annotations[AnnotationTypes::SOURCE_IDENTIFIERS], + policy + ); + } + + string full_url = rule.getHost() == "*" + ? "Any" + : rule.getHost(); + tuple splited_host_name = splitHostName(rule.getHost()); + + createRateLimitSection( + full_url, + std::get<0>(splited_host_name), + std::get<2>(splited_host_name), + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(), + policy, + rule_annotations + ); + + createThreatPreventionPracticeSections( + full_url, + std::get<0>(splited_host_name), + std::get<2>(splited_host_name), + rule.getMode(), + policy, + rule_annotations + ); + +} +// LCOV_EXCL_STOP + +template +void +PolicyMakerUtils::createPolicyElements( + const vector &rules, + const R &default_rule, + const T &policy, + const string &policy_name) +{ + for (const R &rule : rules) { + createPolicyElementsByRule(rule, default_rule, policy, policy_name); } } +template void -PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, const AppsecLinuxPolicy &appsec_policy) +PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, const T &appsec_policy) { dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name; - ParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule(); + R default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule(); // add default rule to policy - createPolicyElementsByRule(default_rule, default_rule, appsec_policy, policy_name); + createPolicyElementsByRule(default_rule, default_rule, appsec_policy, policy_name); - vector specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); - createPolicyElements(specific_rules, default_rule, appsec_policy, policy_name); + vector specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); + createPolicyElements(specific_rules, default_rule, appsec_policy, policy_name); } +// LCOV_EXCL_START Reason: no test exist +template<> +void +PolicyMakerUtils::createAgentPolicyFromAppsecPolicy( + const string &policy_name, + const V1beta2AppsecLinuxPolicy &appsec_policy) +{ + dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name; + + NewParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule(); + + // add default rule to policy + createPolicyElementsByRule( + default_rule, + default_rule, + appsec_policy, + policy_name); + + vector specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); + createPolicyElements( + specific_rules, + default_rule, + appsec_policy, + policy_name + ); +} +// LCOV_EXCL_STOP + string PolicyMakerUtils::proccesSingleAppsecPolicy( const string &policy_path, @@ -785,24 +1473,10 @@ PolicyMakerUtils::proccesSingleAppsecPolicy( dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr(); return ""; } - createAgentPolicyFromAppsecPolicy(getPolicyName(policy_path), maybe_policy.unpack()); - - PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version); - return dumpPolicyToFile( - policy_wrapper, - local_appsec_policy_path - ); -} - -string -PolicyMakerUtils::proccesMultipleAppsecPolicies( - const map &appsec_policies, - const string &policy_version, - const string &local_appsec_policy_path) -{ - for (const auto &appsec_policy : appsec_policies) { - createAgentPolicyFromAppsecPolicy(appsec_policy.first, appsec_policy.second); - } + createAgentPolicyFromAppsecPolicy( + getPolicyName(policy_path), + maybe_policy.unpack() + ); PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version); return dumpPolicyToFile( diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc index cc73d18..5f748a5 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc @@ -249,6 +249,14 @@ UsersIdentifier::UsersIdentifier(const string &_source_identifier, vector service_policies_copy = status.getServicePolicies(); - for (const pair &policy: service_policies_copy) { + for (const auto &policy: service_policies_copy) { setServiceConfiguration(policy.first, policy.second, OrchestrationStatusConfigType::POLICY); } diff --git a/components/security_apps/orchestration/orchestration_comp.cc b/components/security_apps/orchestration/orchestration_comp.cc index 23d3c5a..771335b 100755 --- a/components/security_apps/orchestration/orchestration_comp.cc +++ b/components/security_apps/orchestration/orchestration_comp.cc @@ -49,13 +49,9 @@ using namespace ReportIS; USE_DEBUG_FLAG(D_ORCHESTRATOR); - -static const string ls_prefix = "ls "; -static const string extract_tenant_profile_suffix = - "| grep tenant " - "| cut -d '_' -f 2,4 " - "| sort --unique " - "| awk -F '_' '{ printf \"%s %s \",$1,$2 }'"; +#if defined(gaia) || defined(smb) +static string fw_last_update_time = ""; +#endif // gaia || smb class HealthCheckStatusListener : public Listener { @@ -202,7 +198,10 @@ public: ReportIS::Audience::INTERNAL ); hybrid_mode_metric.registerListener(); - loadExistingTenantsFromConfDir(); + auto orchestration_tools = Singleton::Consume::by(); + orchestration_tools->loadTenantsFromDir( + getConfigurationWithDefault(getFilesystemPathConfig() + "/conf/", "orchestration", "Conf dir") + ); } void @@ -242,8 +241,14 @@ private: ); auto service_controller = Singleton::Consume::by(); - if (!service_controller->updateServiceConfiguration(policy_file_path, settings_file_path)) { - dbgWarning(D_ORCHESTRATOR) << "Failed to load the policy and settings"; + auto is_update_config = service_controller->updateServiceConfiguration( + policy_file_path, + settings_file_path + ); + if (!is_update_config.ok()) { + dbgWarning(D_ORCHESTRATOR) + << "Failed to load the policy and settings, Error: " + << is_update_config.getErr(); } policy_version = service_controller->getPolicyVersion(); @@ -276,7 +281,9 @@ private: auto update_communication = Singleton::Consume::by(); auto authentication_res = update_communication->authenticateAgent(); if (authentication_res.ok() && !policy_version.empty()) { - auto path_policy_version = update_communication->sendPolicyVersion(policy_version); + auto service_controller = Singleton::Consume::by(); + const string &policy_versions = service_controller->getPolicyVersions(); + auto path_policy_version = update_communication->sendPolicyVersion(policy_version, policy_versions); if (!path_policy_version.ok()) { dbgWarning(D_ORCHESTRATOR) << path_policy_version.getErr(); } @@ -289,59 +296,6 @@ private: return authentication_res; } - void - loadExistingTenantsFromConfDir() - { - dbgTrace(D_ORCHESTRATOR) << "Load existing tenants and profiles from the configuration folder"; - - string global_conf_dir = getConfigurationWithDefault( - getFilesystemPathConfig()+ "/conf/", - "orchestration", - "Conf dir" - ); - string shell_cmd_string = ls_prefix + global_conf_dir + extract_tenant_profile_suffix; - auto shell = Singleton::Consume::by(); - Maybe output_res = shell->getExecOutput(shell_cmd_string); - - if (!output_res.ok()) { - dbgWarning(D_ORCHESTRATOR) - << "Failed to load existing tenants from configuration folder: " + output_res.getErr(); - return; - } - - auto tenant_manager = Singleton::Consume::by(); - stringstream ss(output_res.unpack()); - string tenant_id; - string profile_id; - while (!ss.eof() && getline(ss, tenant_id, ' ') && !ss.eof() && getline(ss, profile_id, ' ')) { - dbgTrace(D_ORCHESTRATOR) << "Add existing tenant_" + tenant_id + "_profile_" + profile_id; - tenant_manager->addActiveTenantAndProfile(tenant_id, profile_id); - } - } - - void - deleteInactiveTenantProfileFiles(const string &tenant_id, const string &profile_id) - { - string global_conf_dir = getConfigurationWithDefault( - getFilesystemPathConfig()+ "/conf/", - "orchestration", - "Conf dir" - ); - string tenant_and_profile_suffix = "tenant_" + tenant_id + "_profile_" + profile_id; - string virtual_policy_dir = global_conf_dir + tenant_and_profile_suffix; - - dbgTrace(D_ORCHESTRATOR) << "Delete virtual policy folder : " << virtual_policy_dir; - if (!NGEN::Filesystem::deleteDirectory(virtual_policy_dir, true)) { - dbgWarning(D_ORCHESTRATOR) << "Failed to delete virtual policy folder : " << virtual_policy_dir; - } - - string settings_file_path = virtual_policy_dir + "_settings.json"; - dbgTrace(D_ORCHESTRATOR) << "Delete settings file " << settings_file_path; - if (!NGEN::Filesystem::deleteFile(settings_file_path)) { - dbgWarning(D_ORCHESTRATOR) << "Failed to delete virtual policy settings file : " << settings_file_path; - } - } - Maybe loadOrchestrationPolicy() { @@ -416,10 +370,11 @@ private: auto orchestration_tools = Singleton::Consume::by(); auto service_controller = Singleton::Consume::by(); - if (service_controller->updateServiceConfiguration(policy_file_path, settings_file_path)) { + auto is_update_config = service_controller->updateServiceConfiguration(policy_file_path, settings_file_path); + if (is_update_config.ok()) { maybe_policy = orchestration_tools->jsonFileToObject(orchestration_policy_file); } else { - dbgWarning(D_ORCHESTRATOR) << "Failed to enforce Orchestration policy. File: " << policy_file_path; + dbgWarning(D_ORCHESTRATOR) << is_update_config.getErr(); } if (!maybe_policy.ok()) { @@ -435,8 +390,11 @@ private: return genError("Failed to copy orchestration policy from backup policy.json file."); } // Try to use the backup policy.json file and re-write the services's policies. - if (service_controller->updateServiceConfiguration(policy_file_path, settings_file_path)) { - maybe_policy= orchestration_tools->jsonFileToObject(orchestration_policy_file); + is_update_config = service_controller->updateServiceConfiguration(policy_file_path, settings_file_path); + if (is_update_config.ok()) { + maybe_policy = orchestration_tools->jsonFileToObject(orchestration_policy_file); + } else { + dbgWarning(D_ORCHESTRATOR) << is_update_config.getErr(); } } @@ -613,18 +571,22 @@ private: // Try to use the backup policy.json file and re-write the services's policies. dbgInfo(D_ORCHESTRATOR) << "Updating services with the new policy."; - if (service_controller->updateServiceConfiguration(policy_file_path + backup_ext, settings_file_path)) { - dbgInfo(D_ORCHESTRATOR) << "Recovering the policy file from backup."; - if (!orchestration_tools->copyFile(policy_file_path + backup_ext, policy_file_path)) { - dbgWarning (D_ORCHESTRATOR) - << "Failed to recover policy file from backup. File: " - << policy_file_path + backup_ext; - return false; - } - return true; + auto is_update_config = service_controller->updateServiceConfiguration( + policy_file_path + backup_ext, + settings_file_path + ); + if (!is_update_config.ok()) { + dbgWarning (D_ORCHESTRATOR) << "Failed to load Orchestration policy. Error: " << is_update_config.getErr(); + return false; } - dbgWarning (D_ORCHESTRATOR) << "Failed to load Orchestration policy."; - return false; + dbgInfo(D_ORCHESTRATOR) << "Recovering the policy file from backup."; + if (!orchestration_tools->copyFile(policy_file_path + backup_ext, policy_file_path)) { + dbgWarning (D_ORCHESTRATOR) + << "Failed to recover policy file from backup. File: " + << policy_file_path + backup_ext; + return false; + } + return true; } string @@ -646,7 +608,8 @@ private: Singleton::Consume::by()->setPolicyVersion(new_policy_version); } auto update_communication = Singleton::Consume::by(); - auto path_policy_version = update_communication->sendPolicyVersion(new_policy_version); + const string &policy_versions = service_controller->getPolicyVersions(); + auto path_policy_version = update_communication->sendPolicyVersion(new_policy_version, policy_versions); if (!path_policy_version.ok()) { dbgWarning(D_ORCHESTRATOR) << path_policy_version.getErr(); } @@ -685,19 +648,21 @@ private: // Calculate the changes between the existing policy to the new one. auto service_controller = Singleton::Consume::by(); string old_policy_version = service_controller->getPolicyVersion(); - bool res = service_controller->updateServiceConfiguration( + auto res = service_controller->updateServiceConfiguration( new_policy_file.unpack(), settings_path, data_updates ); - if (!res) { + if (!res.ok()) { string updated_policy_version = service_controller->getUpdatePolicyVersion(); string error_str = "Failed to update services' policy configuration files. Previous version: " + old_policy_version + ". New version: " + - updated_policy_version; + updated_policy_version + + ". Error: " + + res.getErr(); auto policy_file = getConfigurationWithDefault( filesystem_prefix + "/conf/policy.json", @@ -987,6 +952,22 @@ private: policy_version ); + auto agent_mode = Singleton::Consume::by()->getOrchestrationMode(); + auto policy_mgmt_mode = getSettingWithDefault("management", "profileManagedMode"); + if (agent_mode == OrchestrationMode::HYBRID || policy_mgmt_mode == "declarative") { + auto upgrade_mode = getSettingWithDefault("manual", "upgradeMode"); + if (upgrade_mode != "scheduled") { + request.setUpgradeFields(upgrade_mode); + } else { + request.setUpgradeFields( + upgrade_mode, + getSettingWithDefault("0:00", "upgradeTime"), + getSettingWithDefault(4, "upgradeDurationHours"), + getSettingWithDefault>({}, "upgradeDay") + ); + } + } + auto greedy_update = getProfileAgentSettingWithDefault(false, "orchestration.multitenancy.greedymode"); greedy_update = getConfigurationWithDefault(greedy_update, "orchestration", "Multitenancy Greedy mode"); @@ -1095,16 +1076,16 @@ private: data_updates ); } - if (!orch_policy.ok() && (data_updates.size() > 0 || settings_path != "")) { + if (!orch_policy.ok() && (!data_updates.empty() || !settings_path.empty())) { auto service_controller = Singleton::Consume::by(); - bool res = service_controller->updateServiceConfiguration( + auto res = service_controller->updateServiceConfiguration( "", settings_path, data_updates ); - if (!res) { - dbgWarning(D_ORCHESTRATOR) << "Failed to update new service configuration"; + if (!res.ok()) { + dbgWarning(D_ORCHESTRATOR) << res.getErr(); } } @@ -1271,7 +1252,12 @@ private: } } } - + auto orchestration_tools = Singleton::Consume::by(); + auto conf_dir = getConfigurationWithDefault( + getFilesystemPathConfig() + "/conf/", + "orchestration", + "Conf dir" + ); for (const auto &tenant_profile_set : profiles_to_be_deleted) { auto tenant_id = tenant_profile_set.first; for (const auto &profile_id: tenant_profile_set.second) { @@ -1282,7 +1268,11 @@ private: << ", Profile ID: " << profile_id; tenant_manager->deactivateTenant(tenant_id, profile_id); - deleteInactiveTenantProfileFiles(tenant_id, profile_id); + orchestration_tools->deleteVirtualTenantProfileFiles( + tenant_id, + profile_id, + conf_dir + ); } } @@ -1481,6 +1471,16 @@ private: agent_data_report << AgentReportFieldWithLabel("isVersionEqualOrAboveR8110", "true"); } + auto i_agent_details = Singleton::Consume::by(); + if ( + i_agent_details->getOrchestrationMode() == OrchestrationMode::HYBRID || + getSettingWithDefault("management", "profileManagedMode") == "declarative" + ) { + agent_data_report << AgentReportFieldWithLabel("managedMode", "declarative"); + } else { + agent_data_report << AgentReportFieldWithLabel("managedMode", "management"); + } + #if defined(gaia) || defined(smb) if (i_details_resolver->compareCheckpointVersion(8100, greater_equal())) { agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true"); @@ -1584,7 +1584,9 @@ private: while (true) { static int failure_count = 0; Singleton::Consume::by()->startNewTrace(false); - reportAgentDetailsMetaData(); + if (shouldReportAgentDetailsMetadata()) { + reportAgentDetailsMetaData(); + } auto check_update_result = checkUpdate(); if (!check_update_result.ok()) { failure_count++; @@ -1900,6 +1902,32 @@ private: } } + bool + shouldReportAgentDetailsMetadata() + { + bool should_report_agent_details_metadata = true; +#if defined(gaia) || defined(smb) + auto i_shell_cmd = Singleton::Consume::by(); + auto result = i_shell_cmd->getExecOutput("stat -c %Y $FWDIR/state/local/FW1"); + if (!result.ok()) return should_report_agent_details_metadata; + string current_update_time = result.unpack(); + fw_last_update_time = fw_last_update_time.empty() ? current_update_time : fw_last_update_time; + try { + bool is_fw_dir_changed = stoi(current_update_time) > stoi(fw_last_update_time); + if (!is_fw_dir_changed) { + should_report_agent_details_metadata = false; + } else { + fw_last_update_time = current_update_time; + } + } catch (const exception& err) { + dbgWarning(D_ORCHESTRATOR) + << "Failed to check if access policy was recently updated , Error:" + << err.what(); + } +#endif // gaia || smb + return should_report_agent_details_metadata; + } + class AddProxyRest : public ServerRest { public: @@ -1976,6 +2004,9 @@ OrchestrationComp::preload() registerExpectedSetting>("orchestration", "Orchestration status ignored policies"); registerExpectedSetting("agentType"); registerExpectedSetting("upgradeMode"); + registerExpectedSetting("upgradeTime"); + registerExpectedSetting("upgradeDurationHours"); + registerExpectedSetting>("upgradeDay"); registerExpectedSetting("email-address"); registerExpectedSetting("registered-server"); registerExpectedConfigFile("orchestration", Config::ConfigFileType::Policy); diff --git a/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc b/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc index 6411d73..ff4d60a 100755 --- a/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc +++ b/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc @@ -18,6 +18,7 @@ #include "cereal/external/rapidjson/document.h" #include "cereal/types/vector.hpp" #include "cereal/types/set.hpp" +#include "agent_core_utilities.h" #include #include @@ -27,6 +28,12 @@ using namespace std; using namespace rapidjson; static const string base64_base_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const string ls_prefix = "ls "; +static const string extract_tenant_profile_suffix = + "| grep tenant " + "| cut -d '_' -f 2,4 " + "| sort --unique " + "| awk -F '_' '{ printf \"%s %s \",$1,$2 }'"; class OrchestrationTools::Impl : Singleton::Provide::From { @@ -50,6 +57,12 @@ public: bool doesDirectoryExist(const string &dir_path) const override; bool executeCmd(const string &cmd) const override; bool isNonEmptyFile(const string &path) const override; + void loadTenantsFromDir(const string &dir_path) const override; + bool removeDirectory(const string &path, bool delete_content) const override; + void deleteVirtualTenantProfileFiles( + const std::string &tenant_id, + const std::string &profile_id, + const std::string &conf_path) const override; Maybe calculateChecksum(Package::ChecksumTypes checksum_type, const string &path) const override; @@ -206,6 +219,64 @@ OrchestrationTools::Impl::removeFile(const string &path) const return true; } +bool +OrchestrationTools::Impl::removeDirectory(const string &path, bool delete_content) const +{ + if (!NGEN::Filesystem::deleteDirectory(path, delete_content)) { + dbgDebug(D_ORCHESTRATOR) << "Deletion of the folder at path " << path << " failed."; + return false; + } + dbgDebug(D_ORCHESTRATOR) << "Successfully deleted folder at path " << path; + return true; +} + +void +OrchestrationTools::Impl::deleteVirtualTenantProfileFiles( + const string &tenant_id, + const string &profile_id, + const string &conf_path) const +{ + string tenant_and_profile_suffix = "tenant_" + tenant_id + "_profile_" + profile_id; + string virtual_policy_dir = conf_path + "/" + tenant_and_profile_suffix; + if (!removeDirectory(virtual_policy_dir, true)) { + dbgWarning(D_ORCHESTRATOR) << "Failed to delete virtual policy folder : " << virtual_policy_dir; + } else { + dbgDebug(D_ORCHESTRATOR) << "Virtual policy folder " << virtual_policy_dir << " deleted successfully."; + } + + string settings_file_path = virtual_policy_dir + "_settings.json"; + if (!removeFile(settings_file_path)) { + dbgWarning(D_ORCHESTRATOR) << "Failed to delete virtual policy settings file : " << settings_file_path; + } else { + dbgDebug(D_ORCHESTRATOR) << "Virtual policy settings file " << settings_file_path << " deleted successfully."; + } +} + +void +OrchestrationTools::Impl::loadTenantsFromDir(const string &dir_path) const +{ + dbgTrace(D_ORCHESTRATOR) << "Load existing tenants and profiles from the configuration folder"; + + string shell_cmd_string = ls_prefix + dir_path + extract_tenant_profile_suffix; + auto shell = Singleton::Consume::by(); + Maybe output_res = shell->getExecOutput(shell_cmd_string); + + if (!output_res.ok()) { + dbgWarning(D_ORCHESTRATOR) + << "Failed to load existing tenants from configuration folder: " + output_res.getErr(); + return; + } + + auto tenant_manager = Singleton::Consume::by(); + stringstream ss(output_res.unpack()); + string tenant_id; + string profile_id; + while (!ss.eof() && getline(ss, tenant_id, ' ') && !ss.eof() && getline(ss, profile_id, ' ')) { + dbgTrace(D_ORCHESTRATOR) << "Add existing tenant_" + tenant_id + "_profile_" + profile_id; + tenant_manager->addActiveTenantAndProfile(tenant_id, profile_id); + } +} + Maybe OrchestrationTools::Impl::calculateChecksum(Package::ChecksumTypes checksum_type, const string &path) const { diff --git a/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc b/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc index 9c7f715..c229aca 100755 --- a/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc +++ b/components/security_apps/orchestration/orchestration_tools/orchestration_tools_ut/orchestration_tools_ut.cc @@ -1,6 +1,8 @@ #include "orchestration_tools.h" #include "cptest.h" +#include "mock/mock_tenant_manager.h" +#include "mock/mock_shell_cmd.h" using namespace std; using namespace testing; @@ -17,9 +19,6 @@ public: { str.erase(remove(str.begin(), str.end(), ' '), str.end()); } - - OrchestrationTools orchestration_tools; - I_OrchestrationTools *i_orchestration_tools = Singleton::Consume::from(orchestration_tools); string manifest_file = "manifest.json"; string manifest_text = "{" " \"packages\": [" @@ -45,6 +44,11 @@ public: " }" " ]" "}"; + + OrchestrationTools orchestration_tools; + I_OrchestrationTools *i_orchestration_tools = Singleton::Consume::from(orchestration_tools); + StrictMock mock_tenant_manager; + StrictMock mock_shell_cmd; }; TEST_F(OrchestrationToolsTest, doNothing) @@ -241,6 +245,97 @@ TEST_F(OrchestrationToolsTest, createDirectory) EXPECT_TRUE(i_orchestration_tools->createDirectory(path)); } +TEST_F(OrchestrationToolsTest, removeDirectory) +{ + string dir_path = "/tmp/temp_dir2"; + EXPECT_TRUE(i_orchestration_tools->createDirectory(dir_path)); + EXPECT_TRUE(i_orchestration_tools->doesDirectoryExist(dir_path)); + + stringstream string_stream; + string_stream << "blah blah blah"; + string file_path = dir_path + "/packages.json"; + i_orchestration_tools->writeFile(string_stream.str(), file_path); + + EXPECT_TRUE(i_orchestration_tools->doesFileExist(file_path)); + EXPECT_FALSE(i_orchestration_tools->removeDirectory(dir_path, false)); + EXPECT_TRUE(i_orchestration_tools->doesFileExist(file_path)); + + EXPECT_TRUE(i_orchestration_tools->removeDirectory(dir_path, true)); + EXPECT_FALSE(i_orchestration_tools->doesFileExist(file_path)); + EXPECT_FALSE(i_orchestration_tools->doesDirectoryExist(dir_path)); +} + +TEST_F(OrchestrationToolsTest, deleteVirtualTenantFiles) +{ + stringstream string_stream; + string_stream << "policy policy policy"; + string conf_path = "/tmp/temp_conf"; + EXPECT_TRUE(i_orchestration_tools->createDirectory(conf_path)); + + string policy_folder_path = conf_path + "/tenant_3fdbdd33_profile_c4c498d8"; + string policy_file_path = policy_folder_path + "/policy.json"; + EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path)); + + string settings_file_path = conf_path + "/tenant_3fdbdd33_profile_c4c498d8_settings.json"; + i_orchestration_tools->writeFile(string_stream.str(), settings_file_path); + i_orchestration_tools->writeFile(string_stream.str(), policy_file_path); + + EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path)); + EXPECT_TRUE(i_orchestration_tools->doesFileExist(policy_file_path)); + i_orchestration_tools->deleteVirtualTenantProfileFiles("3fdbdd33", "c4c498d8", conf_path); + EXPECT_FALSE(i_orchestration_tools->doesFileExist(settings_file_path)); + EXPECT_FALSE(i_orchestration_tools->doesFileExist(policy_file_path)); +} + +TEST_F(OrchestrationToolsTest, loadTenants) +{ + stringstream string_stream; + string_stream << "policy policy policy"; + string conf_path = "/tmp/temp_conf"; + EXPECT_TRUE(i_orchestration_tools->createDirectory(conf_path)); + + string policy_folder_path1 = conf_path + "/tenant_3fdbdd33_profile_c4c498d8"; + EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path1)); + + string policy_folder_path2 = conf_path + "/tenant_123456_profile_654321"; + EXPECT_TRUE(i_orchestration_tools->createDirectory(policy_folder_path2)); + + string settings_file_path1 = conf_path + "/tenant_3fdbdd33_profile_c4c498d8_settings.json"; + i_orchestration_tools->writeFile(string_stream.str(), settings_file_path1); + + string settings_file_path2 = conf_path + "/tenant_123456_profile_654321_settings.json"; + i_orchestration_tools->writeFile(string_stream.str(), settings_file_path2); + + string policy_file_path1 = policy_folder_path1 + "/policy.json"; + i_orchestration_tools->writeFile(string_stream.str(), policy_file_path1); + + string policy_file_path2 = policy_folder_path2 + "/policy.json"; + i_orchestration_tools->writeFile(string_stream.str(), policy_file_path2); + + EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path1)); + EXPECT_TRUE(i_orchestration_tools->doesFileExist(settings_file_path2)); + EXPECT_TRUE(i_orchestration_tools->doesFileExist(policy_file_path1)); + EXPECT_TRUE(i_orchestration_tools->doesFileExist(policy_file_path2)); + + EXPECT_CALL( + mock_shell_cmd, + getExecOutput( + "ls /tmp/temp_conf| grep tenant " + "| cut -d '_' -f 2,4 | sort --unique " + "| awk -F '_' '{ printf \"%s %s \",$1,$2 }'", + 200, + false + ) + ).WillOnce(Return(string("3fdbdd33 c4c498d8 123456 654321"))); + EXPECT_CALL(mock_tenant_manager, addActiveTenantAndProfile("3fdbdd33", "c4c498d8")).Times(1); + EXPECT_CALL(mock_tenant_manager, addActiveTenantAndProfile("123456", "654321")).Times(1); + + i_orchestration_tools->loadTenantsFromDir(conf_path); + i_orchestration_tools->deleteVirtualTenantProfileFiles("3fdbdd33", "c4c498d8", conf_path); + EXPECT_FALSE(i_orchestration_tools->doesFileExist(settings_file_path1)); + EXPECT_FALSE(i_orchestration_tools->doesFileExist(policy_file_path1)); +} + TEST_F(OrchestrationToolsTest, base64DecodeEncode) { string clear_text = "{\n" diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc index 0eb2efe..b118ddc 100644 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc @@ -74,17 +74,7 @@ public: ).WillOnce(Return(true)); doEncrypt(); - EXPECT_CALL( - mock_shell_cmd, - getExecOutput( - "ls /etc/cp/conf/" - "| grep tenant " - "| cut -d '_' -f 2,4 " - "| sort --unique " - "| awk -F '_' '{ printf \"%s %s \",$1,$2 }'", - _, - _ - )).WillOnce(Return(Maybe(string("")))); + EXPECT_CALL(mock_orchestration_tools, loadTenantsFromDir(_)).Times(1); orchestration_comp.init(); } @@ -446,7 +436,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) "", false ) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_service_controller, @@ -458,7 +448,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) "2611", false ) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_service_controller, @@ -470,7 +460,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) "2311", true ) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL(mock_ml, yield(A())) .WillOnce( @@ -494,12 +484,10 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) mock_shell_cmd, getExecOutput(_, _, _) ).WillRepeatedly(Return(string("daniel\n1\n"))); + EXPECT_CALL(mock_orchestration_tools, deleteVirtualTenantProfileFiles("321321", "123123", "/etc/cp/conf/")) + .Times(1); try { runRoutine(); } catch (const invalid_argument& e) {} - string debug_str_folder = "Delete virtual policy folder : /etc/cp/conf/tenant_321321_profile_123123"; - string debug_str_settings = "Delete settings file /etc/cp/conf/tenant_321321_profile_123123_settings.json"; - EXPECT_THAT(debug_output.str(), HasSubstr(debug_str_folder)); - EXPECT_THAT(debug_output.str(), HasSubstr(debug_str_settings)); Debug::setNewDefaultStdout(&cout); } diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc index d44a6f7..d362fd6 100755 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc @@ -94,17 +94,7 @@ public: )).WillRepeatedly(DoAll(SaveArg<1>(&message_body), Return(Maybe(string(""))))); doEncrypt(); - EXPECT_CALL( - mock_shell_cmd, - getExecOutput( - "ls /etc/cp/conf/" - "| grep tenant " - "| cut -d '_' -f 2,4 " - "| sort --unique " - "| awk -F '_' '{ printf \"%s %s \",$1,$2 }'", - _, - _ - )).WillOnce(Return(Maybe(string("")))); + EXPECT_CALL(mock_orchestration_tools, loadTenantsFromDir(_)).Times(1); orchestration_comp.init(); } @@ -511,7 +501,8 @@ TEST_F(OrchestrationTest, check_sending_registration_data) ) ); EXPECT_CALL(mock_orchestration_tools, readFile(_)).WillOnce(Return(response)); - EXPECT_CALL(mock_service_controller, updateServiceConfiguration(_, _, _, _, _, _)).WillOnce(Return(true)); + EXPECT_CALL(mock_service_controller, updateServiceConfiguration(_, _, _, _, _, _)) + .WillOnce(Return(Maybe())); EXPECT_CALL(mock_message, setActiveFog(_, _, _, _)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, calculateChecksum(_, _)).WillRepeatedly(Return(string())); EXPECT_CALL(mock_service_controller, getPolicyVersion()).WillRepeatedly(ReturnRef(first_policy_version)); @@ -666,9 +657,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback) ); EXPECT_CALL(mock_status, setPolicyVersion(third_val)); EXPECT_CALL(mock_status, setPolicyVersion(second_val)); - EXPECT_CALL(mock_update_communication, sendPolicyVersion("13")).Times(1).WillOnce(Return(Maybe())); + + string policy_versions; + EXPECT_CALL(mock_service_controller, getPolicyVersions()).WillRepeatedly(ReturnRef(policy_versions)); + EXPECT_CALL(mock_update_communication, sendPolicyVersion("13", _)).Times(1).WillOnce(Return(Maybe())); // Rollback related test: The old policy version 12 is restored - EXPECT_CALL(mock_update_communication, sendPolicyVersion("12")).Times(1).WillOnce(Return(Maybe())); + EXPECT_CALL(mock_update_communication, sendPolicyVersion("12", _)).Times(1).WillOnce(Return(Maybe())); EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce( Invoke( @@ -694,12 +688,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_service_controller, updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_message, @@ -751,7 +745,7 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path_bk, _, _, _, _, _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_orchestration_tools, @@ -858,7 +852,10 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate) .WillOnce(ReturnRef(third_val) ); EXPECT_CALL(mock_status, setPolicyVersion(third_val)); - EXPECT_CALL(mock_update_communication, sendPolicyVersion("13")).Times(1).WillOnce(Return(Maybe())); + + string policy_versions; + EXPECT_CALL(mock_service_controller, getPolicyVersions()).WillRepeatedly(ReturnRef(policy_versions)); + EXPECT_CALL(mock_update_communication, sendPolicyVersion("13", _)).Times(1).WillOnce(Return(Maybe())); EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce( Invoke( @@ -884,12 +881,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_service_controller, updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL( mock_message, @@ -988,7 +985,7 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).Times(2).WillRepeatedly(Return(true)); + ).Times(2).WillRepeatedly(Return(Maybe())); EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(Return(true)); EXPECT_CALL(mock_update_communication, setAddressExtenesion("")); @@ -1108,7 +1105,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path)) @@ -1242,7 +1239,7 @@ TEST_F(OrchestrationTest, manifestUpdate) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path)).WillOnce(Return(response)); @@ -1394,7 +1391,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).Times(2).WillRepeatedly(Return(true)); + ).Times(2).WillRepeatedly(Return(Maybe())); set expected_changed_policies = {}; EXPECT_CALL(mock_service_controller, mockMoveChangedPolicies()).WillOnce(Return(expected_changed_policies)); @@ -1478,7 +1475,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _) - ).WillOnce(Return(false)); + ).WillOnce(Return(Maybe(genError(string(""))))); EXPECT_CALL(mock_ml, yield(A())) .WillOnce( @@ -1544,7 +1541,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path)).WillOnce(Return(response)); @@ -1754,7 +1751,7 @@ TEST_P(OrchestrationTest, orchestrationFirstRun) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); EXPECT_CALL(mock_ml, yield(A())) .WillOnce( @@ -1936,13 +1933,13 @@ TEST_F(OrchestrationTest, dataUpdate) ExpectationSet expectation_set = EXPECT_CALL( mock_service_controller, updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "", _) - ).WillOnce(Return(true)); + ).WillOnce(Return(Maybe())); vector expected_ips_data_types = { "ips" }; EXPECT_CALL( mock_service_controller, updateServiceConfiguration("", "", expected_ips_data_types, "", "", _) - ).After(expectation_set).WillOnce(Return(true)); + ).After(expectation_set).WillOnce(Return(Maybe())); EXPECT_CALL(mock_orchestration_tools, doesDirectoryExist("/etc/cp/conf/data")).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path)).WillOnce(Return(policy_response)); diff --git a/components/security_apps/orchestration/service_controller/service_controller.cc b/components/security_apps/orchestration/service_controller/service_controller.cc index 7e466d0..73828c2 100755 --- a/components/security_apps/orchestration/service_controller/service_controller.cc +++ b/components/security_apps/orchestration/service_controller/service_controller.cc @@ -269,13 +269,13 @@ class ServiceController::Impl public: void init(); - bool + Maybe updateServiceConfiguration( const string &new_policy_path, const string &new_settings_path, const vector &new_data_files, - const string &tenant_id, - const string &profile_id, + const string &child_tenant_id, + const string &child_profile_id, const bool last_iteration ) override; @@ -291,6 +291,7 @@ public: void refreshPendingServices() override; const string & getPolicyVersion() const override; const string & getUpdatePolicyVersion() const override; + const string & getPolicyVersions() const override; void updateReconfStatus(int id, ReconfStatus status) override; void startReconfStatus( int id, @@ -308,9 +309,11 @@ public: private: void cleanUpVirtualFiles(); - bool sendSignalForServices(const set &nano_services_to_update, const string &policy_version); + Maybe sendSignalForServices( + const set &nano_services_to_update, + const string &policy_version_to_update); - bool updateServiceConfigurationFile( + Maybe updateServiceConfigurationFile( const string &configuration_name, const string &configuration_file_path, const string &new_configuration_path); @@ -326,10 +329,12 @@ private: void writeRegisteredServicesToFile(); bool backupConfigurationFile(const string &configuration_file_path); + bool createDirectoryForChildTenant(const string &child_tenant_id, const string &child_profile_id) const; int configuration_id = 0; map registered_services; map pending_services; + string policy_versions; string policy_version; string update_policy_version; string settings_path; @@ -657,14 +662,45 @@ ServiceController::Impl::backupConfigurationFile(const string &config_file_path) } bool +ServiceController::Impl::createDirectoryForChildTenant( + const string &child_tenant_id, + const string &child_profile_id) const +{ + if (child_tenant_id == "") return true; + + auto orchestration_tools = Singleton::Consume::by(); + string dir = getConfigurationWithDefault( + filesystem_prefix + "/conf", + "orchestration", + "Configuration directory" + ); + + dir = dir + "/tenant_" + child_tenant_id + "_profile_" + child_profile_id; + if (orchestration_tools->doesDirectoryExist(dir)) return true; + + if (!orchestration_tools->createDirectory(dir)) { + dbgError(D_ORCHESTRATOR) + << "Failed to create configuration directory for tenant " + << child_tenant_id; + return false; + } + dbgTrace(D_ORCHESTRATOR) << "Created new configuration directory for tenant " << child_tenant_id; + return true; +} + +Maybe ServiceController::Impl::updateServiceConfiguration( const string &new_policy_path, const string &new_settings_path, const vector &new_data_files, - const string &tenant_id, - const string &profile_id, + const string &child_tenant_id, + const string &child_profile_id, const bool last_iteration) { + string tenant_and_profile_ids = ""; + if (!child_tenant_id.empty()) { + tenant_and_profile_ids = " Child tenant id: " + child_tenant_id + ", Child profile id: " + child_profile_id; + } dbgFlow(D_ORCHESTRATOR) << "new_policy_path: " << new_policy_path @@ -672,10 +708,8 @@ ServiceController::Impl::updateServiceConfiguration( << new_settings_path << ", new_data_files: " << makeSeparatedStr(new_data_files, ",") - << ". tenant_id: " - << tenant_id - << ". profile_id: " - << profile_id; + << "." + << tenant_and_profile_ids; if (!new_settings_path.empty()) { settings_path = new_settings_path; @@ -704,8 +738,9 @@ ServiceController::Impl::updateServiceConfiguration( if (new_policy_path == "") { dbgDebug(D_ORCHESTRATOR) << "Policy file was not updated. Sending reload command regarding settings and data"; - - return sendSignalForServices(nano_services_to_update, ""); + auto signal_services = sendSignalForServices(nano_services_to_update, ""); + if (!signal_services.ok()) return signal_services.passErr(); + return Maybe(); } Maybe loaded_policy_json = orchestration_tools->readFile(new_policy_path); @@ -716,14 +751,13 @@ ServiceController::Impl::updateServiceConfiguration( << ". Error: " << loaded_policy_json.getErr(); - return false; + return genError("Failed to load new file: " + new_policy_path + ". Error: " + loaded_policy_json.getErr()); } - auto all_security_policies = orchestration_tools->jsonObjectSplitter( loaded_policy_json.unpack(), - tenant_id, - profile_id + child_tenant_id, + child_profile_id ); if (!all_security_policies.ok()) { @@ -733,12 +767,18 @@ ServiceController::Impl::updateServiceConfiguration( << ". Error: " << all_security_policies.getErr(); - return false; + return genError("Failed to parse json file: " + + new_policy_path + + ". Error: " + + all_security_policies.getErr() + ); } bool was_policy_updated = true; const string version_param = "version"; + const string versions_param = "versions"; string version_value; + string send_signal_for_services_err; for (auto &single_policy : all_security_policies.unpack()) { if (single_policy.first == version_param) { @@ -747,33 +787,27 @@ ServiceController::Impl::updateServiceConfiguration( update_policy_version = version_value; continue; } + if (child_tenant_id.empty() && single_policy.first == versions_param) { + //In a multi-tenant env, only the parent should handle the versions parameter + policy_versions = single_policy.second; + dbgWarning(D_ORCHESTRATOR) << "Found versions parameter in policy file:" << policy_versions; + } dbgDebug(D_ORCHESTRATOR) << "Starting to update policy file. Policy type: " << single_policy.first; - string dir = getConfigurationWithDefault( - filesystem_prefix + "/conf", - "orchestration", - "Configuration directory" - ); - - if (tenant_id != "") { - dir = dir + "/tenant_" + tenant_id + "_profile_" + profile_id; - if (!orchestration_tools->doesDirectoryExist(dir)) { - if (orchestration_tools->createDirectory(dir)) { - dbgTrace(D_ORCHESTRATOR) << "Created new configuration directory for tenant " << tenant_id; - } else { - dbgError(D_ORCHESTRATOR) << "Failed to create configuration directory for tenant "<< tenant_id; - return false; - } - } + if (!createDirectoryForChildTenant(child_tenant_id, child_profile_id)) { + dbgWarning(D_ORCHESTRATOR) + << "Failed to create directory for child. Tenant id: " << child_tenant_id + << ", Profile id: " << child_profile_id; + return genError("Failed to create directory for child tenant"); } string policy_file_path = getPolicyConfigPath( single_policy.first, Config::ConfigFileType::Policy, - tenant_id, - profile_id + child_tenant_id, + child_profile_id ); auto update_config_result = updateServiceConfigurationFile( @@ -782,8 +816,11 @@ ServiceController::Impl::updateServiceConfiguration( single_policy.second ); - if (!update_config_result) { - dbgWarning(D_ORCHESTRATOR) << "Failed to update policy file. Policy name: " << single_policy.first; + if (!update_config_result.ok()) { + send_signal_for_services_err = "Failed to update policy file. Policy name: " + + single_policy.first + + ". Error: " + + update_config_result.getErr(); was_policy_updated = false; continue; } @@ -798,10 +835,10 @@ ServiceController::Impl::updateServiceConfiguration( OrchestrationStatusConfigType::POLICY ); - if (tenant_id != "") { + if (child_tenant_id != "") { auto instances = Singleton::Consume::by()->getInstances( - tenant_id, - profile_id + child_tenant_id, + child_profile_id ); for (const auto &instance_id: instances) { auto relevant_service = registered_services.find(instance_id); @@ -823,18 +860,20 @@ ServiceController::Impl::updateServiceConfiguration( } // 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); + if (!is_multi_tenant_env || last_iteration) { + auto is_send_signal_for_services = sendSignalForServices(nano_services_to_update, version_value); + was_policy_updated &= is_send_signal_for_services.ok(); + if (!is_send_signal_for_services.ok()) send_signal_for_services_err = is_send_signal_for_services.getErr(); + } dbgTrace(D_ORCHESTRATOR) << "was policy updated: " << (was_policy_updated ? "true" : "false"); if (was_policy_updated) { - string config_file_path; string base_path = filesystem_prefix + "/conf/" + - (tenant_id != "" ? "tenant_" + tenant_id + "_profile_" + profile_id + "/" : ""); - config_file_path = getConfigurationWithDefault( + (child_tenant_id != "" ? "tenant_" + child_tenant_id + "_profile_" + child_profile_id + "/" : ""); + + string config_file_path = getConfigurationWithDefault( base_path + "policy.json", "orchestration", "Policy file path" @@ -843,12 +882,12 @@ ServiceController::Impl::updateServiceConfiguration( if (new_policy_path.compare(config_file_path) == 0) { dbgDebug(D_ORCHESTRATOR) << "Enforcing the default policy file"; policy_version = version_value; - return true; + return Maybe(); } if (!backupConfigurationFile(config_file_path)) { dbgWarning(D_ORCHESTRATOR) << "Failed to backup the policy file."; - return false; + return genError("Failed to backup the policy file."); } policy_version = version_value; @@ -856,17 +895,18 @@ ServiceController::Impl::updateServiceConfiguration( // Save the new configuration file. if (!orchestration_tools->copyFile(new_policy_path, config_file_path)) { dbgWarning(D_ORCHESTRATOR) << "Failed to save the policy file."; - return false; + return genError("Failed to save the policy file."); } } - return was_policy_updated; + if (!was_policy_updated && !send_signal_for_services_err.empty()) return genError(send_signal_for_services_err); + return Maybe(); } -bool +Maybe ServiceController::Impl::sendSignalForServices( const set &nano_services_to_update, - const string &policy_version) + const string &policy_version_to_update) { dbgFlow(D_ORCHESTRATOR); for (auto &service_id : nano_services_to_update) { @@ -877,7 +917,7 @@ ServiceController::Impl::sendSignalForServices( } ++configuration_id; - auto reconf_status = nano_service->second.sendNewConfigurations(configuration_id, policy_version); + auto reconf_status = nano_service->second.sendNewConfigurations(configuration_id, policy_version_to_update); if (reconf_status == ReconfStatus::INACTIVE) { dbgWarning(D_ORCHESTRATOR) << "Erasing details regarding inactive service " << service_id; @@ -889,7 +929,7 @@ ServiceController::Impl::sendSignalForServices( dbgDebug(D_ORCHESTRATOR) << "The reconfiguration failed for serivce: " << service_id; services_reconf_status.clear(); services_reconf_names.clear(); - return false; + return genError("The reconfiguration failed for serivce: " + service_id); } } @@ -910,7 +950,7 @@ ServiceController::Impl::sendSignalForServices( dbgDebug(D_ORCHESTRATOR) << "The reconfiguration was successfully completed for all the services"; services_reconf_status.clear(); services_reconf_names.clear(); - return true; + return Maybe(); } case ReconfStatus::IN_PROGRESS: { dbgTrace(D_ORCHESTRATOR) << "Reconfiguration in progress..."; @@ -918,8 +958,10 @@ ServiceController::Impl::sendSignalForServices( break; } case ReconfStatus::FAILED: { + vector failed_services_vec; for(auto &status : services_reconf_status) { if (status.second == ReconfStatus::FAILED) { + failed_services_vec.push_back(services_reconf_names[status.first]); dbgDebug(D_ORCHESTRATOR) << "The reconfiguration failed for serivce " << services_reconf_names[status.first]; @@ -927,13 +969,16 @@ ServiceController::Impl::sendSignalForServices( } services_reconf_status.clear(); services_reconf_names.clear(); - return false; + + string failed_services = makeSeparatedStr(failed_services_vec, ", "); + + return genError("The reconfiguration failed for serivces: " + failed_services); } case ReconfStatus::INACTIVE: { dbgError(D_ORCHESTRATOR) << "Reached inactive state in the middle of reconfiguration!"; services_reconf_status.clear(); services_reconf_names.clear(); - return false; + return genError("Reached inactive state in the middle of reconfiguration!"); } } } @@ -941,10 +986,10 @@ ServiceController::Impl::sendSignalForServices( dbgDebug(D_ORCHESTRATOR) << "The reconfiguration has reached a timeout"; services_reconf_status.clear(); services_reconf_names.clear(); - return false; + return genError("The reconfiguration has reached a timeout"); } -bool +Maybe ServiceController::Impl::updateServiceConfigurationFile( const string &configuration_name, const string &configuration_file_path, @@ -959,7 +1004,7 @@ ServiceController::Impl::updateServiceConfigurationFile( bool service_changed = old_configuration.unpack().compare(new_configuration_path) != 0; if (service_changed == false) { dbgDebug(D_ORCHESTRATOR) << "There is no update for policy file: " << configuration_file_path; - return true; + return Maybe(); } dbgDebug(D_ORCHESTRATOR) << "Starting to update " << configuration_file_path << " to " << new_configuration_path; @@ -972,7 +1017,7 @@ ServiceController::Impl::updateServiceConfigurationFile( dbgDebug(D_ORCHESTRATOR) << "Backup of policy file has been created in: " << configuration_file_path; } else { dbgWarning(D_ORCHESTRATOR) << "Failed to backup policy file"; - return false; + return genError("Failed to backup policy file"); } } else { dbgWarning(D_ORCHESTRATOR) @@ -981,7 +1026,12 @@ ServiceController::Impl::updateServiceConfigurationFile( << ". Error: " << old_configuration.getErr(); - return false; + return genError( + "Failed to read current policy file " + + configuration_file_path + + ". Error: " + + old_configuration.getErr() + ); } } @@ -989,12 +1039,12 @@ ServiceController::Impl::updateServiceConfigurationFile( dbgDebug(D_ORCHESTRATOR) << "New policy file has been saved in: " << configuration_file_path; } else { dbgWarning(D_ORCHESTRATOR) << "Failed to save new policy file"; - return false; + return genError("Failed to save new policy file"); } dbgInfo(D_ORCHESTRATOR) << "Successfully updated policy file: " << configuration_file_path; - return true; + return Maybe(); } ServiceController::ServiceController() : Component("ServiceController"), pimpl(make_unique()) {} @@ -1013,6 +1063,12 @@ ServiceController::Impl::getPolicyVersion() const return policy_version; } +const string & +ServiceController::Impl::getPolicyVersions() const +{ + return policy_versions; +} + const string & ServiceController::Impl::getUpdatePolicyVersion() const { diff --git a/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc b/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc index 68530f9..883a999 100755 --- a/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc +++ b/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc @@ -251,6 +251,7 @@ TEST_F(ServiceControllerTest, UpdateConfiguration) setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); + EXPECT_EQ(i_service_controller->getPolicyVersions(), ""); EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension)) .WillOnce(Return(true)); @@ -288,8 +289,123 @@ TEST_F(ServiceControllerTest, UpdateConfiguration) ) ).WillRepeatedly(Return(string("registered and running"))); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path)); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); + EXPECT_EQ(i_service_controller->getPolicyVersions(), ""); + EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); +} + +TEST_F(ServiceControllerTest, supportVersions) +{ + string versions = "[" + " {" + " \"id\" : \"40c4a460-eb24-f002-decb-f4a7f00423fc\"," + " \"name\" : \"Linux Embedded Agents\"," + " \"version\" : 1" + " }," + " {" + " \"id\" : \"93788960-6969-11ee-be56-0242ac120002\"," + " \"name\" : \"Linux SUPER Embedded Agents\"," + " \"version\" : 420" + " }" + "]"; + + string new_configuration = "{" + " \"version\": \"" + version_value + "\"" + " \"versions\": " + versions + + " \"l4_firewall\":" + " {" + " \"app\": \"netfilter\"," + " \"l4_firewall_rules\": [" + " {" + " \"name\": \"allow_statefull_conns\"," + " \"flags\": [\"established\"]," + " \"action\": \"accept\"" + " }," + " {" + " \"name\": \"icmp drop\"," + " \"flags\": [\"log\"]," + " \"services\": [{\"name\":\"icmp\"}]," + " \"action\": \"drop\"" + " }" + " ]" + " }" + "}"; + + string l4_firewall = "{" + " \"app\": \"netfilter\"," + " \"l4_firewall_rules\": [" + " {" + " \"name\": \"allow_statefull_conns\"," + " \"flags\": [\"established\"]," + " \"action\": \"accept\"" + " }," + " {" + " \"name\": \"icmp drop\"," + " \"flags\": [\"log\"]," + " \"services\": [{\"name\":\"icmp\"}]," + " \"action\": \"drop\"" + " }" + " ]" + "}"; + + string policy_versions_path = "/etc/cp/conf/versions/versions.policy"; + Maybe> json_parser_return = + map({{"l4_firewall", l4_firewall}, {"version", version_value}, {"versions", versions}}); + EXPECT_CALL(mock_orchestration_tools, readFile(file_name)).WillOnce(Return(new_configuration)); + EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _)) + .WillOnce(Return(json_parser_return)); + EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_versions_path)).WillOnce(Return(false)); + EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(false)); + EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, writeFile(versions, policy_versions_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_status, + setServiceConfiguration("versions", policy_versions_path, OrchestrationStatusConfigType::POLICY)); + EXPECT_CALL(mock_orchestration_status, + setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY)); + + EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); + EXPECT_EQ(i_service_controller->getPolicyVersions(), ""); + + EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true)); + EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true)); + + string general_settings_path = "/my/settings/path"; + string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}"; + + Flags conn_flags; + conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN); + EXPECT_CALL( + mock_message, + sendMessage( + true, + "{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}", + I_Messaging::Method::POST, + string("127.0.0.1"), + l4_firewall_service_port, + conn_flags, + string("/set-new-configuration"), + string(), + _, + MessageTypeTag::GENERIC + ) + ).WillOnce(Return(Maybe(reply_msg))); + + EXPECT_CALL( + mock_shell_cmd, + getExecOutput( + "/etc/cp/watchdog/cp-nano-watchdog --status --verbose --service mock access control" + " --family family1 --id id2", + _, + _ + ) + ).WillRepeatedly(Return(string("registered and running"))); + + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); + EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); + EXPECT_EQ(i_service_controller->getPolicyVersions(), versions); EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); } @@ -393,7 +509,7 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration) ) ).WillOnce(Return(Maybe(reply_msg))); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path)); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); } @@ -501,7 +617,7 @@ TEST_F(ServiceControllerTest, writeRegisteredServicesFromFile) ) ).WillRepeatedly(Return(string("registered and running"))); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path)); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); EXPECT_EQ(orchestrationRegisteredServicesFileToString(registered_services_file_path), expected_json); @@ -641,7 +757,7 @@ TEST_F(ServiceControllerTest, noPolicyUpdate) ) ).WillRepeatedly(Return(string("registered and running"))); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); } @@ -734,7 +850,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations) ).WillOnce(Return(Maybe(reply_msg1))); // both policy and settings now being updated - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path)); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); @@ -771,7 +887,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations) ) ).WillRepeatedly(Return(Maybe(reply_msg2))); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path)); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); } @@ -884,7 +1000,7 @@ TEST_F(ServiceControllerTest, backup) ).WillOnce(Return(Maybe(reply_msg))); EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); } @@ -999,7 +1115,7 @@ TEST_F(ServiceControllerTest, backup_file_doesnt_exist) ).WillOnce(Return(Maybe(reply_msg))); EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); } @@ -1117,7 +1233,7 @@ TEST_F(ServiceControllerTest, backupAttempts) EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true)); EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); } @@ -1231,7 +1347,7 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration) ) ).WillOnce(Return(Maybe(reply_msg))); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); set changed_policies = { "/etc/cp/conf/l4_firewall/l4_firewall.policy", "/etc/cp/conf/orchestration/orchestration.policy" @@ -1249,7 +1365,7 @@ TEST_F(ServiceControllerTest, badJsonFile) { Maybe err = genError("Error"); EXPECT_CALL(mock_orchestration_tools, readFile(file_name)).Times(1).WillRepeatedly(Return(err)); - EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); } TEST_F(ServiceControllerTest, emptyServices) @@ -1266,7 +1382,7 @@ TEST_F(ServiceControllerTest, emptyServices) EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true)); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); } TEST_F(ServiceControllerTest, failingWhileLoadingCurrentConfiguration) @@ -1317,7 +1433,7 @@ TEST_F(ServiceControllerTest, failingWhileLoadingCurrentConfiguration) .WillOnce(Return(json_parser_return)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, readFile(l4_firewall_policy_path)).WillOnce(Return(err)); - EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); } TEST_F(ServiceControllerTest, failingWhileCopyingCurrentConfiguration) @@ -1392,7 +1508,7 @@ TEST_F(ServiceControllerTest, failingWhileCopyingCurrentConfiguration) ).WillOnce(Return(false)); EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); - EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), ""); } @@ -1468,7 +1584,7 @@ TEST_F(ServiceControllerTest, ErrorUpdateConfigurationRest) EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true)); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); EXPECT_THAT( capture_debug.str(), HasSubstr("Service mock access control is inactive") @@ -1554,7 +1670,7 @@ TEST_F(ServiceControllerTest, errorWhileWrtingNewConfiguration) writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(false) ); - EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "")); + EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, "").ok()); } TEST_F(ServiceControllerTest, testPortsRest) @@ -1690,7 +1806,13 @@ TEST_F(ServiceControllerTest, testMultitenantConfFiles) ).WillRepeatedly(Return(string("registered and running"))); EXPECT_TRUE( - i_service_controller->updateServiceConfiguration(conf_file_name, settings_file_name, {}, tenant, profile) + i_service_controller->updateServiceConfiguration( + conf_file_name, + settings_file_name, + {}, + tenant, + profile + ).ok() ); } } @@ -1821,7 +1943,7 @@ TEST_F(ServiceControllerTest, test_delayed_reconf) EXPECT_CALL(mock_ml, yield(chrono::microseconds(2000000))).WillOnce(Invoke(func)); - EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path)); + EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok()); EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); } diff --git a/components/security_apps/orchestration/update_communication/fog_authenticator.cc b/components/security_apps/orchestration/update_communication/fog_authenticator.cc index aea0be6..8522e1d 100755 --- a/components/security_apps/orchestration/update_communication/fog_authenticator.cc +++ b/components/security_apps/orchestration/update_communication/fog_authenticator.cc @@ -177,6 +177,16 @@ FogAuthenticator::registerAgent( request << details; } + auto i_agent_details = Singleton::Consume::by(); + if ( + i_agent_details->getOrchestrationMode() == OrchestrationMode::HYBRID || + getSettingWithDefault("management", "profileManagedMode") == "declarative" + ) { + request << make_pair("managedMode", "declarative"); + } else { + request << make_pair("managedMode", "management"); + } + if (details_resolver->isReverseProxy()) { request << make_pair("reverse_proxy", "true"); } @@ -202,7 +212,6 @@ FogAuthenticator::registerAgent( auto fog_messaging = Singleton::Consume::by(); if (fog_messaging->sendObject(request, HTTPMethod::POST, fog_address_ex + "/agents")) { dbgDebug(D_ORCHESTRATOR) << "Agent has registered successfully."; - auto i_agent_details = Singleton::Consume::by(); i_agent_details->setAgentId(request.getAgentId()); i_agent_details->setProfileId(request.getProfileId()); i_agent_details->setTenantId(request.getTenantId()); @@ -252,7 +261,7 @@ FogAuthenticator::getAccessToken(const UserCredentials &user_credentials) const } dbgInfo(D_ORCHESTRATOR) << "New access token was saved"; - fog_messaging->loadAccessToken(); + Singleton::Consume::by()->loadAccessToken(); return AccessToken(request.getAccessToken(), chrono::seconds(request.getExpirationTime())); } diff --git a/components/security_apps/orchestration/update_communication/fog_communication.cc b/components/security_apps/orchestration/update_communication/fog_communication.cc index f9d2366..21bac79 100755 --- a/components/security_apps/orchestration/update_communication/fog_communication.cc +++ b/components/security_apps/orchestration/update_communication/fog_communication.cc @@ -117,13 +117,20 @@ FogCommunication::downloadAttributeFile(const GetResourceFile &resourse_file) } Maybe -FogCommunication::sendPolicyVersion(const string &policy_version) const +FogCommunication::sendPolicyVersion(const string &policy_version, const string &policy_versions) const { - PolicyVersionPatchRequest request(policy_version); + PolicyVersionPatchRequest request(policy_version, policy_versions); auto fog_messaging = Singleton::Consume::by(); + dbgTrace(D_ORCHESTRATOR) + << "Sending patch request to the fog. Policy version: " + << policy_version + << " , Policy versions: " + << policy_versions; if (fog_messaging->sendNoReplyObject(request, HTTPMethod::PATCH, fog_address_ex + "/agents")) { - dbgInfo(D_ORCHESTRATOR) + dbgTrace(D_ORCHESTRATOR) << "Patch request was sent successfully to the fog." + << " Policy versions: " + << policy_versions << " Policy version: " << policy_version; return Maybe(); diff --git a/components/security_apps/orchestration/update_communication/hybrid_communication.cc b/components/security_apps/orchestration/update_communication/hybrid_communication.cc index 997d806..966f913 100755 --- a/components/security_apps/orchestration/update_communication/hybrid_communication.cc +++ b/components/security_apps/orchestration/update_communication/hybrid_communication.cc @@ -157,7 +157,7 @@ HybridCommunication::downloadAttributeFile(const GetResourceFile &resourse_file) } Maybe -HybridCommunication::sendPolicyVersion(const string &policy_version) const +HybridCommunication::sendPolicyVersion(const string &policy_version, const string &) const { dbgFlow(D_ORCHESTRATOR); policy_version.empty(); diff --git a/components/security_apps/orchestration/update_communication/local_communication.cc b/components/security_apps/orchestration/update_communication/local_communication.cc index 77cab09..ba5743c 100755 --- a/components/security_apps/orchestration/update_communication/local_communication.cc +++ b/components/security_apps/orchestration/update_communication/local_communication.cc @@ -175,7 +175,7 @@ LocalCommunication::setAddressExtenesion(const string &) } Maybe -LocalCommunication::sendPolicyVersion(const string &) const +LocalCommunication::sendPolicyVersion(const string &, const string &) const { dbgTrace(D_ORCHESTRATOR) << "Agent in offline mode, no need to send policy version"; return Maybe(); diff --git a/components/security_apps/orchestration/update_communication/update_communication.cc b/components/security_apps/orchestration/update_communication/update_communication.cc index 348d966..3ecfd26 100755 --- a/components/security_apps/orchestration/update_communication/update_communication.cc +++ b/components/security_apps/orchestration/update_communication/update_communication.cc @@ -75,9 +75,9 @@ public: } Maybe - sendPolicyVersion(const string &policy_version) const override + sendPolicyVersion(const string &policy_version, const string &policy_versions) const override { - return i_update_comm_impl->sendPolicyVersion(policy_version); + return i_update_comm_impl->sendPolicyVersion(policy_version, policy_versions); } Maybe diff --git a/components/security_apps/orchestration/update_communication/update_communication_ut/local_communication_ut.cc b/components/security_apps/orchestration/update_communication/update_communication_ut/local_communication_ut.cc index 22440be..aec9925 100755 --- a/components/security_apps/orchestration/update_communication/update_communication_ut/local_communication_ut.cc +++ b/components/security_apps/orchestration/update_communication/update_communication_ut/local_communication_ut.cc @@ -39,9 +39,9 @@ public: } Maybe - sendPolicyVersion(const string &version) + sendPolicyVersion(const string &version, const string &policy_versions) { - return local_communication.sendPolicyVersion(version); + return local_communication.sendPolicyVersion(version, policy_versions); } Maybe @@ -228,6 +228,6 @@ TEST_F(LocalCommunicationTest, setAddressExtenesion) TEST_F(LocalCommunicationTest, sendPolicyVersion) { - auto res = sendPolicyVersion("12"); + auto res = sendPolicyVersion("12", ""); EXPECT_TRUE(res.ok()); } diff --git a/components/security_apps/waap/waap_clib/CMakeLists.txt b/components/security_apps/waap/waap_clib/CMakeLists.txt index ae1196f..93d7132 100755 --- a/components/security_apps/waap/waap_clib/CMakeLists.txt +++ b/components/security_apps/waap/waap_clib/CMakeLists.txt @@ -83,6 +83,7 @@ add_library(waap_clib LogGenWrapper.cc WaapSampleValue.cc ParserGql.cc + ParserPercentEncode.cc ) add_definitions("-Wno-unused-function") diff --git a/components/security_apps/waap/waap_clib/DeepParser.cc b/components/security_apps/waap/waap_clib/DeepParser.cc index 36fb493..cba668c 100755 --- a/components/security_apps/waap/waap_clib/DeepParser.cc +++ b/components/security_apps/waap/waap_clib/DeepParser.cc @@ -23,6 +23,7 @@ #include "ParserHTML.h" #include "ParserBinary.h" #include "ParserMultipartForm.h" +#include "ParserPercentEncode.h" #include "ParserDelimiter.h" #include "WaapAssetState.h" #include "Waf2Regex.h" @@ -232,16 +233,16 @@ 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 decoded_val, key; + std::string decoded_val, decoded_key; base64_variants base64_status = Waap::Util::b64Test (cur_val, - key, + decoded_key, decoded_val); dbgTrace(D_WAAP_DEEP_PARSER) << " status = " << base64_status << " key = " - << key + << decoded_key << " value = " << decoded_val; @@ -255,7 +256,7 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i if (decoded_val.size() > 0) { cur_val = decoded_val; base64ParamFound = true; - rc = onKv(key.c_str(), key.size(), cur_val.data(), cur_val.size(), flags); + rc = onKv(decoded_key.c_str(), decoded_key.size(), cur_val.data(), cur_val.size(), flags); dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc; if (rc != CONTINUE_PARSING) { return rc; @@ -284,11 +285,6 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i // Calculate various statistics over currently processed value ValueStatsAnalyzer valueStats(cur_val_html_escaped); - if (valueStats.isUrlEncoded && !Waap::Util::testUrlBareUtf8Evasion(cur_val) && - !Waap::Util::testUrlBadUtf8Evasion(cur_val)) { - Waap::Util::decodePercentEncoding(cur_val); - } - if (valueStats.canSplitPipe || valueStats.canSplitSemicolon) { std::string key = IndicatorsFiltersManager::generateKey(m_key.first(), m_key.str(), m_pTransaction); @@ -373,14 +369,14 @@ 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)) { + if (Waap::Util::detectJSONasParameter(cur_val, decoded_key, decoded_val)) { dbgTrace(D_WAAP_DEEP_PARSER) << " detectJSONasParameter was true: key = " - << key + << decoded_key << " value = " << decoded_val; - rc = onKv(key.c_str(), key.size(), decoded_val.data(), decoded_val.size(), flags); + rc = onKv(decoded_key.c_str(), decoded_key.size(), decoded_val.data(), decoded_val.size(), flags); dbgTrace(D_WAAP_DEEP_PARSER) << " After processing potential JSON rc = " << rc; if (rc != CONTINUE_PARSING) { @@ -746,6 +742,13 @@ void DeepParser::createInternalParser(const char *k, size_t k_len, std::string& bool isUrlParamPayload, int flags) { + dbgTrace(D_WAAP_DEEP_PARSER) + << "Starting create parsers for value: >>>" + << cur_val + << "<<<"; + dbgTrace(D_WAAP_DEEP_PARSER) + << "Stats:\n " + << valueStats.textual; bool isPipesType = false, isSemicolonType = false, isAsteriskType = false, isCommaType = false, isAmperType = false; bool isKeyValDelimited = false; @@ -887,27 +890,36 @@ void DeepParser::createInternalParser(const char *k, size_t k_len, std::string& // Note that this function must not add more than one parser // because only the topmost parser will run on the value. // Normally, DeepParser will take care of recursively run other parsers. - if (isHtmlType && + if (valueStats.isUrlEncoded && + !Waap::Util::testUrlBareUtf8Evasion(cur_val)) { + if (!valueStats.hasSpace && + valueStats.hasCharAmpersand && + valueStats.hasTwoCharsEqual && + !isBinaryData()) { + dbgTrace(D_WAAP_DEEP_PARSER) << " Starting to parse an Url-encoded data"; + m_parsersDeque.push_front(std::make_shared>(*this)); + } else if (!Waap::Util::testUrlBadUtf8Evasion(cur_val)) { + dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse an percent decoding"; + m_parsersDeque.push_front(std::make_shared>(*this)); + } + } else if (isHtmlType && !isRefererPayload && - !isUrlPayload) - { + !isUrlPayload) { // HTML detected dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse an HTML file"; m_parsersDeque.push_front(std::make_shared>(*this)); - } - else if (cur_val.size() > 0 && signatures->php_serialize_identifier.hasMatch(cur_val)) - { + } else if (cur_val.size() > 0 && + signatures->php_serialize_identifier.hasMatch(cur_val)) { // PHP value detected dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse phpSerializedData"; m_parsersDeque.push_front(std::make_shared>(*this)); - } - else if (isPotentialGqlQuery && cur_val.size() > 0 && !validateJson(cur_val.data(), cur_val.size())) { + } 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>(*this)); - } - else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{')) - { + } else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{')) { boost::smatch confulence_match; if (NGEN::Regex::regexMatch(__FILE__, __LINE__, cur_val, confulence_match, signatures->confluence_macro_re)) diff --git a/components/security_apps/waap/waap_clib/DeepParser.h b/components/security_apps/waap/waap_clib/DeepParser.h index e5eaae4..ff80d6a 100755 --- a/components/security_apps/waap/waap_clib/DeepParser.h +++ b/components/security_apps/waap/waap_clib/DeepParser.h @@ -34,6 +34,7 @@ public: virtual int onKv(const char *k, size_t k_len, const char *v, size_t v_len, int flags); void clear(); + void showStats(std::string& buff, const ValueStatsAnalyzer& valueStats); void apiProcessKey(const char *v, size_t v_len); size_t depth() const; void setGlobalMaxObjectDepth(size_t depth) { m_globalMaxObjectDepth = depth; } diff --git a/components/security_apps/waap/waap_clib/ParserPercentEncode.cc b/components/security_apps/waap/waap_clib/ParserPercentEncode.cc new file mode 100644 index 0000000..1f733c2 --- /dev/null +++ b/components/security_apps/waap/waap_clib/ParserPercentEncode.cc @@ -0,0 +1,326 @@ +// 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 "ParserPercentEncode.h" +#include "Waf2Util.h" +#include "debug.h" + +USE_DEBUG_FLAG(D_WAAP_PARSER_PERCENT); + +const std::string ParserPercentEncode::m_parserName = "ParserPercentEncode"; + +ParserPercentEncode::ParserPercentEncode(IParserStreamReceiver &receiver) : + m_receiver(receiver), + m_state(s_start), + m_escapedLen(0), + m_escapedCharCandidate(0) +{ + memset(m_escaped, 0, sizeof(m_escaped)); +} + +ParserPercentEncode::~ParserPercentEncode() +{} + +size_t +ParserPercentEncode::push(const char *buf, size_t len) +{ + size_t i = 0; + size_t pointer_in_buffer = 0; + char c; + int is_last = 0; + + dbgTrace(D_WAAP_PARSER_PERCENT) << "ParserPercentEncode::push(): starting (len=" << len << ")"; + + if (len == 0) { + dbgTrace(D_WAAP_PARSER_PERCENT) << "ParserPercentEncode::push(): end of data signal! m_state=" << m_state; + // flush unescaped data collected (if any) + if (m_escapedLen > 0) + { + if (m_state == s_value_start) + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << m_escaped + << "<<<"; + if (m_receiver.onValue(m_escaped, m_escapedLen) != 0) { + m_state = s_error; + return i; + } + } + m_escapedLen = 0; + } + + if (m_receiver.onKvDone() != 0) + { + m_state = s_error; + return i; + } + + return 0; + } + + while (i < len) + { + c = buf[i]; + is_last = (i == (len - 1)); + + // Checking valid char urlencode + if (c < VALID_URL_CODE_START) + { + dbgDebug(D_WAAP_PARSER_PERCENT) + << "invalid URL encoding character: " + << c; + m_state = s_error; + return i; + } + + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): state=" + << m_state + << "; ch='" + << c + << "'"; + + switch (m_state) + { + case s_start: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): s_start"; + + // fallthrough // + CP_FALL_THROUGH; + } + case s_value_start: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): s_value_start"; + pointer_in_buffer = i; + m_state = s_value; + + // fallthrough // + CP_FALL_THROUGH; + } + case s_value: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): s_value"; + if (c == '%') + { + if (i - pointer_in_buffer > 0) + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << (buf + pointer_in_buffer) + << "<<<"; + if (m_receiver.onValue(buf + pointer_in_buffer, i - pointer_in_buffer) != 0) + { + m_state = s_error; + return i; + } + } + m_state = s_value_escaped1; + break; + } + else + { + // flush unescaped data collected (if any) + if (m_escapedLen > 0) + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << m_escaped + << "<<<"; + if (m_receiver.onValue(m_escaped, m_escapedLen) != 0) + { + m_state = s_error; + return i; + } + m_escapedLen = 0; + pointer_in_buffer = i; + } + } + if (is_last) + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << (buf + pointer_in_buffer) + << "<<<"; + if (m_receiver.onValue(buf + pointer_in_buffer, (i - pointer_in_buffer) + 1) != 0) + { + m_state = s_error; + return i; + } + } + break; + } + case s_value_escaped1: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): s_value_escaped1"; + bool valid; + unsigned char v = from_hex(c, valid); + // character right after the '%' is not a valid hex char. + if (!valid) + { + // dump escaped chars + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << m_escaped + << "<<<"; + if (m_escapedLen > 0 + && m_receiver.onValue(m_escaped, m_escapedLen) != 0) + { + m_state = s_error; + return i; + } + m_escapedLen = 0; + // return the '%' character back to the output. + dbgTrace(D_WAAP_PARSER_PERCENT) << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << "%" + << "<<<"; + if (m_receiver.onValue("%", 1) != 0) + { + return i; + } + + // If the character is '%' - stay in the same state (correctly treat '%%%%hhh' sequences) + if (c != '%') + { + // pass the non-hex character back to the output too. + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << c + << "<<<"; + if (m_receiver.onValue(&c, 1) != 0) + { + return i; + } + + // otherwise (the character is not '%'), switch back to the s_value state + m_state = s_value_start; + } + break; + } + m_escapedCharCandidate = c; + m_escaped[m_escapedLen] = v << 4; + m_state = s_value_escaped2; + break; + } + case s_value_escaped2: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): s_value_escaped2"; + bool valid; + unsigned char v = from_hex(c, valid); + if (!valid) + { + // This situation (2nd character is not valid hex) is not treated right now. + // In this case, v will be equal to 0 and output character will be invalid one. + + // dump escaped chars + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << m_escaped + << "<<<"; + if (m_escapedLen > 0 + && m_receiver.onValue(m_escaped, m_escapedLen) != 0) + { + m_state = s_error; + return i; + } + m_escapedLen = 0; + + // return the '%' character back to the output. + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << "%" + << "<<<"; + if (m_receiver.onValue("%", 1) != 0) + { + return i; + } + // add the character that was thought to be escaped value + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << m_escapedCharCandidate + << "<<<"; + if (m_receiver.onValue(&m_escapedCharCandidate, 1)) + { + return i; + } + + // re parse the character as a key (i is incremented back to current value) + i--; + m_state = s_value_start; + break; + } + m_escapedCharCandidate = 0; + m_escaped[m_escapedLen] |= v; + m_escapedLen++; + if (m_escapedLen >= MAX_PERCENT_ENCODED_SIZE) + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): call onValue with m_escaped = >>>" + << m_escaped + << "<<<"; + if (m_receiver.onValue(m_escaped, m_escapedLen) != 0) + { + m_state = s_error; + return i; + } + m_escapedLen = 0; + } + m_state = s_value_start; + break; + } + case s_error: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): s_error"; + return 0; + } + default: + { + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): URL parser unrecoverable error"; + m_state = s_error; + return 0; + } + } + ++i; + } + + dbgTrace(D_WAAP_PARSER_PERCENT) + << "ParserPercentEncode::push(): finished: len=" + << len; + return len; +} + +void +ParserPercentEncode::finish() +{ + push(NULL, 0); +} + +const std::string & +ParserPercentEncode::name() const +{ + return m_parserName; +} + +bool +ParserPercentEncode::error() const +{ + return m_state == s_error; +} diff --git a/components/security_apps/waap/waap_clib/ParserPercentEncode.h b/components/security_apps/waap/waap_clib/ParserPercentEncode.h new file mode 100644 index 0000000..67c5218 --- /dev/null +++ b/components/security_apps/waap/waap_clib/ParserPercentEncode.h @@ -0,0 +1,58 @@ +// 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_PERCENT_ENCODE_H_ +#define __PARSER_PERCENT_ENCODE_H_ + +#include "ParserBase.h" +#include + +#define MAX_PERCENT_ENCODED_SIZE 255 +#define VALID_URL_CODE_START 32 + +class ParserPercentEncode : public ParserBase { +public: + ParserPercentEncode(IParserStreamReceiver &receiver); + virtual ~ParserPercentEncode(); + 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 1; + } + +private: + enum state + { + s_start, + s_value_start, + s_value, + s_value_escaped1, + s_value_escaped2, + s_end, + s_error + }; + + IParserStreamReceiver &m_receiver; + enum state m_state; + unsigned char m_escapedLen; + char m_escaped[MAX_PERCENT_ENCODED_SIZE]; + char m_escapedCharCandidate; + static const std::string m_parserName; +}; + +#endif diff --git a/components/security_apps/waap/waap_clib/ScoreBuilder.cc b/components/security_apps/waap/waap_clib/ScoreBuilder.cc index 662322d..a2859be 100755 --- a/components/security_apps/waap/waap_clib/ScoreBuilder.cc +++ b/components/security_apps/waap/waap_clib/ScoreBuilder.cc @@ -348,12 +348,12 @@ void ScoreBuilder::calcScore(const std::string &poolName) void ScoreBuilder::snap() { // Copy data from all mutable score pools to "snapshot" keyword->scores map - for (const std::pair &pool : m_keywordsScorePools) { + for (const auto &pool : m_keywordsScorePools) { const std::string &poolName = pool.first; const KeywordsScorePool& keywordScorePool = pool.second; m_snapshotKwScoreMap[poolName]; - for (const std::pair &kwData : keywordScorePool.m_keywordsDataMap) + for (const auto &kwData : keywordScorePool.m_keywordsDataMap) { const std::string &kwName = kwData.first; double kwScore = kwData.second.score; @@ -408,7 +408,7 @@ unsigned int ScoreBuilder::getFpStoreCount() void ScoreBuilder::mergeScores(const ScoreBuilder& baseScores) { - for (const std::pair &pool : baseScores.m_keywordsScorePools) { + for (const auto &pool : baseScores.m_keywordsScorePools) { const std::string &poolName = pool.first; if (m_keywordsScorePools.find(poolName) == m_keywordsScorePools.end()) { m_keywordsScorePools[poolName]; diff --git a/components/security_apps/waap/waap_clib/WaapConfigBase.cc b/components/security_apps/waap/waap_clib/WaapConfigBase.cc index 74f29e3..9d42f6a 100755 --- a/components/security_apps/waap/waap_clib/WaapConfigBase.cc +++ b/components/security_apps/waap/waap_clib/WaapConfigBase.cc @@ -78,6 +78,15 @@ void WaapConfigBase::readJSONByCereal(cereal::JSONInputArchive& ar) cereal::make_nvp("ruleName", m_ruleName) ); + try { + std::string application_urls; + ar(cereal::make_nvp("applicationUrls", application_urls)); + m_applicationUrls = split(application_urls, ';'); + } catch (std::runtime_error& e) { + dbgWarning(D_WAAP) << "Error to load applicationUrls field in policy" << e.what(); + ar.setNextName(nullptr); + } + m_blockingLevel = blockingLevelBySensitivityStr(m_autonomousSecurityLevel); } diff --git a/components/security_apps/waap/waap_clib/WaapConfigBase.h b/components/security_apps/waap/waap_clib/WaapConfigBase.h index 3a15bc5..2cae5f2 100755 --- a/components/security_apps/waap/waap_clib/WaapConfigBase.h +++ b/components/security_apps/waap/waap_clib/WaapConfigBase.h @@ -95,6 +95,7 @@ private: std::shared_ptr m_trustedSourcesPolicy; std::shared_ptr m_waapParameters; std::shared_ptr m_openRedirectPolicy; + std::vector m_applicationUrls; std::shared_ptr m_errorDisclosurePolicy; std::string m_schemaValidationPoicyStatusMessage; std::shared_ptr m_csrfPolicy; diff --git a/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.cc b/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.cc index 5f3a82a..25781fe 100755 --- a/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.cc +++ b/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.cc @@ -233,4 +233,30 @@ ValueStatsAnalyzer::ValueStatsAnalyzer(const std::string &cur_val) } // Detect URLEncode value isUrlEncoded = checkUrlEncoded(cur_val.data(), cur_val.size()); + + textual.clear(); + textual.append("hasCharSlash = "); + textual +=(hasCharSlash ? "true" : "false"); + textual.append("\nhasCharColon = "); + textual +=(hasCharColon ? "true" : "false"); + textual.append("\nhasCharAmpersand = "); + textual +=(hasCharAmpersand ? "true" : "false"); + textual.append("\nhasCharEqual = "); + textual +=(hasCharEqual ? "true" : "false"); + textual.append("\nhasTwoCharsEqual = "); + textual +=(hasTwoCharsEqual ? "true" : "false"); + textual.append("\nhasCharSemicolon = "); + textual +=(hasCharSemicolon ? "true" : "false"); + textual.append("\nhasCharPipe = "); + textual +=(hasCharPipe ? "true" : "false"); + textual.append("\nisUTF16 = "); + textual +=(isUTF16 ? "true" : "false"); + textual.append("\ncanSplitSemicolon = "); + textual +=(canSplitSemicolon ? "true" : "false"); + textual.append("\ncanSplitPipe = "); + textual +=(canSplitPipe ? "true" : "false"); + textual.append("\nhasSpace = "); + textual +=(hasSpace ? "true" : "false"); + textual.append("\nisUrlEncoded = "); + textual +=(isUrlEncoded ? "true" : "false"); } diff --git a/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.h b/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.h index fcd2e30..f2dab93 100755 --- a/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.h +++ b/components/security_apps/waap/waap_clib/WaapValueStatsAnalyzer.h @@ -34,6 +34,7 @@ struct ValueStatsAnalyzer bool canSplitPipe; bool hasSpace; bool isUrlEncoded; + std::string textual; }; diff --git a/components/security_apps/waap/waap_clib/Waf2Engine.cc b/components/security_apps/waap/waap_clib/Waf2Engine.cc index 9196af0..99396f1 100755 --- a/components/security_apps/waap/waap_clib/Waf2Engine.cc +++ b/components/security_apps/waap/waap_clib/Waf2Engine.cc @@ -2277,7 +2277,7 @@ void Waf2Transaction::collectFoundPatterns() { if (m_scanResult) { - for (const std::pair> &found_pattern : m_scanResult->found_patterns) + for (const auto &found_pattern : m_scanResult->found_patterns) { const std::string ®ex_name = found_pattern.first; // the regex name (key) m_found_patterns.insert(regex_name); diff --git a/components/security_apps/waap/waap_clib/Waf2Util.h b/components/security_apps/waap/waap_clib/Waf2Util.h index 089d37d..aade3ac 100755 --- a/components/security_apps/waap/waap_clib/Waf2Util.h +++ b/components/security_apps/waap/waap_clib/Waf2Util.h @@ -1044,14 +1044,14 @@ namespace Util { // trim from start static inline std::string <rim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), - std::not1(std::ptr_fun(std::isspace)))); + [] (char c) { return !std::isspace(c); })); return s; } // trim from end static inline std::string &rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), - std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + [] (char c) { return !std::isspace(c); }).base(), s.end()); return s; } diff --git a/core/agent_details/agent_details.cc b/core/agent_details/agent_details.cc index 7530144..0659797 100755 --- a/core/agent_details/agent_details.cc +++ b/core/agent_details/agent_details.cc @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "config.h" #include "debug.h" @@ -36,6 +38,46 @@ void AgentDetails::init() { registerMachineType(); + loadAccessToken(); + Singleton::Consume::by()->addRecurringRoutine( + I_MainLoop::RoutineType::System, + chrono::seconds(60), + [this] () { loadAccessToken(); }, + "Load access token" + ); + proxies = { + {ProxyProtocol::HTTP, ProxyData()}, + {ProxyProtocol::HTTPS, ProxyData()} + }; + + auto proxy_config = getProfileAgentSetting("agent.config.message.proxy"); + if (proxy_config.ok()) { + setProxy(*proxy_config); + writeAgentDetails(); + } + + registerConfigLoadCb( + [&]() + { + auto proxy_config = getProfileAgentSetting("agent.config.message.proxy"); + if (proxy_config.ok()) { + is_proxy_configured_via_settings = true; + setProxy(*proxy_config); + writeAgentDetails(); + } else if (is_proxy_configured_via_settings) { + is_proxy_configured_via_settings = false; + setProxy(string("")); + writeAgentDetails(); + } + } + ); + + auto load_env_proxy = loadProxy(); + if (!load_env_proxy.ok()) { + dbgDebug(D_ORCHESTRATOR) + << "Could not initialize load proxy from environment, Error: " + << load_env_proxy.getErr(); + } } bool @@ -260,6 +302,36 @@ AgentDetails::getOrchestrationMode() const return orchestration_mode; } +string +AgentDetails::getAccessToken() const +{ + return access_token; +} + +void +AgentDetails::loadAccessToken() +{ + readAgentDetails(); + auto data_path = getConfigurationWithDefault( + getFilesystemPathConfig() + "/data/", + "encryptor", + "Data files directory" + ); + ifstream token_file(data_path + session_token_file_name); + if (!token_file.is_open()) { + dbgWarning(D_ORCHESTRATOR) << "Failed to open session token file: " << data_path + session_token_file_name; + return; + } + stringstream token_steam; + token_steam << token_file.rdbuf(); + + auto new_token = token_steam.str(); + if (access_token != new_token) { + access_token = new_token; + dbgTrace(D_ORCHESTRATOR) << "Loaded the new token"; + } +} + Maybe AgentDetails::getMachineTypeFromDmiTable() { @@ -300,3 +372,235 @@ AgentDetails::registerMachineType() ); dbgInfo(D_ORCHESTRATOR) << "Setting machine type " << static_cast(machine_type.unpack()); } + +string +AgentDetails::convertProxyProtocolToString(ProxyProtocol proto) const +{ + switch(proto) { + case ProxyProtocol::HTTP: return "http"; + case ProxyProtocol::HTTPS: return "https"; + } + dbgAssert(false) << "Unsupported Proxy Protocol " << static_cast(proto); + return ""; +} + +Maybe +AgentDetails::verifyProxySyntax( + const string &protocol, + const string &auth, + const string &domain, + const string &port, + const string &env_proxy) +{ + stringstream verify_string; + verify_string + << protocol + << "://" + << (!auth.empty() ? auth + string("@") : "") + << domain + << ":" + << port + << (env_proxy.back() == '/' ? "/" : ""); + + if (env_proxy.compare(verify_string.str()) != 0) { + return genError(string("Provided proxy has the wrong syntax:" ) + env_proxy); + } + return Maybe(); +} + +Maybe +AgentDetails::loadProxyType(const string &proxy_type) +{ + readAgentDetails(); + auto proxy_config = getProxy(); + if (proxy_config.ok()) { + if (proxy_config.unpack() == "none") { + return Maybe(string()); + } + return proxy_config; + } + +#ifdef gaia + I_ShellCmd *shell_cmd = Singleton::Consume::by(); + auto proxy_ip = shell_cmd->getExecOutput("dbget proxy:ip-address| tr -d '\n'"); + if (!proxy_ip.ok()) return proxy_ip; + auto proxy_port = shell_cmd->getExecOutput("dbget proxy:port| tr -d '\n'"); + if (!proxy_port.ok()) return proxy_port; + if (*proxy_port != "" && *proxy_ip != "") return ("http://" + *proxy_ip + ":" + *proxy_port); + + const string umis_file_path(string(getenv("CPDIR")) + "/tmp/umis_objects.C"); + + { + ifstream umis_file(umis_file_path.c_str()); + if (!umis_file.good()) return Maybe(string()); + } + + const string read_umis_cmd = "cat " + umis_file_path + " | grep -w \""; + const string parse_value_command = "\" | awk -F \"[ \\t]+\" '{printf $NF}' | tr -d \"()\""; + + auto use_proxy = shell_cmd->getExecOutput(read_umis_cmd + "use_proxy" + parse_value_command); + if (!use_proxy.ok()) + return genError("Failed to read use_proxy from " + umis_file_path + ": " + use_proxy.getErr()); + + if (use_proxy.unpack() == "true") { + auto umis_proxy_add = shell_cmd->getExecOutput(read_umis_cmd + "proxy_address" + parse_value_command); + if (!umis_proxy_add.ok() || *umis_proxy_add == "") return umis_proxy_add; + auto umis_proxy_port = shell_cmd->getExecOutput(read_umis_cmd + "proxy_port" + parse_value_command); + if (!umis_proxy_port.ok() || *umis_proxy_port == "") return umis_proxy_port; + + return ("http://" + *umis_proxy_add + ":" + *umis_proxy_port); + } else { + dbgTrace(D_ORCHESTRATOR) << "Smart Console Proxy is turned off"; + } + return Maybe(string()); +#else // not gaia + char *proxy = getenv(proxy_type.c_str()); + if (proxy) return string(proxy); + + proxy = getenv(boost::algorithm::to_upper_copy(proxy_type).c_str()); + if (proxy) return string(proxy); + return Maybe(string()); +#endif // gaia +} + +Maybe +AgentDetails::loadProxyType(ProxyProtocol protocol) +{ + dbgAssert(protocol == ProxyProtocol::HTTP || protocol == ProxyProtocol::HTTPS) + << "Unsupported Proxy Protocol " << static_cast(protocol); + + static const map env_var_name = { + {ProxyProtocol::HTTPS, "https_proxy"}, + {ProxyProtocol::HTTP, "http_proxy"} + }; + auto env_proxy = loadProxyType(env_var_name.at(protocol)); + if (!env_proxy.ok()) return genError(env_proxy.getErr()); + if (env_proxy.unpack().empty()) { + return Maybe(); + } + + string protocol_regex = "(http|https)://"; + const static boost::regex no_auth_proxy_regex(protocol_regex + "(.)*:[0-9]{0,5}(/|)"); + const static boost::regex auth_proxy_regex(protocol_regex + "(.)*:(.)*@(.)*:[0-9]{0,5}(/|)"); + + ProxyData env_proxy_data; + env_proxy_data.is_exists = true; + string proxy_copy; + if (!NGEN::Regex::regexMatch(__FILE__, __LINE__, env_proxy.unpack(), boost::regex(protocol_regex + "(.)*"))) { + env_proxy = "http://" + env_proxy.unpack(); + } + proxy_copy.assign(env_proxy.unpack()); + env_proxy_data.protocol = env_proxy.unpack().substr(0, proxy_copy.find(":")); + proxy_copy.erase(0, proxy_copy.find(":") + 3); //remove "http://" or "https://" + + if (NGEN::Regex::regexMatch(__FILE__, __LINE__, env_proxy.unpack(), auth_proxy_regex)) { + env_proxy_data.auth = string(&proxy_copy[0], &proxy_copy[proxy_copy.find("@")]); + proxy_copy.erase(0, proxy_copy.find("@") + 1); // remove "user:pass@" + } else if (!NGEN::Regex::regexMatch(__FILE__, __LINE__, env_proxy.unpack(), no_auth_proxy_regex)) { + return genError(string("Provided proxy has wrong syntax: ") + env_proxy.unpack()); + } + env_proxy_data.domain = proxy_copy.substr(0, proxy_copy.find(":")); + proxy_copy.erase(0, proxy_copy.find(":") + 1); // remove "host:" + env_proxy_data.port = static_cast(stoi(proxy_copy)); + + auto proxy_syntax = verifyProxySyntax( + env_proxy_data.protocol, + env_proxy_data.auth, + env_proxy_data.domain, + to_string(env_proxy_data.port), + env_proxy.unpack() + ); + if (!proxy_syntax.ok()) return proxy_syntax; + if (env_proxy_data == proxies.at(protocol)) { + return Maybe(); + } + + proxies.at(protocol) = env_proxy_data; + dbgInfo(D_ORCHESTRATOR) + << convertProxyProtocolToString(protocol) + << " proxy was successfully loaded, " + << getProxyAddress(protocol).unpack(); + + return Maybe(); +} + +Maybe +AgentDetails::getProxyDomain(ProxyProtocol protocol) const +{ + if (proxies.find(protocol) == proxies.end()) { + return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); + } + if (proxies.at(protocol).domain.empty()) return genError( + convertProxyProtocolToString(protocol) + string(" proxy domain is unset") + ); + return proxies.at(protocol).domain; +} + +Maybe +AgentDetails::getProxyCredentials(ProxyProtocol protocol) const +{ + if (proxies.find(protocol) == proxies.end()) { + return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); + } + if (proxies.at(protocol).auth.empty()) return genError( + convertProxyProtocolToString(protocol) + string(" proxy auth is unset") + ); + return proxies.at(protocol).auth; +} + +Maybe +AgentDetails::getProxyPort(ProxyProtocol protocol) const +{ + if (proxies.find(protocol) == proxies.end()) { + return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); + } + if (proxies.at(protocol).port == 0) return genError( + convertProxyProtocolToString(protocol) + string(" proxy port is unset") + ); + return proxies.at(protocol).port; +} + +bool +AgentDetails::getProxyExists(ProxyProtocol protocol) const +{ + if (proxies.find(protocol) == proxies.end()) { + dbgInfo(D_ORCHESTRATOR) + << "Proxy type is not loaded in map, type: " + << convertProxyProtocolToString(protocol); + return false; + } + return proxies.at(protocol).is_exists; +} + +Maybe +AgentDetails::getProxyAddress(ProxyProtocol protocol) const +{ + if (proxies.find(protocol) == proxies.end()) { + return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); + } + if (proxies.at(protocol).protocol.empty() || + proxies.at(protocol).domain.empty() || + proxies.at(protocol).port == 0) { + return genError( + string("Can't construct ") + + convertProxyProtocolToString(protocol) + + string(" proxy address") + ); + } + return proxies.at(protocol).protocol + + "://" + + proxies.at(protocol).domain + + ":" + + to_string(proxies.at(protocol).port); +} + +Maybe +AgentDetails::loadProxy() +{ + if (getConfigurationFlag("orchestration-mode") == "offline_mode") return Maybe(); + for (const auto &proxy_type : proxies) { + auto loaded_proxy = loadProxyType(proxy_type.first); + if (!loaded_proxy.ok()) return loaded_proxy; + } + return Maybe(); +} diff --git a/core/agent_details/agent_details_ut/agent_details_ut.cc b/core/agent_details/agent_details_ut/agent_details_ut.cc index cc4eac8..47f04ce 100644 --- a/core/agent_details/agent_details_ut/agent_details_ut.cc +++ b/core/agent_details/agent_details_ut/agent_details_ut.cc @@ -1,7 +1,11 @@ #include "agent_details.h" +#include +#include + #include "mock/mock_encryptor.h" #include "mock/mock_shell_cmd.h" +#include "mock/mock_mainloop.h" #include "cptest.h" #include "config.h" #include "config_component.h" @@ -24,133 +28,6 @@ public: StrictMock mock_encryptor; StrictMock mock_shell_cmd; Config::I_Config *config = nullptr; + StrictMock mock_ml; }; -TEST_F(AgentDetailsTest, doNothing) -{ -} - -TEST_F(AgentDetailsTest, basicTest) -{ - const vector agent_details_vec { - "{", - " \"Fog domain\": \"fog.com\",", - " \"Agent ID\": \"fdfdf-5454-dfd\",", - " \"Fog port\": 443,", - " \"Encrypted connection\": false,", - " \"Orchestration mode\": \"offline_mode\",", - " \"Tenant ID\": \"tenant_id\",", - " \"Profile ID\": \"profile\",", - " \"Proxy\": \"http://proxy.checkpoint.com/\",", - " \"OpenSSL certificates directory\": \"\"", - "}" - }; - AgentDetails agent_details; - env.preload(); - agent_details.preload(); - EXPECT_CALL( - mock_shell_cmd, - getExecOutput("dmidecode -s system-manufacturer | tr -d '\\n'", _, _) - ).WillOnce(Return(string("Microsoft Corporation"))); - env.init(); - agent_details.init(); - - auto i_conf = Singleton::Consume::from(conf); - i_conf->reloadConfiguration(); - - CPTestTempfile agent_details_file(agent_details_vec); - setConfiguration(agent_details_file.fname, "Agent details", "File path"); - - EXPECT_TRUE(agent_details.readAgentDetails()); - EXPECT_EQ(agent_details.getFogDomain().unpack(), "fog.com"); - EXPECT_EQ(agent_details.getFogPort().unpack(), 443); - EXPECT_EQ(agent_details.getAgentId(), "fdfdf-5454-dfd"); - EXPECT_FALSE(agent_details.getSSLFlag()); - - agent_details.setSSLFlag(true); - agent_details.setFogPort(80); - agent_details.setFogDomain("fog.checkpoint.com"); - agent_details.setAgentId("dfdfdf-dfd"); - agent_details.setClusterId("d5bd7949-554e-4fac-86c3-6e4e5d46a034"); - EXPECT_EQ(agent_details.getFogDomain().unpack(), "fog.checkpoint.com"); - EXPECT_EQ(agent_details.getFogPort().unpack(), 80); - EXPECT_EQ(agent_details.getAgentId(), "dfdfdf-dfd"); - EXPECT_EQ(agent_details.getTenantId(), "tenant_id"); - EXPECT_EQ(agent_details.getProfileId(), "profile"); - EXPECT_EQ(agent_details.getClusterId(), "d5bd7949-554e-4fac-86c3-6e4e5d46a034"); - - EXPECT_TRUE(agent_details.writeAgentDetails()); - - EXPECT_TRUE(agent_details.readAgentDetails()); - EXPECT_EQ(agent_details.getFogDomain().unpack(), "fog.checkpoint.com"); - EXPECT_EQ(agent_details.getFogPort().unpack(), 80); - EXPECT_EQ(agent_details.getAgentId(), "dfdfdf-dfd"); - EXPECT_EQ(agent_details.getClusterId(), "d5bd7949-554e-4fac-86c3-6e4e5d46a034"); - EXPECT_TRUE(agent_details.getSSLFlag()); - EXPECT_THAT(agent_details.getProxy(), IsValue("http://proxy.checkpoint.com/")); - agent_details.setProxy("none"); - EXPECT_THAT(agent_details.getProxy(), IsValue("none")); - - EXPECT_TRUE(agent_details.getOrchestrationMode() == OrchestrationMode::OFFLINE); - agent_details.setOrchestrationMode(OrchestrationMode::ONLINE); - EXPECT_TRUE(agent_details.getOrchestrationMode() == OrchestrationMode::ONLINE); - auto machine_type = Singleton::Consume::from(env)->get("MachineType"); - EXPECT_EQ(machine_type.unpack(), I_AgentDetails::MachineType::AZURE); -} - -TEST_F(AgentDetailsTest, openSSL) -{ - const vector agent_details_vec { - "{", - " \"Fog domain\": \"fog.com\",", - " \"Agent ID\": \"fdfdf-5454-dfd\",", - " \"Fog port\": 443,", - " \"Encrypted connection\": false,", - " \"Tenant ID\": \"tenant_id\",", - " \"Profile ID\": \"profile\",", - " \"OpenSSL certificates directory\": \"\"", - "}" - }; - - AgentDetails agent_details; - agent_details.preload(); - - CPTestTempfile agent_details_file(agent_details_vec); - setConfiguration(agent_details_file.fname, "Agent details", "File path"); - - EXPECT_FALSE(agent_details.getSSLFlag()); - EXPECT_THAT(agent_details.getOpenSSLDir(), IsError("OpenSSL certificates directory was not set")); - - agent_details.setOpenSSLDir("a/b/c"); - EXPECT_THAT(agent_details.getOpenSSLDir(), IsValue("a/b/c")); - - agent_details.setFogPort(10); - agent_details.setSSLFlag(false); - agent_details.setFogDomain("www.fog.checkpoint.com"); - agent_details.setOpenSSLDir(""); - - EXPECT_THAT(agent_details.getFogPort(), IsValue(10)); - EXPECT_FALSE(agent_details.getSSLFlag()); - EXPECT_THAT(agent_details.getFogDomain(), IsValue("www.fog.checkpoint.com")); - EXPECT_THAT(agent_details.getOpenSSLDir(), IsError("OpenSSL certificates directory was not set")); - - EXPECT_FALSE(agent_details.getOrchestrationMode() == OrchestrationMode::OFFLINE); - agent_details.setOrchestrationMode(OrchestrationMode::OFFLINE); - EXPECT_TRUE(agent_details.getOrchestrationMode() == OrchestrationMode::OFFLINE); -} - -TEST_F(AgentDetailsTest, unrecognizedMachineType) -{ - env.preload(); - env.init(); - AgentDetails agent_details; - EXPECT_CALL( - mock_shell_cmd, - getExecOutput("dmidecode -s system-manufacturer | tr -d '\\n'", _, _) - ).WillOnce(Return(string("Skynet"))); - agent_details.preload(); - agent_details.init(); - - auto machine_type = Singleton::Consume::from(env)->get("MachineType"); - EXPECT_EQ(machine_type.unpack(), I_AgentDetails::MachineType::UNRECOGNIZED); -} diff --git a/core/agent_details_reporter/agent_details_reporter.cc b/core/agent_details_reporter/agent_details_reporter.cc index 886562b..c34ea5b 100644 --- a/core/agent_details_reporter/agent_details_reporter.cc +++ b/core/agent_details_reporter/agent_details_reporter.cc @@ -192,7 +192,7 @@ AgentDetailsReporter::Impl::addAttr(const map &attr, bool allow_ { dbgFlow(D_AGENT_DETAILS); bool ret = true; - for (const pair &single_attr : attr) { + for (const auto &single_attr : attr) { if (!addAttr(single_attr.first, single_attr.second, allow_override)) ret = false; } @@ -219,7 +219,7 @@ AgentDetailsReporter::Impl::sendAttributes() return true; } - for (const pair &new_attr : new_attributes) { + for (const auto &new_attr : new_attributes) { attributes[new_attr.first] = new_attr.second; } @@ -354,7 +354,7 @@ void AgentDetailsReporter::Impl::fini() { if (!new_attributes.empty()) { - for (const pair &new_attr : new_attributes) { + for (const auto &new_attr : new_attributes) { attributes[new_attr.first] = new_attr.second; } } @@ -382,7 +382,7 @@ AgentDetailsReporter::Impl::sendReport( if (agent_version.ok()) additional_metadata.setAgentVersion(*agent_version); if (!new_attributes.empty()) { - for (const pair &new_attr : new_attributes) { + for (const auto &new_attr : new_attributes) { attributes[new_attr.first] = new_attr.second; } AttrSerializer(attributes, "save"); diff --git a/core/config/config.cc b/core/config/config.cc index 64ab463..ce0a843 100644 --- a/core/config/config.cc +++ b/core/config/config.cc @@ -823,7 +823,7 @@ ConfigComponent::Impl::fillMultiTenantExpectedConfigFiles(const map> &tenant_profiles : active_tenants) { + for (const auto &tenant_profiles : active_tenants) { const string &tenant = tenant_profiles.first; const set &profile_ids = tenant_profiles.second; for (const auto &profile_id : profile_ids) { diff --git a/core/connkey/connkey.cc b/core/connkey/connkey.cc index ab4e04c..5a7ce93 100755 --- a/core/connkey/connkey.cc +++ b/core/connkey/connkey.cc @@ -12,6 +12,7 @@ // limitations under the License. #include +#include #include #include @@ -142,6 +143,130 @@ IPAddr::isInRange(const IPAddr &left, const IPAddr &right) const return (*this >= left) && (*this <= right); } +Maybe +IPAddr::calculateSubnetStart(int subnet_value) +{ + if (type == IPType::V4) { + return calculateSubnetStartV4(subnet_value); + } else { + return calculateSubnetStartV6(subnet_value); + } +} + +Maybe +IPAddr::calculateSubnetEnd(int subnet_value) +{ + if (type == IPType::V4) { + return calculateSubnetEndV4(subnet_value); + } else { + return calculateSubnetEndV6(subnet_value); + } +} + +Maybe +IPAddr::calculateSubnetStartV4(int subnet_value) +{ + if (subnet_value < 0 || subnet_value > 32) { + return genError("Invalid subnet value: "); + } + uint32_t ip = ntohl(v4.s_addr); + uint32_t mask = (0xFFFFFFFF << (32 - subnet_value)); + uint32_t subnet = ip & mask; + subnet = ntohl(subnet); + return string(inet_ntoa(*(struct in_addr *)&subnet)); +} + +Maybe +IPAddr::calculateSubnetStartV6(int subnet_value) +{ + if (subnet_value < 0 || subnet_value > 128) { + return genError("Invalid subnet value: "); + } + + // represent IPV6 as a binary + bitset<128> mask; + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 8; ++j) { + mask[i * 8 + j] = (v6.s6_addr[i] >> (7 - j)) & 1; + } + } + + // set the subnet bits to 0 + for (int i = subnet_value; i < 128; i++) { + mask.reset(i); + } + + // convert the binary to IPV6 + for (int i = 0; i < 16; ++i) { + uint8_t byteValue = 0; + for (int j = 0; j < 8; ++j) { + byteValue |= (mask[i * 8 + j] << (7 - j)); + } + v6.s6_addr[i] = byteValue; + } + + // convert to string + ostringstream oss; + for (int i = 0; i < 16; i+=2) { + if (i > 0) + oss << ":"; + oss << hex << ((v6.s6_addr[i] << 8) + v6.s6_addr[i+1]); + } + return oss.str(); +} + +Maybe +IPAddr::calculateSubnetEndV4(int subnet_value) +{ + if (subnet_value < 0 || subnet_value > 32) { + return genError("Invalid subnet value: "); + } + uint32_t ip = ntohl(v4.s_addr); + uint32_t mask = (0xFFFFFFFF << (32 - subnet_value)); + uint32_t subnet = ip & mask; + subnet |= ~mask; + subnet = ntohl(subnet); + return string(inet_ntoa(*(struct in_addr *)&subnet)); +} + +Maybe +IPAddr::calculateSubnetEndV6(int subnet_value) +{ + if (subnet_value < 0 || subnet_value > 128) { + return genError("Invalid subnet value: "); + } + + // represent IPV6 as a binary + bitset<128> mask; + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 8; ++j) { + mask[i * 8 + j] = (v6.s6_addr[i] >> (7 - j)) & 1; + } + } + + // set the host bits to 1 + for (int i = subnet_value; i < 128; i++) { + mask.set(i); + } + + // convert the binary to IPV6 + for (int i = 0; i < 16; ++i) { + uint8_t byteValue = 0; + for (int j = 0; j < 8; ++j) { + byteValue |= (mask[i * 8 + j] << (7 - j)); + } + v6.s6_addr[i] = byteValue; + } + + // convert to string + ostringstream oss; + for (int i = 0; i < 16; i += 2) { + if (i > 0) oss << ":"; + oss << hex << ((v6.s6_addr[i] << 8) + v6.s6_addr[i + 1]); + } + return oss.str(); +} + Maybe IPAddr::createIPAddr(const string &ip_text) { diff --git a/core/debug_is/debug.cc b/core/debug_is/debug.cc index 2f13e72..9fc7a23 100755 --- a/core/debug_is/debug.cc +++ b/core/debug_is/debug.cc @@ -544,7 +544,7 @@ Debug::applyOverrides() } } else { auto should_add_file_stream = true; - for (const pair> &elem : active_streams) { + for (const auto &elem : active_streams) { if (elem.first != "STDOUT" && elem.first != "FOG") should_add_file_stream = false; break; } diff --git a/core/encryptor/encryptor.cc b/core/encryptor/encryptor.cc index 2ee6289..935dd2d 100644 --- a/core/encryptor/encryptor.cc +++ b/core/encryptor/encryptor.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include "cpnano_base64/base64.h" #include "config.h" diff --git a/core/include/general/table/table_impl.h b/core/include/general/table/table_impl.h index 5b3db83..ec80225 100644 --- a/core/include/general/table/table_impl.h +++ b/core/include/general/table/table_impl.h @@ -22,8 +22,8 @@ #include #include -#include "debug.h" #include "time_print.h" +#include "debug.h" #include "singleton.h" #include "context.h" #include "table/table_helpers.h" diff --git a/core/include/general/tenant_profile_pair.h b/core/include/general/tenant_profile_pair.h index c44f728..5e21a4a 100644 --- a/core/include/general/tenant_profile_pair.h +++ b/core/include/general/tenant_profile_pair.h @@ -25,8 +25,13 @@ public: : tenant_id(_tenant_id), profile_id(_profile_id) - { - } + {} + + TenantProfilePair(const std::pair &tenant_profile_pair) + : + tenant_id(tenant_profile_pair.first), + profile_id(tenant_profile_pair.second) + {} size_t hash() const diff --git a/core/include/internal/proto_message_comp.h b/core/include/internal/proto_message_comp.h index 3c46c54..0453eb8 100644 --- a/core/include/internal/proto_message_comp.h +++ b/core/include/internal/proto_message_comp.h @@ -26,6 +26,7 @@ #include "i_rest_api.h" #include "i_messaging_buffer.h" #include "i_shell_cmd.h" +#include "i_proxy_configuration.h" #include "component.h" class ProtoMessageComp @@ -38,7 +39,8 @@ class ProtoMessageComp Singleton::Consume, Singleton::Consume, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume { public: ProtoMessageComp(); diff --git a/core/include/services_sdk/interfaces/i_agent_details.h b/core/include/services_sdk/interfaces/i_agent_details.h index 8adcc69..d5bae32 100755 --- a/core/include/services_sdk/interfaces/i_agent_details.h +++ b/core/include/services_sdk/interfaces/i_agent_details.h @@ -38,12 +38,14 @@ public: virtual std::string getProfileId() const = 0; // Agent Details - virtual Maybe getProxy() const = 0; - virtual void setProxy(const std::string &_proxy) = 0; - virtual void setAgentId(const std::string &_agent_id) = 0; - virtual std::string getAgentId() const = 0; + virtual Maybe getProxy() const = 0; + virtual void setProxy(const std::string &_proxy) = 0; + virtual void setAgentId(const std::string &_agent_id) = 0; + virtual std::string getAgentId() const = 0; virtual void setOrchestrationMode(OrchestrationMode _orchstration_mode) = 0; - virtual OrchestrationMode getOrchestrationMode() const = 0; + virtual OrchestrationMode getOrchestrationMode() const = 0; + virtual std::string getAccessToken() const = 0; + virtual void loadAccessToken() = 0; // OpenSSL virtual void setOpenSSLDir(const std::string &openssl_dir) = 0; diff --git a/core/include/services_sdk/interfaces/i_messaging.h b/core/include/services_sdk/interfaces/i_messaging.h index 141364c..0cb9bd4 100755 --- a/core/include/services_sdk/interfaces/i_messaging.h +++ b/core/include/services_sdk/interfaces/i_messaging.h @@ -31,12 +31,6 @@ USE_DEBUG_FLAG(D_COMMUNICATION); -enum class ProxyProtocol -{ - HTTP, - HTTPS -}; - enum class MessageTypeTag { GENERIC, @@ -141,16 +135,8 @@ public: return genError("Failed to download file. Error: " + response.getErr()); } - virtual Maybe getProxyDomain(ProxyProtocol protocol) const = 0; - virtual Maybe getProxyCredentials(ProxyProtocol protocol) const = 0; - virtual Maybe getProxyPort(ProxyProtocol protocol) const = 0; - virtual bool getProxyExists(ProxyProtocol protocol) const = 0; - virtual Maybe getProxyAddress(ProxyProtocol protocol) const = 0; - virtual Maybe loadProxy() = 0; virtual bool setActiveFog(MessageTypeTag tag) = 0; - virtual void loadAccessToken() = 0; virtual bool setActiveFog(const string &host, const uint16_t port, bool is_secure, MessageTypeTag tag) = 0; - virtual std::string getAccessToken() = 0; protected: ~I_Messaging() {} diff --git a/core/include/services_sdk/interfaces/i_proxy_configuration.h b/core/include/services_sdk/interfaces/i_proxy_configuration.h new file mode 100644 index 0000000..d10f451 --- /dev/null +++ b/core/include/services_sdk/interfaces/i_proxy_configuration.h @@ -0,0 +1,38 @@ +// 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 __I_PROXY_CONFIGURATION_H__ +#define __I_PROXY_CONFIGURATION_H__ + +#include + +#include "maybe_res.h" + +enum class ProxyProtocol +{ + HTTP, + HTTPS +}; + +class I_ProxyConfiguration +{ +public: + virtual Maybe getProxyDomain(ProxyProtocol protocol) const = 0; + virtual Maybe getProxyCredentials(ProxyProtocol protocol) const = 0; + virtual Maybe getProxyPort(ProxyProtocol protocol) const = 0; + virtual bool getProxyExists(ProxyProtocol protocol) const = 0; + virtual Maybe getProxyAddress(ProxyProtocol protocol) const = 0; + virtual Maybe loadProxy() = 0; +}; + +#endif // __I_PROXY_CONFIGURATION_H__ diff --git a/core/include/services_sdk/interfaces/mock/mock_agent_details.h b/core/include/services_sdk/interfaces/mock/mock_agent_details.h index ac9d492..37c171b 100755 --- a/core/include/services_sdk/interfaces/mock/mock_agent_details.h +++ b/core/include/services_sdk/interfaces/mock/mock_agent_details.h @@ -26,6 +26,8 @@ public: MOCK_METHOD1(setProxy, void(const std::string&)); MOCK_METHOD1(setAgentId, void(const std::string&)); MOCK_CONST_METHOD0(getAgentId, std::string()); + MOCK_METHOD0(loadAccessToken, void()); + MOCK_CONST_METHOD0(getAccessToken, std::string()); // OpenSSL MOCK_METHOD1(setOpenSSLDir, void(const std::string&)); diff --git a/core/include/services_sdk/interfaces/mock/mock_messaging.h b/core/include/services_sdk/interfaces/mock/mock_messaging.h index bcc62e5..9a56d7e 100755 --- a/core/include/services_sdk/interfaces/mock/mock_messaging.h +++ b/core/include/services_sdk/interfaces/mock/mock_messaging.h @@ -57,20 +57,12 @@ public: ) ); - MOCK_METHOD0(loadAccessToken, void()); MOCK_METHOD0(setActiveFog, bool()); MOCK_METHOD1(setActiveFog, bool(MessageTypeTag)); MOCK_METHOD0(unsetFogProxy, void()); MOCK_METHOD0(loadFogProxy, void()); MOCK_METHOD4(setActiveFog, bool(const string &, const uint16_t, const bool, MessageTypeTag)); - MOCK_METHOD0(getAccessToken, string()); - MOCK_CONST_METHOD1(getProxyDomain, Maybe(ProxyProtocol protocol)); - MOCK_CONST_METHOD1(getProxyCredentials, Maybe(ProxyProtocol protocol)); - MOCK_CONST_METHOD1(getProxyPort, Maybe(ProxyProtocol protocol)); - MOCK_CONST_METHOD1(getProxyExists, bool(ProxyProtocol protocol)); - MOCK_CONST_METHOD1(getProxyAddress, Maybe(ProxyProtocol protocol)); - MOCK_METHOD0(loadProxy, Maybe()); }; #endif // __MOCK_MESSAGING_H__ diff --git a/core/include/services_sdk/resources/agent_details.h b/core/include/services_sdk/resources/agent_details.h index 5419582..7baa58b 100755 --- a/core/include/services_sdk/resources/agent_details.h +++ b/core/include/services_sdk/resources/agent_details.h @@ -20,17 +20,42 @@ #include "i_encryptor.h" #include "i_shell_cmd.h" #include "i_environment.h" +#include "i_mainloop.h" +#include "i_proxy_configuration.h" #include "singleton.h" #include "component.h" #include "enum_array.h" +#include "agent_core_utilities.h" + +class ProxyData +{ +public: + bool + operator==(const ProxyData &other) const + { + return protocol==other.protocol && + domain==other.domain && + is_exists==other.is_exists && + port==other.port && + auth==other.auth; + } + + std::string protocol = ""; + std::string domain = ""; + std::string auth = ""; + bool is_exists = false; + uint16_t port = 0; +}; class AgentDetails : public Component, Singleton::Provide::SelfInterface, + Singleton::Provide::SelfInterface, Singleton::Consume, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume { public: AgentDetails() : Component("AgentDetails") {} @@ -39,15 +64,17 @@ public: void init(); - Maybe getProxy() const; - Maybe getFogDomain() const; - Maybe getFogPort() const; - std::string getAgentId() const; - std::string getTenantId() const; - std::string getProfileId() const; - Maybe getOpenSSLDir() const; - std::string getClusterId() const; - OrchestrationMode getOrchestrationMode() const; + Maybe getProxy() const; + Maybe getFogDomain() const; + Maybe getFogPort() const; + std::string getAgentId() const; + std::string getTenantId() const; + std::string getProfileId() const; + Maybe getOpenSSLDir() const; + std::string getClusterId() const; + OrchestrationMode getOrchestrationMode() const; + std::string getAccessToken() const; + void loadAccessToken(); void setFogDomain(const std::string &_fog_domain) { fog_domain = _fog_domain; } void setFogPort(const uint16_t _fog_port) { fog_port = _fog_port; } @@ -67,6 +94,14 @@ public: void serialize(cereal::JSONInputArchive &ar); void setClusterId(const std::string &_cluster_id); + + Maybe getProxyDomain(ProxyProtocol protocol) const; + Maybe getProxyCredentials(ProxyProtocol protocol) const; + Maybe getProxyPort(ProxyProtocol protocol) const; + bool getProxyExists(ProxyProtocol protocol) const; + Maybe getProxyAddress(ProxyProtocol protocol) const; + Maybe loadProxy(); + private: std::string fog_domain = ""; std::string agent_id = ""; @@ -77,13 +112,27 @@ private: std::string cluster_id = ""; std::string filesystem_path = "/etc/cp"; std::string log_files_path = "/var/log"; + std::string access_token = ""; uint16_t fog_port = 0; bool encrypted_connection = false; OrchestrationMode orchestration_mode = OrchestrationMode::ONLINE; + bool is_proxy_configured_via_settings = false; + std::map proxies; static const std::map machineTypes; void registerMachineType(); Maybe getMachineTypeFromDmiTable(); + + std::string convertProxyProtocolToString(ProxyProtocol proto) const; + Maybe verifyProxySyntax( + const std::string &protocol, + const std::string &auth, + const std::string &domain, + const std::string &port, + const std::string &env_proxy + ); + Maybe loadProxyType(const std::string &proxy_type); + Maybe loadProxyType(ProxyProtocol protocol); }; #endif // __AGENT_DETAILS_H__ diff --git a/core/include/services_sdk/resources/component_is/components_list_impl.h b/core/include/services_sdk/resources/component_is/components_list_impl.h index 93decba..7ae12bc 100755 --- a/core/include/services_sdk/resources/component_is/components_list_impl.h +++ b/core/include/services_sdk/resources/component_is/components_list_impl.h @@ -22,6 +22,7 @@ #include "component.h" #include "time_proxy.h" +#include "time_print.h" #include "debug.h" #include "config_component.h" #include "mainloop.h" diff --git a/core/include/services_sdk/resources/debug_flags.h b/core/include/services_sdk/resources/debug_flags.h index 7d3578b..3db35b1 100755 --- a/core/include/services_sdk/resources/debug_flags.h +++ b/core/include/services_sdk/resources/debug_flags.h @@ -90,10 +90,12 @@ DEFINE_FLAG(D_COMPONENT, D_ALL) DEFINE_FLAG(D_WAAP_PARSER_RAW, D_WAAP_PARSER) DEFINE_FLAG(D_WAAP_PARSER_URLENCODE, D_WAAP_PARSER) DEFINE_FLAG(D_WAAP_PARSER_PHPSERIALIZE, D_WAAP_PARSER) + DEFINE_FLAG(D_WAAP_PARSER_PERCENT, D_WAAP_PARSER) DEFINE_FLAG(D_WAAP_OVERRIDE, D_WAAP) DEFINE_FLAG(D_IPS, D_COMPONENT) DEFINE_FLAG(D_FILE_UPLOAD, D_COMPONENT) + DEFINE_FLAG(D_RATE_LIMIT, D_COMPONENT) DEFINE_FLAG(D_PARSER, D_COMPONENT) DEFINE_FLAG(D_WS, D_COMPONENT) diff --git a/core/include/services_sdk/resources/intelligence_invalidation.h b/core/include/services_sdk/resources/intelligence_invalidation.h index 2580960..4b2bb92 100644 --- a/core/include/services_sdk/resources/intelligence_invalidation.h +++ b/core/include/services_sdk/resources/intelligence_invalidation.h @@ -28,7 +28,7 @@ namespace Intelligence { enum class ClassifierType { CLASS, CATEGORY, FAMILY, GROUP, ORDER, KIND }; -enum class ObjectType { ASSET, ZONE, POLICY_PACKAGE, CONFIGURATION, SESSION }; +enum class ObjectType { ASSET, ZONE, POLICY_PACKAGE, CONFIGURATION, SESSION, SHORTLIVED }; class Invalidation { diff --git a/core/include/services_sdk/resources/rest.h b/core/include/services_sdk/resources/rest.h index 06f1680..a668bc9 100644 --- a/core/include/services_sdk/resources/rest.h +++ b/core/include/services_sdk/resources/rest.h @@ -11,8 +11,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// @file rest.h +/// @brief Header file for RESTful communication functionalities. +/// +/// This file defines classes and utilities for RESTful communication, including input/output handling, +/// schema generation, and client-server interactions. + #ifndef __REST_H__ #define __REST_H__ + #include "cereal/archives/json.hpp" #include "cereal/types/common.hpp" #include "cereal/types/string.hpp" @@ -24,19 +31,32 @@ #include "debug.h" #include "maybe_res.h" - #include "rest/schema_printer.h" +/// @class JsonError +/// @brief Class representing JSON parsing errors. +/// +/// This class is used to represent errors that occur during JSON parsing. class JsonError { public: + /// @brief Constructor for JsonError class. + /// @param e The error message to be stored. JsonError(const std::string &e) : err(e) {} - const std::string & getMsg() const { return err; } + + /// @brief Retrieves the error message. + /// @return The error message as a constant reference to a string. + const std::string &getMsg() const { return err; } private: - std::string err; + std::string err; ///< Error message. }; +/// @class BasicRest +/// @brief Base class for RESTful communication handling. +/// +/// The BasicRest class provides basic functionalities for handling RESTful communication, +/// including input/output handling, schema generation, and client-server interactions. class BasicRest { using InputFunc = std::function; @@ -44,16 +64,32 @@ class BasicRest using SchemaFunc = std::function; public: + /// @brief Enumeration representing the direction of communication (Client to Server, Server to Client, or Both). enum class Direction { C2S, S2C, BOTH }; + + /// @brief Enumeration representing the type of parameter (Mandatory, Optional, or Default). enum class ParamType { MANDATORY, OPTIONAL, DEFAULT }; + /// @brief Destructor for the BasicRest class. virtual ~BasicRest() = default; - void load(cereal::JSONInputArchive &ar) { for (auto it : input_funcs) it(ar); } + /// @brief Loads data from the JSON input archive. + /// @param ar The JSON input archive. + void load(cereal::JSONInputArchive &ar) { for (auto it : input_funcs) it(ar); } + + /// @brief Saves data to the JSON output archive. + /// @param ar The JSON output archive. void save(cereal::JSONOutputArchive &ar) const { for (auto it : output_funcs) it(ar); } + /// @brief Outputs the schema to an output stream. + /// @param out The output stream to write the schema to. + /// @param level The indentation level for the schema. void performOutputingSchema(std::ostream &out, int level = 0); + /// @brief Adds a schema for the given REST parameter type. + /// @tparam RestParamType The type of the REST parameter. + /// @param label The label for the parameter in the schema. + /// @param is_mandatory A boolean indicating whether the parameter is mandatory in the schema. template void addSchema(const std::string &label, bool is_mandatory) @@ -67,6 +103,12 @@ public: if (is_mandatory) required.push_back(label); }; + /// @brief Adds an input parameter of the given REST parameter type. + /// @tparam RestParamType The type of the REST parameter. + /// @param param The REST parameter to add as an input. + /// @param label The label for the parameter in the input. + /// @param type The parameter type (Mandatory, Optional, or Default). + /// @param val The default value for the parameter (used for default parameters). template void addInput(RestParam ¶m, const std::string &label, ParamType type, const RestParamType &val) @@ -86,6 +128,12 @@ public: input_funcs.push_back(func); } + /// @brief Adds an output parameter of the given REST parameter type. + /// @tparam RestParamType The type of the REST parameter. + /// @param param The REST parameter to add as an output. + /// @param label The label for the parameter in the output. + /// @param type The parameter type (Mandatory, Optional, or Default). + /// @param val The default value for the parameter (used for default parameters). template void addOutput(RestParam ¶m, const std::string &label, ParamType type, const RestParamType &val) @@ -111,37 +159,78 @@ private: void outputSchema(std::ostream &os, int level); void outputRequired(std::ostream &os, int level); - std::vector input_funcs; - std::vector output_funcs; - std::vector schema_func; - std::vector required; + std::vector input_funcs; ///< Vector storing input functions. + std::vector output_funcs; ///< Vector storing output functions. + std::vector schema_func; ///< Vector storing schema functions. + std::vector required; ///< Vector storing the names of required parameters. }; +/// @class ServerRest +/// @brief Class representing a server-side RESTful communication handler. +/// +/// The ServerRest class is used for server-side RESTful communication and provides +/// functionality for handling REST calls. class ServerRest : public BasicRest { public: + /// @brief Virtual function for handling a REST call. virtual void doCall() = 0; + /// @brief Performs the REST call using the input stream. + /// @param in The input stream containing the JSON data for the REST call. + /// @return A Maybe object containing the result of the REST call (either the JSON data or an error message). Maybe performRestCall(std::istream &in); protected: - static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; } + /// @brief Determines if the direction is for input. + /// @param dir The direction of the communication. + /// @return True if the direction is for input, false otherwise. + static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; } + + /// @brief Determines if the direction is for output. + /// @param dir The direction of the communication. + /// @return True if the direction is for output, false otherwise. static constexpr bool isOutput(BasicRest::Direction dir) { return dir != BasicRest::Direction::C2S; } + + /// @brief Determines if the direction is for schema. + /// @param dir The direction of the communication. + /// @return True if the direction is for schema, false otherwise. static constexpr bool isSchema(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; } }; +/// @class ClientRest +/// @brief Class representing a client-side RESTful communication handler. +/// +/// The ClientRest class is used for client-side RESTful communication and provides +/// functionality for generating and loading JSON data. class ClientRest : public BasicRest { public: + /// @brief Generates JSON data from the object's state. + /// @return A Maybe object containing the JSON data, or an error message if serialization fails. Maybe genJson() const; + + /// @brief Loads JSON data into the object's state. + /// @param json The JSON data to be loaded. + /// @return True if the JSON data is successfully loaded, false otherwise. bool loadJson(const std::string &json); protected: - static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::C2S; } - static constexpr bool isOutput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; } - static constexpr bool isSchema(BasicRest::Direction) { return false; } -}; + /// @brief Determines if the direction is for input. + /// @param dir The direction of the communication. + /// @return True if the direction is for input, false otherwise. + static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::C2S; } + /// @brief Determines if the direction is for output. + /// @param dir The direction of the communication. + /// @return True if the direction is for output, false otherwise. + static constexpr bool isOutput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; } + + /// @brief Determines if the direction is for schema. + /// @param dir The direction of the communication. + /// @return True if the direction is for schema, false otherwise. + static constexpr bool isSchema(BasicRest::Direction) { return false; } +}; template class InputAdder @@ -303,34 +392,217 @@ private: std::map obj; }; +/// @def C2S_LABEL_PARAM(type, name, label) +/// @brief Add a mandatory parameter for the Client-to-Server (C2S) direction. +/// +/// This macro is used to add a mandatory parameter to a REST request sent from +/// the client to the server. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. #define C2S_LABEL_PARAM(type, name, label) \ ADD_MANDATORY_PARAM(BasicRest::Direction::C2S, type, name, label) + +/// @def S2C_LABEL_PARAM(type, name, label) +/// @brief Add a mandatory parameter for the Server-to-Client (S2C) direction. +/// +/// This macro is used to add a mandatory parameter to a REST response sent from +/// the server to the client. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. #define S2C_LABEL_PARAM(type, name, label) \ ADD_MANDATORY_PARAM(BasicRest::Direction::S2C, type, name, label) + +/// @def BOTH_LABEL_PARAM(type, name, label) +/// @brief Add a mandatory parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions. +/// +/// This macro is used to add a mandatory parameter that is used in both the request +/// and response of a REST communication. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. #define BOTH_LABEL_PARAM(type, name, label) \ ADD_MANDATORY_PARAM(BasicRest::Direction::BOTH, type, name, label) + +/// @def C2S_PARAM(type, name) +/// @brief Add a mandatory parameter for the Client-to-Server (C2S) direction with the parameter +/// label being the same as the parameter name. +/// +/// This macro is a shorthand for adding a mandatory parameter to a REST request with +/// the same label as the parameter name. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. #define C2S_PARAM(type, name) C2S_LABEL_PARAM(type, name, #name) + +/// @def S2C_PARAM(type, name) +/// @brief Add a mandatory parameter for the Server-to-Client (S2C) direction with the parameter +/// label being the same as the parameter name. +/// +/// This macro is a shorthand for adding a mandatory parameter to a REST response with +/// the same label as the parameter name. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. #define S2C_PARAM(type, name) S2C_LABEL_PARAM(type, name, #name) + +/// @def BOTH_PARAM(type, name) +/// @brief Add a mandatory parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions +/// with the parameter label being the same as the parameter name. +/// +/// This macro is a shorthand for adding a mandatory parameter that is used in both the +/// request and response of a REST communication with the same label as the parameter name. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. #define BOTH_PARAM(type, name) BOTH_LABEL_PARAM(type, name, #name) +/// @def C2S_LABEL_OPTIONAL_PARAM(type, name, label) +/// @brief Add an optional parameter for the Client-to-Server (C2S) direction. +/// +/// This macro is used to add an optional parameter to a REST request sent from the client +/// to the server. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. #define C2S_LABEL_OPTIONAL_PARAM(type, name, label) \ ADD_OPTIONAL_PARAM(BasicRest::Direction::C2S, type, name, label) + +/// @def S2C_LABEL_OPTIONAL_PARAM(type, name, label) +/// @brief Add an optional parameter for the Server-to-Client (S2C) direction. +/// +/// This macro is used to add an optional parameter to a REST response sent from the server +/// to the client. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. #define S2C_LABEL_OPTIONAL_PARAM(type, name, label) \ ADD_OPTIONAL_PARAM(BasicRest::Direction::S2C, type, name, label) + +/// @def BOTH_LABEL_OPTIONAL_PARAM(type, name, label) +/// @brief Add an optional parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions. +/// +/// This macro is used to add an optional parameter that can be used in both the request +/// and response of a REST communication. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. #define BOTH_LABEL_OPTIONAL_PARAM(type, name, label) \ ADD_OPTIONAL_PARAM(BasicRest::Direction::BOTH, type, name, label) + +/// @def C2S_OPTIONAL_PARAM(type, name) +/// @brief Add an optional parameter for the Client-to-Server (C2S) direction with the parameter label +/// being the same as the parameter name. +/// +/// This macro is a shorthand for adding an optional parameter to a REST request with +/// the same label as the parameter name. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. #define C2S_OPTIONAL_PARAM(type, name) C2S_LABEL_OPTIONAL_PARAM(type, name, #name) + +/// @def S2C_OPTIONAL_PARAM(type, name) +/// @brief Add an optional parameter for the Server-to-Client (S2C) direction with the parameter label +/// being the same as the parameter name. +/// +/// This macro is a shorthand for adding an optional parameter to a REST response with +/// the same label as the parameter name. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. #define S2C_OPTIONAL_PARAM(type, name) S2C_LABEL_OPTIONAL_PARAM(type, name, #name) + +/// @def BOTH_OPTIONAL_PARAM(type, name) +/// @brief Add an optional parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions +/// with the parameter label being the same as the parameter name. +/// +/// This macro is a shorthand for adding an optional parameter that can be used in both the +/// request and response of a REST communication with the same label as the parameter name. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. #define BOTH_OPTIONAL_PARAM(type, name) BOTH_LABEL_OPTIONAL_PARAM(type, name, #name) +/// @def C2S_LABEL_DEAFULT_PARAM(type, name, label, val) +/// @brief Add a parameter with a default value for the Client-to-Server (C2S) direction. +/// +/// This macro is used to add a parameter to a REST request with a default value. If the +/// parameter is not provided in the request, the default value will be used. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. +/// @param val The default value of the parameter. #define C2S_LABEL_DEAFULT_PARAM(type, name, label, val) \ ADD_DEFAULT_PARAM(BasicRest::Direction::C2S, type, name, label, val) + +/// @def S2C_LABEL_DEAFULT_PARAM(type, name, label, val) +/// @brief Add a parameter with a default value for the Server-to-Client (S2C) direction. +/// +/// This macro is used to add a parameter to a REST response with a default value. If the +/// parameter is not provided in the response, the default value will be used. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. +/// @param val The default value of the parameter. #define S2C_LABEL_DEAFULT_PARAM(type, name, label, val) \ ADD_DEFAULT_PARAM(BasicRest::Direction::S2C, type, name, label, val) + +/// @def BOTH_LABEL_DEAFULT_PARAM(type, name, label, val) +/// @brief Add a parameter with a default value for both Client-to-Server (C2S) and Server-to-Client (S2C) directions. +/// +/// This macro is used to add a parameter to a REST response with a default value. If the +/// parameter is not provided in the response, the default value will be used. +/// +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param label The label or name of the parameter as it appears in the JSON data. +/// @param val The default value of the parameter. #define BOTH_LABEL_DEAFULT_PARAM(type, name, label, val) \ ADD_DEFAULT_PARAM(BasicRest::Direction::BOTH, type, name, label, val) + +/// @def C2S_DEAFULT_PARAM(type, name, val) +/// @brief Add a parameter with a default value for the Client-to-Server (C2S) direction with the parameter label +/// being the same as the parameter name. +/// +/// This macro is used to add a parameter to a REST request with +/// the same label as the parameter name and a default value. If the +/// parameter is not provided in the request, the default value will be used. +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param val The default value of the parameter. #define C2S_DEAFULT_PARAM(type, name, val) C2S_LABEL_DEAFULT_PARAM(type, name, #name, val) + +/// @def C2S_DEAFULT_PARAM(type, name, val) +/// @brief Add a parameter with a default value for the Server-to-Client (S2C) direction with the parameter +/// label being the same as the parameter name. +/// +/// This macro is used to add a parameter to a REST request with +/// the same label as the parameter name and a default value. If the +/// parameter is not provided in the request, the default value will be used. +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param val The default value of the parameter. #define S2C_DEAFULT_PARAM(type, name, val) S2C_LABEL_DEAFULT_PARAM(type, name, #name, val) + +/// @def C2S_DEAFULT_PARAM(type, name, val) +/// @brief Add a parameter with a default value for the Client-to-Server (C2S) and Server-to-Client (S2C) directions +/// with the parameter label being the same as the parameter name. +/// +/// This macro is used to add a parameter to a REST request with +/// the same label as the parameter name and a default value. If the +/// parameter is not provided in the request, the default value will be used. +/// @param type The data type of the parameter. +/// @param name The variable name of the parameter. +/// @param val The default value of the parameter. #define BOTH_DEAFULT_PARAM(type, name, val) BOTH_LABEL_DEAFULT_PARAM(type, name, #name, val) #endif // __REST_H__ diff --git a/core/include/services_sdk/utilities/connkey.h b/core/include/services_sdk/utilities/connkey.h index 2267bb2..09843c5 100755 --- a/core/include/services_sdk/utilities/connkey.h +++ b/core/include/services_sdk/utilities/connkey.h @@ -119,6 +119,10 @@ public: return !(*this > other); } + Maybe calculateSubnetStart(int subnet_value); + + Maybe calculateSubnetEnd(int subnet_value); + // Checks if the IP address is in the range [left, right] inclusive. // All IPAddrs must be of the same kind, or the result is false. bool isInRange(const IPAddr &left, const IPAddr &right) const; @@ -149,6 +153,14 @@ private: // Additional fields to be used by ConnKey class and placed here to save space, IPAddr class should ignore them. IPProto proto; PortNumber port; + + Maybe calculateSubnetStartV4(int subnet_value); + + Maybe calculateSubnetEndV4(int subnet_value); + + Maybe calculateSubnetStartV6(int subnet_value); + + Maybe calculateSubnetEndV6(int subnet_value); }; namespace ConnKeyUtil { @@ -171,12 +183,30 @@ public: static Maybe> createRange(const std::string &maybe_range) { - std::string start_range = maybe_range.substr(0, maybe_range.find("-")); - std::string end_range = maybe_range.substr(maybe_range.find("-") + 1); - if (end_range.empty()) { - end_range = start_range; - } + std::string start_range; + std::string end_range; + size_t delimiter_position; + if ((delimiter_position = maybe_range.find("-")) != std::string::npos) { + // If it's a range. + start_range = maybe_range.substr(0, delimiter_position); + end_range = maybe_range.substr(delimiter_position + 1); + if (end_range.empty()) { + end_range = start_range; + } + } else if ((delimiter_position = maybe_range.find("/")) != std::string::npos) { + // If it's a subnet. + IPAddr ip; + ConnKeyUtil::fromString((maybe_range.substr(0, delimiter_position)), ip); + std::string subnet = maybe_range.substr(delimiter_position + 1); + int subnet_value = std::stoi(subnet); + start_range = ip.calculateSubnetStart(subnet_value).unpack(); + end_range = ip.calculateSubnetEnd(subnet_value).unpack(); + } else { + // If it's a single IP. + start_range = maybe_range; + end_range = maybe_range; + } RangeType _start; if (!ConnKeyUtil::fromString(start_range, _start)) { return genError("Error in start value of custom range, value: " + start_range); @@ -188,7 +218,7 @@ public: } if (_start > _end) { - return genError("Error in creating custom range, invalid range: " + maybe_range); + return genError("Error in creating custom range, invalid range: " + maybe_range); } return CustomRange(_start, _end); diff --git a/core/intelligence_is_v2/intelligence_comp_v2.cc b/core/intelligence_is_v2/intelligence_comp_v2.cc index ddf7bf2..b5ec870 100755 --- a/core/intelligence_is_v2/intelligence_comp_v2.cc +++ b/core/intelligence_is_v2/intelligence_comp_v2.cc @@ -49,7 +49,8 @@ static const map object_names = { { "zone", Intelligence::ObjectType::ZONE }, { "policyPackage", Intelligence::ObjectType::POLICY_PACKAGE }, { "configuration", Intelligence::ObjectType::CONFIGURATION }, - { "session", Intelligence::ObjectType::SESSION } + { "session", Intelligence::ObjectType::SESSION }, + { "shortLived", Intelligence::ObjectType::SHORTLIVED } }; class InvalidationRegistration @@ -128,7 +129,9 @@ public: void performCallBacks(const Invalidation &invalidation) const override { + dbgDebug(D_INTELLIGENCE) << "Looking for callbacks for invalidation " << invalidation.genObject(); for (auto ®isted_invalidation : callbacks) { + dbgTrace(D_INTELLIGENCE) << "Checking against: " << registed_invalidation.second.first.genObject(); performCallBacksImpl(invalidation, registed_invalidation.second); } } diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc new file mode 100644 index 0000000..66edd2d --- /dev/null +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc @@ -0,0 +1,138 @@ +// Copyright (C) 2023 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 "intelligence_is_v2/intelligence_query_v2.h" + +#include "cptest.h" + +using namespace std; +using namespace testing; + +USE_DEBUG_FLAG(D_INTELLIGENCE); + +TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequest) { + QueryRequest request(Condition::EQUALS, "phase", "testing", true); + IntelligenceQuery query(request, true); + + std::string expected = "{\n" + " \"limit\": 20,\n" + " \"fullResponse\": true,\n" + " \"query\": {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.phase\",\n" + " \"value\": \"testing\"\n" + " }\n" + "}"; + + EXPECT_EQ(*query.genJson(), expected); +} + +TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) { + QueryRequest request(Condition::EQUALS, "phase", "testing", true); + IntelligenceQuery query(request, false); + std::string expected = "{" + "\"limit\":20," + "\"fullResponse\":true," + "\"query\":{" + "\"operator\":\"equals\"," + "\"key\":\"mainAttributes.phase\"," + "\"value\":\"testing\"" + "}}"; + + EXPECT_EQ(*query.genJson(), expected); +} + +TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequestSpaces) { + QueryRequest request(Condition::EQUALS, "ph ase", "te sti\" n g\\", true); + IntelligenceQuery query(request, false); + std::string expected = "{" + "\"limit\":20," + "\"fullResponse\":true," + "\"query\":{" + "\"operator\":\"equals\"," + "\"key\":\"mainAttributes.ph ase\"," + "\"value\":\"te sti\\\" n g\\\\\"" + "}}"; + + EXPECT_EQ(*query.genJson(), expected); +} + +TEST(IntelligenceQueryTestV2, genJsonPrettyBulkRequests) { + QueryRequest request1(Condition::EQUALS, "phase", "testing", true); + QueryRequest request2(Condition::EQUALS, "height", "testing", 25); + std::vector requests = {request1, request2}; + IntelligenceQuery query(requests, true); + + std::string expected = "{\n" + " \"queries\": [\n" + " {\n" + " \"query\": {\n" + " \"limit\": 20,\n" + " \"fullResponse\": true,\n" + " \"query\": {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.phase\",\n" + " \"value\": \"testing\"\n" + " }\n" + " },\n" + " \"index\": 0\n" + " },\n" + " {\n" + " \"query\": {\n" + " \"limit\": 20,\n" + " \"fullResponse\": true,\n" + " \"query\": {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.height\",\n" + " \"value\": \"testing\"\n" + " }\n" + " },\n" + " \"index\": 1\n" + " }\n" + " ]\n" + "}"; + + EXPECT_EQ(*query.genJson(), expected); +} + +TEST(IntelligenceQueryTestV2, genJsonUnprettyBulkRequest) { + QueryRequest request1(Condition::EQUALS, "phase", "testing", true); + QueryRequest request2(Condition::EQUALS, "height", "testing", 25); + std::vector requests = {request1, request2}; + IntelligenceQuery query(requests, false); + +std::string expected = "{" + "\"queries\":[{" + "\"query\":{" + "\"limit\":20," + "\"fullResponse\":true," + "\"query\":{" + "\"operator\":\"equals\"," + "\"key\":\"mainAttributes.phase\"," + "\"value\":\"testing\"" + "}}," + "\"index\":0" + "},{" + "\"query\":{" + "\"limit\":20," + "\"fullResponse\":true," + "\"query\":{" + "\"operator\":\"equals\"," + "\"key\":\"mainAttributes.height\"," + "\"value\":\"testing\"" + "}}," + "\"index\":1" + "}]}"; + + EXPECT_EQ(*query.genJson(), expected); +} diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc new file mode 100644 index 0000000..d3e8996 --- /dev/null +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc @@ -0,0 +1,448 @@ +#include "intelligence_invalidation.h" + +#include "cptest.h" +#include "mock/mock_messaging.h" +#include "mock/mock_mainloop.h" +#include "mock/mock_time_get.h" +#include "mock/mock_rest_api.h" +#include "mock/mock_agent_details.h" +#include "intelligence_comp_v2.h" +#include "config_component.h" + +using namespace std; +using namespace Intelligence; +using namespace testing; + +static const string invalidation_uri = "/api/v2/intelligence/invalidation"; + +TEST(InvalidationBasic, SettersAndGetters) +{ + Invalidation invalidation("aaa"); + + EXPECT_EQ(invalidation.getClassifier(ClassifierType::CLASS), "aaa"); + EXPECT_EQ(invalidation.getClassifier(ClassifierType::CATEGORY), ""); + EXPECT_EQ(invalidation.getClassifier(ClassifierType::FAMILY), ""); + EXPECT_EQ(invalidation.getClassifier(ClassifierType::GROUP), ""); + EXPECT_EQ(invalidation.getClassifier(ClassifierType::ORDER), ""); + EXPECT_EQ(invalidation.getClassifier(ClassifierType::KIND), ""); + + EXPECT_FALSE(invalidation.getStringAttr("attr1").ok()); + EXPECT_FALSE(invalidation.getStringSetAttr("attr2").ok()); + EXPECT_FALSE(invalidation.getSourceId().ok()); + EXPECT_FALSE(invalidation.getObjectType().ok()); + + set vals = { "2", "3" }; + + invalidation + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setStringAttr("attr1", "1") + .setStringSetAttr("attr2", vals) + .setSourceId("id") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_EQ(invalidation.getClassifier(ClassifierType::CATEGORY), "bbb"); + EXPECT_EQ(invalidation.getClassifier(ClassifierType::FAMILY), "ccc"); + EXPECT_EQ(invalidation.getStringAttr("attr1").unpack(), "1"); + EXPECT_EQ(invalidation.getStringSetAttr("attr2").unpack(), vals); + EXPECT_EQ(invalidation.getSourceId().unpack(), "id"); + EXPECT_EQ(invalidation.getObjectType().unpack(), Intelligence::ObjectType::ASSET); +} + +TEST(InvalidationBasic, Matching) +{ + set vals = { "2", "3" }; + auto base_invalidation = Invalidation("aaa") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setStringAttr("attr1", "1") + .setStringSetAttr("attr2", vals); + + + auto matching_invalidation = Invalidation("aaa") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::GROUP, "ddd") + .setStringAttr("attr1", "1") + .setStringSetAttr("attr2", vals) + .setStringAttr("attr3", "6") + .setSourceId("id") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_TRUE(base_invalidation.matches(matching_invalidation)); + + auto missing_attr_invalidation = Invalidation("aaa") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::GROUP, "ddd") + .setStringAttr("attr1", "1") + .setStringAttr("attr2", "2") + .setStringAttr("attr3", "6") + .setSourceId("id") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_FALSE(base_invalidation.matches(missing_attr_invalidation)); + + set vals2 = { "1", "5" }; + auto has_extra_value_invalidation = Invalidation("aaa") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::GROUP, "ddd") + .setStringSetAttr("attr1", vals2) + .setStringSetAttr("attr2", vals) + .setStringAttr("attr3", "6") + .setSourceId("id") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_TRUE(base_invalidation.matches(has_extra_value_invalidation)); +} + +class IntelligenceInvalidation : public Test +{ +public: + IntelligenceInvalidation() : i_intelligence(Singleton::Consume::from(intelligence)) + { + EXPECT_CALL( + mock_ml, + addRecurringRoutine(I_MainLoop::RoutineType::System, chrono::microseconds(7200000000), _, _, _) + ).WillRepeatedly(Return(0)); + + EXPECT_CALL( + mock_ml, + addRecurringRoutine(I_MainLoop::RoutineType::System, _, _, "Sending intelligence invalidation", _) + ).WillRepeatedly(DoAll(SaveArg<2>(&routine), Return(0))); + + EXPECT_CALL( + mock_rest, + mockRestCall(_, "new-invalidation/source/invalidation", _) + ).WillRepeatedly( + WithArg<2>(Invoke(this, &IntelligenceInvalidation::saveRestServerCB)) + ); + + EXPECT_CALL( + mock_rest, + getListeningPort() + ).WillRepeatedly(Return(7000)); + + conf.preload(); + intelligence.preload(); + intelligence.init(); + } + + bool + saveRestServerCB(const unique_ptr &p) + { + mock_invalidation = p->getRest(); + return true; + } + + StrictMock messaging_mock; + StrictMock mock_ml; + NiceMock mock_time; + NiceMock mock_details; + StrictMock mock_rest; + ConfigComponent conf; + ::Environment env; + IntelligenceComponentV2 intelligence; + I_Intelligence_IS_V2 *i_intelligence; + function callback = + [this] (const Invalidation &incoming) { recieved_invalidations.push_back(incoming); }; + vector recieved_invalidations; + unique_ptr mock_invalidation; + I_MainLoop::Routine routine; +}; + +TEST_F(IntelligenceInvalidation, sending_incomplete_invalidation) +{ + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_FALSE(invalidation.report(i_intelligence)); +} + +TEST_F(IntelligenceInvalidation, sending_public_invalidation) +{ + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + string invalidation_json; + EXPECT_CALL( + messaging_mock, + sendMessage(false, _, I_Messaging::Method::POST, invalidation_uri, _, _, true, MessageTypeTag::INTELLIGENCE) + ).WillOnce(DoAll(SaveArg<1>(&invalidation_json), Return(string()))); + EXPECT_TRUE(invalidation.report(i_intelligence)); + + string expected_json = + "{ \"invalidations\": [ { " + "\"class\": \"aaa\", " + "\"category\": \"bbb\", " + "\"family\": \"ccc\", " + "\"objectType\": \"asset\", " + "\"sourceId\": \"id\", " + "\"mainAttributes\": [ { \"attr2\": \"2\" } ]" + " } ] }"; + EXPECT_EQ(invalidation_json, expected_json); +} + +TEST_F(IntelligenceInvalidation, sending_private_invalidation) +{ + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + + stringstream configuration; + configuration << "{"; + configuration << " \"agentSettings\":["; + configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}"; + configuration << " ],"; + configuration << " \"intelligence\":{"; + configuration << " \"local intelligence server ip\":\"127.0.0.1\","; + configuration << " \"local intelligence server primary port\":9090"; + configuration << " }"; + configuration << "}"; + Singleton::Consume::from(conf)->loadConfiguration(configuration); + + string invalidation_json; + EXPECT_CALL( + messaging_mock, + sendMessage(false, _, I_Messaging::Method::POST, "127.0.0.1", 9090, _, invalidation_uri, _, _, _) + ).WillOnce(DoAll(SaveArg<1>(&invalidation_json), Return(string()))); + EXPECT_TRUE(invalidation.report(i_intelligence)); + + string expected_json = + "{ \"invalidations\": [ { " + "\"class\": \"aaa\", " + "\"category\": \"bbb\", " + "\"family\": \"ccc\", " + "\"objectType\": \"asset\", " + "\"sourceId\": \"id\", " + "\"mainAttributes\": [ { \"attr2\": \"2\" } ]" + " } ] }"; + EXPECT_EQ(invalidation_json, expected_json); +} + +TEST_F(IntelligenceInvalidation, register_for_invalidation) +{ + stringstream configuration; + configuration << "{"; + configuration << " \"agentSettings\":["; + configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}"; + configuration << " ],"; + configuration << " \"intelligence\":{"; + configuration << " \"local intelligence server ip\":\"127.0.0.1\","; + configuration << " \"local intelligence server primary port\":9090"; + configuration << " }"; + configuration << "}"; + Singleton::Consume::from(conf)->loadConfiguration(configuration); + + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + string body; + EXPECT_CALL( + messaging_mock, + sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _) + ).WillOnce(DoAll( + SaveArg<1>(&body), + Return(string()) + )); + + EXPECT_NE(i_intelligence->registerInvalidation(invalidation, callback), 0); + + EXPECT_THAT(body, HasSubstr("\"url\": \"http://127.0.0.1:7000/set-new-invalidation\"")); + EXPECT_THAT(body, HasSubstr("\"apiVersion\": \"v2\", \"communicationType\": \"sync\"")); + EXPECT_THAT(body, HasSubstr("\"mainAttributes\": [ { \"attr2\": \"2\" } ]")); +} + +TEST_F(IntelligenceInvalidation, invalidation_callback) +{ + stringstream configuration; + configuration << "{"; + configuration << " \"agentSettings\":["; + configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}"; + configuration << " ],"; + configuration << " \"intelligence\":{"; + configuration << " \"local intelligence server ip\":\"127.0.0.1\","; + configuration << " \"local intelligence server primary port\":9090"; + configuration << " }"; + configuration << "}"; + Singleton::Consume::from(conf)->loadConfiguration(configuration); + + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_CALL( + messaging_mock, + sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _) + ).WillOnce(Return(string())); + + EXPECT_NE(i_intelligence->registerInvalidation(invalidation, callback), 0); + + set vals = { "1", "5", "2" }; + auto invalidation2 = Invalidation("aaa") + .setStringSetAttr("attr2", vals) + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + stringstream json; + json << invalidation2.genObject(); + mock_invalidation->performRestCall(json); + + EXPECT_EQ(recieved_invalidations.size(), 1); + EXPECT_EQ(recieved_invalidations[0].getStringSetAttr("attr2").unpack(), vals); +} + +TEST_F(IntelligenceInvalidation, delete_invalidation_callback) +{ + stringstream configuration; + configuration << "{"; + configuration << " \"agentSettings\":["; + configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}"; + configuration << " ],"; + configuration << " \"intelligence\":{"; + configuration << " \"local intelligence server ip\":\"127.0.0.1\","; + configuration << " \"local intelligence server primary port\":9090"; + configuration << " }"; + configuration << "}"; + Singleton::Consume::from(conf)->loadConfiguration(configuration); + + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_CALL( + messaging_mock, + sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _) + ).WillOnce(Return(string())); + + auto callback_id = i_intelligence->registerInvalidation(invalidation, callback); + i_intelligence->unregisterInvalidation(*callback_id); + + set vals = { "1", "5", "2" }; + auto invalidation2 = Invalidation("aaa") + .setStringSetAttr("attr2", vals) + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + stringstream json; + json << invalidation2.genObject(); + mock_invalidation->performRestCall(json); + + EXPECT_EQ(recieved_invalidations.size(), 0); +} + +TEST_F(IntelligenceInvalidation, invalidation_short_handling) +{ + stringstream configuration; + configuration << "{"; + configuration << " \"agentSettings\":["; + configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}"; + configuration << " ],"; + configuration << " \"intelligence\":{"; + configuration << " \"local intelligence server ip\":\"127.0.0.1\","; + configuration << " \"local intelligence server primary port\":9090"; + configuration << " }"; + configuration << "}"; + Singleton::Consume::from(conf)->loadConfiguration(configuration); + + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_CALL( + messaging_mock, + sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _) + ).WillOnce(Return(string())); + invalidation.startListening(i_intelligence, callback); + + invalidation.stopListening(i_intelligence); + + set vals = { "1", "5", "2" }; + auto invalidation2 = Invalidation("aaa") + .setStringSetAttr("attr2", vals) + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + stringstream json; + json << invalidation2.genObject(); + mock_invalidation->performRestCall(json); + + EXPECT_EQ(recieved_invalidations.size(), 0); +} + +TEST_F(IntelligenceInvalidation, routine_registration) +{ + stringstream configuration; + configuration << "{"; + configuration << " \"agentSettings\":["; + configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}"; + configuration << " ],"; + configuration << " \"intelligence\":{"; + configuration << " \"local intelligence server ip\":\"127.0.0.1\","; + configuration << " \"local intelligence server primary port\":9090"; + configuration << " }"; + configuration << "}"; + Singleton::Consume::from(conf)->loadConfiguration(configuration); + + routine(); + + auto invalidation = Invalidation("aaa") + .setStringAttr("attr2", "2") + .setSourceId("id") + .setClassifier(ClassifierType::FAMILY, "ccc") + .setClassifier(ClassifierType::CATEGORY, "bbb") + .setObjectType(Intelligence::ObjectType::ASSET); + + EXPECT_CALL( + messaging_mock, + sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _) + ).WillOnce(Return(string())); + + i_intelligence->registerInvalidation(invalidation, callback); + + string body; + EXPECT_CALL( + messaging_mock, + sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _) + ).WillOnce(DoAll( + SaveArg<1>(&body), + Return(string()) + )); + + routine(); + + EXPECT_THAT(body, HasSubstr("\"url\": \"http://127.0.0.1:7000/set-new-invalidation\"")); + EXPECT_THAT(body, HasSubstr("\"apiVersion\": \"v2\", \"communicationType\": \"sync\"")); + EXPECT_THAT(body, HasSubstr("\"mainAttributes\": [ { \"attr2\": \"2\" } ]")); +} diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/json_stream_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/json_stream_ut.cc new file mode 100644 index 0000000..d9652c8 --- /dev/null +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/json_stream_ut.cc @@ -0,0 +1,132 @@ +// Copyright (C) 2023 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 "intelligence_is_v2/json_stream.h" + +#include "cptest.h" +#include "cereal/archives/json.hpp" +#include "boost/algorithm/string.hpp" +#include "boost/format.hpp" + +#include + +using namespace std; +using namespace testing; + +USE_DEBUG_FLAG(D_INTELLIGENCE); + +string +addSlashesToSpecialChars(const string &input) +{ + string output; + for(auto c : input) + { + switch (c) + { + case '\n': + output += "\\n"; + break; + case '\t': + output += "\\t"; + break; + case '\"': + case '\\': + output += '\\'; + //no break + default: + output += c; + break; + } + } + + return output; +} + +void +testJsonStream(const string &key, const string &value, bool is_pretty) +{ + stringstream str_stream; + JsonStream json_stream(&str_stream, is_pretty); + { + cereal::JSONOutputArchive out_ar(json_stream); + out_ar.setNextName("regular_num"); + out_ar.writeName(); + out_ar.saveValue(15.34); + out_ar.setNextName(key.c_str()); + out_ar.writeName(); + out_ar.saveValue(value.c_str()); + } + + string expected_key = addSlashesToSpecialChars(key); + string expected_value = addSlashesToSpecialChars(value); + + const string JSON_STRING_WITH_SPACES = "{\n \"regular_num\": 15.34,\n \"%s\": \"%s\"\n}"; + const string JSON_STRING_WITHOUT_SPACES = "{\"regular_num\":15.34,\"%s\":\"%s\"}"; + boost::format frmt(is_pretty ? JSON_STRING_WITH_SPACES : JSON_STRING_WITHOUT_SPACES); + frmt = frmt % expected_key; + frmt = frmt % expected_value; + + string expected = frmt.str(); + string actual = str_stream.str(); + EXPECT_EQ(actual, expected); +} + +TEST(JsonStreamTest, prettyOneWord) +{ + testJsonStream("regular_key", "regular_value", true); +} + +TEST(JsonStreamTest, unprettyOneWord) +{ + testJsonStream("regular_key", "regular_value", false); +} + +TEST(JsonStreamTest, prettyTwoWords) +{ + testJsonStream("spaced key", "spaced value", true); +} + +TEST(JsonStreamTest, unprettyTwoWords) +{ + testJsonStream("spaced key", "spaced value", false); +} + +TEST(JsonStreamTest, prettyWithEnterTab) +{ + testJsonStream("entered\nkey", "tabbed\tvalue", true); +} + +TEST(JsonStreamTest, unprettyWithEnterTab) +{ + testJsonStream("entered\nkey", "tabbed\tvalue", false); +} + +TEST(JsonStreamTest, prettyWithQout) +{ + testJsonStream("qout \" key\"", "qout \" value\"", true); +} + +TEST(JsonStreamTest, unprettyWithQout) +{ + testJsonStream("qout \" key\"", "qout \" value\"", false); +} + +TEST(JsonStreamTest, prettyWithSlashQout) +{ + testJsonStream("qout \\\" key\\\"", "qout \\\" value\\\"", true); +} + +TEST(JsonStreamTest, unprettyWithSlashQout) +{ + testJsonStream("qout \\\" key\\\"", "qout \\\" value\\\"", false); +} diff --git a/core/intelligence_is_v2/invalidation.cc b/core/intelligence_is_v2/invalidation.cc index 2cace7e..6115118 100644 --- a/core/intelligence_is_v2/invalidation.cc +++ b/core/intelligence_is_v2/invalidation.cc @@ -106,7 +106,8 @@ static const map convertObjectType = { { Intelligence::ObjectType::ZONE, "zone" }, { Intelligence::ObjectType::POLICY_PACKAGE, "policyPackage" }, { Intelligence::ObjectType::CONFIGURATION, "configuration" }, - { Intelligence::ObjectType::SESSION, "session" } + { Intelligence::ObjectType::SESSION, "session" }, + { Intelligence::ObjectType::SHORTLIVED, "shortLived" } }; Maybe diff --git a/core/mainloop/mainloop.cc b/core/mainloop/mainloop.cc index 78f7ac6..388de22 100644 --- a/core/mainloop/mainloop.cc +++ b/core/mainloop/mainloop.cc @@ -287,7 +287,10 @@ MainloopComponent::Impl::run() dbgTrace(D_MAINLOOP) << "Ending execution of corutine. Routine named: " << curr_iter->second.getRoutineName(); - if (getTimer()->getMonotonicTime() > stop_time + large_exceeding) { + if ( + getTimer()->getMonotonicTime() > stop_time + large_exceeding && + curr_iter->second.getRoutineName() != "Orchestration runner" + ) { dbgWarning(D_MAINLOOP) << "Routine execution exceeded run time. Routine name: " << curr_iter->second.getRoutineName(); @@ -532,9 +535,15 @@ MainloopComponent::Impl::stop(const RoutineMap::iterator &iter) if (iter->second.isActive()) { dbgDebug(D_MAINLOOP) << "Stoping the routine " << iter->first; do_stop = true; + auto env = Singleton::Consume::by()->saveEnvironment(); + RoutineMap::iterator save_routine = curr_iter; + curr_iter = iter; // We are going to let the routine run one last time, so it can throw an exception which will cause the stack // to clean up nicely. - iter->second.run(); + // We swap curr_iter to in case the routine will print debug messages and we can see the real Routine id + curr_iter->second.run(); + curr_iter = save_routine; + Singleton::Consume::by()->loadEnvironment(move(env)); do_stop = false; } } diff --git a/core/message/message.cc b/core/message/message.cc index fcf7c02..9b2e790 100755 --- a/core/message/message.cc +++ b/core/message/message.cc @@ -216,10 +216,6 @@ public: void init() { - proxies = { - {ProxyProtocol::HTTP, ProxyData()}, - {ProxyProtocol::HTTPS, ProxyData()} - }; initSSL(); timer = Singleton::Consume::by(); encryptor = Singleton::Consume::by(); @@ -227,8 +223,8 @@ public: msg_buffer = Singleton::Consume::by(); MessageConnection::timer = Singleton::Consume::by(); agent_details = Singleton::Consume::by(); + proxy_configuration = Singleton::Consume::by(); agent_details->readAgentDetails(); - loadAccessToken(); if (!setActiveFog()) { dbgDebug(D_COMMUNICATION) << "Could not initialize active fog connection"; @@ -240,42 +236,6 @@ public: auto cache_timeout = getConfigurationWithDefault(2, "message", "Cache timeout"); cache.startExpiration(seconds(cache_timeout), mainloop, timer); - auto proxy_config = getProfileAgentSetting("agent.config.message.proxy"); - if (proxy_config.ok()) { - agent_details->setProxy(*proxy_config); - agent_details->writeAgentDetails(); - } - - registerConfigLoadCb( - [&]() - { - auto proxy_config = getProfileAgentSetting("agent.config.message.proxy"); - if (proxy_config.ok()) { - is_proxy_configured_via_settings = true; - agent_details->setProxy(*proxy_config); - agent_details->writeAgentDetails(); - } else if (is_proxy_configured_via_settings) { - is_proxy_configured_via_settings = false; - agent_details->setProxy(string("")); - agent_details->writeAgentDetails(); - } - } - ); - - auto load_env_proxy = loadProxy(); - if (!load_env_proxy.ok()) { - dbgDebug(D_COMMUNICATION) - << "Could not initialize load proxy from environment, Error: " - << load_env_proxy.getErr(); - } - - Singleton::Consume::by()->addRecurringRoutine( - I_MainLoop::RoutineType::System, - seconds(60), - [this] () { loadAccessToken(); }, - "Load access token" - ); - auto metrics_debugs_interval = chrono::seconds(getConfigurationWithDefault( 600, @@ -324,30 +284,6 @@ public: MessageConnection::timer = nullptr; } - void - loadAccessToken() - { - filesystem_prefix = getFilesystemPathConfig(); - dbgTrace(D_COMMUNICATION) << "ProtoMessageComp, file systen prefix: " << filesystem_prefix << endl; - auto data_path = getConfigurationWithDefault( - filesystem_prefix + "/data/", - "encryptor", - "Data files directory" - ); - ifstream token_file(data_path + session_token_file_name); - if (!token_file.is_open()) { - dbgWarning(D_COMMUNICATION) << "Failed to open session token file"; - return; - } - stringstream token_steam; - token_steam << token_file.rdbuf(); - - auto new_token = token_steam.str(); - if (access_token != new_token) { - access_token = new_token; - dbgTrace(D_COMMUNICATION) << "Loaded the new token"; - } - } // LCOV_EXCL_START Reason: No proxy for ut void setFogProxy(const string &host, const uint16_t port, ProxyProtocol proto) @@ -355,7 +291,7 @@ public: dbgTrace(D_COMMUNICATION) << "Proxy was set. Proxy: " << host << ":" << port; MessageConnection::proxy_host = host; MessageConnection::proxy_port = port; - auto proxy_auth = getProxyCredentials(proto); + auto proxy_auth = proxy_configuration->getProxyCredentials(proto); if (proxy_auth.ok()) { MessageConnection::proxy_auth = proxy_auth.unpack(); } @@ -368,23 +304,23 @@ public: MessageConnKey fog_key = make_tuple("fog", 0, tag); proxy_protocol = is_secure ? ProxyProtocol::HTTPS : ProxyProtocol::HTTP; - auto load_env_proxy = loadProxy(); + auto load_env_proxy = proxy_configuration->loadProxy(); if (!load_env_proxy.ok()) { dbgDebug(D_COMMUNICATION) << "Could not initialize load proxy from environment, Error: " << load_env_proxy.getErr(); } - if (getProxyExists(proxy_protocol)) { - auto proxy_host = getProxyDomain(proxy_protocol); - auto proxy_port = getProxyPort(proxy_protocol); + if (proxy_configuration->getProxyExists(proxy_protocol)) { + auto proxy_host = proxy_configuration->getProxyDomain(proxy_protocol); + auto proxy_port = proxy_configuration->getProxyPort(proxy_protocol); if (proxy_host.ok() && proxy_port.ok()) { setFogProxy(proxy_host.unpack(), proxy_port.unpack(), proxy_protocol); } } Maybe conn = MessageConnection::startNewConnection( - host, port, is_secure, tag, getProxyExists(proxy_protocol) + host, port, is_secure, tag, proxy_configuration->getProxyExists(proxy_protocol) ); if (!conn.ok()) { dbgWarning(D_COMMUNICATION) @@ -403,7 +339,7 @@ public: << ":" << port << " via " - << (getProxyExists(proxy_protocol) ? "proxy, using " : "") + << (proxy_configuration->getProxyExists(proxy_protocol) ? "proxy, using " : "") << (is_secure ? "secure" : "clear") << " connection"; @@ -652,7 +588,7 @@ public: return sendMessage(conn_iter->second, get_reply, body, method, url, headers, err_call_back); } } - auto load_env_proxy = loadProxy(); + auto load_env_proxy = proxy_configuration->loadProxy(); if (!load_env_proxy.ok()) return genError(load_env_proxy.getErr()); Maybe conn = MessageConnection::startNewConnection( @@ -682,153 +618,6 @@ public: return sendMessage(active_conn, get_reply, body, method, url, headers, err_call_back); } - string getAccessToken() override - { - return access_token; - } - - Maybe - getProxyDomain(ProxyProtocol protocol) const override - { - if (proxies.find(protocol) == proxies.end()) { - return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); - } - if (proxies.at(protocol).domain.empty()) return genError( - convertProxyProtocolToString(protocol) + string(" proxy domain is unset") - ); - return proxies.at(protocol).domain; - } - - Maybe - getProxyCredentials(ProxyProtocol protocol) const override - { - if (proxies.find(protocol) == proxies.end()) { - return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); - } - if (proxies.at(protocol).auth.empty()) return genError( - convertProxyProtocolToString(protocol) + string(" proxy auth is unset") - ); - return proxies.at(protocol).auth; - } - - Maybe - getProxyPort(ProxyProtocol protocol) const override - { - if (proxies.find(protocol) == proxies.end()) { - return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); - } - if (proxies.at(protocol).port == 0) return genError( - convertProxyProtocolToString(protocol) + string(" proxy port is unset") - ); - return proxies.at(protocol).port; - } - - bool - getProxyExists(ProxyProtocol protocol) const override - { - if (proxies.find(protocol) == proxies.end()) { - dbgInfo(D_COMMUNICATION) - << "Proxy type is not loaded in map, type: " - << convertProxyProtocolToString(protocol); - return false; - } - return proxies.at(protocol).is_exists; - } - - Maybe - getProxyAddress(ProxyProtocol protocol) const override - { - if (proxies.find(protocol) == proxies.end()) { - return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol)); - } - if (proxies.at(protocol).protocol.empty() || - proxies.at(protocol).domain.empty() || - proxies.at(protocol).port == 0) { - return genError( - string("Can't construct ") + - convertProxyProtocolToString(protocol) + - string(" proxy address") - ); - } - return proxies.at(protocol).protocol + - "://" + - proxies.at(protocol).domain + - ":" + - to_string(proxies.at(protocol).port); - } - - Maybe - loadProxy() override - { - if (getConfigurationFlag("orchestration-mode") == "offline_mode") return Maybe(); - for (const auto &proxy_type : proxies) { - auto loaded_proxy = loadProxyType(proxy_type.first); - if (!loaded_proxy.ok()) return loaded_proxy; - } - return Maybe(); - } - - Maybe - loadProxyType(ProxyProtocol protocol) - { - dbgAssert(protocol == ProxyProtocol::HTTP || protocol == ProxyProtocol::HTTPS) - << "Unsupported Proxy Protocol " << static_cast(protocol); - - static const map env_var_name = { - {ProxyProtocol::HTTPS, "https_proxy"}, - {ProxyProtocol::HTTP, "http_proxy"} - }; - auto env_proxy = loadProxyType(env_var_name.at(protocol)); - if (!env_proxy.ok()) return genError(env_proxy.getErr()); - if (env_proxy.unpack().empty()) { - return Maybe(); - } - - string protocol_regex = "(http|https)://"; - const static boost::regex no_auth_proxy_regex(protocol_regex + "(.)*:[0-9]{0,5}(/|)"); - const static boost::regex auth_proxy_regex(protocol_regex + "(.)*:(.)*@(.)*:[0-9]{0,5}(/|)"); - - ProxyData env_proxy_data; - env_proxy_data.is_exists = true; - string proxy_copy; - if (!NGEN::Regex::regexMatch(__FILE__, __LINE__, env_proxy.unpack(), boost::regex(protocol_regex + "(.)*"))) { - env_proxy = "http://" + env_proxy.unpack(); - } - proxy_copy.assign(env_proxy.unpack()); - env_proxy_data.protocol = env_proxy.unpack().substr(0, proxy_copy.find(":")); - proxy_copy.erase(0, proxy_copy.find(":") + 3); //remove "http://" or "https://" - - if (NGEN::Regex::regexMatch(__FILE__, __LINE__, env_proxy.unpack(), auth_proxy_regex)) { - env_proxy_data.auth = string(&proxy_copy[0], &proxy_copy[proxy_copy.find("@")]); - proxy_copy.erase(0, proxy_copy.find("@") + 1); // remove "user:pass@" - } else if (!NGEN::Regex::regexMatch(__FILE__, __LINE__, env_proxy.unpack(), no_auth_proxy_regex)) { - return genError(string("Provided proxy has wrong syntax: ") + env_proxy.unpack()); - } - env_proxy_data.domain = proxy_copy.substr(0, proxy_copy.find(":")); - proxy_copy.erase(0, proxy_copy.find(":") + 1); // remove "host:" - env_proxy_data.port = static_cast(stoi(proxy_copy)); - - auto proxy_syntax = verifyProxySyntax( - env_proxy_data.protocol, - env_proxy_data.auth, - env_proxy_data.domain, - to_string(env_proxy_data.port), - env_proxy.unpack() - ); - if (!proxy_syntax.ok()) return proxy_syntax; - if (env_proxy_data == proxies.at(protocol)) { - return Maybe(); - } - - proxies.at(protocol) = env_proxy_data; - dbgInfo(D_COMMUNICATION) - << convertProxyProtocolToString(protocol) - << " proxy was successfully loaded, " - << getProxyAddress(protocol).unpack(); - - return Maybe(); - } - private: Maybe sendMessage( @@ -935,85 +724,6 @@ private: return genError("Failed to send HTTP request"); } - Maybe - verifyProxySyntax( - const string &protocol, - const string &auth, - const string &domain, - const string &port, - const string &env_proxy) - { - stringstream verify_string; - verify_string - << protocol - << "://" - << (!auth.empty() ? auth + string("@") : "") - << domain - << ":" - << port - << (env_proxy.back() == '/' ? "/" : ""); - - if (env_proxy.compare(verify_string.str()) != 0) { - return genError(string("Provided proxy has the wrong syntax:" ) + env_proxy); - } - return Maybe(); - } - - Maybe - loadProxyType(const string &proxy_type) - { - agent_details->readAgentDetails(); - auto proxy_config = agent_details->getProxy(); - if (proxy_config.ok()) { - if (proxy_config.unpack() == "none") { - return Maybe(string()); - } - return proxy_config; - } - -#ifdef gaia - I_ShellCmd *shell_cmd = Singleton::Consume::by(); - auto proxy_ip = shell_cmd->getExecOutput("dbget proxy:ip-address| tr -d '\n'"); - if (!proxy_ip.ok()) return proxy_ip; - auto proxy_port = shell_cmd->getExecOutput("dbget proxy:port| tr -d '\n'"); - if (!proxy_port.ok()) return proxy_port; - if (*proxy_port != "" && *proxy_ip != "") return ("http://" + *proxy_ip + ":" + *proxy_port); - - const string umis_file_path(string(getenv("CPDIR")) + "/tmp/umis_objects.C"); - - { - ifstream umis_file(umis_file_path.c_str()); - if (!umis_file.good()) return Maybe(string()); - } - - const string read_umis_cmd = "cat " + umis_file_path + " | grep -w \""; - const string parse_value_command = "\" | awk -F \"[ \\t]+\" '{printf $NF}' | tr -d \"()\""; - - auto use_proxy = shell_cmd->getExecOutput(read_umis_cmd + "use_proxy" + parse_value_command); - if (!use_proxy.ok()) - return genError("Failed to read use_proxy from " + umis_file_path + ": " + use_proxy.getErr()); - - if (use_proxy.unpack() == "true") { - auto umis_proxy_add = shell_cmd->getExecOutput(read_umis_cmd + "proxy_address" + parse_value_command); - if (!umis_proxy_add.ok() || *umis_proxy_add == "") return umis_proxy_add; - auto umis_proxy_port = shell_cmd->getExecOutput(read_umis_cmd + "proxy_port" + parse_value_command); - if (!umis_proxy_port.ok() || *umis_proxy_port == "") return umis_proxy_port; - - return ("http://" + *umis_proxy_add + ":" + *umis_proxy_port); - } else { - dbgTrace(D_COMMUNICATION) << "Smart Console Proxy is turned off"; - } - return Maybe(string()); -#else // not gaia - char *proxy = getenv(proxy_type.c_str()); - if (proxy) return string(proxy); - - proxy = getenv(boost::algorithm::to_upper_copy(proxy_type).c_str()); - if (proxy) return string(proxy); - return Maybe(string()); -#endif // gaia - } - string base64Decode(const string &input) const { @@ -1087,6 +797,8 @@ private: } } + const string &access_token = agent_details->getAccessToken(); + if (!conn.isExternal() && !access_token.empty() && headers.find("Authorization") == std::string::npos) { req.insertHeader("Authorization", "Bearer " + access_token); } @@ -1186,17 +898,6 @@ private: return count; } - string - convertProxyProtocolToString(ProxyProtocol proto) const - { - switch(proto) { - case ProxyProtocol::HTTP: return "http"; - case ProxyProtocol::HTTPS: return "https"; - } - dbgAssert(false) << "Unsupported Proxy Protocol " << static_cast(proto); - return ""; - } - Maybe stringToMethod(const string &name) { @@ -1209,40 +910,19 @@ private: return genError("Cannot convert unknown HTTP method to Enum. Method name: " + name); } - class ProxyData - { - public: - bool - operator==(const ProxyData &other) const - { - return protocol==other.protocol && - domain==other.domain && - is_exists==other.is_exists && - port==other.port && - auth==other.auth; - } - - string protocol = ""; - string domain = ""; - string auth = ""; - bool is_exists = false; - uint16_t port = 0; - }; - - bool is_proxy_configured_via_settings = false; - uint64_t number_of_reconnects = 0; - uint64_t number_of_reconnect_failures = 0; - uint64_t number_of_send_failure = 0; - I_AgentDetails *agent_details = nullptr; - I_MainLoop *mainloop = nullptr; - I_TimeGet *timer = nullptr; - I_Encryptor *encryptor = nullptr; - I_MessagingBuffer *msg_buffer = nullptr; + bool is_proxy_configured_via_settings = false; + uint64_t number_of_reconnects = 0; + uint64_t number_of_reconnect_failures = 0; + uint64_t number_of_send_failure = 0; + I_AgentDetails *agent_details = nullptr; + I_MainLoop *mainloop = nullptr; + I_TimeGet *timer = nullptr; + I_Encryptor *encryptor = nullptr; + I_MessagingBuffer *msg_buffer = nullptr; + I_ProxyConfiguration *proxy_configuration = nullptr; map active_connections; map tag_to_active_conn_key; - map proxies; ProxyProtocol proxy_protocol; - string access_token; TemporaryCache cache; static const map proxyProtocolToString; set pending_signatures; @@ -1671,7 +1351,7 @@ MessageConnection::receiveResponse(I_MessageDecoder &decoder) } if (connection_closed_count > 0) { - dbgInfo(D_COMMUNICATION) + dbgTrace(D_COMMUNICATION) << "Connection was reconnected. Type: " << tagToString(tag) << ", number of attempts: " diff --git a/core/rest/rest_conn.cc b/core/rest/rest_conn.cc index 9a7a721..ff49807 100644 --- a/core/rest/rest_conn.cc +++ b/core/rest/rest_conn.cc @@ -71,6 +71,7 @@ RestConn::parseConn() const string uri; os >> uri; string identifier = uri.substr(uri.find_first_of('/') + 1); + dbgDebug(D_API) << "Call identifier: " << identifier; uint len = 0; while (true) { @@ -88,6 +89,8 @@ RestConn::parseConn() const } } + dbgDebug(D_API) << "Message length: " << len; + if (method=="POST" && len==0) { dbgWarning(D_API) << "No length was found - could be chunked, but we still do not support that"; sendResponse("411 Length Required", ""); @@ -97,6 +100,8 @@ RestConn::parseConn() const stringstream body; body.str(readSize(len)); + dbgTrace(D_API) << "Message content: " << body.str(); + Maybe res = (method == "POST") ? invoke->invokeRest(identifier, body) : invoke->getSchema(identifier); if (res.ok()) { diff --git a/core/socket_is/socket_is.cc b/core/socket_is/socket_is.cc index 93f86bf..aa95a24 100755 --- a/core/socket_is/socket_is.cc +++ b/core/socket_is/socket_is.cc @@ -94,7 +94,7 @@ public: int res = send(socket_int, data.data() + bytes_sent, data.size() - bytes_sent, MSG_NOSIGNAL); if (res <= 0) { - dbgWarning(D_SOCKET) << "Failed to send data"; + dbgWarning(D_SOCKET) << "Failed to send data, Error: " << strerror(errno); return false; } diff --git a/nodes/orchestration/package/cpnano_debug/cpnano_debug.cc b/nodes/orchestration/package/cpnano_debug/cpnano_debug.cc index dcc0374..1461b71 100755 --- a/nodes/orchestration/package/cpnano_debug/cpnano_debug.cc +++ b/nodes/orchestration/package/cpnano_debug/cpnano_debug.cc @@ -621,7 +621,7 @@ public: if (streams.size() == 0) streams.push_back(DebugStreamConf(default_output_stream)); for (DebugStreamConf &stream : streams) { - for (const pair &flag : new_flags) { + for (const auto &flag : new_flags) { stream.streams[flag.first] = flag.second; } } @@ -634,7 +634,7 @@ public: if (stream.streams["Output"] != output) continue; does_stream_exist = true; - for (const pair &flag : new_flags) { + for (const auto &flag : new_flags) { stream.streams[flag.first] = flag.second; } } @@ -648,7 +648,7 @@ public: { if (output == "") { for (DebugStreamConf &stream : streams) { - for (const string flag : flags) { + for (const string &flag : flags) { stream.streams.erase(flag); } } @@ -658,7 +658,7 @@ public: for (DebugStreamConf &stream : streams) { if (stream.streams["Output"] != output) continue; - for (const string flag : flags) { + for (const string &flag : flags) { stream.streams.erase(flag); } } @@ -692,7 +692,7 @@ public: output_stream = "Output: " + output_stream; debug_map.insert({ "context: " + context, output_stream }); - for (const pair &flag : stream.streams) { + for (const auto &flag : stream.streams) { if (flag.first == "Output") continue; debug_map.insert({ output_stream, flag.first + " = " + flag.second }); } @@ -745,7 +745,7 @@ public: addDebug(const map &new_flags) { kernel_debug.front().erase("All"); - for (const pair &flag : new_flags) { + for (const auto &flag : new_flags) { kernel_debug.front()[flag.first] = flag.second; } } @@ -758,7 +758,7 @@ public: multimap debug_map; for (const map &stream : kernel_debug) { if (stream.find("All") != stream.end() && stream.find("All")->second == "None") continue; - for (const pair &flag : stream) { + for (const auto &flag : stream) { debug_map.insert({ "kernel debug", flag.first + " = " + flag.second }); } } @@ -791,7 +791,7 @@ public: DebugLevel min_level = max_debug_level; for (const map &stream : kernel_debug) { if (stream.find("ALL") != stream.end() && stream.find("ALL")->second == "None") continue; - for (const pair &flag : stream) { + for (const auto &flag : stream) { if (find(flags_to_ignore.begin(), flags_to_ignore.end(), flag.first) != flags_to_ignore.end()) { continue; } @@ -1048,13 +1048,13 @@ DebugCli::show() const vector &debug_conf = service.second; for (const DebugConf &debug : debug_conf) { multimap debug_sub_map = debug.mapDebugConf(getServiceString(service.first)); - for (const pair &debug_map_section : debug_sub_map) { + for (const auto &debug_map_section : debug_sub_map) { debug_map.insert(debug_map_section); } } if (service.first == Service::ACCESS_CONTROL) { multimap debug_sub_map = kernel_debug_conf.mapDebugConf(getServiceString(service.first)); - for (const pair &debug_map_section : debug_sub_map) { + for (const auto &debug_map_section : debug_sub_map) { debug_map.insert(debug_map_section); } }