Aug_23_2023-Dev

This commit is contained in:
Ned Wright
2023-08-23 14:15:32 +00:00
parent 702c1184ea
commit b25fd8def5
115 changed files with 8292 additions and 1189 deletions

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

View File

@@ -12,6 +12,7 @@
// limitations under the License.
#include <stdio.h>
#include <bitset>
#include <string.h>
#include <arpa/inet.h>
@@ -142,6 +143,130 @@ IPAddr::isInRange(const IPAddr &left, const IPAddr &right) const
return (*this >= left) && (*this <= right);
}
Maybe<string>
IPAddr::calculateSubnetStart(int subnet_value)
{
if (type == IPType::V4) {
return calculateSubnetStartV4(subnet_value);
} else {
return calculateSubnetStartV6(subnet_value);
}
}
Maybe<string>
IPAddr::calculateSubnetEnd(int subnet_value)
{
if (type == IPType::V4) {
return calculateSubnetEndV4(subnet_value);
} else {
return calculateSubnetEndV6(subnet_value);
}
}
Maybe<string>
IPAddr::calculateSubnetStartV4(int subnet_value)
{
if (subnet_value < 0 || subnet_value > 32) {
return genError("Invalid subnet value: ");
}
uint32_t ip = ntohl(v4.s_addr);
uint32_t mask = (0xFFFFFFFF << (32 - subnet_value));
uint32_t subnet = ip & mask;
subnet = ntohl(subnet);
return string(inet_ntoa(*(struct in_addr *)&subnet));
}
Maybe<string>
IPAddr::calculateSubnetStartV6(int subnet_value)
{
if (subnet_value < 0 || subnet_value > 128) {
return genError("Invalid subnet value: ");
}
// represent IPV6 as a binary
bitset<128> mask;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 8; ++j) {
mask[i * 8 + j] = (v6.s6_addr[i] >> (7 - j)) & 1;
}
}
// set the subnet bits to 0
for (int i = subnet_value; i < 128; i++) {
mask.reset(i);
}
// convert the binary to IPV6
for (int i = 0; i < 16; ++i) {
uint8_t byteValue = 0;
for (int j = 0; j < 8; ++j) {
byteValue |= (mask[i * 8 + j] << (7 - j));
}
v6.s6_addr[i] = byteValue;
}
// convert to string
ostringstream oss;
for (int i = 0; i < 16; i+=2) {
if (i > 0)
oss << ":";
oss << hex << ((v6.s6_addr[i] << 8) + v6.s6_addr[i+1]);
}
return oss.str();
}
Maybe<string>
IPAddr::calculateSubnetEndV4(int subnet_value)
{
if (subnet_value < 0 || subnet_value > 32) {
return genError("Invalid subnet value: ");
}
uint32_t ip = ntohl(v4.s_addr);
uint32_t mask = (0xFFFFFFFF << (32 - subnet_value));
uint32_t subnet = ip & mask;
subnet |= ~mask;
subnet = ntohl(subnet);
return string(inet_ntoa(*(struct in_addr *)&subnet));
}
Maybe<string>
IPAddr::calculateSubnetEndV6(int subnet_value)
{
if (subnet_value < 0 || subnet_value > 128) {
return genError("Invalid subnet value: ");
}
// represent IPV6 as a binary
bitset<128> mask;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 8; ++j) {
mask[i * 8 + j] = (v6.s6_addr[i] >> (7 - j)) & 1;
}
}
// set the host bits to 1
for (int i = subnet_value; i < 128; i++) {
mask.set(i);
}
// convert the binary to IPV6
for (int i = 0; i < 16; ++i) {
uint8_t byteValue = 0;
for (int j = 0; j < 8; ++j) {
byteValue |= (mask[i * 8 + j] << (7 - j));
}
v6.s6_addr[i] = byteValue;
}
// convert to string
ostringstream oss;
for (int i = 0; i < 16; i += 2) {
if (i > 0) oss << ":";
oss << hex << ((v6.s6_addr[i] << 8) + v6.s6_addr[i + 1]);
}
return oss.str();
}
Maybe<IPAddr>
IPAddr::createIPAddr(const string &ip_text)
{

View File

@@ -544,7 +544,7 @@ Debug::applyOverrides()
}
} else {
auto should_add_file_stream = true;
for (const pair<string, shared_ptr<Debug::DebugStream>> &elem : active_streams) {
for (const auto &elem : active_streams) {
if (elem.first != "STDOUT" && elem.first != "FOG") should_add_file_stream = false;
break;
}

View File

@@ -17,6 +17,7 @@
#include <vector>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include "cpnano_base64/base64.h"
#include "config.h"

View File

@@ -22,8 +22,8 @@
#include <memory>
#include <iostream>
#include "debug.h"
#include "time_print.h"
#include "debug.h"
#include "singleton.h"
#include "context.h"
#include "table/table_helpers.h"

View File

@@ -25,8 +25,13 @@ public:
:
tenant_id(_tenant_id),
profile_id(_profile_id)
{
}
{}
TenantProfilePair(const std::pair<std::string, std::string> &tenant_profile_pair)
:
tenant_id(tenant_profile_pair.first),
profile_id(tenant_profile_pair.second)
{}
size_t
hash() const

View File

@@ -26,6 +26,7 @@
#include "i_rest_api.h"
#include "i_messaging_buffer.h"
#include "i_shell_cmd.h"
#include "i_proxy_configuration.h"
#include "component.h"
class ProtoMessageComp
@@ -38,7 +39,8 @@ class ProtoMessageComp
Singleton::Consume<I_Encryptor>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_MessagingBuffer>,
Singleton::Consume<I_ShellCmd>
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_ProxyConfiguration>
{
public:
ProtoMessageComp();

View File

@@ -38,12 +38,14 @@ public:
virtual std::string getProfileId() const = 0;
// Agent Details
virtual Maybe<std::string> getProxy() const = 0;
virtual void setProxy(const std::string &_proxy) = 0;
virtual void setAgentId(const std::string &_agent_id) = 0;
virtual std::string getAgentId() const = 0;
virtual Maybe<std::string> getProxy() const = 0;
virtual void setProxy(const std::string &_proxy) = 0;
virtual void setAgentId(const std::string &_agent_id) = 0;
virtual std::string getAgentId() const = 0;
virtual void setOrchestrationMode(OrchestrationMode _orchstration_mode) = 0;
virtual OrchestrationMode getOrchestrationMode() const = 0;
virtual OrchestrationMode getOrchestrationMode() const = 0;
virtual std::string getAccessToken() const = 0;
virtual void loadAccessToken() = 0;
// OpenSSL
virtual void setOpenSSLDir(const std::string &openssl_dir) = 0;

View File

@@ -31,12 +31,6 @@
USE_DEBUG_FLAG(D_COMMUNICATION);
enum class ProxyProtocol
{
HTTP,
HTTPS
};
enum class MessageTypeTag
{
GENERIC,
@@ -141,16 +135,8 @@ public:
return genError("Failed to download file. Error: " + response.getErr());
}
virtual Maybe<std::string> getProxyDomain(ProxyProtocol protocol) const = 0;
virtual Maybe<std::string> getProxyCredentials(ProxyProtocol protocol) const = 0;
virtual Maybe<uint16_t> getProxyPort(ProxyProtocol protocol) const = 0;
virtual bool getProxyExists(ProxyProtocol protocol) const = 0;
virtual Maybe<std::string> getProxyAddress(ProxyProtocol protocol) const = 0;
virtual Maybe<void> loadProxy() = 0;
virtual bool setActiveFog(MessageTypeTag tag) = 0;
virtual void loadAccessToken() = 0;
virtual bool setActiveFog(const string &host, const uint16_t port, bool is_secure, MessageTypeTag tag) = 0;
virtual std::string getAccessToken() = 0;
protected:
~I_Messaging() {}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __I_PROXY_CONFIGURATION_H__
#define __I_PROXY_CONFIGURATION_H__
#include <string>
#include "maybe_res.h"
enum class ProxyProtocol
{
HTTP,
HTTPS
};
class I_ProxyConfiguration
{
public:
virtual Maybe<std::string> getProxyDomain(ProxyProtocol protocol) const = 0;
virtual Maybe<std::string> getProxyCredentials(ProxyProtocol protocol) const = 0;
virtual Maybe<uint16_t> getProxyPort(ProxyProtocol protocol) const = 0;
virtual bool getProxyExists(ProxyProtocol protocol) const = 0;
virtual Maybe<std::string> getProxyAddress(ProxyProtocol protocol) const = 0;
virtual Maybe<void> loadProxy() = 0;
};
#endif // __I_PROXY_CONFIGURATION_H__

View File

@@ -26,6 +26,8 @@ public:
MOCK_METHOD1(setProxy, void(const std::string&));
MOCK_METHOD1(setAgentId, void(const std::string&));
MOCK_CONST_METHOD0(getAgentId, std::string());
MOCK_METHOD0(loadAccessToken, void());
MOCK_CONST_METHOD0(getAccessToken, std::string());
// OpenSSL
MOCK_METHOD1(setOpenSSLDir, void(const std::string&));

View File

@@ -57,20 +57,12 @@ public:
)
);
MOCK_METHOD0(loadAccessToken, void());
MOCK_METHOD0(setActiveFog, bool());
MOCK_METHOD1(setActiveFog, bool(MessageTypeTag));
MOCK_METHOD0(unsetFogProxy, void());
MOCK_METHOD0(loadFogProxy, void());
MOCK_METHOD4(setActiveFog, bool(const string &, const uint16_t, const bool, MessageTypeTag));
MOCK_METHOD0(getAccessToken, string());
MOCK_CONST_METHOD1(getProxyDomain, Maybe<std::string>(ProxyProtocol protocol));
MOCK_CONST_METHOD1(getProxyCredentials, Maybe<std::string>(ProxyProtocol protocol));
MOCK_CONST_METHOD1(getProxyPort, Maybe<uint16_t>(ProxyProtocol protocol));
MOCK_CONST_METHOD1(getProxyExists, bool(ProxyProtocol protocol));
MOCK_CONST_METHOD1(getProxyAddress, Maybe<std::string>(ProxyProtocol protocol));
MOCK_METHOD0(loadProxy, Maybe<void>());
};
#endif // __MOCK_MESSAGING_H__

View File

@@ -20,17 +20,42 @@
#include "i_encryptor.h"
#include "i_shell_cmd.h"
#include "i_environment.h"
#include "i_mainloop.h"
#include "i_proxy_configuration.h"
#include "singleton.h"
#include "component.h"
#include "enum_array.h"
#include "agent_core_utilities.h"
class ProxyData
{
public:
bool
operator==(const ProxyData &other) const
{
return protocol==other.protocol &&
domain==other.domain &&
is_exists==other.is_exists &&
port==other.port &&
auth==other.auth;
}
std::string protocol = "";
std::string domain = "";
std::string auth = "";
bool is_exists = false;
uint16_t port = 0;
};
class AgentDetails
:
public Component,
Singleton::Provide<I_AgentDetails>::SelfInterface,
Singleton::Provide<I_ProxyConfiguration>::SelfInterface,
Singleton::Consume<I_Encryptor>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_Environment>
Singleton::Consume<I_Environment>,
Singleton::Consume<I_MainLoop>
{
public:
AgentDetails() : Component("AgentDetails") {}
@@ -39,15 +64,17 @@ public:
void init();
Maybe<std::string> getProxy() const;
Maybe<std::string> getFogDomain() const;
Maybe<uint16_t> getFogPort() const;
std::string getAgentId() const;
std::string getTenantId() const;
std::string getProfileId() const;
Maybe<std::string> getOpenSSLDir() const;
std::string getClusterId() const;
OrchestrationMode getOrchestrationMode() const;
Maybe<std::string> getProxy() const;
Maybe<std::string> getFogDomain() const;
Maybe<uint16_t> getFogPort() const;
std::string getAgentId() const;
std::string getTenantId() const;
std::string getProfileId() const;
Maybe<std::string> getOpenSSLDir() const;
std::string getClusterId() const;
OrchestrationMode getOrchestrationMode() const;
std::string getAccessToken() const;
void loadAccessToken();
void setFogDomain(const std::string &_fog_domain) { fog_domain = _fog_domain; }
void setFogPort(const uint16_t _fog_port) { fog_port = _fog_port; }
@@ -67,6 +94,14 @@ public:
void serialize(cereal::JSONInputArchive &ar);
void setClusterId(const std::string &_cluster_id);
Maybe<std::string> getProxyDomain(ProxyProtocol protocol) const;
Maybe<std::string> getProxyCredentials(ProxyProtocol protocol) const;
Maybe<uint16_t> getProxyPort(ProxyProtocol protocol) const;
bool getProxyExists(ProxyProtocol protocol) const;
Maybe<std::string> getProxyAddress(ProxyProtocol protocol) const;
Maybe<void> loadProxy();
private:
std::string fog_domain = "";
std::string agent_id = "";
@@ -77,13 +112,27 @@ private:
std::string cluster_id = "";
std::string filesystem_path = "/etc/cp";
std::string log_files_path = "/var/log";
std::string access_token = "";
uint16_t fog_port = 0;
bool encrypted_connection = false;
OrchestrationMode orchestration_mode = OrchestrationMode::ONLINE;
bool is_proxy_configured_via_settings = false;
std::map<ProxyProtocol, ProxyData> proxies;
static const std::map<std::string, I_AgentDetails::MachineType> machineTypes;
void registerMachineType();
Maybe<I_AgentDetails::MachineType> getMachineTypeFromDmiTable();
std::string convertProxyProtocolToString(ProxyProtocol proto) const;
Maybe<void> verifyProxySyntax(
const std::string &protocol,
const std::string &auth,
const std::string &domain,
const std::string &port,
const std::string &env_proxy
);
Maybe<std::string> loadProxyType(const std::string &proxy_type);
Maybe<void> loadProxyType(ProxyProtocol protocol);
};
#endif // __AGENT_DETAILS_H__

View File

@@ -22,6 +22,7 @@
#include "component.h"
#include "time_proxy.h"
#include "time_print.h"
#include "debug.h"
#include "config_component.h"
#include "mainloop.h"

View File

@@ -90,10 +90,12 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_WAAP_PARSER_RAW, D_WAAP_PARSER)
DEFINE_FLAG(D_WAAP_PARSER_URLENCODE, D_WAAP_PARSER)
DEFINE_FLAG(D_WAAP_PARSER_PHPSERIALIZE, D_WAAP_PARSER)
DEFINE_FLAG(D_WAAP_PARSER_PERCENT, D_WAAP_PARSER)
DEFINE_FLAG(D_WAAP_OVERRIDE, D_WAAP)
DEFINE_FLAG(D_IPS, D_COMPONENT)
DEFINE_FLAG(D_FILE_UPLOAD, D_COMPONENT)
DEFINE_FLAG(D_RATE_LIMIT, D_COMPONENT)
DEFINE_FLAG(D_PARSER, D_COMPONENT)
DEFINE_FLAG(D_WS, D_COMPONENT)

View File

@@ -28,7 +28,7 @@ namespace Intelligence
{
enum class ClassifierType { CLASS, CATEGORY, FAMILY, GROUP, ORDER, KIND };
enum class ObjectType { ASSET, ZONE, POLICY_PACKAGE, CONFIGURATION, SESSION };
enum class ObjectType { ASSET, ZONE, POLICY_PACKAGE, CONFIGURATION, SESSION, SHORTLIVED };
class Invalidation
{

View File

@@ -11,8 +11,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/// @file rest.h
/// @brief Header file for RESTful communication functionalities.
///
/// This file defines classes and utilities for RESTful communication, including input/output handling,
/// schema generation, and client-server interactions.
#ifndef __REST_H__
#define __REST_H__
#include "cereal/archives/json.hpp"
#include "cereal/types/common.hpp"
#include "cereal/types/string.hpp"
@@ -24,19 +31,32 @@
#include "debug.h"
#include "maybe_res.h"
#include "rest/schema_printer.h"
/// @class JsonError
/// @brief Class representing JSON parsing errors.
///
/// This class is used to represent errors that occur during JSON parsing.
class JsonError
{
public:
/// @brief Constructor for JsonError class.
/// @param e The error message to be stored.
JsonError(const std::string &e) : err(e) {}
const std::string & getMsg() const { return err; }
/// @brief Retrieves the error message.
/// @return The error message as a constant reference to a string.
const std::string &getMsg() const { return err; }
private:
std::string err;
std::string err; ///< Error message.
};
/// @class BasicRest
/// @brief Base class for RESTful communication handling.
///
/// The BasicRest class provides basic functionalities for handling RESTful communication,
/// including input/output handling, schema generation, and client-server interactions.
class BasicRest
{
using InputFunc = std::function<void(cereal::JSONInputArchive &)>;
@@ -44,16 +64,32 @@ class BasicRest
using SchemaFunc = std::function<void(std::ostream &, int)>;
public:
/// @brief Enumeration representing the direction of communication (Client to Server, Server to Client, or Both).
enum class Direction { C2S, S2C, BOTH };
/// @brief Enumeration representing the type of parameter (Mandatory, Optional, or Default).
enum class ParamType { MANDATORY, OPTIONAL, DEFAULT };
/// @brief Destructor for the BasicRest class.
virtual ~BasicRest() = default;
void load(cereal::JSONInputArchive &ar) { for (auto it : input_funcs) it(ar); }
/// @brief Loads data from the JSON input archive.
/// @param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar) { for (auto it : input_funcs) it(ar); }
/// @brief Saves data to the JSON output archive.
/// @param ar The JSON output archive.
void save(cereal::JSONOutputArchive &ar) const { for (auto it : output_funcs) it(ar); }
/// @brief Outputs the schema to an output stream.
/// @param out The output stream to write the schema to.
/// @param level The indentation level for the schema.
void performOutputingSchema(std::ostream &out, int level = 0);
/// @brief Adds a schema for the given REST parameter type.
/// @tparam RestParamType The type of the REST parameter.
/// @param label The label for the parameter in the schema.
/// @param is_mandatory A boolean indicating whether the parameter is mandatory in the schema.
template <typename RestParamType>
void
addSchema(const std::string &label, bool is_mandatory)
@@ -67,6 +103,12 @@ public:
if (is_mandatory) required.push_back(label);
};
/// @brief Adds an input parameter of the given REST parameter type.
/// @tparam RestParamType The type of the REST parameter.
/// @param param The REST parameter to add as an input.
/// @param label The label for the parameter in the input.
/// @param type The parameter type (Mandatory, Optional, or Default).
/// @param val The default value for the parameter (used for default parameters).
template <typename RestParamType>
void
addInput(RestParam<RestParamType> &param, const std::string &label, ParamType type, const RestParamType &val)
@@ -86,6 +128,12 @@ public:
input_funcs.push_back(func);
}
/// @brief Adds an output parameter of the given REST parameter type.
/// @tparam RestParamType The type of the REST parameter.
/// @param param The REST parameter to add as an output.
/// @param label The label for the parameter in the output.
/// @param type The parameter type (Mandatory, Optional, or Default).
/// @param val The default value for the parameter (used for default parameters).
template <typename RestParamType>
void
addOutput(RestParam<RestParamType> &param, const std::string &label, ParamType type, const RestParamType &val)
@@ -111,37 +159,78 @@ private:
void outputSchema(std::ostream &os, int level);
void outputRequired(std::ostream &os, int level);
std::vector<InputFunc> input_funcs;
std::vector<OutputFunc> output_funcs;
std::vector<SchemaFunc> schema_func;
std::vector<std::string> required;
std::vector<InputFunc> input_funcs; ///< Vector storing input functions.
std::vector<OutputFunc> output_funcs; ///< Vector storing output functions.
std::vector<SchemaFunc> schema_func; ///< Vector storing schema functions.
std::vector<std::string> required; ///< Vector storing the names of required parameters.
};
/// @class ServerRest
/// @brief Class representing a server-side RESTful communication handler.
///
/// The ServerRest class is used for server-side RESTful communication and provides
/// functionality for handling REST calls.
class ServerRest : public BasicRest
{
public:
/// @brief Virtual function for handling a REST call.
virtual void doCall() = 0;
/// @brief Performs the REST call using the input stream.
/// @param in The input stream containing the JSON data for the REST call.
/// @return A Maybe object containing the result of the REST call (either the JSON data or an error message).
Maybe<std::string> performRestCall(std::istream &in);
protected:
static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; }
/// @brief Determines if the direction is for input.
/// @param dir The direction of the communication.
/// @return True if the direction is for input, false otherwise.
static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; }
/// @brief Determines if the direction is for output.
/// @param dir The direction of the communication.
/// @return True if the direction is for output, false otherwise.
static constexpr bool isOutput(BasicRest::Direction dir) { return dir != BasicRest::Direction::C2S; }
/// @brief Determines if the direction is for schema.
/// @param dir The direction of the communication.
/// @return True if the direction is for schema, false otherwise.
static constexpr bool isSchema(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; }
};
/// @class ClientRest
/// @brief Class representing a client-side RESTful communication handler.
///
/// The ClientRest class is used for client-side RESTful communication and provides
/// functionality for generating and loading JSON data.
class ClientRest : public BasicRest
{
public:
/// @brief Generates JSON data from the object's state.
/// @return A Maybe object containing the JSON data, or an error message if serialization fails.
Maybe<std::string> genJson() const;
/// @brief Loads JSON data into the object's state.
/// @param json The JSON data to be loaded.
/// @return True if the JSON data is successfully loaded, false otherwise.
bool loadJson(const std::string &json);
protected:
static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::C2S; }
static constexpr bool isOutput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; }
static constexpr bool isSchema(BasicRest::Direction) { return false; }
};
/// @brief Determines if the direction is for input.
/// @param dir The direction of the communication.
/// @return True if the direction is for input, false otherwise.
static constexpr bool isInput(BasicRest::Direction dir) { return dir != BasicRest::Direction::C2S; }
/// @brief Determines if the direction is for output.
/// @param dir The direction of the communication.
/// @return True if the direction is for output, false otherwise.
static constexpr bool isOutput(BasicRest::Direction dir) { return dir != BasicRest::Direction::S2C; }
/// @brief Determines if the direction is for schema.
/// @param dir The direction of the communication.
/// @return True if the direction is for schema, false otherwise.
static constexpr bool isSchema(BasicRest::Direction) { return false; }
};
template <bool is_input>
class InputAdder
@@ -303,34 +392,217 @@ private:
std::map<std::string, N> obj;
};
/// @def C2S_LABEL_PARAM(type, name, label)
/// @brief Add a mandatory parameter for the Client-to-Server (C2S) direction.
///
/// This macro is used to add a mandatory parameter to a REST request sent from
/// the client to the server.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
#define C2S_LABEL_PARAM(type, name, label) \
ADD_MANDATORY_PARAM(BasicRest::Direction::C2S, type, name, label)
/// @def S2C_LABEL_PARAM(type, name, label)
/// @brief Add a mandatory parameter for the Server-to-Client (S2C) direction.
///
/// This macro is used to add a mandatory parameter to a REST response sent from
/// the server to the client.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
#define S2C_LABEL_PARAM(type, name, label) \
ADD_MANDATORY_PARAM(BasicRest::Direction::S2C, type, name, label)
/// @def BOTH_LABEL_PARAM(type, name, label)
/// @brief Add a mandatory parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions.
///
/// This macro is used to add a mandatory parameter that is used in both the request
/// and response of a REST communication.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
#define BOTH_LABEL_PARAM(type, name, label) \
ADD_MANDATORY_PARAM(BasicRest::Direction::BOTH, type, name, label)
/// @def C2S_PARAM(type, name)
/// @brief Add a mandatory parameter for the Client-to-Server (C2S) direction with the parameter
/// label being the same as the parameter name.
///
/// This macro is a shorthand for adding a mandatory parameter to a REST request with
/// the same label as the parameter name.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
#define C2S_PARAM(type, name) C2S_LABEL_PARAM(type, name, #name)
/// @def S2C_PARAM(type, name)
/// @brief Add a mandatory parameter for the Server-to-Client (S2C) direction with the parameter
/// label being the same as the parameter name.
///
/// This macro is a shorthand for adding a mandatory parameter to a REST response with
/// the same label as the parameter name.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
#define S2C_PARAM(type, name) S2C_LABEL_PARAM(type, name, #name)
/// @def BOTH_PARAM(type, name)
/// @brief Add a mandatory parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions
/// with the parameter label being the same as the parameter name.
///
/// This macro is a shorthand for adding a mandatory parameter that is used in both the
/// request and response of a REST communication with the same label as the parameter name.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
#define BOTH_PARAM(type, name) BOTH_LABEL_PARAM(type, name, #name)
/// @def C2S_LABEL_OPTIONAL_PARAM(type, name, label)
/// @brief Add an optional parameter for the Client-to-Server (C2S) direction.
///
/// This macro is used to add an optional parameter to a REST request sent from the client
/// to the server.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
#define C2S_LABEL_OPTIONAL_PARAM(type, name, label) \
ADD_OPTIONAL_PARAM(BasicRest::Direction::C2S, type, name, label)
/// @def S2C_LABEL_OPTIONAL_PARAM(type, name, label)
/// @brief Add an optional parameter for the Server-to-Client (S2C) direction.
///
/// This macro is used to add an optional parameter to a REST response sent from the server
/// to the client.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
#define S2C_LABEL_OPTIONAL_PARAM(type, name, label) \
ADD_OPTIONAL_PARAM(BasicRest::Direction::S2C, type, name, label)
/// @def BOTH_LABEL_OPTIONAL_PARAM(type, name, label)
/// @brief Add an optional parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions.
///
/// This macro is used to add an optional parameter that can be used in both the request
/// and response of a REST communication.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
#define BOTH_LABEL_OPTIONAL_PARAM(type, name, label) \
ADD_OPTIONAL_PARAM(BasicRest::Direction::BOTH, type, name, label)
/// @def C2S_OPTIONAL_PARAM(type, name)
/// @brief Add an optional parameter for the Client-to-Server (C2S) direction with the parameter label
/// being the same as the parameter name.
///
/// This macro is a shorthand for adding an optional parameter to a REST request with
/// the same label as the parameter name.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
#define C2S_OPTIONAL_PARAM(type, name) C2S_LABEL_OPTIONAL_PARAM(type, name, #name)
/// @def S2C_OPTIONAL_PARAM(type, name)
/// @brief Add an optional parameter for the Server-to-Client (S2C) direction with the parameter label
/// being the same as the parameter name.
///
/// This macro is a shorthand for adding an optional parameter to a REST response with
/// the same label as the parameter name.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
#define S2C_OPTIONAL_PARAM(type, name) S2C_LABEL_OPTIONAL_PARAM(type, name, #name)
/// @def BOTH_OPTIONAL_PARAM(type, name)
/// @brief Add an optional parameter for both Client-to-Server (C2S) and Server-to-Client (S2C) directions
/// with the parameter label being the same as the parameter name.
///
/// This macro is a shorthand for adding an optional parameter that can be used in both the
/// request and response of a REST communication with the same label as the parameter name.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
#define BOTH_OPTIONAL_PARAM(type, name) BOTH_LABEL_OPTIONAL_PARAM(type, name, #name)
/// @def C2S_LABEL_DEAFULT_PARAM(type, name, label, val)
/// @brief Add a parameter with a default value for the Client-to-Server (C2S) direction.
///
/// This macro is used to add a parameter to a REST request with a default value. If the
/// parameter is not provided in the request, the default value will be used.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
/// @param val The default value of the parameter.
#define C2S_LABEL_DEAFULT_PARAM(type, name, label, val) \
ADD_DEFAULT_PARAM(BasicRest::Direction::C2S, type, name, label, val)
/// @def S2C_LABEL_DEAFULT_PARAM(type, name, label, val)
/// @brief Add a parameter with a default value for the Server-to-Client (S2C) direction.
///
/// This macro is used to add a parameter to a REST response with a default value. If the
/// parameter is not provided in the response, the default value will be used.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
/// @param val The default value of the parameter.
#define S2C_LABEL_DEAFULT_PARAM(type, name, label, val) \
ADD_DEFAULT_PARAM(BasicRest::Direction::S2C, type, name, label, val)
/// @def BOTH_LABEL_DEAFULT_PARAM(type, name, label, val)
/// @brief Add a parameter with a default value for both Client-to-Server (C2S) and Server-to-Client (S2C) directions.
///
/// This macro is used to add a parameter to a REST response with a default value. If the
/// parameter is not provided in the response, the default value will be used.
///
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param label The label or name of the parameter as it appears in the JSON data.
/// @param val The default value of the parameter.
#define BOTH_LABEL_DEAFULT_PARAM(type, name, label, val) \
ADD_DEFAULT_PARAM(BasicRest::Direction::BOTH, type, name, label, val)
/// @def C2S_DEAFULT_PARAM(type, name, val)
/// @brief Add a parameter with a default value for the Client-to-Server (C2S) direction with the parameter label
/// being the same as the parameter name.
///
/// This macro is used to add a parameter to a REST request with
/// the same label as the parameter name and a default value. If the
/// parameter is not provided in the request, the default value will be used.
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param val The default value of the parameter.
#define C2S_DEAFULT_PARAM(type, name, val) C2S_LABEL_DEAFULT_PARAM(type, name, #name, val)
/// @def C2S_DEAFULT_PARAM(type, name, val)
/// @brief Add a parameter with a default value for the Server-to-Client (S2C) direction with the parameter
/// label being the same as the parameter name.
///
/// This macro is used to add a parameter to a REST request with
/// the same label as the parameter name and a default value. If the
/// parameter is not provided in the request, the default value will be used.
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param val The default value of the parameter.
#define S2C_DEAFULT_PARAM(type, name, val) S2C_LABEL_DEAFULT_PARAM(type, name, #name, val)
/// @def C2S_DEAFULT_PARAM(type, name, val)
/// @brief Add a parameter with a default value for the Client-to-Server (C2S) and Server-to-Client (S2C) directions
/// with the parameter label being the same as the parameter name.
///
/// This macro is used to add a parameter to a REST request with
/// the same label as the parameter name and a default value. If the
/// parameter is not provided in the request, the default value will be used.
/// @param type The data type of the parameter.
/// @param name The variable name of the parameter.
/// @param val The default value of the parameter.
#define BOTH_DEAFULT_PARAM(type, name, val) BOTH_LABEL_DEAFULT_PARAM(type, name, #name, val)
#endif // __REST_H__

View File

@@ -119,6 +119,10 @@ public:
return !(*this > other);
}
Maybe<std::string> calculateSubnetStart(int subnet_value);
Maybe<std::string> calculateSubnetEnd(int subnet_value);
// Checks if the IP address is in the range [left, right] inclusive.
// All IPAddrs must be of the same kind, or the result is false.
bool isInRange(const IPAddr &left, const IPAddr &right) const;
@@ -149,6 +153,14 @@ private:
// Additional fields to be used by ConnKey class and placed here to save space, IPAddr class should ignore them.
IPProto proto;
PortNumber port;
Maybe<std::string> calculateSubnetStartV4(int subnet_value);
Maybe<std::string> calculateSubnetEndV4(int subnet_value);
Maybe<std::string> calculateSubnetStartV6(int subnet_value);
Maybe<std::string> calculateSubnetEndV6(int subnet_value);
};
namespace ConnKeyUtil {
@@ -171,12 +183,30 @@ public:
static Maybe<CustomRange<RangeType>>
createRange(const std::string &maybe_range)
{
std::string start_range = maybe_range.substr(0, maybe_range.find("-"));
std::string end_range = maybe_range.substr(maybe_range.find("-") + 1);
if (end_range.empty()) {
end_range = start_range;
}
std::string start_range;
std::string end_range;
size_t delimiter_position;
if ((delimiter_position = maybe_range.find("-")) != std::string::npos) {
// If it's a range.
start_range = maybe_range.substr(0, delimiter_position);
end_range = maybe_range.substr(delimiter_position + 1);
if (end_range.empty()) {
end_range = start_range;
}
} else if ((delimiter_position = maybe_range.find("/")) != std::string::npos) {
// If it's a subnet.
IPAddr ip;
ConnKeyUtil::fromString((maybe_range.substr(0, delimiter_position)), ip);
std::string subnet = maybe_range.substr(delimiter_position + 1);
int subnet_value = std::stoi(subnet);
start_range = ip.calculateSubnetStart(subnet_value).unpack();
end_range = ip.calculateSubnetEnd(subnet_value).unpack();
} else {
// If it's a single IP.
start_range = maybe_range;
end_range = maybe_range;
}
RangeType _start;
if (!ConnKeyUtil::fromString(start_range, _start)) {
return genError("Error in start value of custom range, value: " + start_range);
@@ -188,7 +218,7 @@ public:
}
if (_start > _end) {
return genError("Error in creating custom range, invalid range: " + maybe_range);
return genError("Error in creating custom range, invalid range: " + maybe_range);
}
return CustomRange(_start, _end);

View File

@@ -49,7 +49,8 @@ static const map<string, Intelligence::ObjectType> object_names = {
{ "zone", Intelligence::ObjectType::ZONE },
{ "policyPackage", Intelligence::ObjectType::POLICY_PACKAGE },
{ "configuration", Intelligence::ObjectType::CONFIGURATION },
{ "session", Intelligence::ObjectType::SESSION }
{ "session", Intelligence::ObjectType::SESSION },
{ "shortLived", Intelligence::ObjectType::SHORTLIVED }
};
class InvalidationRegistration
@@ -128,7 +129,9 @@ public:
void
performCallBacks(const Invalidation &invalidation) const override
{
dbgDebug(D_INTELLIGENCE) << "Looking for callbacks for invalidation " << invalidation.genObject();
for (auto &registed_invalidation : callbacks) {
dbgTrace(D_INTELLIGENCE) << "Checking against: " << registed_invalidation.second.first.genObject();
performCallBacksImpl(invalidation, registed_invalidation.second);
}
}

View File

@@ -0,0 +1,138 @@
// Copyright (C) 2023 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "intelligence_is_v2/intelligence_query_v2.h"
#include "cptest.h"
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_INTELLIGENCE);
TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequest) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true);
IntelligenceQuery<int> query(request, true);
std::string expected = "{\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.phase\",\n"
" \"value\": \"testing\"\n"
" }\n"
"}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true);
IntelligenceQuery<int> query(request, false);
std::string expected = "{"
"\"limit\":20,"
"\"fullResponse\":true,"
"\"query\":{"
"\"operator\":\"equals\","
"\"key\":\"mainAttributes.phase\","
"\"value\":\"testing\""
"}}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequestSpaces) {
QueryRequest request(Condition::EQUALS, "ph ase", "te sti\" n g\\", true);
IntelligenceQuery<int> query(request, false);
std::string expected = "{"
"\"limit\":20,"
"\"fullResponse\":true,"
"\"query\":{"
"\"operator\":\"equals\","
"\"key\":\"mainAttributes.ph ase\","
"\"value\":\"te sti\\\" n g\\\\\""
"}}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonPrettyBulkRequests) {
QueryRequest request1(Condition::EQUALS, "phase", "testing", true);
QueryRequest request2(Condition::EQUALS, "height", "testing", 25);
std::vector<QueryRequest> requests = {request1, request2};
IntelligenceQuery<int> query(requests, true);
std::string expected = "{\n"
" \"queries\": [\n"
" {\n"
" \"query\": {\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.phase\",\n"
" \"value\": \"testing\"\n"
" }\n"
" },\n"
" \"index\": 0\n"
" },\n"
" {\n"
" \"query\": {\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.height\",\n"
" \"value\": \"testing\"\n"
" }\n"
" },\n"
" \"index\": 1\n"
" }\n"
" ]\n"
"}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonUnprettyBulkRequest) {
QueryRequest request1(Condition::EQUALS, "phase", "testing", true);
QueryRequest request2(Condition::EQUALS, "height", "testing", 25);
std::vector<QueryRequest> requests = {request1, request2};
IntelligenceQuery<int> query(requests, false);
std::string expected = "{"
"\"queries\":[{"
"\"query\":{"
"\"limit\":20,"
"\"fullResponse\":true,"
"\"query\":{"
"\"operator\":\"equals\","
"\"key\":\"mainAttributes.phase\","
"\"value\":\"testing\""
"}},"
"\"index\":0"
"},{"
"\"query\":{"
"\"limit\":20,"
"\"fullResponse\":true,"
"\"query\":{"
"\"operator\":\"equals\","
"\"key\":\"mainAttributes.height\","
"\"value\":\"testing\""
"}},"
"\"index\":1"
"}]}";
EXPECT_EQ(*query.genJson(), expected);
}

View File

@@ -0,0 +1,448 @@
#include "intelligence_invalidation.h"
#include "cptest.h"
#include "mock/mock_messaging.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_agent_details.h"
#include "intelligence_comp_v2.h"
#include "config_component.h"
using namespace std;
using namespace Intelligence;
using namespace testing;
static const string invalidation_uri = "/api/v2/intelligence/invalidation";
TEST(InvalidationBasic, SettersAndGetters)
{
Invalidation invalidation("aaa");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::CLASS), "aaa");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::CATEGORY), "");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::FAMILY), "");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::GROUP), "");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::ORDER), "");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::KIND), "");
EXPECT_FALSE(invalidation.getStringAttr("attr1").ok());
EXPECT_FALSE(invalidation.getStringSetAttr("attr2").ok());
EXPECT_FALSE(invalidation.getSourceId().ok());
EXPECT_FALSE(invalidation.getObjectType().ok());
set<string> vals = { "2", "3" };
invalidation
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setStringAttr("attr1", "1")
.setStringSetAttr("attr2", vals)
.setSourceId("id")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_EQ(invalidation.getClassifier(ClassifierType::CATEGORY), "bbb");
EXPECT_EQ(invalidation.getClassifier(ClassifierType::FAMILY), "ccc");
EXPECT_EQ(invalidation.getStringAttr("attr1").unpack(), "1");
EXPECT_EQ(invalidation.getStringSetAttr("attr2").unpack(), vals);
EXPECT_EQ(invalidation.getSourceId().unpack(), "id");
EXPECT_EQ(invalidation.getObjectType().unpack(), Intelligence::ObjectType::ASSET);
}
TEST(InvalidationBasic, Matching)
{
set<string> vals = { "2", "3" };
auto base_invalidation = Invalidation("aaa")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setStringAttr("attr1", "1")
.setStringSetAttr("attr2", vals);
auto matching_invalidation = Invalidation("aaa")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::GROUP, "ddd")
.setStringAttr("attr1", "1")
.setStringSetAttr("attr2", vals)
.setStringAttr("attr3", "6")
.setSourceId("id")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_TRUE(base_invalidation.matches(matching_invalidation));
auto missing_attr_invalidation = Invalidation("aaa")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::GROUP, "ddd")
.setStringAttr("attr1", "1")
.setStringAttr("attr2", "2")
.setStringAttr("attr3", "6")
.setSourceId("id")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_FALSE(base_invalidation.matches(missing_attr_invalidation));
set<string> vals2 = { "1", "5" };
auto has_extra_value_invalidation = Invalidation("aaa")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::GROUP, "ddd")
.setStringSetAttr("attr1", vals2)
.setStringSetAttr("attr2", vals)
.setStringAttr("attr3", "6")
.setSourceId("id")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_TRUE(base_invalidation.matches(has_extra_value_invalidation));
}
class IntelligenceInvalidation : public Test
{
public:
IntelligenceInvalidation() : i_intelligence(Singleton::Consume<I_Intelligence_IS_V2>::from(intelligence))
{
EXPECT_CALL(
mock_ml,
addRecurringRoutine(I_MainLoop::RoutineType::System, chrono::microseconds(7200000000), _, _, _)
).WillRepeatedly(Return(0));
EXPECT_CALL(
mock_ml,
addRecurringRoutine(I_MainLoop::RoutineType::System, _, _, "Sending intelligence invalidation", _)
).WillRepeatedly(DoAll(SaveArg<2>(&routine), Return(0)));
EXPECT_CALL(
mock_rest,
mockRestCall(_, "new-invalidation/source/invalidation", _)
).WillRepeatedly(
WithArg<2>(Invoke(this, &IntelligenceInvalidation::saveRestServerCB))
);
EXPECT_CALL(
mock_rest,
getListeningPort()
).WillRepeatedly(Return(7000));
conf.preload();
intelligence.preload();
intelligence.init();
}
bool
saveRestServerCB(const unique_ptr<RestInit> &p)
{
mock_invalidation = p->getRest();
return true;
}
StrictMock<MockMessaging> messaging_mock;
StrictMock<MockMainLoop> mock_ml;
NiceMock<MockTimeGet> mock_time;
NiceMock<MockAgentDetails> mock_details;
StrictMock<MockRestApi> mock_rest;
ConfigComponent conf;
::Environment env;
IntelligenceComponentV2 intelligence;
I_Intelligence_IS_V2 *i_intelligence;
function<void(const Invalidation &)> callback =
[this] (const Invalidation &incoming) { recieved_invalidations.push_back(incoming); };
vector<Invalidation> recieved_invalidations;
unique_ptr<ServerRest> mock_invalidation;
I_MainLoop::Routine routine;
};
TEST_F(IntelligenceInvalidation, sending_incomplete_invalidation)
{
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_FALSE(invalidation.report(i_intelligence));
}
TEST_F(IntelligenceInvalidation, sending_public_invalidation)
{
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
string invalidation_json;
EXPECT_CALL(
messaging_mock,
sendMessage(false, _, I_Messaging::Method::POST, invalidation_uri, _, _, true, MessageTypeTag::INTELLIGENCE)
).WillOnce(DoAll(SaveArg<1>(&invalidation_json), Return(string())));
EXPECT_TRUE(invalidation.report(i_intelligence));
string expected_json =
"{ \"invalidations\": [ { "
"\"class\": \"aaa\", "
"\"category\": \"bbb\", "
"\"family\": \"ccc\", "
"\"objectType\": \"asset\", "
"\"sourceId\": \"id\", "
"\"mainAttributes\": [ { \"attr2\": \"2\" } ]"
" } ] }";
EXPECT_EQ(invalidation_json, expected_json);
}
TEST_F(IntelligenceInvalidation, sending_private_invalidation)
{
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
stringstream configuration;
configuration << "{";
configuration << " \"agentSettings\":[";
configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}";
configuration << " ],";
configuration << " \"intelligence\":{";
configuration << " \"local intelligence server ip\":\"127.0.0.1\",";
configuration << " \"local intelligence server primary port\":9090";
configuration << " }";
configuration << "}";
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
string invalidation_json;
EXPECT_CALL(
messaging_mock,
sendMessage(false, _, I_Messaging::Method::POST, "127.0.0.1", 9090, _, invalidation_uri, _, _, _)
).WillOnce(DoAll(SaveArg<1>(&invalidation_json), Return(string())));
EXPECT_TRUE(invalidation.report(i_intelligence));
string expected_json =
"{ \"invalidations\": [ { "
"\"class\": \"aaa\", "
"\"category\": \"bbb\", "
"\"family\": \"ccc\", "
"\"objectType\": \"asset\", "
"\"sourceId\": \"id\", "
"\"mainAttributes\": [ { \"attr2\": \"2\" } ]"
" } ] }";
EXPECT_EQ(invalidation_json, expected_json);
}
TEST_F(IntelligenceInvalidation, register_for_invalidation)
{
stringstream configuration;
configuration << "{";
configuration << " \"agentSettings\":[";
configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}";
configuration << " ],";
configuration << " \"intelligence\":{";
configuration << " \"local intelligence server ip\":\"127.0.0.1\",";
configuration << " \"local intelligence server primary port\":9090";
configuration << " }";
configuration << "}";
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
string body;
EXPECT_CALL(
messaging_mock,
sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _)
).WillOnce(DoAll(
SaveArg<1>(&body),
Return(string())
));
EXPECT_NE(i_intelligence->registerInvalidation(invalidation, callback), 0);
EXPECT_THAT(body, HasSubstr("\"url\": \"http://127.0.0.1:7000/set-new-invalidation\""));
EXPECT_THAT(body, HasSubstr("\"apiVersion\": \"v2\", \"communicationType\": \"sync\""));
EXPECT_THAT(body, HasSubstr("\"mainAttributes\": [ { \"attr2\": \"2\" } ]"));
}
TEST_F(IntelligenceInvalidation, invalidation_callback)
{
stringstream configuration;
configuration << "{";
configuration << " \"agentSettings\":[";
configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}";
configuration << " ],";
configuration << " \"intelligence\":{";
configuration << " \"local intelligence server ip\":\"127.0.0.1\",";
configuration << " \"local intelligence server primary port\":9090";
configuration << " }";
configuration << "}";
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_CALL(
messaging_mock,
sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _)
).WillOnce(Return(string()));
EXPECT_NE(i_intelligence->registerInvalidation(invalidation, callback), 0);
set<string> vals = { "1", "5", "2" };
auto invalidation2 = Invalidation("aaa")
.setStringSetAttr("attr2", vals)
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
stringstream json;
json << invalidation2.genObject();
mock_invalidation->performRestCall(json);
EXPECT_EQ(recieved_invalidations.size(), 1);
EXPECT_EQ(recieved_invalidations[0].getStringSetAttr("attr2").unpack(), vals);
}
TEST_F(IntelligenceInvalidation, delete_invalidation_callback)
{
stringstream configuration;
configuration << "{";
configuration << " \"agentSettings\":[";
configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}";
configuration << " ],";
configuration << " \"intelligence\":{";
configuration << " \"local intelligence server ip\":\"127.0.0.1\",";
configuration << " \"local intelligence server primary port\":9090";
configuration << " }";
configuration << "}";
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_CALL(
messaging_mock,
sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _)
).WillOnce(Return(string()));
auto callback_id = i_intelligence->registerInvalidation(invalidation, callback);
i_intelligence->unregisterInvalidation(*callback_id);
set<string> vals = { "1", "5", "2" };
auto invalidation2 = Invalidation("aaa")
.setStringSetAttr("attr2", vals)
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
stringstream json;
json << invalidation2.genObject();
mock_invalidation->performRestCall(json);
EXPECT_EQ(recieved_invalidations.size(), 0);
}
TEST_F(IntelligenceInvalidation, invalidation_short_handling)
{
stringstream configuration;
configuration << "{";
configuration << " \"agentSettings\":[";
configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}";
configuration << " ],";
configuration << " \"intelligence\":{";
configuration << " \"local intelligence server ip\":\"127.0.0.1\",";
configuration << " \"local intelligence server primary port\":9090";
configuration << " }";
configuration << "}";
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_CALL(
messaging_mock,
sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _)
).WillOnce(Return(string()));
invalidation.startListening(i_intelligence, callback);
invalidation.stopListening(i_intelligence);
set<string> vals = { "1", "5", "2" };
auto invalidation2 = Invalidation("aaa")
.setStringSetAttr("attr2", vals)
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
stringstream json;
json << invalidation2.genObject();
mock_invalidation->performRestCall(json);
EXPECT_EQ(recieved_invalidations.size(), 0);
}
TEST_F(IntelligenceInvalidation, routine_registration)
{
stringstream configuration;
configuration << "{";
configuration << " \"agentSettings\":[";
configuration << " {\"key\":\"agent.config.useLocalIntelligence\",\"id\":\"id1\",\"value\":\"true\"}";
configuration << " ],";
configuration << " \"intelligence\":{";
configuration << " \"local intelligence server ip\":\"127.0.0.1\",";
configuration << " \"local intelligence server primary port\":9090";
configuration << " }";
configuration << "}";
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
routine();
auto invalidation = Invalidation("aaa")
.setStringAttr("attr2", "2")
.setSourceId("id")
.setClassifier(ClassifierType::FAMILY, "ccc")
.setClassifier(ClassifierType::CATEGORY, "bbb")
.setObjectType(Intelligence::ObjectType::ASSET);
EXPECT_CALL(
messaging_mock,
sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _)
).WillOnce(Return(string()));
i_intelligence->registerInvalidation(invalidation, callback);
string body;
EXPECT_CALL(
messaging_mock,
sendMessage(_, _, _, "127.0.0.1", 9090, _, "/api/v2/intelligence/invalidation/register", _, _, _)
).WillOnce(DoAll(
SaveArg<1>(&body),
Return(string())
));
routine();
EXPECT_THAT(body, HasSubstr("\"url\": \"http://127.0.0.1:7000/set-new-invalidation\""));
EXPECT_THAT(body, HasSubstr("\"apiVersion\": \"v2\", \"communicationType\": \"sync\""));
EXPECT_THAT(body, HasSubstr("\"mainAttributes\": [ { \"attr2\": \"2\" } ]"));
}

View File

@@ -0,0 +1,132 @@
// Copyright (C) 2023 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "intelligence_is_v2/json_stream.h"
#include "cptest.h"
#include "cereal/archives/json.hpp"
#include "boost/algorithm/string.hpp"
#include "boost/format.hpp"
#include <sstream>
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_INTELLIGENCE);
string
addSlashesToSpecialChars(const string &input)
{
string output;
for(auto c : input)
{
switch (c)
{
case '\n':
output += "\\n";
break;
case '\t':
output += "\\t";
break;
case '\"':
case '\\':
output += '\\';
//no break
default:
output += c;
break;
}
}
return output;
}
void
testJsonStream(const string &key, const string &value, bool is_pretty)
{
stringstream str_stream;
JsonStream json_stream(&str_stream, is_pretty);
{
cereal::JSONOutputArchive out_ar(json_stream);
out_ar.setNextName("regular_num");
out_ar.writeName();
out_ar.saveValue(15.34);
out_ar.setNextName(key.c_str());
out_ar.writeName();
out_ar.saveValue(value.c_str());
}
string expected_key = addSlashesToSpecialChars(key);
string expected_value = addSlashesToSpecialChars(value);
const string JSON_STRING_WITH_SPACES = "{\n \"regular_num\": 15.34,\n \"%s\": \"%s\"\n}";
const string JSON_STRING_WITHOUT_SPACES = "{\"regular_num\":15.34,\"%s\":\"%s\"}";
boost::format frmt(is_pretty ? JSON_STRING_WITH_SPACES : JSON_STRING_WITHOUT_SPACES);
frmt = frmt % expected_key;
frmt = frmt % expected_value;
string expected = frmt.str();
string actual = str_stream.str();
EXPECT_EQ(actual, expected);
}
TEST(JsonStreamTest, prettyOneWord)
{
testJsonStream("regular_key", "regular_value", true);
}
TEST(JsonStreamTest, unprettyOneWord)
{
testJsonStream("regular_key", "regular_value", false);
}
TEST(JsonStreamTest, prettyTwoWords)
{
testJsonStream("spaced key", "spaced value", true);
}
TEST(JsonStreamTest, unprettyTwoWords)
{
testJsonStream("spaced key", "spaced value", false);
}
TEST(JsonStreamTest, prettyWithEnterTab)
{
testJsonStream("entered\nkey", "tabbed\tvalue", true);
}
TEST(JsonStreamTest, unprettyWithEnterTab)
{
testJsonStream("entered\nkey", "tabbed\tvalue", false);
}
TEST(JsonStreamTest, prettyWithQout)
{
testJsonStream("qout \" key\"", "qout \" value\"", true);
}
TEST(JsonStreamTest, unprettyWithQout)
{
testJsonStream("qout \" key\"", "qout \" value\"", false);
}
TEST(JsonStreamTest, prettyWithSlashQout)
{
testJsonStream("qout \\\" key\\\"", "qout \\\" value\\\"", true);
}
TEST(JsonStreamTest, unprettyWithSlashQout)
{
testJsonStream("qout \\\" key\\\"", "qout \\\" value\\\"", false);
}

View File

@@ -106,7 +106,8 @@ static const map<Intelligence::ObjectType, string> convertObjectType = {
{ Intelligence::ObjectType::ZONE, "zone" },
{ Intelligence::ObjectType::POLICY_PACKAGE, "policyPackage" },
{ Intelligence::ObjectType::CONFIGURATION, "configuration" },
{ Intelligence::ObjectType::SESSION, "session" }
{ Intelligence::ObjectType::SESSION, "session" },
{ Intelligence::ObjectType::SHORTLIVED, "shortLived" }
};
Maybe<string>

View File

@@ -287,7 +287,10 @@ MainloopComponent::Impl::run()
dbgTrace(D_MAINLOOP) <<
"Ending execution of corutine. Routine named: " <<
curr_iter->second.getRoutineName();
if (getTimer()->getMonotonicTime() > stop_time + large_exceeding) {
if (
getTimer()->getMonotonicTime() > stop_time + large_exceeding &&
curr_iter->second.getRoutineName() != "Orchestration runner"
) {
dbgWarning(D_MAINLOOP)
<< "Routine execution exceeded run time. Routine name: "
<< curr_iter->second.getRoutineName();
@@ -532,9 +535,15 @@ MainloopComponent::Impl::stop(const RoutineMap::iterator &iter)
if (iter->second.isActive()) {
dbgDebug(D_MAINLOOP) << "Stoping the routine " << iter->first;
do_stop = true;
auto env = Singleton::Consume<I_Environment>::by<MainloopComponent>()->saveEnvironment();
RoutineMap::iterator save_routine = curr_iter;
curr_iter = iter;
// We are going to let the routine run one last time, so it can throw an exception which will cause the stack
// to clean up nicely.
iter->second.run();
// We swap curr_iter to in case the routine will print debug messages and we can see the real Routine id
curr_iter->second.run();
curr_iter = save_routine;
Singleton::Consume<I_Environment>::by<MainloopComponent>()->loadEnvironment(move(env));
do_stop = false;
}
}

View File

@@ -216,10 +216,6 @@ public:
void
init()
{
proxies = {
{ProxyProtocol::HTTP, ProxyData()},
{ProxyProtocol::HTTPS, ProxyData()}
};
initSSL();
timer = Singleton::Consume<I_TimeGet>::by<ProtoMessageComp>();
encryptor = Singleton::Consume<I_Encryptor>::by<ProtoMessageComp>();
@@ -227,8 +223,8 @@ public:
msg_buffer = Singleton::Consume<I_MessagingBuffer>::by<ProtoMessageComp>();
MessageConnection::timer = Singleton::Consume<I_TimeGet>::by<ProtoMessageComp>();
agent_details = Singleton::Consume<I_AgentDetails>::by<ProtoMessageComp>();
proxy_configuration = Singleton::Consume<I_ProxyConfiguration>::by<ProtoMessageComp>();
agent_details->readAgentDetails();
loadAccessToken();
if (!setActiveFog()) {
dbgDebug(D_COMMUNICATION) << "Could not initialize active fog connection";
@@ -240,42 +236,6 @@ public:
auto cache_timeout = getConfigurationWithDefault<int>(2, "message", "Cache timeout");
cache.startExpiration(seconds(cache_timeout), mainloop, timer);
auto proxy_config = getProfileAgentSetting<string>("agent.config.message.proxy");
if (proxy_config.ok()) {
agent_details->setProxy(*proxy_config);
agent_details->writeAgentDetails();
}
registerConfigLoadCb(
[&]()
{
auto proxy_config = getProfileAgentSetting<string>("agent.config.message.proxy");
if (proxy_config.ok()) {
is_proxy_configured_via_settings = true;
agent_details->setProxy(*proxy_config);
agent_details->writeAgentDetails();
} else if (is_proxy_configured_via_settings) {
is_proxy_configured_via_settings = false;
agent_details->setProxy(string(""));
agent_details->writeAgentDetails();
}
}
);
auto load_env_proxy = loadProxy();
if (!load_env_proxy.ok()) {
dbgDebug(D_COMMUNICATION)
<< "Could not initialize load proxy from environment, Error: "
<< load_env_proxy.getErr();
}
Singleton::Consume<I_MainLoop>::by<ProtoMessageComp>()->addRecurringRoutine(
I_MainLoop::RoutineType::System,
seconds(60),
[this] () { loadAccessToken(); },
"Load access token"
);
auto metrics_debugs_interval =
chrono::seconds(getConfigurationWithDefault<uint64_t>(
600,
@@ -324,30 +284,6 @@ public:
MessageConnection::timer = nullptr;
}
void
loadAccessToken()
{
filesystem_prefix = getFilesystemPathConfig();
dbgTrace(D_COMMUNICATION) << "ProtoMessageComp, file systen prefix: " << filesystem_prefix << endl;
auto data_path = getConfigurationWithDefault<string>(
filesystem_prefix + "/data/",
"encryptor",
"Data files directory"
);
ifstream token_file(data_path + session_token_file_name);
if (!token_file.is_open()) {
dbgWarning(D_COMMUNICATION) << "Failed to open session token file";
return;
}
stringstream token_steam;
token_steam << token_file.rdbuf();
auto new_token = token_steam.str();
if (access_token != new_token) {
access_token = new_token;
dbgTrace(D_COMMUNICATION) << "Loaded the new token";
}
}
// LCOV_EXCL_START Reason: No proxy for ut
void
setFogProxy(const string &host, const uint16_t port, ProxyProtocol proto)
@@ -355,7 +291,7 @@ public:
dbgTrace(D_COMMUNICATION) << "Proxy was set. Proxy: " << host << ":" << port;
MessageConnection::proxy_host = host;
MessageConnection::proxy_port = port;
auto proxy_auth = getProxyCredentials(proto);
auto proxy_auth = proxy_configuration->getProxyCredentials(proto);
if (proxy_auth.ok()) {
MessageConnection::proxy_auth = proxy_auth.unpack();
}
@@ -368,23 +304,23 @@ public:
MessageConnKey fog_key = make_tuple("fog", 0, tag);
proxy_protocol = is_secure ? ProxyProtocol::HTTPS : ProxyProtocol::HTTP;
auto load_env_proxy = loadProxy();
auto load_env_proxy = proxy_configuration->loadProxy();
if (!load_env_proxy.ok()) {
dbgDebug(D_COMMUNICATION)
<< "Could not initialize load proxy from environment, Error: "
<< load_env_proxy.getErr();
}
if (getProxyExists(proxy_protocol)) {
auto proxy_host = getProxyDomain(proxy_protocol);
auto proxy_port = getProxyPort(proxy_protocol);
if (proxy_configuration->getProxyExists(proxy_protocol)) {
auto proxy_host = proxy_configuration->getProxyDomain(proxy_protocol);
auto proxy_port = proxy_configuration->getProxyPort(proxy_protocol);
if (proxy_host.ok() && proxy_port.ok()) {
setFogProxy(proxy_host.unpack(), proxy_port.unpack(), proxy_protocol);
}
}
Maybe<MessageConnection> conn = MessageConnection::startNewConnection(
host, port, is_secure, tag, getProxyExists(proxy_protocol)
host, port, is_secure, tag, proxy_configuration->getProxyExists(proxy_protocol)
);
if (!conn.ok()) {
dbgWarning(D_COMMUNICATION)
@@ -403,7 +339,7 @@ public:
<< ":"
<< port
<< " via "
<< (getProxyExists(proxy_protocol) ? "proxy, using " : "")
<< (proxy_configuration->getProxyExists(proxy_protocol) ? "proxy, using " : "")
<< (is_secure ? "secure" : "clear")
<< " connection";
@@ -652,7 +588,7 @@ public:
return sendMessage(conn_iter->second, get_reply, body, method, url, headers, err_call_back);
}
}
auto load_env_proxy = loadProxy();
auto load_env_proxy = proxy_configuration->loadProxy();
if (!load_env_proxy.ok()) return genError(load_env_proxy.getErr());
Maybe<MessageConnection> conn = MessageConnection::startNewConnection(
@@ -682,153 +618,6 @@ public:
return sendMessage(active_conn, get_reply, body, method, url, headers, err_call_back);
}
string getAccessToken() override
{
return access_token;
}
Maybe<string>
getProxyDomain(ProxyProtocol protocol) const override
{
if (proxies.find(protocol) == proxies.end()) {
return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol));
}
if (proxies.at(protocol).domain.empty()) return genError(
convertProxyProtocolToString(protocol) + string(" proxy domain is unset")
);
return proxies.at(protocol).domain;
}
Maybe<string>
getProxyCredentials(ProxyProtocol protocol) const override
{
if (proxies.find(protocol) == proxies.end()) {
return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol));
}
if (proxies.at(protocol).auth.empty()) return genError(
convertProxyProtocolToString(protocol) + string(" proxy auth is unset")
);
return proxies.at(protocol).auth;
}
Maybe<uint16_t>
getProxyPort(ProxyProtocol protocol) const override
{
if (proxies.find(protocol) == proxies.end()) {
return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol));
}
if (proxies.at(protocol).port == 0) return genError(
convertProxyProtocolToString(protocol) + string(" proxy port is unset")
);
return proxies.at(protocol).port;
}
bool
getProxyExists(ProxyProtocol protocol) const override
{
if (proxies.find(protocol) == proxies.end()) {
dbgInfo(D_COMMUNICATION)
<< "Proxy type is not loaded in map, type: "
<< convertProxyProtocolToString(protocol);
return false;
}
return proxies.at(protocol).is_exists;
}
Maybe<string>
getProxyAddress(ProxyProtocol protocol) const override
{
if (proxies.find(protocol) == proxies.end()) {
return genError("Proxy type is not loaded in map, type: " + convertProxyProtocolToString(protocol));
}
if (proxies.at(protocol).protocol.empty() ||
proxies.at(protocol).domain.empty() ||
proxies.at(protocol).port == 0) {
return genError(
string("Can't construct ") +
convertProxyProtocolToString(protocol) +
string(" proxy address")
);
}
return proxies.at(protocol).protocol +
"://" +
proxies.at(protocol).domain +
":" +
to_string(proxies.at(protocol).port);
}
Maybe<void>
loadProxy() override
{
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>();
}
Maybe<void>
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_COMMUNICATION)
<< convertProxyProtocolToString(protocol)
<< " proxy was successfully loaded, "
<< getProxyAddress(protocol).unpack();
return Maybe<void>();
}
private:
Maybe<string>
sendMessage(
@@ -935,85 +724,6 @@ private:
return genError("Failed to send HTTP request");
}
Maybe<void>
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>
loadProxyType(const string &proxy_type)
{
agent_details->readAgentDetails();
auto proxy_config = agent_details->getProxy();
if (proxy_config.ok()) {
if (proxy_config.unpack() == "none") {
return Maybe<string>(string());
}
return proxy_config;
}
#ifdef gaia
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<ProtoMessageComp>();
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_COMMUNICATION) << "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
}
string
base64Decode(const string &input) const
{
@@ -1087,6 +797,8 @@ private:
}
}
const string &access_token = agent_details->getAccessToken();
if (!conn.isExternal() && !access_token.empty() && headers.find("Authorization") == std::string::npos) {
req.insertHeader("Authorization", "Bearer " + access_token);
}
@@ -1186,17 +898,6 @@ private:
return count;
}
string
convertProxyProtocolToString(ProxyProtocol proto) const
{
switch(proto) {
case ProxyProtocol::HTTP: return "http";
case ProxyProtocol::HTTPS: return "https";
}
dbgAssert(false) << "Unsupported Proxy Protocol " << static_cast<int>(proto);
return "";
}
Maybe<Method>
stringToMethod(const string &name)
{
@@ -1209,40 +910,19 @@ private:
return genError("Cannot convert unknown HTTP method to Enum. Method name: " + name);
}
class ProxyData
{
public:
bool
operator==(const ProxyData &other) const
{
return protocol==other.protocol &&
domain==other.domain &&
is_exists==other.is_exists &&
port==other.port &&
auth==other.auth;
}
string protocol = "";
string domain = "";
string auth = "";
bool is_exists = false;
uint16_t port = 0;
};
bool is_proxy_configured_via_settings = false;
uint64_t number_of_reconnects = 0;
uint64_t number_of_reconnect_failures = 0;
uint64_t number_of_send_failure = 0;
I_AgentDetails *agent_details = nullptr;
I_MainLoop *mainloop = nullptr;
I_TimeGet *timer = nullptr;
I_Encryptor *encryptor = nullptr;
I_MessagingBuffer *msg_buffer = nullptr;
bool is_proxy_configured_via_settings = false;
uint64_t number_of_reconnects = 0;
uint64_t number_of_reconnect_failures = 0;
uint64_t number_of_send_failure = 0;
I_AgentDetails *agent_details = nullptr;
I_MainLoop *mainloop = nullptr;
I_TimeGet *timer = nullptr;
I_Encryptor *encryptor = nullptr;
I_MessagingBuffer *msg_buffer = nullptr;
I_ProxyConfiguration *proxy_configuration = nullptr;
map<MessageConnKey, MessageConnection> active_connections;
map<MessageTypeTag, MessageConnKey> tag_to_active_conn_key;
map<ProxyProtocol, ProxyData> proxies;
ProxyProtocol proxy_protocol;
string access_token;
TemporaryCache<string, string> cache;
static const map<ProxyProtocol, string> proxyProtocolToString;
set<HTTPRequestSignature> pending_signatures;
@@ -1671,7 +1351,7 @@ MessageConnection::receiveResponse(I_MessageDecoder<T> &decoder)
}
if (connection_closed_count > 0) {
dbgInfo(D_COMMUNICATION)
dbgTrace(D_COMMUNICATION)
<< "Connection was reconnected. Type: "
<< tagToString(tag)
<< ", number of attempts: "

View File

@@ -71,6 +71,7 @@ RestConn::parseConn() const
string uri;
os >> uri;
string identifier = uri.substr(uri.find_first_of('/') + 1);
dbgDebug(D_API) << "Call identifier: " << identifier;
uint len = 0;
while (true) {
@@ -88,6 +89,8 @@ RestConn::parseConn() const
}
}
dbgDebug(D_API) << "Message length: " << len;
if (method=="POST" && len==0) {
dbgWarning(D_API) << "No length was found - could be chunked, but we still do not support that";
sendResponse("411 Length Required", "");
@@ -97,6 +100,8 @@ RestConn::parseConn() const
stringstream body;
body.str(readSize(len));
dbgTrace(D_API) << "Message content: " << body.str();
Maybe<string> res = (method == "POST") ? invoke->invokeRest(identifier, body) : invoke->getSchema(identifier);
if (res.ok()) {

View File

@@ -94,7 +94,7 @@ public:
int res = send(socket_int, data.data() + bytes_sent, data.size() - bytes_sent, MSG_NOSIGNAL);
if (res <= 0) {
dbgWarning(D_SOCKET) << "Failed to send data";
dbgWarning(D_SOCKET) << "Failed to send data, Error: " << strerror(errno);
return false;
}