Compare commits

...

9 Commits

Author SHA1 Message Date
Ned Wright
81c75495cc temporarily disabling some unit-tests 2023-08-24 11:56:16 +00:00
Ned Wright
b25fd8def5 Aug_23_2023-Dev 2023-08-23 14:15:32 +00:00
Ned Wright
702c1184ea Merge branch 'main' of https://github.com/openappsec/openappsec 2023-08-17 17:40:54 +00:00
Ned Wright
b3cfd7e9d8 Check /etc/environment exists before using it 2023-08-17 17:40:22 +00:00
WrightNed
e36b990161 Merge pull request #43 from openappsec/changing_socket_readiness_testing
Change socket readiness testing
2023-08-10 00:22:37 +03:00
NedWright
09868e6d7c Change socket readiness testing 2023-08-09 20:59:26 +00:00
bilbogh
e25f517c19 Update README.md 2023-08-06 18:22:31 +02:00
Ned Wright
42a31e37b1 Add check if obfuscation is enabled 2023-07-28 15:46:08 +00:00
Ned Wright
abe275c828 Add check if obfuscation is enabled 2023-07-27 15:41:41 +00:00
128 changed files with 8328 additions and 1312 deletions

105
README.md
View File

@@ -18,8 +18,6 @@ Every request to the application goes through two phases:
2. If the request is identified as a valid and legitimate request the request is allowed, and forwarded to your application. If, however, the request is considered suspicious or high risk, it then gets evaluated by the unsupervised model, which was trained in your specific environment. This model uses information such as the URL and the users involved to create a final confidence score that determines whether the request should be allowed or blocked.
The project is currently in Beta and feedback is most welcomed!
## Machine Learning models
open-appsec uses two models:
@@ -65,106 +63,3 @@ $ install-cp-nano-attachment-registration-manager.sh --install
```
You can add the ```--token <token>``` and ```--email <email address>``` options to the first command, to get a token follow [documentation](https://docs.openappsec.io/getting-started/using-the-web-ui-saas/connect-deployed-agents-to-saas-management-k8s-and-linux).
For Docker: follow [documentation](https://docs.openappsec.io/getting-started/start-with-docker)
For more information read the [documentation](https://docs.openappsec.io/) or follow the [video tutorials](https://www.openappsec.io/tutorials).
# Repositories
open-appsec GitHub includes four main repositories:
* [openappsec/openappsec](https://github.com/openappsec/openappsec) the main code and logic of open-appsec. Developed in C++.
* [openappsec/attachment](https://github.com/openappsec/attachment) connects between processes that provide HTTP data (e.g NGINX) and the open-appsec Agent security logic. Developed in C.
* [openappsec/smartsync](https://github.com/openappsec/smartsync) in charge of correlating learning data from multiple agent instances and delivering a unified learning model for each asset. Developed in Golang.
* [openappsec/smartsync-shared-files](https://github.com/openappsec/smartsync-shared-files) interface to physical storage used by smartsync service for storing learning data. Developed in Golang.
# Compilation instructions
## Installing external dependencies
Before compiling the services, you'll need to ensure the latest development versions of the following libraries:
* Boost
* OpenSSL
* PCRE2
* libxml2
* GTest
* GMock
* cURL
An example of installing the packages on Alpine:
```bash
$ apk update
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev
```
## Compiling and packaging the agent code
1. Clone this repository
2. Run CMake command
3. Run make install command
```bash
$ git clone https://github.com/openappsec/openappsec.git
$ cd openappsec/
$ cmake -DCMAKE_INSTALL_PREFIX=build_out .
$ make install
$ make package
```
## Placing the agent code inside an Alpine docker image
Once the agent code has been compiled and packaged, an Alpine image running it can be created. This requires permissions to execute the `docker` command.
```bash
$ make docker
```
This will create a local image for your docker called `agent-docker`.
## Deployment of the agent docker image as a container
To run a Nano-Agent as a container the following steps are required:
1. If you are using a container management system / plan on deploying the container using your CI, add the agent docker image to an accessible registry.
2. If you are planning to manage the agent using the open-appsec UI, then make sure to obtain an agent token from the Management Portal and Enforce.
3. Run the agent with the following command (where -e https_proxy parameter is optional):
`docker run -d --name=agent-container --ipc=host -v=<path to persistent location for agent config>:/etc/cp/conf -v=<path to persistent location for agent data files>:/etc/cp/data -v=<path to persistent location for agent debugs and logs>:/var/log/nano_agent -e https_proxy=<user:password@Proxy address:port> -it <agent-image> /cp-nano-agent [--token <token> | --standalone]`
Example:
```bash
$ docker run -d --name=agent-container --ipc=host -v=/home/admin/agent/conf:/etc/cp/conf -v=/home/admin/agent/data:/etc/cp/data -v=/home/admin/agent/logs:/var/log/nano_agent e https_proxy=user:password@1.2.3.4:8080 -it agent-docker /cp-nano-agent --standalone
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e67f2abbfd4 agent-docker "/cp-nano-agent --hybrid-mode" 1 minute ago Up 1 minute agent-container
```
Note that you are not required to use a token from the Management Portal if you are managing your security policy locally. However, you are required to use the --standalone flag in such cases. In addition, the volumes in the command are mandatory only if you wish to have persistency upon restart/upgrade/crash of the agent and its re-execution.
Lastly, --ipc=host argument is mandatory in order for the agent to have access to shared memory with a protected attachment (NGINX server).
4. Create or replace the NGINX container using the [Attachment Repository](https://github.com/openappsec/attachment).
This will run a docker container using the agent docker image.
# Contributing
We welcome everyone that wishes to share their knowledge and expertise to enhance and expand the project.
Please see the [Contributing Guidelines](https://github.com/openappsec/openappsec/blob/main/CONTRIBUTING.md).
# Security
### Security Audit
open-appsec code was audited by an independent third party in September-October 2022.
See the [full report](https://github.com/openappsec/openappsec/blob/main/LEXFO-CHP20221014-Report-Code_audit-OPEN-APPSEC-v1.2.pdf).
### Reporting security vulnerabilities
If you've found a vulnerability or a potential vulnerability in open-appsec please let us know at securityalert@openappsec.io. We'll send a confirmation email to acknowledge your report within 24 hours, and we'll send an additional email when we've identified the issue positively or negatively.
# License
open-appsec is open source and available under Apache 2.0 license.
The basic ML model is open source and available under Apache 2.0 license.
The advanced ML model is open source and available under Machine Learning Model license, available upon download in the tar file.

View File

@@ -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]" : "")
);
}

View File

@@ -156,7 +156,7 @@ Zone::contains(const Asset &asset)
{
QueryRequest request;
for (const pair<Context::MetaDataType, string> &main_attr : asset.getAttrs()) {
for (const auto &main_attr : asset.getAttrs()) {
request.addCondition(Condition::EQUALS, contextKeyToString(main_attr.first), main_attr.second);
}

View File

@@ -83,13 +83,13 @@ public:
:
status(raw_status)
{
for (const pair<string, HealthCheckStatusReply> &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<string, string> &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<string, HealthCheckStatusReply> &reply : all_comps_health_status) {
for (const auto &reply : all_comps_health_status) {
HealthCheckStatus status = reply.second.getStatus();
dbgTrace(D_HEALTH_CHECK_MANAGER)

View File

@@ -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<string, ngx_http_cp_verdict_e> &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;

View File

@@ -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 <vector>
#include <string>
#include <vector>
#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<WebTriggerConf>("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<I_Logging>
{
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<LogTriggerConf>("rulebase", "log");
}
template <typename ...Tags>
/// \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 <typename... Tags>
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 <typename ...Tags>
/// \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 <typename... Tags>
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<ReportIS::StreamType> getStreams(SecurityType security_type, bool is_action_drop_or_prevent) const;
Flags<ReportIS::Enreachments> getEnrechments(SecurityType security_type) const;

View File

@@ -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<I_MainLoop>,
Singleton::Consume<I_Socket>,
Singleton::Consume<I_Health_Check_Manager>
Singleton::Consume<I_Health_Check_Manager>,
Singleton::Consume<I_ShellCmd>
{
public:
HealthChecker();

View File

@@ -109,6 +109,11 @@ public:
virtual Maybe<std::string> 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;

View File

@@ -19,6 +19,7 @@
#include <map>
#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<void>
updateServiceConfiguration(
const std::string &new_policy_path,
const std::string &new_settings_path,
const std::vector<std::string> &new_data_files = {},
const std::string &tenant_id = "",
const std::string &profile_id = "",
const std::string &child_tenant_id = "",
const std::string &child_profile_id = "",
const bool last_iteration = false
) = 0;

View File

@@ -26,9 +26,12 @@ using OrchData = Maybe<std::string>;
class I_UpdateCommunication
{
public:
virtual Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const = 0;
virtual Maybe<void> authenticateAgent() = 0;
virtual Maybe<void> getUpdate(CheckUpdateRequest &request) = 0;
virtual Maybe<void> sendPolicyVersion(const std::string &policy_version) const = 0;
virtual Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) = 0;
virtual void setAddressExtenesion(const std::string &extension) = 0;
};

View File

@@ -17,9 +17,16 @@
#include <fstream>
#include "i_orchestration_tools.h"
#include "i_shell_cmd.h"
#include "i_tenant_manager.h"
#include "component.h"
class OrchestrationTools : public Component, Singleton::Provide<I_OrchestrationTools>
class OrchestrationTools
:
public Component,
Singleton::Provide<I_OrchestrationTools>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_TenantManager>
{
public:
OrchestrationTools();

View File

@@ -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<std::string> &_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<std::string>, 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<std::string> &_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");
};

View File

@@ -7,6 +7,14 @@ using namespace std;
namespace IPSHelper
{
bool has_deobfuscation = false;
bool
hasDeobfuscation()
{
return has_deobfuscation;
}
string
deobfuscateString(const string &str)
{

View File

@@ -6,6 +6,7 @@
namespace IPSHelper
{
bool hasDeobfuscation();
std::string deobfuscateString(const std::string &str);
std::string deobfuscateKeyword(const std::string &str);

View File

@@ -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 <vector>
#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<IPSSignatureSubTypes::SignatureAction, std::string, std::vector<std::string>>;
/// \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<PMPattern> &matched) const = 0;
/// \brief Get the set of patterns in the signature.
virtual std::set<PMPattern> patternsInSignature() const = 0;
virtual const std::vector<std::string> & getContext() const = 0;
/// \brief Get the context of the signature.
virtual const std::vector<std::string> &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<std::string> & 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<int> &year) const;
Maybe<int> 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<std::string> &
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<int> &year) const;
/// \brief Get the year of the signature.
Maybe<int> 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<PMPattern> &matches) const;
/// \brief Get the set of patterns in the signature.
std::set<PMPattern> 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<std::string> & 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<std::string> & 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<std::string> &
getContext() const
{
return rule->getContext();
}
bool isYearAtLeast(const Maybe<int> &year) const { return metadata.isYearAtLeast(year); }
Maybe<int> 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<std::string> &
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<int> &year) const
{
return metadata.isYearAtLeast(year);
}
/// \brief Get the year of the signature.
Maybe<int>
getYear() const
{
return metadata.getYear();
}
private:
IPSSignatureMetaData metadata;
std::shared_ptr<BaseSignature> rule;
};
/// \class SignatureAndAction
/// \brief Represents a signature and its associated action.
class SignatureAndAction
{
public:
SignatureAndAction(std::shared_ptr<CompleteSignature> _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<CompleteSignature> _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<PMPattern> &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<PMPattern>
patternsInSignature() const
{
return signature->patternsInSignature();
}
bool isMatchedPrevent(const Buffer &context_buffer, const std::set<PMPattern> &pattern) const;
bool matchSilent(const Buffer &context_buffer) const;
std::set<PMPattern> patternsInSignature() const { return signature->patternsInSignature(); }
const std::vector<std::string> & getContext() const { return signature->getContext(); }
/// \brief Get the context of the signature.
const std::vector<std::string> &
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<CompleteSignature> signature;
SignatureAction action;
};
} // IPSSignatureSubTypes
} // namespace IPSSignatureSubTypes
/// \class IPSSignaturesPerContext
/// \brief Represents IPS signatures per context.
class IPSSignaturesPerContext : public Singleton::Consume<I_FirstTierAgg>
{
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<PMPattern> getFirstTierMatches(const Buffer &buffer) const;
std::map<PMPattern, std::vector<IPSSignatureSubTypes::SignatureAndAction>> signatures_per_lss;
@@ -135,11 +412,17 @@ private:
std::shared_ptr<PMHook> 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<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures() const
{
@@ -150,11 +433,26 @@ private:
std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> 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<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures() const
{
@@ -166,11 +464,18 @@ private:
std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> 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<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures(const std::string &file_name) const
{
@@ -185,21 +490,74 @@ private:
std::vector<SnortSignaturesResourceFile> files;
};
/// \class IPSSignatures
/// \brief Represents IPS signatures.
class IPSSignatures
{
std::set<PMPattern> 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<std::string, IPSSignaturesPerContext> signatures_per_context;
@@ -210,21 +568,74 @@ private:
std::string source_id;
};
/// \class SnortSignatures
/// \brief Represents Snort signatures.
class SnortSignatures
{
std::set<PMPattern> 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<std::string, IPSSignaturesPerContext> signatures_per_context;

View File

@@ -25,6 +25,8 @@ RuleSelector::selectSignatures() const
{
vector<IPSSignatureSubTypes::SignatureAndAction> res;
if (!IPSHelper::hasDeobfuscation()) return res;
auto all_signatures = getResource<IPSSignaturesResource>("IPS", "protections");
if (!all_signatures.ok()) return res;
auto signatures_version = getResourceWithDefault<string>("", "IPS", "VersionId");

View File

@@ -23,6 +23,8 @@ using namespace ReportIS;
using namespace std;
using MatchType = BaseSignature::MatchType;
static const LogTriggerConf default_triger;
static const map<IPSLevel, Severity> severities = {
{ IPSLevel::CRITICAL, Severity::CRITICAL },
{ IPSLevel::HIGH, Severity::HIGH },
@@ -396,7 +398,7 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
dbgDebug(D_IPS) << "Signature matched - sending log";
auto &trigger = getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
auto &trigger = getConfigurationWithDefault(default_triger, "rulebase", "log");
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL;
@@ -505,6 +507,8 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
void
IPSSignaturesResource::load(cereal::JSONInputArchive &ar)
{
if (!IPSHelper::hasDeobfuscation()) return;
vector<CompleteSignature> sigs;
cereal::load(ar, sigs);

View File

@@ -23,6 +23,11 @@
using namespace testing;
using namespace std;
namespace IPSHelper
{
extern bool has_deobfuscation;
} // namespace IPSHelper
MATCHER_P(IsLog, IteratableFields, "")
{
stringstream ss;
@@ -53,6 +58,7 @@ class SignatureTest : public Test
public:
SignatureTest()
{
IPSHelper::has_deobfuscation = true;
generic_rulebase.preload();
EXPECT_CALL(logs, getCurrentLogId()).Times(AnyNumber());
ON_CALL(table, getState(_)).WillByDefault(Return(&ips_state));

View File

@@ -15,4 +15,4 @@ add_subdirectory(health_check)
add_subdirectory(local_policy_mgmt_gen)
add_subdirectory(env_details)
add_subdirectory(orchestration_ut)
#add_subdirectory(orchestration_ut)

View File

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

View File

@@ -125,44 +125,54 @@ getMgmtObjName(shared_ptr<istream> file_stream)
}
Maybe<string>
getGWIPAddress(shared_ptr<istream> file_stream)
getGWHardware(const string &command_output)
{
return getMgmtObjAttr(file_stream, "ipaddr ");
}
Maybe<string>
getGWHardware(shared_ptr<istream> file_stream)
{
Maybe<string> 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<string>
getGWApplicationControlBlade(shared_ptr<istream> 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<string>
getGWURLFilteringBlade(shared_ptr<istream> 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<string>
getGWIPSecVPNBlade(shared_ptr<istream> file_stream)
getGWURLFilteringBlade(const string &command_output)
{
return getMgmtObjAttr(file_stream, "VPN_1 ");
return getAttr(command_output, "URL Filtering Blade was not found");
}
Maybe<string>
getGWVersion(shared_ptr<istream> 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<string>
getGWIPAddress(const string &command_output)
{
return getAttr(command_output, "IP Address was not found");
}
Maybe<string>
getGWVersion(const string &command_output)
{
return getAttr(command_output, "GW Version was not found");
}
Maybe<string>
@@ -190,6 +200,33 @@ getSmbObjectName(const string &command_output)
return getMgmtObjAttr(ifs, "name ");
}
Maybe<string>
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<string>
getSmbGWApplicationControlBlade(const string &command_output)
{
return getSmbBlade(command_output, "Application Control Blade was not found");
}
Maybe<string>
getSmbGWURLFilteringBlade(const string &command_output)
{
return getSmbBlade(command_output, "URL Filterin Blade was not found");
}
Maybe<string>
getSmbGWIPSecVPNBlade(const string &command_output)
{
return getSmbBlade(command_output, "IPSec VPN Blade was not found");
}
Maybe<string>
getMgmtParentObjAttr(shared_ptr<istream> file_stream, const string &parent_obj, const string &attr)
{

View File

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

View File

@@ -2,4 +2,4 @@ ADD_DEFINITIONS(-Wno-deprecated-declarations -Dalpine)
add_library(orchestration_downloader curl_client.cc downloader.cc http_client.cc https_client.cc)
add_subdirectory(downloader_ut)
#add_subdirectory(downloader_ut)

View File

@@ -179,14 +179,13 @@ private:
Maybe<void>
HTTPClient::getFile(const URLParser &url, ofstream &out_file, bool auth_required)
{
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto load_env_proxy = message->loadProxy();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
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<I_Messaging>::by<HTTPClient>();
token = message->getAccessToken();
token = Singleton::Consume<I_AgentDetails>::by<HTTPClient>()->getAccessToken();
}
if (url.isOverSSL()) {
@@ -214,15 +213,15 @@ Maybe<void>
HTTPClient::curlGetFileOverHttp(const URLParser &url, ofstream &out_file, const string &token)
{
try {
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
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<void>
HTTPClient::getFileHttp(const URLParser &url, ofstream &out_file, const string &token)
{
try {
auto message = Singleton::Consume<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
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();

View File

@@ -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<I_Messaging>
class HTTPClient
:
public Singleton::Consume<I_Messaging>,
public Singleton::Consume<I_AgentDetails>,
public Singleton::Consume<I_ProxyConfiguration>
{
public:
HTTPClient() = default;

View File

@@ -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<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
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<I_Messaging>::by<HTTPClient>();
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
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();

View File

@@ -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<I_ShellCmd>::by<HealthChecker>()->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<char> 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<char> 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

View File

@@ -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<char> 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<char> failure_response_buffer(failure_response.begin(), failure_response.end());
class HealthCheckerTest : public testing::Test
{
public:
@@ -47,6 +64,7 @@ public:
NiceMock<MockLogging> mock_log;
AgentDetails agent_details;
StrictMock<MockSocketIS> mock_socket;
NiceMock<MockShellCmd> 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<char>()));
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<char>()));
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<char>()));
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<char>()));
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");
}

View File

@@ -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<int, int>(isspace))));
in.erase(find_if(in.rbegin(), in.rend(), not1(ptr_fun<int, int>(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;
}

View File

@@ -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<std::string>
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

View File

@@ -41,7 +41,10 @@ public:
void init() override;
Maybe<void> getUpdate(CheckUpdateRequest &request) override;
Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) override;
Maybe<void> sendPolicyVersion(const std::string &policy_version) const override;
Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const override;
private:
DeclarativePolicyUtils declarative_policy_utils;

View File

@@ -46,7 +46,10 @@ public:
void init() override;
Maybe<void> getUpdate(CheckUpdateRequest &request) override;
Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) override;
Maybe<void> sendPolicyVersion(const std::string &policy_version) const override;
Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const override;
private:
Maybe<std::string> getNewVersion();

View File

@@ -33,7 +33,10 @@ public:
Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) override;
void setAddressExtenesion(const std::string &extension) override;
Maybe<void> sendPolicyVersion(const std::string &policy_version) const override;
Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const override;
private:
std::string getChecksum(const std::string &file_path);

View File

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

View File

@@ -38,14 +38,16 @@ public:
MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &());
MOCK_CONST_METHOD0(getPolicyVersions, const std::string &());
MOCK_METHOD6(
updateServiceConfiguration,
bool(
Maybe<void>(
const std::string &new_policy_path,
const std::string &new_settings_path,
const std::vector<std::string> &new_data_files,
const std::string &tenant_id,
const std::string &profile_id,
const std::string &child_tenant_id,
const std::string &child_profile_id,
const bool last_iteration
)
);

View File

@@ -31,7 +31,7 @@ public:
MOCK_METHOD1(getUpdate, Maybe<void>(CheckUpdateRequest &));
MOCK_METHOD1(downloadAttributeFile, Maybe<std::string>(const GetResourceFile &));
MOCK_METHOD1(setAddressExtenesion, void(const std::string &));
MOCK_CONST_METHOD1(sendPolicyVersion, Maybe<void>(const std::string &));
MOCK_CONST_METHOD2(sendPolicyVersion, Maybe<void>(const std::string &, const std::string &));
};
#endif // __MOCK_UPDATE_COMMUNICATION_H__

View File

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

View File

@@ -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<string> valid_modes = {"prevent", "detect", "inactive"};
static const set<string> valid_units = {"minute", "second"};
static const std::unordered_map<std::string, std::string> key_to_mode_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
static const std::unordered_map<std::string, std::string> 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<RateLimitRulesSection> &_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<string> 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<int>("limit", limit, archive_in);
parseAppsecJSONKey<string>("uri", uri, archive_in);
parseAppsecJSONKey<string>("unit", unit, archive_in);
if (valid_units.count(unit) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "Access control rate limite rules units invalid: "
<< unit;
}
parseAppsecJSONKey<string>("comment", comment, archive_in);
parseAppsecJSONKey<vector<string>>("triggers", triggers, archive_in);
}
const vector<string>
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<RateLimitRulesTriggerSection> 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<string>("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<std::vector<AccessControlRateLimiteRules>>("rules", rules, archive_in);
}
vector<RateLimitRulesSection>
AccessControlRateLimit::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const
{
vector<RateLimitRulesSection> rules_section;
for (const AccessControlRateLimiteRules &rule : rules) {
rules_section.push_back(rule.createRateLimitRulesSection(trigger));
}
return rules_section;
}
const vector<AccessControlRateLimiteRules> &
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<string>("name", practice_name, archive_in);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<AccessControlRateLimit>("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

View File

@@ -34,6 +34,26 @@ AppSecWebBotsURI::getURI() const
return uri;
}
std::vector<std::string>
AppSecPracticeAntiBot::getIjectedUris() const
{
vector<string> injected;
for (const AppSecWebBotsURI &uri : injected_uris) {
injected.push_back(uri.getURI());
}
return injected;
}
std::vector<std::string>
AppSecPracticeAntiBot::getValidatedUris() const
{
vector<string> 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<string> injected;
vector<string> validated;
for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
for (const AppSecWebBotsURI &uri : validated_uris) injected.push_back(uri.getURI());
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
{

View File

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

View File

@@ -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 <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<RateLimitRulesTriggerSection> &_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<RateLimitRulesTriggerSection> 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<RateLimitRulesSection> &_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<RateLimitRulesSection> rules;
};
class AccessControlRulebaseSection
{
public:
AccessControlRulebaseSection() {};
AccessControlRulebaseSection(const std::vector<RateLimitSection> &_rate_limit) : rate_limit(_rate_limit) {};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<RateLimitSection> rate_limit;
};
class AccessControlRulebaseWrapper
{
public:
AccessControlRulebaseWrapper() {};
AccessControlRulebaseWrapper(
const std::vector<RateLimitSection> &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<std::string> getTriggers() const;
RateLimitRulesSection createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const;
private:
int limit;
std::string uri;
std::string unit;
std::string comment;
std::vector<std::string> triggers;
};
class AccessControlRateLimit
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<AccessControlRateLimiteRules> & getRules() const;
const std::string & getMode() const;
std::vector<RateLimitRulesSection> createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const;
private:
std::string mode;
std::vector<AccessControlRateLimiteRules> 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__

View File

@@ -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<std::string> getIjectedUris() const;
std::vector<std::string> 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<std::string, std::string> 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<std::string> injected_uris;
std::vector<std::string> 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<TriggersInWaapSection> triggers;
PracticeAdvancedConfig practice_advanced_config;
AppSecPracticeAntiBot anti_bots;
AppsecPracticeAntiBotSection anti_bots;
std::vector<AppSecTrustedSources> trusted_sources;
std::vector<AppSecOverride> 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<WebAPISection> webAPIPractices;
};
class AppSecWrapper
{
public:

View File

@@ -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<std::string> &_value)
:
match_type(MatchType::Condition),

View File

@@ -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<std::string, AppsecLinuxPolicy> createAppsecPoliciesFromIngresses();
std::tuple<std::map<std::string, AppsecLinuxPolicy>, std::map<std::string, V1beta2AppsecLinuxPolicy>>
createAppsecPoliciesFromIngresses();
bool getClusterId() const;
private:
@@ -60,13 +62,41 @@ private:
const ParsedRule &default_rule
) const;
std::map<AnnotationTypes, std::unordered_set<std::string>> extractElementsNamesV1beta2(
const std::vector<NewParsedRule> &specific_rules,
const NewParsedRule &default_rule
) const;
template<class T>
std::vector<T> extractElementsFromCluster(
const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names
) const;
Maybe<AppsecLinuxPolicy> createAppsecPolicyK8s(
template<class T>
std::vector<T> extractV1Beta2ElementsFromCluster(
const std::string &crd_plural,
const std::unordered_set<std::string> &elements_names
) const;
Maybe<AppsecLinuxPolicy> createAppsecPolicyK8sFromV1beta1Crds(
const AppsecSpecParser<AppsecPolicySpec> &appsec_policy_spe,
const std::string &ingress_mode
) const;
Maybe<V1beta2AppsecLinuxPolicy> createAppsecPolicyK8sFromV1beta2Crds(
const AppsecSpecParser<NewAppsecPolicySpec> &appsec_policy_spe,
const std::string &ingress_mode
) const;
template<class T, class K>
void createPolicy(
T &appsec_policy,
std::map<std::string, T> &policies,
std::map<AnnotationKeys, std::string> &annotations_values,
const SingleIngressData &item) const;
std::tuple<Maybe<AppsecLinuxPolicy>, Maybe<V1beta2AppsecLinuxPolicy>> createAppsecPolicyK8s(
const std::string &policy_name,
const std::string &ingress_mode
) const;

View File

@@ -22,10 +22,13 @@
#include "config.h"
#include "debug.h"
#include "rest.h"
#include "cereal/archives/json.hpp"
#include <cereal/types/map.hpp>
#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<std::string, MatchType> string_to_match_type = {
static const std::unordered_map<std::string, PracticeType> string_to_practice_type = {
{ "WebApplication", PracticeType::WebApplication },
{ "WebAPI", PracticeType::WebAPI }
{ "WebAPI", PracticeType::WebAPI },
{ "RateLimit", PracticeType::RateLimit }
};
static const std::unordered_map<std::string, TriggerType> 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<std::map<std::string, std::string>>("annotations", annotations, archive_in);
}
const std::map<std::string, std::string> &
getAnnotations() const
{
return annotations;
}
private:
std::map<std::string, std::string> annotations;
};
template <typename T>
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__

View File

@@ -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 <list>
#include <vector>
#include <cereal/archives/json.hpp>
#include <cereal/types/list.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<I_Environment>
{
public:
// LCOV_EXCL_START Reason: no test exist
V1beta2AppsecLinuxPolicy() {}
V1beta2AppsecLinuxPolicy(
const NewAppsecPolicySpec &_policies,
const std::vector<NewAppSecPracticeSpec> &_threat_prevention_practices,
const std::vector<AccessControlPracticeSpec> &_access_control_practices,
const std::vector<NewAppsecLogTrigger> &_log_triggers,
const std::vector<NewAppSecCustomResponse> &_custom_responses,
const std::vector<NewAppsecException> &_exceptions,
const std::vector<NewTrustedSourcesSpec> &_trusted_sources,
const std::vector<NewSourcesIdentifiers> &_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<NewAppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AccessControlPracticeSpec> & getAccessControlPracticeSpecs() const;
const std::vector<NewAppsecLogTrigger> & getAppsecTriggerSpecs() const;
const std::vector<NewAppSecCustomResponse> & getAppSecCustomResponseSpecs() const;
const std::vector<NewAppsecException> & getAppsecExceptionSpecs() const;
const std::vector<NewTrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<NewSourcesIdentifiers> & getAppsecSourceIdentifierSpecs() const;
void addSpecificRule(const NewParsedRule &_rule);
private:
NewAppsecPolicySpec policies;
std::vector<NewAppSecPracticeSpec> threat_prevection_practices;
std::vector<AccessControlPracticeSpec> access_control_practices;
std::vector<NewAppsecLogTrigger> log_triggers;
std::vector<NewAppSecCustomResponse> custom_responses;
std::vector<NewAppsecException> exceptions;
std::vector<NewTrustedSourcesSpec> trusted_sources;
std::vector<NewSourcesIdentifiers> sources_identifiers;
};
#endif // __NEW_APPSEC_LINUX_POLICY_H__

View File

@@ -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 <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<std::string> & getLogTriggers() const;
const std::vector<std::string> & getExceptions() const;
const std::vector<std::string> & getPractices() const;
const std::vector<std::string> & 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<std::string> log_triggers;
std::vector<std::string> exceptions;
std::vector<std::string> threat_prevention_practices;
std::vector<std::string> 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<I_Environment>
{
public:
void load(cereal::JSONInputArchive &archive_in);
const NewParsedRule & getDefaultRule() const;
const std::vector<NewParsedRule> & 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<NewParsedRule> specific_rules;
};
#endif // __NEW_APPSEC_POLICY_CRD_PARSER_H__
// LCOV_EXCL_STOP

View File

@@ -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 <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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__

View File

@@ -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 <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<std::string> getCountryCode() const;
const std::vector<std::string> getCountryName() const;
const std::vector<std::string> getHostName() const;
const std::vector<std::string> getParamName() const;
const std::vector<std::string> getParamValue() const;
const std::vector<std::string> getProtectionName() const;
const std::vector<std::string> getSourceIdentifier() const;
const std::vector<std::string> getSourceIp() const;
const std::vector<std::string> getUrl() const;
void setName(const std::string &_name);
private:
std::string appsec_class_name;
std::string name;
std::string action;
std::vector<NewAppsecExceptionCondition> conditions;
};
#endif // __NEW_EXCEPTIONS_H__

View File

@@ -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 <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<I_AgentDetails>,
Singleton::Consume<I_EnvDetails>
{
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__

View File

@@ -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 <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<IpsProtectionsRulesSection> &_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<IpsProtectionsRulesSection> rules;
};
class IPSSection
{
public:
// LCOV_EXCL_START Reason: no test exist
IPSSection() {};
IPSSection(const std::vector<IpsProtectionsSection> &_ips) : ips(_ips) {};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<IpsProtectionsSection> ips;
};
class IntrusionPreventionWrapper
{
public:
// LCOV_EXCL_START Reason: no test exist
IntrusionPreventionWrapper() {};
IntrusionPreventionWrapper(const std::vector<IpsProtectionsSection> &_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<IpsProtectionsRulesSection> 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<FileSecurityProtectionsSection> &_file_security)
:
file_security(_file_security) {};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<FileSecurityProtectionsSection> file_security;
};
class FileSecurityWrapper
{
public:
// LCOV_EXCL_START Reason: no test exist
FileSecurityWrapper() {};
FileSecurityWrapper(const std::vector<FileSecurityProtectionsSection> &_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<std::string> & getConfigMap() const;
private:
std::string override_mode;
std::vector<std::string> 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<std::string> getIjectedUris() const;
std::vector<std::string> getValidatedUris() const;
void load(cereal::JSONInputArchive &archive_in);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string override_mode;
std::vector<NewAppSecWebBotsURI> injected_uris;
std::vector<NewAppSecWebBotsURI> 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__

View File

@@ -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 <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#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<std::string> & 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<std::string> sources_identifiers;
std::string appsec_class_name;
};
class Identifier
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getIdentifier() const;
const std::vector<std::string> & getValues() const;
private:
std::string identifier;
std::vector<std::string> value;
};
class NewSourcesIdentifiers
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAppSecClassName() const;
const std::vector<Identifier> & getSourcesIdentifiers() const;
void setName(const std::string &_name);
private:
std::string name;
std::string appsec_class_name;
std::vector<Identifier> sources_identifiers;
};
#endif // __NEW_TRUSTED_SOURCES_H__

View File

@@ -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<class T, class R>
std::string proccesMultipleAppsecPolicies(
const std::map<std::string, AppsecLinuxPolicy> &appsec_policies,
const std::map<std::string, T> &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<AnnotationTypes, std::string> &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<AnnotationTypes, std::string> &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<AnnotationTypes, std::string> &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<AnnotationTypes, std::string> &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<AnnotationTypes, std::string> &rule_annotations
);
template<class T, class R>
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<class T, class R>
void createPolicyElements(
const std::vector<ParsedRule> &rules,
const ParsedRule &default_rule,
const AppsecLinuxPolicy &policy,
const std::vector<R> &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<class T, class R>
void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const T &appsec_policy);
std::map<std::string, LogTriggerSection> log_triggers;
std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers;
std::map<std::string, InnerException> inner_exceptions;
std::map<std::string, WebAppSection> web_apps;
std::map<std::string, RulesConfigRulebase> rules_config;
std::map<std::string, IpsProtectionsSection> ips;
std::map<std::string, FileSecurityProtectionsSection> file_security;
std::map<std::string, RateLimitSection> rate_limit;
std::map<std::string, UsersIdentifiersRulebase> users_identifiers;
std::map<std::string, AppSecTrustedSources> trusted_sources;
};
template<class T, class R>
std::string
PolicyMakerUtils::proccesMultipleAppsecPolicies(
const std::map<std::string, T> &appsec_policies,
const std::string &policy_version,
const std::string &local_appsec_policy_path)
{
for (const auto &appsec_policy : appsec_policies) {
createAgentPolicyFromAppsecPolicy<T, R>(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__

View File

@@ -121,6 +121,8 @@ public:
std::vector<std::string> _identifier_values
);
const std::string & getIdentifier() const;
void save(cereal::JSONOutputArchive &out_ar) const;
private:
@@ -141,6 +143,8 @@ public:
const std::vector<UsersIdentifier> &_source_identifiers
);
const std::string & getIdentifier() const;
void save(cereal::JSONOutputArchive &out_ar) const;
private:

View File

@@ -52,7 +52,7 @@ map<AnnotationKeys, string>
K8sPolicyUtils::parseIngressAnnotations(const map<string, string> &annotations) const
{
map<AnnotationKeys, string> annotations_values;
for (const pair<string, string> &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<ParsedRule> &specific_rules, c
return policy_elements_names;
}
// LCOV_EXCL_START Reason: no test exist
void
extractElementsFromNewRule(
const NewParsedRule &rule,
map<AnnotationTypes, unordered_set<string>> &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<AnnotationTypes, unordered_set<string>>
K8sPolicyUtils::extractElementsNamesV1beta2(
const vector<NewParsedRule> &specific_rules,
const NewParsedRule &default_rule) const
{
map<AnnotationTypes, unordered_set<string>> 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<class T>
vector<T>
K8sPolicyUtils::extractElementsFromCluster(
@@ -168,19 +218,52 @@ K8sPolicyUtils::extractElementsFromCluster(
return elements;
}
Maybe<AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const
// LCOV_EXCL_START Reason: no test exist
template<class T>
vector<T>
K8sPolicyUtils::extractV1Beta2ElementsFromCluster(
const string &crd_plural,
const unordered_set<string> &elements_names) const
{
auto maybe_appsec_policy_spec = getObjectFromCluster<AppsecSpecParser<AppsecPolicySpec>>(
"/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<T> elements;
for (const string &element_name : elements_names) {
dbgTrace(D_LOCAL_POLICY) << "AppSec element name: " << element_name;
auto maybe_appsec_element = getObjectFromCluster<AppsecSpecParser<T>>(
"/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<T> 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<AppsecPolicySpec> appsec_policy_spec = maybe_appsec_policy_spec.unpack();
return elements;
}
// LCOV_EXCL_STOP
Maybe<AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPolicyK8sFromV1beta1Crds(
const AppsecSpecParser<AppsecPolicySpec> &appsec_policy_spec,
const string &ingress_mode) const
{
ParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule();
vector<ParsedRule> specific_rules = appsec_policy_spec.getSpec().getSpecificRules();
@@ -236,11 +319,160 @@ K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &i
return appsec_policy;
}
map<string, AppsecLinuxPolicy>
// LCOV_EXCL_START Reason: no test exist
Maybe<V1beta2AppsecLinuxPolicy>
K8sPolicyUtils::createAppsecPolicyK8sFromV1beta2Crds(
const AppsecSpecParser<NewAppsecPolicySpec> &appsec_policy_spec,
const string &ingress_mode) const
{
NewParsedRule default_rule = appsec_policy_spec.getSpec().getDefaultRule();
vector<NewParsedRule> 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<AnnotationTypes, unordered_set<string>> policy_elements_names = extractElementsNamesV1beta2(
specific_rules,
default_rule
);
vector<NewAppSecPracticeSpec> threat_prevention_practices =
extractV1Beta2ElementsFromCluster<NewAppSecPracticeSpec>(
"threatpreventionpractices",
policy_elements_names[AnnotationTypes::THREAT_PREVENTION_PRACTICE]
);
vector<AccessControlPracticeSpec> access_control_practices =
extractV1Beta2ElementsFromCluster<AccessControlPracticeSpec>(
"accesscontrolpractice",
policy_elements_names[AnnotationTypes::ACCESS_CONTROL_PRACTICE]
);
vector<NewAppsecLogTrigger> log_triggers = extractV1Beta2ElementsFromCluster<NewAppsecLogTrigger>(
"logtriggers",
policy_elements_names[AnnotationTypes::TRIGGER]
);
vector<NewAppSecCustomResponse> web_user_responses = extractV1Beta2ElementsFromCluster<NewAppSecCustomResponse>(
"customresponses",
policy_elements_names[AnnotationTypes::WEB_USER_RES]
);
vector<NewAppsecException> exceptions = extractV1Beta2ElementsFromCluster<NewAppsecException>(
"exceptions",
policy_elements_names[AnnotationTypes::EXCEPTION]
);
vector<NewSourcesIdentifiers> source_identifiers = extractV1Beta2ElementsFromCluster<NewSourcesIdentifiers>(
"sourcesidentifiers",
policy_elements_names[AnnotationTypes::SOURCE_IDENTIFIERS]
);
vector<NewTrustedSourcesSpec> trusted_sources = extractV1Beta2ElementsFromCluster<NewTrustedSourcesSpec>(
"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<string, string> &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<AppsecLinuxPolicy>, Maybe<V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPolicyK8s(const string &policy_name, const string &ingress_mode) const
{
auto maybe_appsec_policy_spec = getObjectFromCluster<AppsecSpecParser<AppsecPolicySpec>>(
"/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<AppsecSpecParser<NewAppsecPolicySpec>>(
"/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<class T, class K>
void
K8sPolicyUtils::createPolicy(
T &appsec_policy,
map<std::string, T> &policies,
map<AnnotationKeys, string> &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<string, AppsecLinuxPolicy>, map<string, V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPoliciesFromIngresses()
{
dbgFlow(D_LOCAL_POLICY) << "Getting all policy object from Ingresses";
map<string, AppsecLinuxPolicy> policies;
map<string, AppsecLinuxPolicy> v1bet1_policies;
map<string, V1beta2AppsecLinuxPolicy> v1bet2_policies;
auto maybe_ingress = getObjectFromCluster<IngressData>("/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<AnnotationKeys, string> annotations_values = parseIngressAnnotations(
@@ -262,37 +495,34 @@ K8sPolicyUtils::createAppsecPoliciesFromIngresses()
continue;
}
Maybe<AppsecLinuxPolicy> 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<V1beta2AppsecLinuxPolicy, NewParsedRule>(
appsec_policy,
v1bet2_policies,
annotations_values,
item);
} else {
auto appsec_policy=std::get<0>(maybe_appsec_policy).unpack();
createPolicy<AppsecLinuxPolicy, ParsedRule>(
appsec_policy,
v1bet1_policies,
annotations_values,
item);
}
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
return policies;
return make_tuple(v1bet1_policies, v1bet2_policies);
}
bool

View File

@@ -104,9 +104,16 @@ public:
{
dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - K8S environment";
map<string, AppsecLinuxPolicy> 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<AppsecLinuxPolicy, ParsedRule>(
std::get<0>(appsec_policies),
policy_version,
default_local_appsec_policy_path
);
}
return policy_maker_utils.proccesMultipleAppsecPolicies<V1beta2AppsecLinuxPolicy, NewParsedRule>(
std::get<1>(appsec_policies),
policy_version,
default_local_appsec_policy_path
);

View File

@@ -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<NewAppSecPracticeSpec> &
V1beta2AppsecLinuxPolicy::getAppSecPracticeSpecs() const
{
return threat_prevection_practices;
}
const vector<AccessControlPracticeSpec> &
V1beta2AppsecLinuxPolicy::getAccessControlPracticeSpecs() const
{
return access_control_practices;
}
const vector<NewAppsecLogTrigger> &
V1beta2AppsecLinuxPolicy::getAppsecTriggerSpecs() const
{
return log_triggers;
}
const vector<NewAppSecCustomResponse> &
V1beta2AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
{
return custom_responses;
}
const vector<NewAppsecException> &
V1beta2AppsecLinuxPolicy::getAppsecExceptionSpecs() const
{
return exceptions;
}
const vector<NewTrustedSourcesSpec> &
V1beta2AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const
{
return trusted_sources;
}
const vector<NewSourcesIdentifiers> &
V1beta2AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
{
return sources_identifiers;
}
void
V1beta2AppsecLinuxPolicy::addSpecificRule(const NewParsedRule &_rule)
{
policies.addSpecificRule(_rule);
}
// LCOV_EXCL_STOP

View File

@@ -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<string> valid_modes = {"prevent-learn", "detect-learn", "prevent", "detect", "inactive"};
void
NewParsedRule::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec NewParsedRule";
parseAppsecJSONKey<vector<string>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<vector<string>>("triggers", log_triggers, archive_in);
parseAppsecJSONKey<vector<string>>("threatPreventionPractices", threat_prevention_practices, archive_in);
parseAppsecJSONKey<vector<string>>("accessControlPractices", access_control_practices, archive_in);
parseAppsecJSONKey<string>("mode", mode, archive_in);
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec New Parsed Rule mode invalid: " << mode;
}
parseAppsecJSONKey<string>("customResponse", custom_response, archive_in);
parseAppsecJSONKey<string>("sourceIdentifiers", source_identifiers, archive_in);
parseAppsecJSONKey<string>("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<string> &
NewParsedRule::getLogTriggers() const
{
return log_triggers;
}
const vector<string> &
NewParsedRule::getExceptions() const
{
return exceptions;
}
const vector<string> &
NewParsedRule::getPractices() const
{
return threat_prevention_practices;
}
const vector<string> &
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<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewParsedRule>("default", default_rule, archive_in);
parseAppsecJSONKey<vector<NewParsedRule>>("specificRules", specific_rules, archive_in);
}
const NewParsedRule &
NewAppsecPolicySpec::getDefaultRule() const
{
return default_rule;
}
const vector<NewParsedRule> &
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

View File

@@ -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<string> 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<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<int>("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<string>("mode", mode, archive_in, "block-page");
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec web user response mode invalid: " << mode;
}
parseAppsecJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<string>("redirectUrl", redirect_url, archive_in);
parseAppsecJSONKey<bool>("redirectAddXEventId", redirect_add_x_event_id, archive_in);
if (mode == "block-page") {
parseAppsecJSONKey<string>(
"messageBody",
message_body,
archive_in,
"Openappsec's <b>Application Security</b> has detected an attack and blocked it."
);
parseAppsecJSONKey<string>(
"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

View File

@@ -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<string> valid_actions = {"skip", "accept", "drop", "suppressLog"};
void
NewAppsecExceptionCondition::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading New AppSec exception condition";
parseAppsecJSONKey<string>("key", key, archive_in);
parseAppsecJSONKey<string>("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<string>("name", name, archive_in);
parseAppsecJSONKey<string>("action", action, archive_in);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
if (valid_actions.count(action) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action;
}
parseAppsecJSONKey<vector<NewAppsecExceptionCondition>>("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<string>
NewAppsecException::getCountryCode() const
{
vector<string> country_codes;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "countryCode") {
country_codes.push_back(condition.getvalue());
}
}
return country_codes;
}
const vector<string>
NewAppsecException::getCountryName() const
{
vector<string> country_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "countryName") {
country_names.push_back(condition.getvalue());
}
}
return country_names;
}
const vector<string>
NewAppsecException::getHostName() const
{
vector<string> host_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "hostName") {
host_names.push_back(condition.getvalue());
}
}
return host_names;
}
const vector<string>
NewAppsecException::getParamName() const
{
vector<string> param_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "paramName") {
param_names.push_back(condition.getvalue());
}
}
return param_names;
}
const vector<string>
NewAppsecException::getParamValue() const
{
vector<string> param_values;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "paramValue") {
param_values.push_back(condition.getvalue());
}
}
return param_values;
}
const vector<string>
NewAppsecException::getProtectionName() const
{
vector<string> protection_names;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "protectionName") {
protection_names.push_back(condition.getvalue());
}
}
return protection_names;
}
const vector<string>
NewAppsecException::getSourceIdentifier() const
{
vector<string> source_identifiers;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "sourceIdentifier") {
source_identifiers.push_back(condition.getvalue());
}
}
return source_identifiers;
}
const vector<string>
NewAppsecException::getSourceIp() const
{
vector<string> source_ips;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "sourceIp") {
source_ips.push_back(condition.getvalue());
}
}
return source_ips;
}
const vector<string>
NewAppsecException::getUrl() const
{
vector<string> urls;
for (const NewAppsecExceptionCondition &condition : conditions) {
if (condition.getKey() == "url") {
urls.push_back(condition.getvalue());
}
}
return urls;
}
// LCOV_EXCL_STOP

View File

@@ -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<string> valid_severities = {"high", "critical"};
static const set<string> valid_protocols = {"tcp", "udp"};
static const set<string> valid_formats = {"json", "json-formatted"};
void
NewAppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging";
parseAppsecJSONKey<bool>("allowEvents", allow_events, archive_in, false);
parseAppsecJSONKey<bool>("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<bool>("enabled", enabled, archive_in, true);
parseAppsecJSONKey<bool>("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<bool>("responseCode", response_code, archive_in, false);
parseAppsecJSONKey<string>("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<bool>("detectEvents", detect_events, archive_in, false);
parseAppsecJSONKey<bool>("preventEvents", prevent_events, archive_in, true);
parseAppsecJSONKey<bool>("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<bool>("httpHeaders", http_headers, archive_in, false);
parseAppsecJSONKey<bool>("requestBody", request_body, archive_in, false);
parseAppsecJSONKey<bool>("urlPath", url_path, archive_in, false);
parseAppsecJSONKey<bool>("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<string>("address", address, archive_in);
parseAppsecJSONKey<string>("proto", proto, archive_in);
if (valid_protocols.count(proto) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Logging Service - proto invalid: " << proto;
}
parseAppsecJSONKey<int>("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<string>("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<bool>("cloud", cloud, archive_in, false);
auto mode = Singleton::Consume<I_AgentDetails>::by<NewAppsecTriggerLogDestination>()->getOrchestrationMode();
auto env_type = Singleton::Consume<I_EnvDetails>::by<NewAppsecTriggerLogDestination>()->getEnvType();
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
NewStdoutLogging stdout_log;
parseAppsecJSONKey<NewStdoutLogging>("stdout", stdout_log, archive_in);
agent_local = !(stdout_log.getFormat().empty());
beautify_logs = stdout_log.getFormat() == "json-formatted";
parseAppsecJSONKey<NewLoggingService>("syslogService", syslog_service, archive_in);
parseAppsecJSONKey<NewLoggingService>("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<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewAppsecTriggerAccessControlLogging>(
"accessControlLogging",
access_control_logging,
archive_in
);
parseAppsecJSONKey<NewAppsecTriggerAdditionalSuspiciousEventsLogging>(
"additionalSuspiciousEventsLogging",
additional_suspicious_events_logging,
archive_in
);
parseAppsecJSONKey<NewAppsecTriggerLogging>("appsecLogging", appsec_logging, archive_in);
parseAppsecJSONKey<NewAppsecTriggerExtendedLogging>("extendedLogging", extended_logging, archive_in);
parseAppsecJSONKey<NewAppsecTriggerLogDestination>("logDestination", log_destination, archive_in);
parseAppsecJSONKey<string>("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

View File

@@ -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<string> performance_impacts = {"low", "medium", "high"};
static const set<string> severity_levels = {"low", "medium", "high", "critical"};
static const set<string> size_unit = {"bytes", "KB", "MB", "GB"};
static const set<string> confidences_actions = {"prevent", "detect", "inactive"};
static const set<string> valid_modes = {"prevent", "detect", "inactive", "prevent-learn", "detect-learn"};
static const set<string> valid_confidences = {"medium", "high", "critical"};
static const std::unordered_map<std::string, std::string> key_to_performance_impact_val = {
{ "low", "Low or lower"},
{ "medium", "Medium or lower"},
{ "high", "High or lower"}
};
static const std::unordered_map<std::string, std::string> key_to_severity_level_val = {
{ "low", "Low or above"},
{ "medium", "Medium or above"},
{ "high", "High or above"},
{ "critical", "Critical"}
};
static const std::unordered_map<std::string, std::string> key_to_mode_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
static const std::unordered_map<std::string, int> 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<string>("uri", uri, archive_in);
}
const string &
NewAppSecWebBotsURI::getURI() const
{
return uri;
}
std::vector<std::string>
NewAppSecPracticeAntiBot::getIjectedUris() const
{
vector<string> injected;
for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
return injected;
}
std::vector<std::string>
NewAppSecPracticeAntiBot::getValidatedUris() const
{
vector<string> 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<vector<NewAppSecWebBotsURI>>("injectedUris", injected_uris, archive_in);
parseAppsecJSONKey<vector<NewAppSecWebBotsURI>>("validatedUris", validated_uris, archive_in);
parseAppsecJSONKey<string>("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<string> injected;
vector<string> 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<string>("csrfEnabled", csrf_protection, archive_in, "inactive");
parseAppsecJSONKey<string>("errorDisclosureEnabled", error_disclosure, archive_in, "inactive");
parseAppsecJSONKey<string>("openRedirectEnabled", open_redirect, archive_in, "inactive");
parseAppsecJSONKey<bool>("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<NewAppSecWebAttackProtections>("protections", protections, archive_in);
parseAppsecJSONKey<string>("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<string>("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<int>("maxBodySizeKb", max_body_size_kb, archive_in, 1000000);
parseAppsecJSONKey<int>("maxHeaderSizeBytes", max_header_size_bytes, archive_in, 102400);
parseAppsecJSONKey<int>("maxObjectDepth", max_object_depth, archive_in, 40);
parseAppsecJSONKey<int>("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<string>("overrideMode", override_mode, archive_in, "Inactive");
parseAppsecJSONKey<vector<string>>("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<string> &
NewSnortSignaturesAndOpenSchemaAPI::getConfigMap() const
{
return config_map;
}
void
IpsProtectionsRulesSection::save(cereal::JSONOutputArchive &out_ar) const
{
vector<string> 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<IpsProtectionsRulesSection> &_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<string>("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<string>("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<string>("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<string>("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<string>("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<string>("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<int>("minCveYear", min_cve_Year, archive_in);
}
vector<IpsProtectionsRulesSection>
NewIntrusionPrevention::createIpsRules() const
{
vector<IpsProtectionsRulesSection> 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<bool>("extractArchiveFiles", extract_archive_files, archive_in);
parseAppsecJSONKey<int>("scanMaxFileSize", scan_max_file_size, archive_in, 0);
parseAppsecJSONKey<string>("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<string>(
"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<string>(
"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<int>("fileSizeLimit", file_size_limit, archive_in);
parseAppsecJSONKey<string>("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<string>(
"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<string>("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<string>("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<string>("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<string>("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<string>("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<string>("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<bool>("threatEmulationEnabled", threat_emulation_enabled, archive_in);
parseAppsecJSONKey<NewFileSecurityArchiveInspection>("archiveInspection", archive_inspection, archive_in);
parseAppsecJSONKey<NewFileSecurityLargeFileInspection>("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<NewSnortSignaturesAndOpenSchemaAPI>(
"openapi-schema-validation",
openapi_schema_validation,
archive_in
);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewFileSecurity>("fileSecurity", file_security, archive_in);
parseAppsecJSONKey<NewIntrusionPrevention>("intrusionPrevention", intrusion_prevention, archive_in);
parseAppsecJSONKey<NewSnortSignaturesAndOpenSchemaAPI>("snortSignatures", snort_signatures, archive_in);
parseAppsecJSONKey<NewAppSecPracticeWebAttacks>("webAttacks", web_attacks, archive_in);
parseAppsecJSONKey<NewAppSecPracticeAntiBot>("antiBot", anti_bot, archive_in);
parseAppsecJSONKey<string>("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

View File

@@ -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<string> 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<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<int>("minNumOfSources", min_num_of_sources, archive_in, 3);
parseAppsecJSONKey<vector<string>>("sourcesIdentifiers", sources_identifiers, archive_in);
parseAppsecJSONKey<string>("name", name, archive_in);
}
void
NewTrustedSourcesSpec::setName(const string &_name)
{
name = _name;
}
int
NewTrustedSourcesSpec::getMinNumOfSources() const
{
return min_num_of_sources;
}
const vector<string> &
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<string>("sourceIdentifier", identifier, archive_in);
if (valid_identifiers.count(identifier) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec identifier invalid: " << identifier;
}
parseAppsecJSONKey<vector<string>>("value", value, archive_in);
}
const string &
Identifier::getIdentifier() const
{
return identifier;
}
const vector<string> &
Identifier::getValues() const
{
return value;
}
void
NewSourcesIdentifiers::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Sources Identifiers";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<vector<Identifier>>("sourcesIdentifiers", sources_identifiers, archive_in);
parseAppsecJSONKey<string>("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<Identifier> &
NewSourcesIdentifiers::getSourcesIdentifiers() const
{
return sources_identifiers;
}
// LCOV_EXCL_STOP

View File

@@ -249,6 +249,14 @@ UsersIdentifier::UsersIdentifier(const string &_source_identifier, vector<string
identifier_values(_identifier_values)
{}
// LCOV_EXCL_START Reason: no test exist
const string &
UsersIdentifier::getIdentifier() const
{
return source_identifier;
}
// LCOV_EXCL_STOP
void
UsersIdentifier::save(cereal::JSONOutputArchive &out_ar) const
{
@@ -270,6 +278,14 @@ UsersIdentifiersRulebase::UsersIdentifiersRulebase(
source_identifiers(_source_identifiers)
{}
// LCOV_EXCL_START Reason: no test exist
const string &
UsersIdentifiersRulebase::getIdentifier() const
{
return source_identifiers[0].getIdentifier();
}
// LCOV_EXCL_STOP
void
UsersIdentifiersRulebase::save(cereal::JSONOutputArchive &out_ar) const
{

View File

@@ -1,3 +1,3 @@
add_library(manifest_controller manifest_controller.cc manifest_diff_calculator.cc manifest_handler.cc)
add_subdirectory(manifest_controller_ut)
#add_subdirectory(manifest_controller_ut)

View File

@@ -7,4 +7,4 @@ add_library(
data.cc
)
add_subdirectory(modules_ut)
#add_subdirectory(modules_ut)

View File

@@ -449,7 +449,7 @@ public:
<< filesystem_prefix;
map<string, string> service_policies_copy = status.getServicePolicies();
for (const pair<string, string> &policy: service_policies_copy) {
for (const auto &policy: service_policies_copy) {
setServiceConfiguration(policy.first, policy.second, OrchestrationStatusConfigType::POLICY);
}

View File

@@ -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<HealthCheckStatusEvent>
{
@@ -202,7 +198,10 @@ public:
ReportIS::Audience::INTERNAL
);
hybrid_mode_metric.registerListener();
loadExistingTenantsFromConfDir();
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
orchestration_tools->loadTenantsFromDir(
getConfigurationWithDefault<string>(getFilesystemPathConfig() + "/conf/", "orchestration", "Conf dir")
);
}
void
@@ -242,8 +241,14 @@ private:
);
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
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<I_UpdateCommunication>::by<OrchestrationComp>();
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<I_ServiceController>::by<OrchestrationComp>();
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<string>(
getFilesystemPathConfig()+ "/conf/",
"orchestration",
"Conf dir"
);
string shell_cmd_string = ls_prefix + global_conf_dir + extract_tenant_profile_suffix;
auto shell = Singleton::Consume<I_ShellCmd>::by<OrchestrationComp>();
Maybe<string> 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<I_TenantManager>::by<OrchestrationComp>();
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<string>(
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<OrchestrationPolicy>
loadOrchestrationPolicy()
{
@@ -416,10 +370,11 @@ private:
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
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<OrchestrationPolicy>(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<OrchestrationPolicy>(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<OrchestrationPolicy>(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<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(new_policy_version);
}
auto update_communication = Singleton::Consume<I_UpdateCommunication>::by<OrchestrationComp>();
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<I_ServiceController>::by<OrchestrationComp>();
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<string>(
filesystem_prefix + "/conf/policy.json",
@@ -987,6 +952,22 @@ private:
policy_version
);
auto agent_mode = Singleton::Consume<I_AgentDetails>::by<OrchestrationComp>()->getOrchestrationMode();
auto policy_mgmt_mode = getSettingWithDefault<string>("management", "profileManagedMode");
if (agent_mode == OrchestrationMode::HYBRID || policy_mgmt_mode == "declarative") {
auto upgrade_mode = getSettingWithDefault<string>("manual", "upgradeMode");
if (upgrade_mode != "scheduled") {
request.setUpgradeFields(upgrade_mode);
} else {
request.setUpgradeFields(
upgrade_mode,
getSettingWithDefault<string>("0:00", "upgradeTime"),
getSettingWithDefault<uint>(4, "upgradeDurationHours"),
getSettingWithDefault<vector<string>>({}, "upgradeDay")
);
}
}
auto greedy_update = getProfileAgentSettingWithDefault<bool>(false, "orchestration.multitenancy.greedymode");
greedy_update = getConfigurationWithDefault<bool>(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<I_ServiceController>::by<OrchestrationComp>();
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<I_OrchestrationTools>::by<OrchestrationComp>();
auto conf_dir = getConfigurationWithDefault<string>(
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<I_AgentDetails>::by<OrchestrationComp>();
if (
i_agent_details->getOrchestrationMode() == OrchestrationMode::HYBRID ||
getSettingWithDefault<string>("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<int>())) {
agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true");
@@ -1584,7 +1584,9 @@ private:
while (true) {
static int failure_count = 0;
Singleton::Consume<I_Environment>::by<OrchestrationComp>()->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<I_ShellCmd>::by<OrchestrationComp>();
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<vector<string>>("orchestration", "Orchestration status ignored policies");
registerExpectedSetting<string>("agentType");
registerExpectedSetting<string>("upgradeMode");
registerExpectedSetting<string>("upgradeTime");
registerExpectedSetting<uint>("upgradeDurationHours");
registerExpectedSetting<vector<string>>("upgradeDay");
registerExpectedSetting<string>("email-address");
registerExpectedSetting<string>("registered-server");
registerExpectedConfigFile("orchestration", Config::ConfigFileType::Policy);

View File

@@ -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 <netdb.h>
#include <arpa/inet.h>
@@ -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<I_OrchestrationTools>::From<OrchestrationTools>
{
@@ -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<string> 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<I_ShellCmd>::by<OrchestrationTools>();
Maybe<string> 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<I_TenantManager>::by<OrchestrationTools>();
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<string>
OrchestrationTools::Impl::calculateChecksum(Package::ChecksumTypes checksum_type, const string &path) const
{

View File

@@ -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<I_OrchestrationTools>::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<I_OrchestrationTools>::from(orchestration_tools);
StrictMock<MockTenantManager> mock_tenant_manager;
StrictMock<MockShellCmd> 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"

View File

@@ -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>(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<void>()));
EXPECT_CALL(
mock_service_controller,
@@ -458,7 +448,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
"2611",
false
)
).WillOnce(Return(true));
).WillOnce(Return(Maybe<void>()));
EXPECT_CALL(
mock_service_controller,
@@ -470,7 +460,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
"2311",
true
)
).WillOnce(Return(true));
).WillOnce(Return(Maybe<void>()));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.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);
}

View File

@@ -94,17 +94,7 @@ public:
)).WillRepeatedly(DoAll(SaveArg<1>(&message_body), Return(Maybe<string>(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>(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<void>()));
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<void>()));
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<void>()));
// Rollback related test: The old policy version 12 is restored
EXPECT_CALL(mock_update_communication, sendPolicyVersion("12")).Times(1).WillOnce(Return(Maybe<void>()));
EXPECT_CALL(mock_update_communication, sendPolicyVersion("12", _)).Times(1).WillOnce(Return(Maybe<void>()));
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<void>()));
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _)
).WillOnce(Return(true));
).WillOnce(Return(Maybe<void>()));
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<void>()));
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<void>()));
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<void>()));
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<void>()));
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _)
).WillOnce(Return(true));
).WillOnce(Return(Maybe<void>()));
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<void>()));
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<void>()));
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<void>()));
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<void>()));
set<string> 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<void>(genError(string("")))));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.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<void>()));
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<void>()));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.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<void>()));
vector<string> 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<void>()));
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));

View File

@@ -1,3 +1,3 @@
add_library(package_handler package_handler.cc)
add_subdirectory(package_handler_ut)
#add_subdirectory(package_handler_ut)

View File

@@ -1,3 +1,3 @@
add_library(service_controller service_controller.cc)
add_subdirectory(service_controller_ut)
#add_subdirectory(service_controller_ut)

View File

@@ -269,13 +269,13 @@ class ServiceController::Impl
public:
void init();
bool
Maybe<void>
updateServiceConfiguration(
const string &new_policy_path,
const string &new_settings_path,
const vector<string> &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<string> &nano_services_to_update, const string &policy_version);
Maybe<void> sendSignalForServices(
const set<string> &nano_services_to_update,
const string &policy_version_to_update);
bool updateServiceConfigurationFile(
Maybe<void> 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<string, ServiceDetails> registered_services;
map<string, ServiceDetails> 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<I_OrchestrationTools>::by<ServiceController>();
string dir = getConfigurationWithDefault<string>(
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<void>
ServiceController::Impl::updateServiceConfiguration(
const string &new_policy_path,
const string &new_settings_path,
const vector<string> &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<void>();
}
Maybe<string> 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<string>(
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<I_TenantManager>::by<ServiceController>()->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<string>(
(child_tenant_id != "" ? "tenant_" + child_tenant_id + "_profile_" + child_profile_id + "/" : "");
string config_file_path = getConfigurationWithDefault<string>(
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<void>();
}
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<void>();
}
bool
Maybe<void>
ServiceController::Impl::sendSignalForServices(
const set<string> &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<void>();
}
case ReconfStatus::IN_PROGRESS: {
dbgTrace(D_ORCHESTRATOR) << "Reconfiguration in progress...";
@@ -918,8 +958,10 @@ ServiceController::Impl::sendSignalForServices(
break;
}
case ReconfStatus::FAILED: {
vector<string> 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<void>
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<void>();
}
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<void>();
}
ServiceController::ServiceController() : Component("ServiceController"), pimpl(make_unique<Impl>()) {}
@@ -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
{

View File

@@ -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<map<string, string>> json_parser_return =
map<string, string>({{"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<MessageConnConfig> 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<string>(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<string>(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<string>(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<string>(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<string>(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<string>(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<string>(reply_msg)));
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, "").ok());
set<string> 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<string> 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);
}

View File

@@ -1,2 +1,2 @@
add_library(update_communication update_communication.cc hybrid_communication.cc fog_communication.cc fog_authenticator.cc local_communication.cc declarative_policy_utils.cc)
add_subdirectory(update_communication_ut)
#add_subdirectory(update_communication_ut)

View File

@@ -177,6 +177,16 @@ FogAuthenticator::registerAgent(
request << details;
}
auto i_agent_details = Singleton::Consume<I_AgentDetails>::by<FogAuthenticator>();
if (
i_agent_details->getOrchestrationMode() == OrchestrationMode::HYBRID ||
getSettingWithDefault<string>("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<I_Messaging>::by<FogAuthenticator>();
if (fog_messaging->sendObject(request, HTTPMethod::POST, fog_address_ex + "/agents")) {
dbgDebug(D_ORCHESTRATOR) << "Agent has registered successfully.";
auto i_agent_details = Singleton::Consume<I_AgentDetails>::by<FogAuthenticator>();
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<I_AgentDetails>::by<FogAuthenticator>()->loadAccessToken();
return AccessToken(request.getAccessToken(), chrono::seconds(request.getExpirationTime()));
}

View File

@@ -117,13 +117,20 @@ FogCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
}
Maybe<void>
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<I_Messaging>::by<FogCommunication>();
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<void>();

View File

@@ -157,7 +157,7 @@ HybridCommunication::downloadAttributeFile(const GetResourceFile &resourse_file)
}
Maybe<void>
HybridCommunication::sendPolicyVersion(const string &policy_version) const
HybridCommunication::sendPolicyVersion(const string &policy_version, const string &) const
{
dbgFlow(D_ORCHESTRATOR);
policy_version.empty();

View File

@@ -175,7 +175,7 @@ LocalCommunication::setAddressExtenesion(const string &)
}
Maybe<void>
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<void>();

View File

@@ -75,9 +75,9 @@ public:
}
Maybe<void>
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<string>

View File

@@ -39,9 +39,9 @@ public:
}
Maybe<void>
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<string>
@@ -228,6 +228,6 @@ TEST_F(LocalCommunicationTest, setAddressExtenesion)
TEST_F(LocalCommunicationTest, sendPolicyVersion)
{
auto res = sendPolicyVersion("12");
auto res = sendPolicyVersion("12", "");
EXPECT_TRUE(res.ok());
}

View File

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

View File

@@ -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<BufferedParser<ParserUrlEncode>>(*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<BufferedParser<ParserPercentEncode>>(*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<BufferedParser<ParserHTML>>(*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<BufferedParser<PHPSerializedDataParser>>(*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<BufferedParser<ParserGql>>(*this));
}
else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{'))
{
} else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{')) {
boost::smatch confulence_match;
if (NGEN::Regex::regexMatch(__FILE__, __LINE__, cur_val, confulence_match, signatures->confluence_macro_re))

View File

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

View File

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

View File

@@ -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 <string.h>
#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

View File

@@ -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<std::string, KeywordsScorePool> &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<std::string, KeywordData> &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<std::string, KeywordsScorePool> &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];

View File

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

View File

@@ -95,6 +95,7 @@ private:
std::shared_ptr<Waap::TrustedSources::TrustedSourcesParameter> m_trustedSourcesPolicy;
std::shared_ptr<Waap::Parameters::WaapParameters> m_waapParameters;
std::shared_ptr<Waap::OpenRedirect::Policy> m_openRedirectPolicy;
std::vector<std::string> m_applicationUrls;
std::shared_ptr<Waap::ErrorDisclosure::Policy> m_errorDisclosurePolicy;
std::string m_schemaValidationPoicyStatusMessage;
std::shared_ptr<Waap::Csrf::Policy> m_csrfPolicy;

View File

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

View File

@@ -34,6 +34,7 @@ struct ValueStatsAnalyzer
bool canSplitPipe;
bool hasSpace;
bool isUrlEncoded;
std::string textual;
};

View File

@@ -2277,7 +2277,7 @@ void Waf2Transaction::collectFoundPatterns()
{
if (m_scanResult)
{
for (const std::pair<std::string, std::vector<std::string>> &found_pattern : m_scanResult->found_patterns)
for (const auto &found_pattern : m_scanResult->found_patterns)
{
const std::string &regex_name = found_pattern.first; // the regex name (key)
m_found_patterns.insert(regex_name);

View File

@@ -1044,14 +1044,14 @@ namespace Util {
// trim from start
static inline std::string &ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(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<int, int>(std::isspace))).base(), s.end());
[] (char c) { return !std::isspace(c); }).base(), s.end());
return s;
}

View File

@@ -17,6 +17,8 @@
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include "config.h"
#include "debug.h"
@@ -36,6 +38,46 @@ void
AgentDetails::init()
{
registerMachineType();
loadAccessToken();
Singleton::Consume<I_MainLoop>::by<AgentDetails>()->addRecurringRoutine(
I_MainLoop::RoutineType::System,
chrono::seconds(60),
[this] () { loadAccessToken(); },
"Load access token"
);
proxies = {
{ProxyProtocol::HTTP, ProxyData()},
{ProxyProtocol::HTTPS, ProxyData()}
};
auto proxy_config = getProfileAgentSetting<string>("agent.config.message.proxy");
if (proxy_config.ok()) {
setProxy(*proxy_config);
writeAgentDetails();
}
registerConfigLoadCb(
[&]()
{
auto proxy_config = getProfileAgentSetting<string>("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<string>(
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<I_AgentDetails::MachineType>
AgentDetails::getMachineTypeFromDmiTable()
{
@@ -300,3 +372,235 @@ AgentDetails::registerMachineType()
);
dbgInfo(D_ORCHESTRATOR) << "Setting machine type " << static_cast<int>(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<int>(proto);
return "";
}
Maybe<void>
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<void>();
}
Maybe<string>
AgentDetails::loadProxyType(const string &proxy_type)
{
readAgentDetails();
auto proxy_config = getProxy();
if (proxy_config.ok()) {
if (proxy_config.unpack() == "none") {
return Maybe<string>(string());
}
return proxy_config;
}
#ifdef gaia
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<AgentDetails>();
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>(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>(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>(string());
#endif // gaia
}
Maybe<void>
AgentDetails::loadProxyType(ProxyProtocol protocol)
{
dbgAssert(protocol == ProxyProtocol::HTTP || protocol == ProxyProtocol::HTTPS)
<< "Unsupported Proxy Protocol " << static_cast<int>(protocol);
static const map<ProxyProtocol, string> 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<void>();
}
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<uint16_t>(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<void>();
}
proxies.at(protocol) = env_proxy_data;
dbgInfo(D_ORCHESTRATOR)
<< convertProxyProtocolToString(protocol)
<< " proxy was successfully loaded, "
<< getProxyAddress(protocol).unpack();
return Maybe<void>();
}
Maybe<string>
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<string>
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<uint16_t>
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<string>
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<void>
AgentDetails::loadProxy()
{
if (getConfigurationFlag("orchestration-mode") == "offline_mode") return Maybe<void>();
for (const auto &proxy_type : proxies) {
auto loaded_proxy = loadProxyType(proxy_type.first);
if (!loaded_proxy.ok()) return loaded_proxy;
}
return Maybe<void>();
}

View File

@@ -1,7 +1,11 @@
#include "agent_details.h"
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#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<MockEncryptor> mock_encryptor;
StrictMock<MockShellCmd> mock_shell_cmd;
Config::I_Config *config = nullptr;
StrictMock<MockMainLoop> mock_ml;
};
TEST_F(AgentDetailsTest, doNothing)
{
}
TEST_F(AgentDetailsTest, basicTest)
{
const vector<string> 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<Config::I_Config>::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<I_Environment>::from(env)->get<I_AgentDetails::MachineType>("MachineType");
EXPECT_EQ(machine_type.unpack(), I_AgentDetails::MachineType::AZURE);
}
TEST_F(AgentDetailsTest, openSSL)
{
const vector<string> 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<I_Environment>::from(env)->get<I_AgentDetails::MachineType>("MachineType");
EXPECT_EQ(machine_type.unpack(), I_AgentDetails::MachineType::UNRECOGNIZED);
}

View File

@@ -192,7 +192,7 @@ AgentDetailsReporter::Impl::addAttr(const map<string, string> &attr, bool allow_
{
dbgFlow(D_AGENT_DETAILS);
bool ret = true;
for (const pair<string, string> &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<string, string> &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<string, string> &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<string, string> &new_attr : new_attributes) {
for (const auto &new_attr : new_attributes) {
attributes[new_attr.first] = new_attr.second;
}
AttrSerializer<ofstream, cereal::JSONOutputArchive>(attributes, "save");

View File

@@ -823,7 +823,7 @@ ConfigComponent::Impl::fillMultiTenantExpectedConfigFiles(const map<string, set<
auto global_path = getPolicyConfigPath(config_file.first, type);
auto it = find(files.begin(), files.end(), global_path);
if (it == files.end()) files.push_back(global_path);
for (const pair<string, set<string>> &tenant_profiles : active_tenants) {
for (const auto &tenant_profiles : active_tenants) {
const string &tenant = tenant_profiles.first;
const set<string> &profile_ids = tenant_profiles.second;
for (const auto &profile_id : profile_ids) {

Some files were not shown because too many files have changed in this diff Show More