#include "chrome/browser/enterprise/connectors/connectors_manager.h"
#include <optional>
#include <set>
#include <utility>
#include "base/json/json_reader.h"
#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "components/enterprise/connectors/core/common.h"
#include "components/enterprise/connectors/core/connectors_prefs.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/safe_browsing/core/common/features.h"
#include "content/public/test/browser_task_environment.h"
#include "storage/browser/file_system/file_system_url.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
#include "chrome/browser/enterprise/connectors/analysis/source_destination_test_util.h"
#endif
#if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
#include "chrome/browser/enterprise/connectors/test/fake_content_analysis_sdk_manager.h"
#endif
namespace enterprise_connectors {
namespace {
#if !BUILDFLAG(IS_ANDROID)
constexpr AnalysisConnector kAllAnalysisConnectors[] = …;
constexpr char kEmptySettingsPref[] = …;
constexpr char kNormalCloudAnalysisSettingsPref[] = …;
constexpr char kNormalLocalAnalysisSettingsPref[] = …;
constexpr char kDlpAndMalwareUrl[] = …;
constexpr char kOnlyDlpUrl[] = …;
constexpr char kOnlyMalwareUrl[] = …;
constexpr char kNoTagsUrl[] = …;
constexpr char kNoProviderReportingSettings[] = …;
constexpr char kNormalReportingSettingsWithoutEvents[] = …;
constexpr char kNormalReportingSettingsWithEvents[] = …;
#endif
}
class ConnectorsManagerTest : public testing::Test { … };
#if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
class ConnectorsManagerLocalAnalysisPolicyTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<std::tuple<AnalysisConnector, bool>> { … };
TEST_P(ConnectorsManagerLocalAnalysisPolicyTest, Test) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
class ConnectorsManagerConnectorPoliciesTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<
std::tuple<AnalysisConnector, const char*, const char*>> { … };
TEST_P(ConnectorsManagerConnectorPoliciesTest, NormalPref) { … }
TEST_P(ConnectorsManagerConnectorPoliciesTest, EmptyPref) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
using VolumeInfo = SourceDestinationTestingHelper::VolumeInfo;
namespace {
constexpr char kNormalCloudSourceDestinationSettingsPref[] = R"([{
"service_provider": "google",
"enable": [
{
"source_destination_list": [
{
"sources": [{
"file_system_type": "ANY"
}],
"destinations": [{
"file_system_type": "ANY"
}]
}
],
"tags": ["dlp", "malware"]
},
],
"disable": [
{
"source_destination_list": [
{
"sources": [{
"file_system_type": "REMOVABLE"
}],
"destinations": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
]
}
],
"tags": ["dlp"]
},
{
"source_destination_list": [
{
"sources": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
],
"destinations": [{
"file_system_type": "REMOVABLE"
}]
}
],
"tags": ["malware"]},
{
"source_destination_list": [
{
"sources": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
],
"destinations": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
]
}
],
"tags": ["dlp", "malware"]
},
],
"block_until_verdict": 1,
"block_password_protected": true,
"block_large_files": true,
"minimum_data_size": 123,
}])";
constexpr char kNormalLocalSourceDestinationSettingsPref[] = R"([{
"service_provider": "local_user_agent",
"enable": [
{
"source_destination_list": [
{
"sources": [{
"file_system_type": "ANY"
}],
"destinations": [{
"file_system_type": "ANY"
}]
}
],
"tags": ["dlp", "malware"]
},
],
"disable": [
{
"source_destination_list": [
{
"sources": [{
"file_system_type": "REMOVABLE"
}],
"destinations": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
]
}
],
"tags": ["dlp"]
},
{
"source_destination_list": [
{
"sources": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
],
"destinations": [{
"file_system_type": "REMOVABLE"
}]
}
],
"tags": ["malware"]},
{
"source_destination_list": [
{
"sources": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
],
"destinations": [
{"file_system_type": "MY_FILES"},
{"file_system_type": "GOOGLE_DRIVE"}
]
}
],
"tags": ["dlp", "malware"]
},
],
"block_until_verdict": 1,
"block_password_protected": true,
"block_large_files": true,
"minimum_data_size": 123,
}])";
constexpr VolumeInfo kRemovableVolumeInfo{
file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION, std::nullopt,
"REMOVABLE"};
constexpr VolumeInfo kProvidedVolumeInfo{file_manager::VOLUME_TYPE_PROVIDED,
std::nullopt, "PROVIDED"};
constexpr VolumeInfo kMyFilesVolumeInfo{
file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY, std::nullopt, "MY_FILES"};
constexpr VolumeInfo kDriveVolumeInfo{file_manager::VOLUME_TYPE_GOOGLE_DRIVE,
std::nullopt, "GOOGLE_DRIVE"};
constexpr std::initializer_list<VolumeInfo> kVolumeInfos{
kRemovableVolumeInfo, kProvidedVolumeInfo, kMyFilesVolumeInfo,
kDriveVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kDlpMalwareVolumePair1 = {
kRemovableVolumeInfo, kProvidedVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kDlpMalwareVolumePair2 = {
kProvidedVolumeInfo, kRemovableVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kNoDlpNoMalwareVolumePair1 = {
kMyFilesVolumeInfo, kDriveVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kNoDlpNoMalwareVolumePair2 = {
kDriveVolumeInfo, kMyFilesVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kNoDlpMalwareVolumePair1 = {
kRemovableVolumeInfo, kMyFilesVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kNoDlpMalwareVolumePair2 = {
kRemovableVolumeInfo, kDriveVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kDlpNoMalwareVolumePair1 = {
kMyFilesVolumeInfo, kRemovableVolumeInfo};
constexpr std::pair<VolumeInfo, VolumeInfo> kDlpNoMalwareVolumePair2 = {
kDriveVolumeInfo, kRemovableVolumeInfo};
using SourceDestinationTestingTuple =
std::tuple<AnalysisConnector,
const std::pair<VolumeInfo, VolumeInfo>*,
const char*>;
static auto testingTupleToString = [](const auto& info) {
std::string name;
auto [connector, volume_info_pair, pref] = info.param;
name += volume_info_pair->first.fs_config_string;
name += "_";
name += volume_info_pair->second.fs_config_string;
if (pref == kNormalCloudSourceDestinationSettingsPref) {
name += "_cloud";
} else if (pref == kNormalLocalSourceDestinationSettingsPref) {
name += "_local";
} else {
name += "_unknown";
}
return name;
};
}
class ConnectorsManagerConnectorPoliciesSourceDestinationTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<SourceDestinationTestingTuple> {
public:
ConnectorsManagerConnectorPoliciesSourceDestinationTest() {
source_destination_testing_helper_ =
std::make_unique<SourceDestinationTestingHelper>(profile_,
kVolumeInfos);
}
~ConnectorsManagerConnectorPoliciesSourceDestinationTest() override {
profile_manager_.DeleteAllTestingProfiles();
}
AnalysisConnector connector() const { return std::get<0>(GetParam()); }
storage::FileSystemURL source_volume_url() const {
return source_destination_testing_helper_->GetTestFileSystemURLForVolume(
std::get<1>(GetParam())->first);
}
storage::FileSystemURL destination_volume_url() const {
return source_destination_testing_helper_->GetTestFileSystemURLForVolume(
std::get<1>(GetParam())->second);
}
const char* pref_value() const { return std::get<2>(GetParam()); }
const char* pref() const { return ConnectorPref(connector()); }
void SetUpExpectedAnalysisSettings(const char* pref) {
auto expected_settings =
ExpectedAnalysisSettings(pref, std::get<1>(GetParam()));
expect_settings_ = expected_settings.has_value();
if (expected_settings.has_value()) {
expected_tags_ = expected_settings.value().tags;
expected_block_until_verdict_ =
expected_settings.value().block_until_verdict;
expected_block_password_protected_files_ =
expected_settings.value().block_password_protected_files;
expected_block_large_files_ = expected_settings.value().block_large_files;
}
}
protected:
std::optional<AnalysisSettings> ExpectedAnalysisSettings(
const char* pref,
const std::pair<VolumeInfo, VolumeInfo>* volume_pair) {
if (pref == kEmptySettingsPref ||
volume_pair == &kNoDlpNoMalwareVolumePair1 ||
volume_pair == &kNoDlpNoMalwareVolumePair2)
return std::nullopt;
AnalysisSettings settings;
settings.block_until_verdict = BlockUntilVerdict::kBlock;
settings.block_password_protected_files = true;
settings.block_large_files = true;
if (volume_pair == &kDlpMalwareVolumePair1 ||
volume_pair == &kDlpMalwareVolumePair2) {
settings.tags = {{"dlp", TagSettings()}, {"malware", TagSettings()}};
} else if (volume_pair == &kDlpNoMalwareVolumePair1 ||
volume_pair == &kDlpNoMalwareVolumePair2) {
settings.tags = {{"dlp", TagSettings()}};
} else if (volume_pair == &kNoDlpMalwareVolumePair1 ||
volume_pair == &kNoDlpMalwareVolumePair2) {
settings.tags = {{"malware", TagSettings()}};
} else {
NOTREACHED_IN_MIGRATION();
}
if (pref == kNormalLocalSourceDestinationSettingsPref)
settings.tags.erase("malware");
if (settings.tags.empty())
return std::nullopt;
return settings;
}
std::unique_ptr<SourceDestinationTestingHelper>
source_destination_testing_helper_;
bool expect_settings_;
};
TEST_P(ConnectorsManagerConnectorPoliciesSourceDestinationTest, NormalPref) {
ConnectorsManager manager(pref_service(), GetServiceProviderConfig());
ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty());
ScopedConnectorPref scoped_pref(pref_service(), pref(), pref_value());
SetUpExpectedAnalysisSettings(pref_value());
auto settings_from_manager = manager.GetAnalysisSettings(
profile_, source_volume_url(), destination_volume_url(), connector());
ASSERT_EQ(expect_settings_, settings_from_manager.has_value());
if (settings_from_manager.has_value())
ValidateSettings(settings_from_manager.value());
const auto& cached_settings =
manager.GetAnalysisConnectorsSettingsForTesting();
ASSERT_EQ(1u, cached_settings.size());
ASSERT_EQ(1u, cached_settings.count(connector()));
ASSERT_EQ(1u, cached_settings.at(connector()).size());
auto settings_from_cache =
cached_settings.at(connector())
.at(0)
.GetAnalysisSettings(profile_, source_volume_url(),
destination_volume_url(),
DataRegion::NO_PREFERENCE);
ASSERT_EQ(expect_settings_, settings_from_cache.has_value());
if (settings_from_cache.has_value())
ValidateSettings(settings_from_cache.value());
}
TEST_P(ConnectorsManagerConnectorPoliciesSourceDestinationTest, EmptyPref) {
ConnectorsManager manager(pref_service(), GetServiceProviderConfig());
ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty());
ScopedConnectorPref scoped_pref(pref_service(), pref(), kEmptySettingsPref);
ASSERT_FALSE(manager
.GetAnalysisSettings(profile_, source_volume_url(),
destination_volume_url(), connector())
.has_value());
ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty());
}
INSTANTIATE_TEST_SUITE_P(
,
ConnectorsManagerConnectorPoliciesSourceDestinationTest,
testing::Combine(
testing::Values(AnalysisConnector::FILE_TRANSFER),
testing::Values(&kDlpMalwareVolumePair1,
&kDlpMalwareVolumePair2,
&kNoDlpNoMalwareVolumePair1,
&kNoDlpNoMalwareVolumePair2,
&kNoDlpMalwareVolumePair1,
&kNoDlpMalwareVolumePair2,
&kDlpNoMalwareVolumePair1,
&kDlpNoMalwareVolumePair2),
testing::Values(kNormalCloudSourceDestinationSettingsPref)),
testingTupleToString);
#endif
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
class ConnectorsManagerAnalysisConnectorsTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<
std::tuple<AnalysisConnector, const char*>> { … };
TEST_P(ConnectorsManagerAnalysisConnectorsTest, DynamicPolicies) { … }
TEST_P(ConnectorsManagerAnalysisConnectorsTest, NamesAndConfigs) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
class ConnectorsManagerAnalysisConnectorsSourceDestinationTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<
std::tuple<AnalysisConnector, const char*>> {
public:
ConnectorsManagerAnalysisConnectorsSourceDestinationTest() {
source_destination_testing_helper_ =
std::make_unique<SourceDestinationTestingHelper>(profile_,
kVolumeInfos);
}
~ConnectorsManagerAnalysisConnectorsSourceDestinationTest() override {
profile_manager_.DeleteAllTestingProfiles();
}
storage::FileSystemURL source_volume_url() const {
return source_destination_testing_helper_->GetTestFileSystemURLForVolume(
kDlpMalwareVolumePair1.first);
}
storage::FileSystemURL destination_volume_url() const {
return source_destination_testing_helper_->GetTestFileSystemURLForVolume(
kDlpMalwareVolumePair1.second);
}
AnalysisConnector connector() const { return std::get<0>(GetParam()); }
const char* pref_value() const { return std::get<1>(GetParam()); }
const char* pref() const { return ConnectorPref(connector()); }
protected:
std::unique_ptr<SourceDestinationTestingHelper>
source_destination_testing_helper_;
};
TEST_P(ConnectorsManagerAnalysisConnectorsSourceDestinationTest,
DynamicPolicies) {
ConnectorsManager manager(pref_service(), GetServiceProviderConfig());
ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty());
{
ScopedConnectorPref scoped_pref(pref_service(), pref(), pref_value());
const auto& cached_settings =
manager.GetAnalysisConnectorsSettingsForTesting();
ASSERT_FALSE(cached_settings.empty());
ASSERT_EQ(1u, cached_settings.count(connector()));
ASSERT_EQ(1u, cached_settings.at(connector()).size());
auto settings = cached_settings.at(connector())
.at(0)
.GetAnalysisSettings(profile_, source_volume_url(),
destination_volume_url(),
DataRegion::NO_PREFERENCE);
ASSERT_TRUE(settings.has_value());
expected_block_until_verdict_ = BlockUntilVerdict::kBlock;
expected_block_password_protected_files_ = true;
expected_block_large_files_ = true;
if (pref_value() == kNormalCloudSourceDestinationSettingsPref)
expected_tags_ = {{"dlp", TagSettings()}, {"malware", TagSettings()}};
else
expected_tags_ = {{"dlp", TagSettings()}};
ValidateSettings(settings.value());
}
ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty());
}
INSTANTIATE_TEST_SUITE_P(
ConnectorsManagerAnalysisConnectorsSourceDestinationTest,
ConnectorsManagerAnalysisConnectorsSourceDestinationTest,
testing::Combine(
testing::Values(AnalysisConnector::FILE_TRANSFER),
testing::Values(kNormalCloudSourceDestinationSettingsPref,
kNormalLocalSourceDestinationSettingsPref)));
#endif
#if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
class ConnectorsManagerLocalAnalysisConnectorTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<AnalysisConnector> { … };
TEST_P(ConnectorsManagerLocalAnalysisConnectorTest, DynamicPolicies) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if !BUILDFLAG(IS_ANDROID)
class ConnectorsManagerDataRegionTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<
std::tuple<AnalysisConnector, DataRegion>> { … };
TEST_P(ConnectorsManagerDataRegionTest, RegionalizedEndpoint) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
TEST_F(ConnectorsManagerTest, ReportingUrlFlagOverrideNoProviderSettings) { … }
TEST_F(ConnectorsManagerTest,
ReportingUrlFlagOverrideNormalSettingsWithoutEvents) { … }
TEST_F(ConnectorsManagerTest,
ReportingUrlFlagOverrideNormalSettingsWithEvents) { … }
}