| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #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/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/policy/core/common/policy_types.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/scoped_user_pref_update.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) |
| #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" // nogncheck |
| #endif |
| |
| namespace enterprise_connectors { |
| |
| namespace { |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| constexpr AnalysisConnector kAllAnalysisConnectors[] = { |
| AnalysisConnector::FILE_DOWNLOADED, AnalysisConnector::FILE_ATTACHED, |
| AnalysisConnector::BULK_DATA_ENTRY, AnalysisConnector::PRINT}; |
| |
| constexpr DataRegion kAllDataRegions[] = { |
| DataRegion::NO_PREFERENCE, DataRegion::UNITED_STATES, DataRegion::EUROPE}; |
| |
| constexpr char kEmptySettingsPref[] = "[]"; |
| |
| constexpr char kNormalCloudAnalysisSettingsPref[] = R"([ |
| { |
| "service_provider": "google", |
| "enable": [ |
| {"url_list": ["*"], "tags": ["dlp", "malware"]}, |
| ], |
| "disable": [ |
| {"url_list": ["no.dlp.com", "no.dlp.or.malware.ca"], "tags": ["dlp"]}, |
| {"url_list": ["no.malware.com", "no.dlp.or.malware.ca"], |
| "tags": ["malware"]}, |
| ], |
| "block_until_verdict": 1, |
| "block_password_protected": true, |
| "block_large_files": true, |
| }, |
| ])"; |
| |
| constexpr char kNormalLocalAnalysisSettingsPref[] = R"([ |
| { |
| "service_provider": "local_user_agent", |
| "enable": [ |
| {"url_list": ["*"], "tags": ["dlp"]}, |
| ], |
| "disable": [ |
| {"url_list": ["no.dlp.com", "no.dlp.or.malware.ca"], "tags": ["dlp"]}, |
| ], |
| "block_until_verdict": 1, |
| "block_password_protected": true, |
| "block_large_files": true, |
| }, |
| ])"; |
| |
| constexpr char kDlpAndMalwareUrl[] = "https://foo.com"; |
| constexpr char kOnlyDlpUrl[] = "https://no.malware.com"; |
| constexpr char kOnlyMalwareUrl[] = "https://no.dlp.com"; |
| constexpr char kNoTagsUrl[] = "https://no.dlp.or.malware.ca"; |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| } // namespace |
| |
| class ConnectorsManagerTest : public testing::Test { |
| public: |
| ConnectorsManagerTest() |
| : profile_manager_(TestingBrowserProcess::GetGlobal()) { |
| EXPECT_TRUE(profile_manager_.SetUp()); |
| profile_ = profile_manager_.CreateTestingProfile("test-user"); |
| } |
| |
| PrefService* pref_service() { return profile_->GetPrefs(); } |
| |
| void ValidateSettings(const AnalysisSettings& settings) { |
| ASSERT_EQ(settings.block_until_verdict, expected_block_until_verdict_); |
| ASSERT_EQ(settings.block_password_protected_files, |
| expected_block_password_protected_files_); |
| ASSERT_EQ(settings.block_large_files, expected_block_large_files_); |
| for (const auto& expected_tag : expected_tags_) { |
| const std::string& tag = expected_tag.first; |
| ASSERT_TRUE(settings.tags.count(tag)); |
| ASSERT_EQ(settings.tags.at(tag).requires_justification, |
| expected_tag.second.requires_justification); |
| ASSERT_EQ(settings.tags.at(tag).custom_message.message, |
| expected_tag.second.custom_message.message); |
| ASSERT_EQ(settings.tags.at(tag).custom_message.learn_more_url, |
| expected_tag.second.custom_message.learn_more_url); |
| } |
| } |
| |
| class ScopedConnectorPref { |
| public: |
| ScopedConnectorPref(PrefService* pref_service, |
| const char* pref, |
| const char* pref_value) |
| : pref_service_(pref_service), pref_(pref) { |
| auto maybe_pref_value = |
| base::JSONReader::Read(pref_value, base::JSON_ALLOW_TRAILING_COMMAS); |
| EXPECT_TRUE(maybe_pref_value.has_value()); |
| if (maybe_pref_value.has_value()) { |
| pref_service_->Set(pref, maybe_pref_value.value()); |
| } |
| } |
| |
| void UpdateScopedConnectorPref(const char* pref_value) { |
| auto maybe_pref_value = |
| base::JSONReader::Read(pref_value, base::JSON_ALLOW_TRAILING_COMMAS); |
| EXPECT_TRUE(maybe_pref_value.has_value()); |
| ASSERT_NE(pref_service_, nullptr); |
| ASSERT_NE(pref_, nullptr); |
| pref_service_->Set(pref_, maybe_pref_value.value()); |
| } |
| |
| ~ScopedConnectorPref() { pref_service_->ClearPref(pref_); } |
| |
| private: |
| raw_ptr<PrefService> pref_service_; |
| const char* pref_; |
| }; |
| |
| protected: |
| content::BrowserTaskEnvironment task_environment_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // This is necessary so the URL flag code works on CrOS. If it's absent, a |
| // CrOS DCHECK fails when trying to access the |
| // BrowserPolicyConnectorAsh as it is not completely initialized. |
| ash::ScopedCrosSettingsTestHelper cros_settings_; |
| #endif |
| |
| TestingProfileManager profile_manager_; |
| raw_ptr<TestingProfile, DanglingUntriaged> profile_; |
| |
| // Set to the default value of their legacy policy. |
| std::map<std::string, TagSettings> expected_tags_ = {}; |
| BlockUntilVerdict expected_block_until_verdict_ = BlockUntilVerdict::kNoBlock; |
| bool expected_block_password_protected_files_ = false; |
| bool expected_block_large_files_ = false; |
| |
| std::set<std::string> expected_mime_types_; |
| }; |
| |
| #if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS) |
| // Platform policies should only act as a kill switch. |
| class ConnectorsManagerLocalAnalysisPolicyTest |
| : public ConnectorsManagerTest, |
| public testing::WithParamInterface<std::tuple<AnalysisConnector, bool>> { |
| protected: |
| AnalysisConnector connector() const { return std::get<0>(GetParam()); } |
| bool set_policy() const { return std::get<1>(GetParam()); } |
| }; |
| |
| TEST_P(ConnectorsManagerLocalAnalysisPolicyTest, Test) { |
| std::unique_ptr<ScopedConnectorPref> scoped_pref = |
| set_policy() ? std::make_unique<ScopedConnectorPref>( |
| pref_service(), AnalysisConnectorPref(connector()), |
| kNormalLocalAnalysisSettingsPref) |
| : nullptr; |
| |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| EXPECT_EQ(set_policy(), manager.IsAnalysisConnectorEnabled(connector())); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| ConnectorsManagerLocalAnalysisPolicyTest, |
| ConnectorsManagerLocalAnalysisPolicyTest, |
| testing::Combine(testing::ValuesIn(kAllAnalysisConnectors), |
| testing::Bool())); |
| #endif // BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS) |
| |
| #if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS) |
| class ConnectorsManagerConnectorPoliciesTest |
| : public ConnectorsManagerTest, |
| public testing::WithParamInterface< |
| std::tuple<AnalysisConnector, const char*, const char*>> { |
| public: |
| ConnectorsManagerConnectorPoliciesTest() = default; |
| |
| AnalysisConnector connector() const { return std::get<0>(GetParam()); } |
| |
| const char* url() const { return std::get<1>(GetParam()); } |
| |
| const char* pref_value() const { return std::get<2>(GetParam()); } |
| |
| const char* pref() const { return AnalysisConnectorPref(connector()); } |
| |
| void SetUpExpectedAnalysisSettings(const char* pref) { |
| auto expected_settings = ExpectedAnalysisSettings(pref, url()); |
| 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 char* url) { |
| if (pref == kEmptySettingsPref || url == kNoTagsUrl) |
| return std::nullopt; |
| |
| AnalysisSettings settings; |
| |
| settings.block_until_verdict = BlockUntilVerdict::kBlock; |
| settings.block_password_protected_files = true; |
| settings.block_large_files = true; |
| |
| if (url == kDlpAndMalwareUrl) |
| settings.tags = {{"dlp", TagSettings()}, {"malware", TagSettings()}}; |
| else if (url == kOnlyDlpUrl) |
| settings.tags = {{"dlp", TagSettings()}}; |
| else if (url == kOnlyMalwareUrl) |
| settings.tags = {{"malware", TagSettings()}}; |
| |
| // The "local_test" service provider doesn't support the "malware" tag, so |
| // remove it from expectations. |
| if (pref == kNormalLocalAnalysisSettingsPref) |
| settings.tags.erase("malware"); |
| if (settings.tags.empty()) |
| return std::nullopt; |
| |
| return settings; |
| } |
| |
| bool expect_settings_; |
| }; |
| |
| TEST_P(ConnectorsManagerConnectorPoliciesTest, NormalPref) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| ScopedConnectorPref scoped_pref(pref_service(), pref(), pref_value()); |
| SetUpExpectedAnalysisSettings(pref_value()); |
| |
| // Verify that the expected settings are returned normally. |
| auto settings_from_manager = |
| manager.GetAnalysisSettings(GURL(url()), connector()); |
| ASSERT_EQ(expect_settings_, settings_from_manager.has_value()); |
| if (settings_from_manager.has_value()) |
| ValidateSettings(settings_from_manager.value()); |
| |
| // Verify that the expected settings are also returned by the cached settings. |
| 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(GURL(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(ConnectorsManagerConnectorPoliciesTest, EmptyPref) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| // If the connector's settings list is empty, no analysis settings are ever |
| // returned. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| ScopedConnectorPref scoped_pref(pref_service(), pref(), kEmptySettingsPref); |
| |
| ASSERT_FALSE( |
| manager.GetAnalysisSettings(GURL(url()), connector()).has_value()); |
| |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| ConnectorsManagerConnectorPoliciesTest, |
| ConnectorsManagerConnectorPoliciesTest, |
| testing::Combine(testing::ValuesIn(kAllAnalysisConnectors), |
| testing::Values(kDlpAndMalwareUrl, |
| kOnlyDlpUrl, |
| kOnlyMalwareUrl, |
| kNoTagsUrl), |
| testing::Values(kNormalCloudAnalysisSettingsPref, |
| kNormalLocalAnalysisSettingsPref))); |
| #endif // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS) |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| 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) { |
| // Can use info.param here to generate the test suffix |
| 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; |
| }; |
| |
| } // namespace |
| |
| class ConnectorsManagerConnectorPoliciesSourceDestinationTest |
| : public ConnectorsManagerTest, |
| public testing::WithParamInterface<SourceDestinationTestingTuple> { |
| public: |
| ConnectorsManagerConnectorPoliciesSourceDestinationTest() { |
| source_destination_testing_helper_ = |
| std::make_unique<SourceDestinationTestingHelper>(profile_, |
| kVolumeInfos); |
| } |
| |
| ~ConnectorsManagerConnectorPoliciesSourceDestinationTest() override { |
| // The testing profile has to be deleted before |
| // source_destination_testing_helper_ is destroyed. |
| 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 AnalysisConnectorPref(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(); |
| } |
| |
| // The "local_user_agent" service provider doesn't support the "malware" |
| // tag, so remove it from expectations. |
| 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()); |
| |
| // Verify that the expected settings are returned normally. |
| 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()); |
| |
| // Verify that the expected settings are also returned by the cached settings. |
| 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()); |
| // If the connector's settings list is empty, no analysis settings are ever |
| // returned. |
| 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 // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS) |
| class ConnectorsManagerAnalysisConnectorsTest |
| : public ConnectorsManagerTest, |
| public testing::WithParamInterface< |
| std::tuple<AnalysisConnector, const char*>> { |
| public: |
| AnalysisConnector connector() const { return std::get<0>(GetParam()); } |
| |
| const char* pref_value() const { return std::get<1>(GetParam()); } |
| |
| const char* pref() const { return AnalysisConnectorPref(connector()); } |
| }; |
| |
| TEST_P(ConnectorsManagerAnalysisConnectorsTest, DynamicPolicies) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| // The cache is initially empty. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| |
| // Once the pref is updated, the settings should be cached, and analysis |
| // settings can be obtained. |
| { |
| 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(GURL(kDlpAndMalwareUrl), |
| 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; |
| |
| // The "local_test" service provider doesn't support the "malware" tag, so |
| // remove it from expectations. |
| if (pref_value() == kNormalCloudAnalysisSettingsPref) |
| expected_tags_ = {{"dlp", TagSettings()}, {"malware", TagSettings()}}; |
| else |
| expected_tags_ = {{"dlp", TagSettings()}}; |
| |
| ValidateSettings(settings.value()); |
| } |
| |
| // The cache should be empty again after the pref is reset. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| } |
| |
| TEST_P(ConnectorsManagerAnalysisConnectorsTest, NamesAndConfigs) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| ScopedConnectorPref scoped_pref(pref_service(), pref(), pref_value()); |
| |
| auto names = manager.GetAnalysisServiceProviderNames(connector()); |
| ASSERT_EQ(1u, names.size()); |
| |
| auto configs = manager.GetAnalysisServiceConfigs(connector()); |
| ASSERT_EQ(1u, configs.size()); |
| |
| if (names[0] == "google") { |
| EXPECT_TRUE(configs[0]->url); |
| EXPECT_FALSE(configs[0]->region_urls.empty()); |
| EXPECT_FALSE(configs[0]->local_path); |
| } else if (names[0] == "local_user_agent") { |
| EXPECT_FALSE(configs[0]->url); |
| EXPECT_TRUE(configs[0]->region_urls.empty()); |
| EXPECT_TRUE(configs[0]->local_path); |
| } else { |
| NOTREACHED() << "Unexpected service provider name"; |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| ConnectorsManagerAnalysisConnectorsTest, |
| ConnectorsManagerAnalysisConnectorsTest, |
| testing::Combine(testing::ValuesIn(kAllAnalysisConnectors), |
| testing::Values(kNormalCloudAnalysisSettingsPref, |
| kNormalLocalAnalysisSettingsPref))); |
| #endif // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS) |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| |
| 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 { |
| // The testing profile has to be deleted before |
| // source_destination_testing_helper_ is destroyed. |
| 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 AnalysisConnectorPref(connector()); } |
| |
| protected: |
| std::unique_ptr<SourceDestinationTestingHelper> |
| source_destination_testing_helper_; |
| }; |
| |
| TEST_P(ConnectorsManagerAnalysisConnectorsSourceDestinationTest, |
| DynamicPolicies) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| // The cache is initially empty. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| |
| // Once the pref is updated, the settings should be cached, and analysis |
| // settings can be obtained. |
| { |
| 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; |
| |
| // The "local_test" service provider doesn't support the "malware" tag, so |
| // remove it from expectations. |
| if (pref_value() == kNormalCloudSourceDestinationSettingsPref) |
| expected_tags_ = {{"dlp", TagSettings()}, {"malware", TagSettings()}}; |
| else |
| expected_tags_ = {{"dlp", TagSettings()}}; |
| |
| ValidateSettings(settings.value()); |
| } |
| |
| // The cache should be empty again after the pref is reset. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| ConnectorsManagerAnalysisConnectorsSourceDestinationTest, |
| ConnectorsManagerAnalysisConnectorsSourceDestinationTest, |
| testing::Combine( |
| testing::Values(AnalysisConnector::FILE_TRANSFER), |
| testing::Values(kNormalCloudSourceDestinationSettingsPref, |
| kNormalLocalSourceDestinationSettingsPref))); |
| |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS) |
| class ConnectorsManagerLocalAnalysisConnectorTest |
| : public ConnectorsManagerTest, |
| public testing::WithParamInterface<AnalysisConnector> { |
| public: |
| AnalysisConnector connector() const { return GetParam(); } |
| |
| const char* pref() const { return AnalysisConnectorPref(connector()); } |
| }; |
| |
| TEST_P(ConnectorsManagerLocalAnalysisConnectorTest, DynamicPolicies) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| FakeContentAnalysisSdkManager content_analysis_sdk_manager; |
| |
| // The cache is initially empty. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| |
| // Once the pref is updated, the settings should be cached, and analysis |
| // settings can be obtained. |
| // Select local service provider first. |
| { |
| ScopedConnectorPref scoped_pref(pref_service(), pref(), |
| kNormalLocalAnalysisSettingsPref); |
| // Force create connection with local agent. |
| content_analysis::sdk::Client::Config config{"local_user_agent"}; |
| content_analysis_sdk_manager.GetClient(config); |
| |
| 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()); |
| |
| // Connection should be established. |
| ASSERT_FALSE(content_analysis_sdk_manager.NoConnectionEstablished()); |
| |
| auto settings = cached_settings.at(connector()) |
| .at(0) |
| .GetAnalysisSettings(GURL(kDlpAndMalwareUrl), |
| 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; |
| |
| // The "local_test" service provider doesn't support the "malware" tag, so |
| // remove it from expectations. |
| expected_tags_ = {{"dlp", TagSettings()}}; |
| |
| ValidateSettings(settings.value()); |
| |
| // Change to cloud service provider. |
| scoped_pref.UpdateScopedConnectorPref(kNormalCloudAnalysisSettingsPref); |
| |
| // Connection should be deleted. |
| ASSERT_TRUE(content_analysis_sdk_manager.NoConnectionEstablished()); |
| ASSERT_FALSE(cached_settings.empty()); |
| ASSERT_EQ(1u, cached_settings.count(connector())); |
| ASSERT_EQ(1u, cached_settings.at(connector()).size()); |
| |
| // Connection should be deleted. |
| ASSERT_TRUE(content_analysis_sdk_manager.NoConnectionEstablished()); |
| |
| settings = cached_settings.at(connector()) |
| .at(0) |
| .GetAnalysisSettings(GURL(kDlpAndMalwareUrl), |
| 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; |
| |
| expected_tags_ = {{"dlp", TagSettings()}, {"malware", TagSettings()}}; |
| |
| ValidateSettings(settings.value()); |
| } |
| |
| // The cache should be empty again after the pref is reset. |
| ASSERT_TRUE(manager.GetAnalysisConnectorsSettingsForTesting().empty()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(ConnectorsManagerLocalAnalysisConnectorTest, |
| ConnectorsManagerLocalAnalysisConnectorTest, |
| testing::ValuesIn(kAllAnalysisConnectors)); |
| #endif // BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS) |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| class ConnectorsManagerDataRegionTest |
| : public ConnectorsManagerTest, |
| public testing::WithParamInterface<std::tuple<AnalysisConnector, |
| DataRegion, |
| DataRegion, |
| policy::PolicyScope>> { |
| public: |
| ConnectorsManagerDataRegionTest() = default; |
| |
| AnalysisConnector connector() const { return std::get<0>(GetParam()); } |
| |
| DataRegion user_data_region() const { return std::get<1>(GetParam()); } |
| |
| DataRegion machine_data_region() const { return std::get<2>(GetParam()); } |
| |
| policy::PolicyScope policy_scope() const { return std::get<3>(GetParam()); } |
| |
| const char* pref() const { return AnalysisConnectorPref(connector()); } |
| |
| protected: |
| void SetUp() override { |
| ConnectorsManagerTest::SetUp(); |
| |
| // Set up the data region setting in both local state and profile prefs. |
| g_browser_process->local_state()->SetInteger( |
| prefs::kChromeDataRegionSetting, |
| static_cast<int>(machine_data_region())); |
| pref_service()->SetInteger(prefs::kChromeDataRegionSetting, |
| static_cast<int>(user_data_region())); |
| |
| // Set up connector scope. |
| pref_service()->SetInteger(AnalysisConnectorScopePref(connector()), |
| policy_scope()); |
| } |
| }; |
| |
| TEST_P(ConnectorsManagerDataRegionTest, RegionalizedEndpoint) { |
| ConnectorsManager manager(pref_service(), GetServiceProviderConfig()); |
| ScopedConnectorPref scoped_pref(pref_service(), pref(), |
| kNormalCloudAnalysisSettingsPref); |
| |
| // Verify that the analysis url in AnalysisSettings matches policy. |
| auto settings_from_manager = |
| manager.GetAnalysisSettings(GURL(kOnlyDlpUrl), connector()); |
| GURL expected_analysis_url = |
| GURL(GetServiceProviderConfig()->at("google").analysis->region_urls |
| [static_cast<size_t>(policy_scope() == policy::POLICY_SCOPE_USER |
| ? user_data_region() |
| : machine_data_region())]); |
| EXPECT_TRUE(settings_from_manager.has_value()); |
| if (settings_from_manager.has_value()) { |
| EXPECT_EQ( |
| expected_analysis_url, |
| settings_from_manager.value().cloud_or_local_settings.analysis_url()); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| ConnectorsManagerDataRegionTest, |
| ConnectorsManagerDataRegionTest, |
| testing::Combine( |
| testing::ValuesIn(kAllAnalysisConnectors), |
| testing::ValuesIn(kAllDataRegions), |
| testing::ValuesIn(kAllDataRegions), |
| testing::Values(policy::PolicyScope::POLICY_SCOPE_USER, |
| policy::PolicyScope::POLICY_SCOPE_MACHINE))); |
| #endif // !BUILDFLAG(IS_ANDROID) |
| } // namespace enterprise_connectors |