blob: c5944540b48606b78d28568fbdb806cc0ca5d332 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// 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/analysis/content_analysis_delegate.h"
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/scoped_refptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/enterprise/connectors/analysis/fake_content_analysis_delegate.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
#include "chrome/browser/policy/dm_token_utils.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "chrome/common/chrome_paths.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/common/proto/connectors.pb.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace enterprise_connectors {
namespace {
constexpr char kDmToken[] = "dm_token";
constexpr char kTestUrl[] = "http://example.com/";
constexpr char kBlockingScansForDlpAndMalware[] = R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp", "malware"]
}
],
"block_until_verdict": 1
})";
constexpr char kBlockingScansForDlp[] = R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp"]
}
],
"block_until_verdict": 1
})";
constexpr char kBlockingScansForMalware[] = R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp"]
}
],
"block_until_verdict": 1
})";
constexpr char kNothingEnabled[] = R"({ "service_provider": "google" })";
// Helpers to get text with sizes relative to the minimum required size of 100
// bytes for scans to trigger.
std::string large_text() {
return std::string(100, 'a');
}
std::string small_text() {
return "random small text";
}
base::ReadOnlySharedMemoryRegion create_page(size_t size) {
base::MappedReadOnlyRegion page =
base::ReadOnlySharedMemoryRegion::Create(size);
memset(page.mapping.memory(), 'a', size);
return std::move(page.region);
}
base::ReadOnlySharedMemoryRegion normal_page() {
return create_page(1024);
}
class ScopedSetDMToken {
public:
explicit ScopedSetDMToken(const policy::DMToken& dm_token) {
SetDMTokenForTesting(dm_token);
}
~ScopedSetDMToken() {
SetDMTokenForTesting(policy::DMToken::CreateEmptyTokenForTesting());
}
};
class BaseTest : public testing::Test {
public:
BaseTest() : profile_manager_(TestingBrowserProcess::GetGlobal()) {
EXPECT_TRUE(profile_manager_.SetUp());
profile_ = profile_manager_.CreateTestingProfile("test-user");
ContentAnalysisDelegate::DisableUIForTesting();
}
void EnableFeatures() {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures({kEnterpriseConnectorsEnabled}, {});
}
void DisableFeatures() {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures({}, {kEnterpriseConnectorsEnabled});
}
void ScanUpload(content::WebContents* web_contents,
ContentAnalysisDelegate::Data data,
ContentAnalysisDelegate::CompletionCallback callback) {
// The access point is only used for metrics and choosing the dialog text if
// one is shown, so its value doesn't affect the tests in this file and can
// always be the same.
ContentAnalysisDelegate::CreateForWebContents(
web_contents, std::move(data), std::move(callback),
safe_browsing::DeepScanAccessPoint::UPLOAD);
}
void CreateFilesForTest(
const std::vector<base::FilePath::StringType>& file_names,
ContentAnalysisDelegate::Data* data,
const std::string& content = "content") {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
for (const auto& file_name : file_names) {
base::FilePath path = temp_dir_.GetPath().Append(file_name);
base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
file.WriteAtCurrentPos(content.data(), content.size());
data->paths.emplace_back(path);
}
}
Profile* profile() { return profile_; }
content::WebContents* contents() {
if (!web_contents_) {
content::WebContents::CreateParams params(profile());
web_contents_ = content::WebContents::Create(params);
}
return web_contents_.get();
}
void RunUntilDone() { run_loop_.Run(); }
void ValidateIsEnabled(const std::string& url,
bool expect_dlp,
bool expect_malware) {
ContentAnalysisDelegate::Data data;
EXPECT_EQ(expect_dlp || expect_malware,
ContentAnalysisDelegate::IsEnabled(profile(), GURL(url), &data,
FILE_ATTACHED));
const auto& tags = data.settings.tags;
EXPECT_EQ(expect_dlp, tags.find("dlp") != tags.end());
EXPECT_EQ(expect_malware, tags.find("malware") != tags.end());
}
protected:
content::BrowserTaskEnvironment task_environment_;
base::test::ScopedFeatureList scoped_feature_list_;
TestingPrefServiceSimple pref_service_;
TestingProfileManager profile_manager_;
raw_ptr<TestingProfile> profile_;
base::ScopedTempDir temp_dir_;
std::unique_ptr<content::WebContents> web_contents_;
base::RunLoop run_loop_;
};
} // namespace
using ContentAnalysisDelegateIsEnabledTest = BaseTest;
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoFeatureNoDMTokenNoPref) {
DisableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateInvalidTokenForTesting());
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoDMTokenNoPref) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateInvalidTokenForTesting());
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoDMToken) {
EnableFeatures();
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlpAndMalware);
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateInvalidTokenForTesting());
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoFeatureNoPref) {
DisableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoFeatureNoDMToken) {
DisableFeatures();
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlpAndMalware);
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateInvalidTokenForTesting());
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoFeature) {
DisableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlpAndMalware);
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpNoPref) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpNoPref2) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kNothingEnabled);
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpNoPref3) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_DOWNLOADED,
kBlockingScansForDlpAndMalware);
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpEnabled) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlp);
ContentAnalysisDelegate::Data data;
EXPECT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_TRUE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpEnabled2) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlp);
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_DOWNLOADED,
kBlockingScansForDlp);
ContentAnalysisDelegate::Data data;
EXPECT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_TRUE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpEnabledWithUrl) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlp);
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_DOWNLOADED,
kBlockingScansForDlp);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
EXPECT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
EXPECT_TRUE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
EXPECT_EQ(kTestUrl, data.url);
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpDisabledByList) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp"]
}
],
"disable": [
{
"url_list": ["http://example.com/"],
"tags": ["dlp"]
}
],
"block_until_verdict": 1
})");
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(kTestUrl),
&data, FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, DlpDisabledByListWithPatterns) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp"]
}
],
"disable": [
{
"url_list": [
"http://example.com/",
"https://*",
"devtools://*",
"*/a/specific/path/",
"*:1234",
"*?q=5678"
],
"tags": ["dlp"]
}
],
"block_until_verdict": 1
})");
ValidateIsEnabled("http://example.com", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("http://google.com", /*dlp*/ true, /*malware*/ false);
ValidateIsEnabled("https://google.com", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("custom://google.com", /*dlp*/ true, /*malware*/ false);
ValidateIsEnabled("custom://version", /*dlp*/ true, /*malware*/ false);
ValidateIsEnabled("devtools://devtools/bundled/inspector.html", /*dlp*/ false,
/*malware*/ false);
ValidateIsEnabled("custom://devtools/bundled/inspector.html", /*dlp*/ true,
/*malware*/ false);
ValidateIsEnabled("http://google.com/a/specific/path/", /*dlp*/ false,
/*malware*/ false);
ValidateIsEnabled("http://google.com/not/a/specific/path/", /*dlp*/ true,
/*malware*/ false);
ValidateIsEnabled("http://google.com:1234", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("http://google.com:4321", /*dlp*/ true, /*malware*/ false);
ValidateIsEnabled("http://google.com?q=5678", /*dlp*/ false,
/*malware*/ false);
ValidateIsEnabled("http://google.com?q=8765", /*dlp*/ true,
/*malware*/ false);
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, MalwareNoPref) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, MalwareNoPref2) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kNothingEnabled);
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, MalwareNoPref3) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_DOWNLOADED,
kBlockingScansForDlpAndMalware);
ContentAnalysisDelegate::Data data;
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(), &data,
FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_FALSE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, MalwareEnabled) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["http://example.com/"],
"tags": ["malware"]
}
],
"block_until_verdict": 1
})");
ContentAnalysisDelegate::Data data;
EXPECT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), GURL(kTestUrl),
&data, FILE_ATTACHED));
EXPECT_FALSE(data.settings.tags.count("dlp"));
EXPECT_TRUE(data.settings.tags.count("malware"));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, NoScanInIncognito) {
GURL url(kTestUrl);
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlpAndMalware);
ContentAnalysisDelegate::Data data;
EXPECT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
// The same URL should not trigger a scan in incognito.
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(
profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), url, &data,
FILE_ATTACHED));
// The same URL should not trigger a scan in non-primary OTR profiles
EXPECT_FALSE(ContentAnalysisDelegate::IsEnabled(
profile()->GetOffTheRecordProfile(
Profile::OTRProfileID::CreateUniqueForTesting(),
/*create_if_needed=*/true),
url, &data, FILE_ATTACHED));
}
TEST_F(ContentAnalysisDelegateIsEnabledTest, MalwareEnabledWithPatterns) {
EnableFeatures();
ScopedSetDMToken scoped_dm_token(
policy::DMToken::CreateValidTokenForTesting(kDmToken));
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
R"(
{
"service_provider": "google",
"enable": [
{
"url_list": [
"http://example.com/",
"https://*",
"devtools://*",
"*/a/specific/path/",
"*:1234",
"*?q=5678"
],
"tags": ["malware"]
}
],
"block_until_verdict": 1
})");
ContentAnalysisDelegate::Data data;
ValidateIsEnabled("http://example.com", /*dlp*/ false, /*malware*/ true);
ValidateIsEnabled("http://google.com", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("https://google.com", /*dlp*/ false, /*malware*/ true);
ValidateIsEnabled("custom://google.com", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("custom://version", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("devtools://devtools/bundled/inspector.html", /*dlp*/ false,
/*malware*/ true);
ValidateIsEnabled("custom://devtools/bundled/inspector.html", /*dlp*/ false,
/*malware*/ false);
ValidateIsEnabled("http://google.com/a/specific/path/", /*dlp*/ false,
/*malware*/ true);
ValidateIsEnabled("http://google.com/not/a/specific/path/", /*dlp*/ false,
/*malware*/ false);
ValidateIsEnabled("http://google.com:1234", /*dlp*/ false, /*malware*/ true);
ValidateIsEnabled("http://google.com:4321", /*dlp*/ false, /*malware*/ false);
ValidateIsEnabled("http://google.com?q=5678", /*dlp*/ false,
/*malware*/ true);
ValidateIsEnabled("http://google.com?q=8765", /*dlp*/ false,
/*malware*/ false);
}
class ContentAnalysisDelegateAuditOnlyTest : public BaseTest {
public:
ContentAnalysisDelegateAuditOnlyTest() = default;
protected:
void SetDLPResponse(ContentAnalysisResponse response) {
dlp_response_ = std::move(response);
}
void PathFailsDeepScan(base::FilePath path,
ContentAnalysisResponse response) {
failures_.insert({std::move(path), std::move(response)});
}
void SetPathIsEncrypted(base::FilePath path) {
encrypted_.insert(std::move(path));
}
void SetScanPolicies(bool dlp, bool malware) {
include_dlp_ = dlp;
include_malware_ = malware;
for (auto connector : {FILE_ATTACHED, BULK_DATA_ENTRY, PRINT}) {
if (include_dlp_ && include_malware_) {
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), connector,
kBlockingScansForDlpAndMalware);
} else if (include_dlp_) {
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), connector,
kBlockingScansForDlp);
} else if (include_malware_) {
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), connector,
kBlockingScansForMalware);
} else {
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), connector,
kNothingEnabled);
}
}
}
void SetUp() override {
BaseTest::SetUp();
EnableFeatures();
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlpAndMalware);
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), BULK_DATA_ENTRY,
kBlockingScansForDlpAndMalware);
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), PRINT,
kBlockingScansForDlpAndMalware);
ContentAnalysisDelegate::SetFactoryForTesting(base::BindRepeating(
&FakeContentAnalysisDelegate::Create, run_loop_.QuitClosure(),
base::BindRepeating(
&ContentAnalysisDelegateAuditOnlyTest::ConnectorStatusCallback,
base::Unretained(this)),
base::BindRepeating(
&ContentAnalysisDelegateAuditOnlyTest::EncryptionStatusCallback,
base::Unretained(this)),
kDmToken));
}
ContentAnalysisResponse ConnectorStatusCallback(const base::FilePath& path) {
// The path succeeds if it is not in the |failures_| maps.
auto it = failures_.find(path);
ContentAnalysisResponse response =
it != failures_.end()
? it->second
: FakeContentAnalysisDelegate::SuccessfulResponse([this]() {
std::set<std::string> tags;
if (include_dlp_ && !dlp_response_.has_value())
tags.insert("dlp");
if (include_malware_)
tags.insert("malware");
return tags;
}());
if (include_dlp_ && dlp_response_.has_value()) {
*response.add_results() = dlp_response_.value().results(0);
}
return response;
}
bool EncryptionStatusCallback(const base::FilePath& path) {
return encrypted_.count(path) > 0;
}
private:
ScopedSetDMToken scoped_dm_token_{
policy::DMToken::CreateValidTokenForTesting(kDmToken)};
bool include_dlp_ = true;
bool include_malware_ = true;
// Paths in this map will be consider to have failed deep scan checks.
// The actual failure response is given for each path.
std::map<base::FilePath, ContentAnalysisResponse> failures_;
// Paths in this set will be considered to contain encryption and will
// not be uploaded.
std::set<base::FilePath> encrypted_;
// DLP response to ovewrite in the callback if present.
absl::optional<ContentAnalysisResponse> dlp_response_ = absl::nullopt;
};
TEST_F(ContentAnalysisDelegateAuditOnlyTest, Empty) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
// Keep |data| empty by not setting any text or paths.
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(0u, result.paths_results.size());
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringData) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
data.text.emplace_back(large_text());
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(1u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
ASSERT_EQ(1u, result.text_results.size());
EXPECT_EQ(0u, result.paths_results.size());
EXPECT_TRUE(result.text_results[0]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringData2) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
data.text.emplace_back(large_text());
data.text.emplace_back(large_text());
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(2u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
ASSERT_EQ(2u, result.text_results.size());
EXPECT_EQ(0u, result.paths_results.size());
EXPECT_TRUE(result.text_results[0]);
EXPECT_TRUE(result.text_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringData3) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
// Because the strings are small, they are exempt from scanning and will be
// allowed even when a negative verdict is mocked.
data.text.emplace_back(small_text());
data.text.emplace_back(small_text());
SetDLPResponse(FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS, "rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(2u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
ASSERT_EQ(2u, result.text_results.size());
EXPECT_EQ(0u, result.paths_results.size());
EXPECT_TRUE(result.text_results[0]);
EXPECT_TRUE(result.text_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, PagePrintAllowed) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data, PRINT));
data.page = normal_page();
ASSERT_TRUE(data.page.IsValid());
bool called = false;
ContentAnalysisDelegate::CreateForWebContents(
contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
// The page data should no longer be valid since it's moved
// to be uploaded in a request.
EXPECT_FALSE(data.page.IsValid());
ASSERT_EQ(0u, result.text_results.size());
EXPECT_EQ(0u, result.paths_results.size());
EXPECT_TRUE(result.page_result);
*called = true;
},
&called),
safe_browsing::DeepScanAccessPoint::PRINT);
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, PagePrintBlocked) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data, PRINT));
data.page = normal_page();
ASSERT_TRUE(data.page.IsValid());
SetDLPResponse(FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS, "rule", TriggeredRule::BLOCK));
bool called = false;
ContentAnalysisDelegate::CreateForWebContents(
contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
// The page data should no longer be valid since it's moved
// to be uploaded in a request.
EXPECT_FALSE(data.page.IsValid());
ASSERT_EQ(0u, result.text_results.size());
EXPECT_EQ(0u, result.paths_results.size());
EXPECT_FALSE(result.page_result);
*called = true;
},
&called),
safe_browsing::DeepScanAccessPoint::PRINT);
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest,
FileDataPositiveMalwareAndDlpVerdicts) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest({FILE_PATH_LITERAL("foo.doc")}, &data);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(1u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
ASSERT_EQ(1u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest,
FileDataPositiveMalwareAndDlpVerdicts2) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest(
{FILE_PATH_LITERAL("foo.doc"), FILE_PATH_LITERAL("bar.doc")}, &data);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
ASSERT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
EXPECT_TRUE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, FileDataPositiveMalwareVerdict) {
SetScanPolicies(/*dlp=*/false, /*malware=*/true);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest(
{FILE_PATH_LITERAL("good.doc"), FILE_PATH_LITERAL("good2.doc")}, &data);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
EXPECT_TRUE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, FileIsEncrypted) {
content::InProcessUtilityThreadHelper in_process_utility_thread_helper;
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED, R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp", "malware"]
}
],
"block_until_verdict": 1,
"block_password_protected": true
})");
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
base::FilePath test_zip;
EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_zip));
test_zip = test_zip.AppendASCII("safe_browsing")
.AppendASCII("download_protection")
.AppendASCII("encrypted.zip");
data.paths.emplace_back(test_zip);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(1u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(1u, result.paths_results.size());
EXPECT_FALSE(result.paths_results[0]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
// Flaky on Mac: https://crbug.com/1143782:
#if defined(OS_MAC)
#define MAYBE_FileIsEncrypted_PolicyAllows DISABLED_FileIsEncrypted_PolicyAllows
#else
#define MAYBE_FileIsEncrypted_PolicyAllows FileIsEncrypted_PolicyAllows
#endif
TEST_F(ContentAnalysisDelegateAuditOnlyTest,
MAYBE_FileIsEncrypted_PolicyAllows) {
content::InProcessUtilityThreadHelper in_process_utility_thread_helper;
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED, R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp", "malware"]
}
],
"block_until_verdict": 1,
"block_password_protected": false
})");
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
base::FilePath test_zip;
EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_zip));
test_zip = test_zip.AppendASCII("safe_browsing")
.AppendASCII("download_protection")
.AppendASCII("encrypted.zip");
data.paths.emplace_back(test_zip);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(1u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(1u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, FileDataNegativeMalwareVerdict) {
SetScanPolicies(/*dlp=*/false, /*malware=*/true);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest(
{FILE_PATH_LITERAL("good.doc"), FILE_PATH_LITERAL("bad.doc")}, &data);
PathFailsDeepScan(data.paths[1], FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
EXPECT_FALSE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, FileDataPositiveDlpVerdict) {
SetScanPolicies(/*dlp=*/true, /*malware=*/false);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest(
{FILE_PATH_LITERAL("good.doc"), FILE_PATH_LITERAL("good2.doc")}, &data);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
EXPECT_TRUE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, FileDataNegativeDlpVerdict) {
SetScanPolicies(/*dlp=*/true, /*malware=*/false);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest(
{FILE_PATH_LITERAL("good.doc"), FILE_PATH_LITERAL("bad.doc")}, &data);
PathFailsDeepScan(data.paths[1], FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
EXPECT_FALSE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest,
FileDataNegativeMalwareAndDlpVerdicts) {
SetScanPolicies(/*dlp=*/true, /*malware=*/true);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest(
{FILE_PATH_LITERAL("good.doc"), FILE_PATH_LITERAL("bad.doc")}, &data);
PathFailsDeepScan(
data.paths[1],
FakeContentAnalysisDelegate::MalwareAndDlpResponse(
TriggeredRule::BLOCK, ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.paths_results[0]);
EXPECT_FALSE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringFileData) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
data.text.emplace_back(large_text());
CreateFilesForTest(
{FILE_PATH_LITERAL("foo.doc"), FILE_PATH_LITERAL("bar.doc")}, &data);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(1u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
ASSERT_EQ(1u, result.text_results.size());
ASSERT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.text_results[0]);
EXPECT_TRUE(result.paths_results[0]);
EXPECT_TRUE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringFileDataNoDLP) {
// Enable malware scan so deep scanning still occurs.
SetScanPolicies(/*dlp=*/false, /*malware=*/true);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
data.text.emplace_back(large_text());
data.text.emplace_back(large_text());
CreateFilesForTest(
{FILE_PATH_LITERAL("foo.doc"), FILE_PATH_LITERAL("bar.doc")}, &data);
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(2u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
ASSERT_EQ(2u, result.text_results.size());
ASSERT_EQ(2u, result.paths_results.size());
EXPECT_TRUE(result.text_results[0]);
EXPECT_TRUE(result.text_results[1]);
EXPECT_TRUE(result.paths_results[0]);
EXPECT_TRUE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringFileDataFailedDLP) {
SetScanPolicies(/*dlp=*/true, /*malware=*/false);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
data.text.emplace_back(large_text());
data.text.emplace_back(large_text());
SetDLPResponse(FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS, "rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(2u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
ASSERT_EQ(2u, result.text_results.size());
ASSERT_EQ(0u, result.paths_results.size());
EXPECT_FALSE(result.text_results[0]);
EXPECT_FALSE(result.text_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, StringFileDataPartialSuccess) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(profile(), url, &data,
BULK_DATA_ENTRY));
data.text.emplace_back(large_text());
CreateFilesForTest({FILE_PATH_LITERAL("foo.doc"),
FILE_PATH_LITERAL("foo_fail_malware_1.doc"),
FILE_PATH_LITERAL("foo_fail_malware_2.doc"),
FILE_PATH_LITERAL("foo_fail_dlp_status.doc"),
FILE_PATH_LITERAL("foo_fail_dlp_rule.doc")},
&data);
// Mark some files with failed scans.
PathFailsDeepScan(data.paths[1], FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::WARN));
PathFailsDeepScan(data.paths[2], FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::BLOCK));
PathFailsDeepScan(data.paths[3], FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::FAILURE,
"", TriggeredRule::REPORT_ONLY));
PathFailsDeepScan(data.paths[4], FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(1u, data.text.size());
EXPECT_EQ(5u, data.paths.size());
ASSERT_EQ(1u, result.text_results.size());
ASSERT_EQ(5u, result.paths_results.size());
EXPECT_TRUE(result.text_results[0]);
EXPECT_TRUE(result.paths_results[0]);
EXPECT_FALSE(result.paths_results[1]);
EXPECT_FALSE(result.paths_results[2]);
EXPECT_TRUE(result.paths_results[3]);
EXPECT_FALSE(result.paths_results[4]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, NoDelay) {
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED, R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp", "malware"]
}
],
"block_until_verdict": 0
})");
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
data.text.emplace_back("dlp_text");
CreateFilesForTest({FILE_PATH_LITERAL("foo_fail_malware_0.doc"),
FILE_PATH_LITERAL("foo_fail_malware_1.doc"),
FILE_PATH_LITERAL("foo_fail_malware_2.doc"),
FILE_PATH_LITERAL("foo_fail_dlp_status.doc"),
FILE_PATH_LITERAL("foo_fail_dlp_rule.doc")},
&data);
// Mark all files and text with failed scans.
SetDLPResponse(FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS, "rule", TriggeredRule::BLOCK));
PathFailsDeepScan(data.paths[0], FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::BLOCK));
PathFailsDeepScan(data.paths[1], FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::WARN));
PathFailsDeepScan(data.paths[2], FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::BLOCK));
PathFailsDeepScan(data.paths[3], FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::FAILURE,
"", TriggeredRule::REPORT_ONLY));
PathFailsDeepScan(data.paths[4], FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(1u, data.text.size());
EXPECT_EQ(5u, data.paths.size());
EXPECT_EQ(1u, result.text_results.size());
EXPECT_EQ(5u, result.paths_results.size());
// All results are set to true since we are not blocking the
// user.
EXPECT_TRUE(result.text_results[0]);
EXPECT_TRUE(result.paths_results[0]);
EXPECT_TRUE(result.paths_results[1]);
EXPECT_TRUE(result.paths_results[2]);
EXPECT_TRUE(result.paths_results[3]);
EXPECT_TRUE(result.paths_results[4]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, EmptyWait) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(0u, data.paths.size());
ASSERT_EQ(0u, result.text_results.size());
ASSERT_EQ(0u, result.paths_results.size());
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, SupportedTypes) {
content::InProcessUtilityThreadHelper in_process_utility_thread_helper;
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
std::vector<base::FilePath::StringType> file_names;
for (const base::FilePath::StringType& supported_type :
safe_browsing::SupportedDlpFileTypes()) {
file_names.push_back(base::FilePath::StringType(FILE_PATH_LITERAL("foo")) +
supported_type);
}
CreateFilesForTest(file_names, &data);
// Mark all files with failed scans.
for (const auto& path : data.paths) {
PathFailsDeepScan(path, FakeContentAnalysisDelegate::MalwareResponse(
TriggeredRule::BLOCK));
}
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(26u, data.paths.size());
EXPECT_EQ(26u, result.paths_results.size());
// The supported types should be marked as false.
for (auto paths_result : result.paths_results)
EXPECT_FALSE(paths_result);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, UnsupportedTypesDefaultPolicy) {
SetScanPolicies(/*dlp=*/true, /*malware=*/false);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
// The file content bytes correspond to an unsupported type (png) so that
// sniffing doesn't indicate the file is supported.
CreateFilesForTest(
{FILE_PATH_LITERAL("foo.these"), FILE_PATH_LITERAL("foo.file"),
FILE_PATH_LITERAL("foo.types"), FILE_PATH_LITERAL("foo.are"),
FILE_PATH_LITERAL("foo.not"), FILE_PATH_LITERAL("foo.supported")},
&data, /*content*/ "\x89PNG\x0D\x0A\x1A\x0A");
// Mark all files with failed scans.
for (const auto& path : data.paths) {
PathFailsDeepScan(path, FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::WARN));
}
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(6u, data.paths.size());
ASSERT_EQ(6u, result.paths_results.size());
// The unsupported types should be marked as true since the
// default policy behavior is to allow them through.
for (const bool path_result : result.paths_results)
EXPECT_TRUE(path_result);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, UnsupportedTypesBlockPolicy) {
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED, R"(
{
"service_provider": "google",
"enable": [
{
"url_list": ["*"],
"tags": ["dlp", "malware"]
}
],
"block_until_verdict": 1,
"block_unsupported_file_types": true
})");
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
EXPECT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
// The file content bytes correspond to an unsupported type (png) so that
// sniffing doesn't indicate the file is supported.
CreateFilesForTest(
{FILE_PATH_LITERAL("foo.these"), FILE_PATH_LITERAL("foo.file"),
FILE_PATH_LITERAL("foo.types"), FILE_PATH_LITERAL("foo.are"),
FILE_PATH_LITERAL("foo.not"), FILE_PATH_LITERAL("foo.supported")},
&data, /*content*/ "\x89PNG\x0D\x0A\x1A\x0A");
// Mark all files with failed scans.
for (const auto& path : data.paths) {
PathFailsDeepScan(path, FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::WARN));
}
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(6u, data.paths.size());
ASSERT_EQ(6u, result.paths_results.size());
// The unsupported types should be marked as false since the
// block policy behavior is to not allow them through.
for (const bool path_result : result.paths_results)
EXPECT_FALSE(path_result);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, SupportedAndUnsupportedTypes) {
SetScanPolicies(/*dlp=*/true, /*malware=*/false);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
// Only 3 of these file types are supported (bzip, cab and doc). They are
// mixed in the list so as to show that insertion order does not matter. The
// file content bytes correspond to an unsupported type (png) so that sniffing
// doesn't indicate the file is supported.
CreateFilesForTest(
{FILE_PATH_LITERAL("foo.bzip"), FILE_PATH_LITERAL("foo.these"),
FILE_PATH_LITERAL("foo.file"), FILE_PATH_LITERAL("foo.types"),
FILE_PATH_LITERAL("foo.cab"), FILE_PATH_LITERAL("foo.are"),
FILE_PATH_LITERAL("foo.not"), FILE_PATH_LITERAL("foo.supported"),
FILE_PATH_LITERAL("foo_no_extension"), FILE_PATH_LITERAL("foo.doc")},
&data, /*content*/ "\x89PNG\x0D\x0A\x1A\x0A");
// Mark all files with failed scans.
for (const auto& path : data.paths) {
PathFailsDeepScan(path, FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS,
"rule", TriggeredRule::BLOCK));
}
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(10u, data.paths.size());
ASSERT_EQ(10u, result.paths_results.size());
// The unsupported types should be marked as true, and the
// valid types as false since they are marked as failed
// scans.
size_t i = 0;
for (const bool expected : {false, true, true, true, false,
true, true, true, true, false}) {
ASSERT_EQ(expected, result.paths_results[i]);
++i;
}
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(ContentAnalysisDelegateAuditOnlyTest, UnsupportedTypeAndDLPFailure) {
SetScanPolicies(/*dlp=*/true, /*malware=*/false);
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
// The file content bytes correspond to an unsupported type (png) so that
// sniffing doesn't indicate the file is supported.
CreateFilesForTest({FILE_PATH_LITERAL("foo.unsupported_extension"),
FILE_PATH_LITERAL("dlp_fail.doc")},
&data, /*content*/ "\x89PNG\x0D\x0A\x1A\x0A");
// Mark DLP as failure.
SetDLPResponse(FakeContentAnalysisDelegate::DlpResponse(
ContentAnalysisResponse::Result::SUCCESS, "rule", TriggeredRule::BLOCK));
bool called = false;
ScanUpload(contents(), std::move(data),
base::BindOnce(
[](bool* called, const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(2u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(2u, result.paths_results.size());
// The unsupported type file should be marked as true, and
// the valid type file as false.
EXPECT_TRUE(result.paths_results[0]);
EXPECT_FALSE(result.paths_results[1]);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
class ContentAnalysisDelegateResultHandlingTest
: public BaseTest,
public testing::WithParamInterface<
std::tuple<safe_browsing::BinaryUploadService::Result, bool>> {
public:
ContentAnalysisDelegateResultHandlingTest() = default;
void SetUp() override {
BaseTest::SetUp();
EnableFeatures();
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
kBlockingScansForDlpAndMalware);
ContentAnalysisDelegate::SetFactoryForTesting(base::BindRepeating(
&FakeContentAnalysisDelegate::Create, run_loop_.QuitClosure(),
base::BindRepeating(
&ContentAnalysisDelegateResultHandlingTest::ConnectorStatusCallback,
base::Unretained(this)),
/*encryption_callback=*/
base::BindRepeating([](const base::FilePath& path) { return false; }),
kDmToken));
}
safe_browsing::BinaryUploadService::Result result() const {
return std::get<0>(GetParam());
}
ContentAnalysisResponse ConnectorStatusCallback(const base::FilePath& path) {
return FakeContentAnalysisDelegate::SuccessfulResponse({"dlp", "malware"});
}
protected:
ScopedSetDMToken scoped_dm_token_{
policy::DMToken::CreateValidTokenForTesting(kDmToken)};
};
TEST_P(ContentAnalysisDelegateResultHandlingTest, Test) {
GURL url(kTestUrl);
ContentAnalysisDelegate::Data data;
FakeContentAnalysisDelegate::SetResponseResult(result());
ASSERT_TRUE(
ContentAnalysisDelegate::IsEnabled(profile(), url, &data, FILE_ATTACHED));
CreateFilesForTest({FILE_PATH_LITERAL("foo.txt")}, &data);
bool called = false;
ScanUpload(
contents(), std::move(data),
base::BindLambdaForTesting(
[this, &called](const ContentAnalysisDelegate::Data& data,
const ContentAnalysisDelegate::Result& result) {
EXPECT_EQ(0u, data.text.size());
EXPECT_EQ(1u, data.paths.size());
EXPECT_EQ(0u, result.text_results.size());
EXPECT_EQ(1u, result.paths_results.size());
bool expected = ContentAnalysisDelegate::ResultShouldAllowDataUse(
this->result(), data.settings);
EXPECT_EQ(expected, result.paths_results[0]);
called = true;
}));
RunUntilDone();
EXPECT_TRUE(called);
}
INSTANTIATE_TEST_SUITE_P(
,
ContentAnalysisDelegateResultHandlingTest,
testing::Combine(
testing::Values(
safe_browsing::BinaryUploadService::Result::UNKNOWN,
safe_browsing::BinaryUploadService::Result::SUCCESS,
safe_browsing::BinaryUploadService::Result::UPLOAD_FAILURE,
safe_browsing::BinaryUploadService::Result::TIMEOUT,
safe_browsing::BinaryUploadService::Result::FILE_TOO_LARGE,
safe_browsing::BinaryUploadService::Result::FAILED_TO_GET_TOKEN,
safe_browsing::BinaryUploadService::Result::UNAUTHORIZED,
safe_browsing::BinaryUploadService::Result::FILE_ENCRYPTED),
testing::Bool()));
class ContentAnalysisDelegateSettingsTest
: public BaseTest,
public testing::WithParamInterface<bool> {
public:
ContentAnalysisDelegateSettingsTest() = default;
void SetUp() override {
BaseTest::SetUp();
EnableFeatures();
// Settings can't be returned if no DM token exists.
SetDMTokenForTesting(policy::DMToken::CreateValidTokenForTesting(kDmToken));
}
bool allowed() const { return !GetParam(); }
const char* bool_setting() const { return GetParam() ? "true" : "false"; }
AnalysisSettings settings() {
absl::optional<AnalysisSettings> settings =
ConnectorsServiceFactory::GetForBrowserContext(profile())
->GetAnalysisSettings(GURL(kTestUrl), FILE_ATTACHED);
EXPECT_TRUE(settings.has_value());
return std::move(settings.value());
}
};
INSTANTIATE_TEST_SUITE_P(,
ContentAnalysisDelegateSettingsTest,
testing::Bool());
TEST_P(ContentAnalysisDelegateSettingsTest, BlockLargeFile) {
auto pref = base::StringPrintf(R"(
{
"service_provider": "google",
"enable": [{"url_list": ["*"], "tags": ["dlp"]}],
"block_large_files": %s
})",
bool_setting());
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
pref);
EXPECT_EQ(allowed(),
ContentAnalysisDelegate::ResultShouldAllowDataUse(
safe_browsing::BinaryUploadService::Result::FILE_TOO_LARGE,
settings()));
}
TEST_P(ContentAnalysisDelegateSettingsTest, BlockPasswordProtected) {
auto pref = base::StringPrintf(R"(
{
"service_provider": "google",
"enable": [{"url_list": ["*"], "tags": ["dlp"]}],
"block_password_protected": %s
})",
bool_setting());
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
pref);
EXPECT_EQ(allowed(),
ContentAnalysisDelegate::ResultShouldAllowDataUse(
safe_browsing::BinaryUploadService::Result::FILE_ENCRYPTED,
settings()));
}
TEST_P(ContentAnalysisDelegateSettingsTest, BlockUnsupportedFileTypes) {
auto pref = base::StringPrintf(R"(
{
"service_provider": "google",
"enable": [{"url_list": ["*"], "tags": ["dlp"]}],
"block_unsupported_file_types": %s
})",
bool_setting());
safe_browsing::SetAnalysisConnector(profile_->GetPrefs(), FILE_ATTACHED,
pref);
EXPECT_EQ(allowed(), ContentAnalysisDelegate::ResultShouldAllowDataUse(
safe_browsing::BinaryUploadService::Result::
DLP_SCAN_UNSUPPORTED_FILE_TYPE,
settings()));
}
} // namespace enterprise_connectors