blob: cde581e61eb2bcae51a5d5277f6876bc7e533868 [file] [log] [blame]
// Copyright 2020 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 <memory>
#include <set>
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_views.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/browser/safe_browsing/dm_token_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "content/public/test/browser_test.h"
using extensions::SafeBrowsingPrivateEventRouter;
using ::testing::_;
using ::testing::Mock;
namespace safe_browsing {
namespace {
base::string16 text() {
return base::UTF8ToUTF16(std::string(100, 'a'));
}
class FakeBinaryUploadService : public BinaryUploadService {
public:
FakeBinaryUploadService() : BinaryUploadService(nullptr, nullptr, nullptr) {}
// Sets whether the user is authorized to upload data for Deep Scanning.
void SetAuthorized(bool authorized) {
authorization_result_ = authorized
? BinaryUploadService::Result::SUCCESS
: BinaryUploadService::Result::UNAUTHORIZED;
}
// Finish the authentication request. Called after ShowForWebContents to
// simulate an async callback.
void ReturnAuthorizedResponse() {
FinishRequest(authorization_request_.get(), authorization_result_);
}
void SetResponseForText(BinaryUploadService::Result result,
const DeepScanningClientResponse& response) {
prepared_text_result_ = result;
prepared_text_response_ = response;
}
void SetResponseForText(
BinaryUploadService::Result result,
const enterprise_connectors::ContentAnalysisResponse& response) {
prepared_text_result_ = result;
prepared_content_analysis_text_response_ = response;
}
void SetResponseForFile(const std::string& path,
BinaryUploadService::Result result,
const DeepScanningClientResponse& response) {
prepared_file_results_[path] = result;
prepared_file_responses_[path] = response;
}
void SetResponseForFile(
const std::string& path,
BinaryUploadService::Result result,
const enterprise_connectors::ContentAnalysisResponse& response) {
prepared_file_results_[path] = result;
prepared_content_analysis_file_responses_[path] = response;
}
void SetShouldAutomaticallyAuthorize(bool authorize) {
should_automatically_authorize_ = authorize;
}
int requests_count() const { return requests_count_; }
void set_use_legacy_proto(bool use_legacy_proto) {
use_legacy_proto_ = use_legacy_proto;
}
private:
bool use_legacy_proto() const { return use_legacy_proto_; }
void UploadForDeepScanning(std::unique_ptr<Request> request) override {
// The first uploaded request is the authentication one.
if (++requests_count_ == 1) {
authorization_request_.swap(request);
if (should_automatically_authorize_)
ReturnAuthorizedResponse();
} else {
std::string file = request->filename();
if (file.empty()) {
if (use_legacy_proto()) {
request->FinishLegacyRequest(prepared_text_result_,
prepared_text_response_);
} else {
request->FinishConnectorRequest(
prepared_text_result_, prepared_content_analysis_text_response_);
}
} else {
if (use_legacy_proto()) {
ASSERT_TRUE(prepared_file_results_.count(file));
ASSERT_TRUE(prepared_file_responses_.count(file));
request->FinishLegacyRequest(prepared_file_results_[file],
prepared_file_responses_[file]);
} else {
ASSERT_TRUE(prepared_file_results_.count(file));
ASSERT_TRUE(prepared_content_analysis_file_responses_.count(file));
request->FinishConnectorRequest(
prepared_file_results_[file],
prepared_content_analysis_file_responses_[file]);
}
}
}
}
BinaryUploadService::Result authorization_result_;
std::unique_ptr<Request> authorization_request_;
BinaryUploadService::Result prepared_text_result_;
DeepScanningClientResponse prepared_text_response_;
enterprise_connectors::ContentAnalysisResponse
prepared_content_analysis_text_response_;
std::map<std::string, BinaryUploadService::Result> prepared_file_results_;
std::map<std::string, DeepScanningClientResponse> prepared_file_responses_;
std::map<std::string, enterprise_connectors::ContentAnalysisResponse>
prepared_content_analysis_file_responses_;
int requests_count_ = 0;
bool should_automatically_authorize_ = false;
bool use_legacy_proto_;
};
FakeBinaryUploadService* FakeBinaryUploadServiceStorage() {
static FakeBinaryUploadService service;
return &service;
}
const std::set<std::string>* DocMimeTypes() {
static std::set<std::string> set = {
"application/msword",
// The 50 MB file can result in no mimetype being found.
""};
return &set;
}
const std::set<std::string>* ExeMimeTypes() {
static std::set<std::string> set = {"application/x-msdownload",
"application/x-ms-dos-executable",
"application/octet-stream"};
return &set;
}
const std::set<std::string>* ZipMimeTypes() {
static std::set<std::string> set = {"application/zip",
"application/x-zip-compressed"};
return &set;
}
const std::set<std::string>* ShellScriptMimeTypes() {
static std::set<std::string> set = {"text/x-sh", "application/x-shellscript"};
return &set;
}
const std::set<std::string>* TextMimeTypes() {
static std::set<std::string> set = {"text/plain"};
return &set;
}
// A fake delegate with minimal overrides to obtain behavior that's as close to
// the real one as possible.
class MinimalFakeDeepScanningDialogDelegate
: public DeepScanningDialogDelegate {
public:
MinimalFakeDeepScanningDialogDelegate(
content::WebContents* web_contents,
DeepScanningDialogDelegate::Data data,
DeepScanningDialogDelegate::CompletionCallback callback)
: DeepScanningDialogDelegate(web_contents,
std::move(data),
std::move(callback),
DeepScanAccessPoint::UPLOAD) {}
static std::unique_ptr<DeepScanningDialogDelegate> Create(
content::WebContents* web_contents,
DeepScanningDialogDelegate::Data data,
DeepScanningDialogDelegate::CompletionCallback callback) {
return std::make_unique<MinimalFakeDeepScanningDialogDelegate>(
web_contents, std::move(data), std::move(callback));
}
private:
BinaryUploadService* GetBinaryUploadService() override {
return FakeBinaryUploadServiceStorage();
}
};
constexpr char kDmToken[] = "dm_token";
constexpr char kTestUrl[] = "https://google.com";
} // namespace
// Tests the behavior of the dialog delegate with minimal overriding of methods.
// Only responses obtained via the BinaryUploadService are faked.
class DeepScanningDialogDelegateBrowserTest
: public DeepScanningBrowserTestBase,
public DeepScanningDialogViews::TestObserver {
public:
explicit DeepScanningDialogDelegateBrowserTest(bool use_legacy_policies)
: DeepScanningBrowserTestBase(use_legacy_policies),
use_legacy_policies_and_protos_(use_legacy_policies) {
DeepScanningDialogViews::SetObserverForTesting(this);
}
void EnableUploadsScanningAndReporting() {
SetDMTokenForTesting(policy::DMToken::CreateValidTokenForTesting(kDmToken));
SetDlpPolicy(CHECK_UPLOADS);
SetMalwarePolicy(SEND_UPLOADS);
SetWaitPolicy(DELAY_UPLOADS);
SetUnsafeEventsReportingPolicy(true);
// Add the wildcard pattern to this policy since malware responses are
// verified for most of these tests.
AddUrlToCheckForMalwareOfUploads("*");
client_ = std::make_unique<policy::MockCloudPolicyClient>();
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(
browser()->profile())
->SetCloudPolicyClientForTesting(client_.get());
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(
browser()->profile())
->SetBinaryUploadServiceForTesting(FakeBinaryUploadServiceStorage());
FakeBinaryUploadServiceStorage()->set_use_legacy_proto(
use_legacy_policies_and_protos_);
}
void DestructorCalled(DeepScanningDialogViews* views) override {
// The test is over once the views are destroyed.
CallQuitClosure();
}
void ExpectNoReport() {
EXPECT_CALL(*client_, UploadRealtimeReport_(_, _)).Times(0);
}
policy::MockCloudPolicyClient* client() { return client_.get(); }
bool use_legacy_protos() const { return use_legacy_policies_and_protos_; }
private:
std::unique_ptr<policy::MockCloudPolicyClient> client_;
base::ScopedTempDir temp_dir_;
bool use_legacy_policies_and_protos_;
};
class DeepScanningDialogDelegateSimpleBrowserTest
: public DeepScanningDialogDelegateBrowserTest,
public testing::WithParamInterface<bool> {
public:
DeepScanningDialogDelegateSimpleBrowserTest()
: DeepScanningDialogDelegateBrowserTest(GetParam()) {}
};
IN_PROC_BROWSER_TEST_P(DeepScanningDialogDelegateSimpleBrowserTest,
Unauthorized) {
EnableUploadsScanningAndReporting();
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(false);
bool called = false;
base::RunLoop run_loop;
base::RepeatingClosure quit_closure = run_loop.QuitClosure();
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = true;
data.text.emplace_back(text());
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::FILE_ATTACHED));
// Nothing should be reported for unauthorized users.
ExpectNoReport();
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[&quit_closure, &called](
const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_EQ(result.text_results.size(), 1u);
ASSERT_EQ(result.paths_results.size(), 1u);
ASSERT_TRUE(result.text_results[0]);
ASSERT_TRUE(result.paths_results[0]);
called = true;
quit_closure.Run();
}),
DeepScanAccessPoint::UPLOAD);
FakeBinaryUploadServiceStorage()->ReturnAuthorizedResponse();
run_loop.Run();
EXPECT_TRUE(called);
// Only 1 request (the authentication one) should have been uploaded.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 1);
}
IN_PROC_BROWSER_TEST_P(DeepScanningDialogDelegateSimpleBrowserTest, Files) {
base::ScopedAllowBlockingForTesting allow_blocking;
// Set up delegate and upload service.
EnableUploadsScanningAndReporting();
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(true);
FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
// Create the files to be opened and scanned.
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = true;
CreateFilesForTest({"ok.doc", "bad.exe"},
{"ok file content", "bad file content"}, &data);
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::FILE_ATTACHED));
// The malware verdict means an event should be reported.
EventReportValidator validator(client());
validator.ExpectDangerousDeepScanningResult(
/*url*/ "about:blank",
/*filename*/ created_file_paths()[1].AsUTF8Unsafe(),
// printf "bad file content" | sha256sum | tr '[:lower:]' '[:upper:]'
/*sha*/
"77AE96C38386429D28E53F5005C46C7B4D8D39BE73D757CE61E0AE65CC1A5A5D",
/*threat_type*/ "DANGEROUS",
/*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
/*mimetypes*/ ExeMimeTypes(),
/*size*/ std::string("bad file content").size());
if (use_legacy_protos()) {
DeepScanningClientResponse ok_response;
ok_response.mutable_dlp_scan_verdict()->set_status(
DlpDeepScanningVerdict::SUCCESS);
ok_response.mutable_malware_scan_verdict()->set_verdict(
MalwareDeepScanningVerdict::CLEAN);
DeepScanningClientResponse bad_response;
bad_response.mutable_dlp_scan_verdict()->set_status(
DlpDeepScanningVerdict::SUCCESS);
bad_response.mutable_malware_scan_verdict()->set_verdict(
MalwareDeepScanningVerdict::MALWARE);
FakeBinaryUploadServiceStorage()->SetResponseForFile(
"ok.doc", BinaryUploadService::Result::SUCCESS, ok_response);
FakeBinaryUploadServiceStorage()->SetResponseForFile(
"bad.exe", BinaryUploadService::Result::SUCCESS, bad_response);
} else {
enterprise_connectors::ContentAnalysisResponse ok_response;
auto* ok_result = ok_response.add_results();
ok_result->set_status(
enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS);
ok_result->set_tag("malware");
enterprise_connectors::ContentAnalysisResponse bad_response;
auto* bad_result = bad_response.add_results();
bad_result->set_status(
enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS);
bad_result->set_tag("malware");
auto* bad_rule = bad_result->add_triggered_rules();
bad_rule->set_action(enterprise_connectors::ContentAnalysisResponse::
Result::TriggeredRule::BLOCK);
bad_rule->set_rule_name("MALWARE");
FakeBinaryUploadServiceStorage()->SetResponseForFile(
"ok.doc", BinaryUploadService::Result::SUCCESS, ok_response);
FakeBinaryUploadServiceStorage()->SetResponseForFile(
"bad.exe", BinaryUploadService::Result::SUCCESS, bad_response);
}
bool called = false;
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
// Start test.
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[&called](const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_TRUE(result.text_results.empty());
ASSERT_EQ(result.paths_results.size(), 2u);
ASSERT_TRUE(result.paths_results[0]);
ASSERT_FALSE(result.paths_results[1]);
called = true;
}),
DeepScanAccessPoint::UPLOAD);
run_loop.Run();
EXPECT_TRUE(called);
// There should have been 1 request per file and 1 for authentication.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 3);
}
IN_PROC_BROWSER_TEST_P(DeepScanningDialogDelegateSimpleBrowserTest, Texts) {
// Set up delegate and upload service.
EnableUploadsScanningAndReporting();
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(true);
EventReportValidator validator(client());
ContentAnalysisScanResult dlp_verdict;
// Prepare a complex DLP response to test that the verdict is reported
// correctly in the sensitive data event.
if (use_legacy_protos()) {
DeepScanningClientResponse response;
DlpDeepScanningVerdict* verdict = response.mutable_dlp_scan_verdict();
verdict->set_status(DlpDeepScanningVerdict::SUCCESS);
DlpDeepScanningVerdict::TriggeredRule* rule1 =
verdict->add_triggered_rules();
rule1->set_rule_id(1);
rule1->set_action(DlpDeepScanningVerdict::TriggeredRule::REPORT_ONLY);
rule1->set_rule_resource_name("resource name 1");
rule1->set_rule_severity("severity 1");
DlpDeepScanningVerdict::MatchedDetector* detector1 =
rule1->add_matched_detectors();
detector1->set_detector_id("id1");
detector1->set_detector_type("dlp1");
detector1->set_display_name("display name 1");
DlpDeepScanningVerdict::TriggeredRule* rule2 =
verdict->add_triggered_rules();
rule2->set_rule_id(3);
rule2->set_action(DlpDeepScanningVerdict::TriggeredRule::BLOCK);
rule2->set_rule_resource_name("resource rule 2");
rule2->set_rule_severity("severity 2");
DlpDeepScanningVerdict::MatchedDetector* detector2_1 =
rule2->add_matched_detectors();
detector2_1->set_detector_id("id2.1");
detector2_1->set_detector_type("type2.1");
detector2_1->set_display_name("display name 2.1");
DlpDeepScanningVerdict::MatchedDetector* detector2_2 =
rule2->add_matched_detectors();
detector2_2->set_detector_id("id2.2");
detector2_2->set_detector_type("type2.2");
detector2_2->set_display_name("display name 2.2");
FakeBinaryUploadServiceStorage()->SetResponseForText(
BinaryUploadService::Result::SUCCESS, response);
dlp_verdict = SensitiveDataVerdictToResult(response.dlp_scan_verdict());
} else {
enterprise_connectors::ContentAnalysisResponse response;
auto* result = response.add_results();
result->set_status(
enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS);
result->set_tag("dlp");
auto* rule1 = result->add_triggered_rules();
rule1->set_action(enterprise_connectors::ContentAnalysisResponse::Result::
TriggeredRule::REPORT_ONLY);
rule1->set_rule_id("1");
rule1->set_rule_name("resource rule 1");
auto* rule2 = result->add_triggered_rules();
rule2->set_action(enterprise_connectors::ContentAnalysisResponse::Result::
TriggeredRule::BLOCK);
rule2->set_rule_id("3");
rule2->set_rule_name("resource rule 2");
FakeBinaryUploadServiceStorage()->SetResponseForText(
BinaryUploadService::Result::SUCCESS, response);
dlp_verdict = ContentAnalysisResultToResult(*result);
}
// The DLP verdict means an event should be reported. The content size is
// equal to the length of the concatenated texts (2 * 100 * 'a') times
// 2 since they are wide characters ((100 + 100) * 2 = 400).
validator.ExpectSensitiveDataEvent(
/*url*/ "about:blank",
/*filename*/ "Text data",
// The hash should not be included for string requests.
/*sha*/ "",
/*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerWebContentUpload,
/*dlp_verdict*/ dlp_verdict,
/*mimetype*/ TextMimeTypes(),
/*size*/ 400);
bool called = false;
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = true;
data.text.emplace_back(text());
data.text.emplace_back(text());
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY));
// Start test.
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[&called](const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_TRUE(result.paths_results.empty());
ASSERT_EQ(result.text_results.size(), 2u);
ASSERT_FALSE(result.text_results[0]);
ASSERT_FALSE(result.text_results[1]);
called = true;
}),
DeepScanAccessPoint::UPLOAD);
FakeBinaryUploadServiceStorage()->ReturnAuthorizedResponse();
run_loop.Run();
EXPECT_TRUE(called);
// There should have been 1 request for all texts and 1 for authentication.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 2);
}
INSTANTIATE_TEST_SUITE_P(,
DeepScanningDialogDelegateSimpleBrowserTest,
testing::Bool());
class DeepScanningDialogDelegatePasswordProtectedFilesBrowserTest
: public DeepScanningDialogDelegateBrowserTest,
public testing::WithParamInterface<
std::tuple<AllowPasswordProtectedFilesValues, bool>> {
public:
DeepScanningDialogDelegatePasswordProtectedFilesBrowserTest()
: DeepScanningDialogDelegateBrowserTest(std::get<1>(GetParam())) {}
AllowPasswordProtectedFilesValues allow_password_protected_files() const {
return std::get<0>(GetParam());
}
bool expected_result() const {
switch (allow_password_protected_files()) {
case ALLOW_NONE:
case ALLOW_DOWNLOADS:
return false;
case ALLOW_UPLOADS:
case ALLOW_UPLOADS_AND_DOWNLOADS:
return true;
}
}
};
IN_PROC_BROWSER_TEST_P(
DeepScanningDialogDelegatePasswordProtectedFilesBrowserTest,
Test) {
base::ScopedAllowBlockingForTesting allow_blocking;
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");
// Set up delegate and upload service.
EnableUploadsScanningAndReporting();
SetAllowPasswordProtectedFilesPolicy(allow_password_protected_files());
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(true);
FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
bool called = false;
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = true;
data.paths.emplace_back(test_zip);
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::FILE_ATTACHED));
// The file should be reported as unscanned.
EventReportValidator validator(client());
validator.ExpectUnscannedFileEvent(
/*url*/ "about:blank",
/*filename*/ test_zip.AsUTF8Unsafe(),
// sha256sum < chrome/test/data/safe_browsing/download_protection/\
// encrypted.zip | tr '[:lower:]' '[:upper:]'
/*sha*/
"701FCEA8B2112FFAB257A8A8DFD3382ABCF047689AB028D42903E3B3AA488D9A",
/*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
/*reason*/ "FILE_PASSWORD_PROTECTED",
/*mimetypes*/ ZipMimeTypes(),
// du chrome/test/data/safe_browsing/download_protection/encrypted.zip -b
/*size*/ 20015);
// Start test.
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[this, &called](const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_TRUE(result.text_results.empty());
ASSERT_EQ(result.paths_results.size(), 1u);
ASSERT_EQ(result.paths_results[0], expected_result());
called = true;
}),
DeepScanAccessPoint::UPLOAD);
run_loop.Run();
EXPECT_TRUE(called);
// Expect 1 request for authentication needed to report the unscanned file
// event.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 1);
}
INSTANTIATE_TEST_SUITE_P(
,
DeepScanningDialogDelegatePasswordProtectedFilesBrowserTest,
testing::Combine(testing::Values(ALLOW_NONE,
ALLOW_DOWNLOADS,
ALLOW_UPLOADS,
ALLOW_UPLOADS_AND_DOWNLOADS),
testing::Bool()));
class DeepScanningDialogDelegateBlockUnsupportedFileTypesBrowserTest
: public DeepScanningDialogDelegateBrowserTest,
public testing::WithParamInterface<
std::tuple<BlockUnsupportedFiletypesValues, bool>> {
public:
DeepScanningDialogDelegateBlockUnsupportedFileTypesBrowserTest()
: DeepScanningDialogDelegateBrowserTest(std::get<1>(GetParam())) {}
BlockUnsupportedFiletypesValues block_unsupported_file_types() const {
return std::get<0>(GetParam());
}
bool expected_result() const {
switch (block_unsupported_file_types()) {
case BLOCK_UNSUPPORTED_FILETYPES_NONE:
case BLOCK_UNSUPPORTED_FILETYPES_DOWNLOADS:
return true;
case BLOCK_UNSUPPORTED_FILETYPES_UPLOADS:
case BLOCK_UNSUPPORTED_FILETYPES_UPLOADS_AND_DOWNLOADS:
return false;
}
}
};
IN_PROC_BROWSER_TEST_P(
DeepScanningDialogDelegateBlockUnsupportedFileTypesBrowserTest,
Test) {
base::ScopedAllowBlockingForTesting allow_blocking;
// Set up delegate and upload service.
EnableUploadsScanningAndReporting();
SetBlockUnsupportedFileTypesPolicy(block_unsupported_file_types());
ClearUrlsToCheckForMalwareOfUploads();
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(true);
FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
// Create the files with unsupported types.
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = false;
CreateFilesForTest({"a.sh"}, {"file content"}, &data);
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::FILE_ATTACHED));
// The file should be reported as unscanned.
EventReportValidator validator(client());
validator.ExpectUnscannedFileEvent(
/*url*/ "about:blank",
/*filename*/ created_file_paths()[0].AsUTF8Unsafe(),
// printf "file content" | sha256sum | tr '[:lower:]' '[:upper:]'
/*sha*/
"E0AC3601005DFA1864F5392AABAF7D898B1B5BAB854F1ACB4491BCD806B76B0C",
/*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
/*reason*/ "DLP_SCAN_UNSUPPORTED_FILE_TYPE",
/*mimetype*/ ShellScriptMimeTypes(),
/*size*/ std::string("file content").size());
bool called = false;
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
// Start test.
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[this, &called](const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_TRUE(result.text_results.empty());
ASSERT_EQ(result.paths_results.size(), 1u);
ASSERT_EQ(result.paths_results[0], expected_result());
called = true;
}),
DeepScanAccessPoint::UPLOAD);
run_loop.Run();
EXPECT_TRUE(called);
// Expect 1 request for authentication needed to report the unscanned file
// event.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 1);
}
INSTANTIATE_TEST_SUITE_P(
,
DeepScanningDialogDelegateBlockUnsupportedFileTypesBrowserTest,
testing::Combine(
testing::Values(BLOCK_UNSUPPORTED_FILETYPES_NONE,
BLOCK_UNSUPPORTED_FILETYPES_DOWNLOADS,
BLOCK_UNSUPPORTED_FILETYPES_UPLOADS,
BLOCK_UNSUPPORTED_FILETYPES_UPLOADS_AND_DOWNLOADS),
testing::Bool()));
class DeepScanningDialogDelegateBlockLargeFileTransferBrowserTest
: public DeepScanningDialogDelegateBrowserTest,
public testing::WithParamInterface<
std::tuple<BlockLargeFileTransferValues, bool>> {
public:
DeepScanningDialogDelegateBlockLargeFileTransferBrowserTest()
: DeepScanningDialogDelegateBrowserTest(std::get<1>(GetParam())) {}
BlockLargeFileTransferValues block_large_file_transfer() const {
return std::get<0>(GetParam());
}
bool expected_result() const {
switch (block_large_file_transfer()) {
case BLOCK_NONE:
case BLOCK_LARGE_DOWNLOADS:
return true;
case BLOCK_LARGE_UPLOADS:
case BLOCK_LARGE_UPLOADS_AND_DOWNLOADS:
return false;
}
}
};
IN_PROC_BROWSER_TEST_P(
DeepScanningDialogDelegateBlockLargeFileTransferBrowserTest,
Test) {
base::ScopedAllowBlockingForTesting allow_blocking;
// Set up delegate and upload service.
EnableUploadsScanningAndReporting();
SetBlockLargeFileTransferPolicy(block_large_file_transfer());
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(true);
FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
// Create the large file.
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = true;
CreateFilesForTest(
{"large.doc"},
{std::string(BinaryUploadService::kMaxUploadSizeBytes + 1, 'a')}, &data);
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::FILE_ATTACHED));
// The file should be reported as unscanned.
EventReportValidator validator(client());
validator.ExpectUnscannedFileEvent(
/*url*/ "about:blank",
/*filename*/ created_file_paths()[0].AsUTF8Unsafe(),
// python3 -c "print('a' * (50 * 1024 * 1024 + 1), end='')" | sha256sum |\
// tr '[:lower:]' '[:upper:]'
/*sha*/
"9EB56DB30C49E131459FE735BA6B9D38327376224EC8D5A1233F43A5B4A25942",
/*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
/*reason*/ "FILE_TOO_LARGE",
/*mimetypes*/ DocMimeTypes(),
/*size*/ BinaryUploadService::kMaxUploadSizeBytes + 1);
bool called = false;
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
// Start test.
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[this, &called](const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_TRUE(result.text_results.empty());
ASSERT_EQ(result.paths_results.size(), 1u);
ASSERT_EQ(result.paths_results[0], expected_result());
called = true;
}),
DeepScanAccessPoint::UPLOAD);
run_loop.Run();
EXPECT_TRUE(called);
// Expect 1 request for authentication needed to report the unscanned file
// event.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 1);
}
INSTANTIATE_TEST_SUITE_P(
,
DeepScanningDialogDelegateBlockLargeFileTransferBrowserTest,
testing::Combine(testing::Values(BLOCK_NONE,
BLOCK_LARGE_DOWNLOADS,
BLOCK_LARGE_UPLOADS,
BLOCK_LARGE_UPLOADS_AND_DOWNLOADS),
testing::Bool()));
class DeepScanningDialogDelegateDelayDeliveryUntilVerdictTest
: public DeepScanningDialogDelegateBrowserTest,
public testing::WithParamInterface<
std::tuple<DelayDeliveryUntilVerdictValues, bool>> {
public:
DeepScanningDialogDelegateDelayDeliveryUntilVerdictTest()
: DeepScanningDialogDelegateBrowserTest(std::get<1>(GetParam())) {}
DelayDeliveryUntilVerdictValues delay_delivery_until_verdict() const {
return std::get<0>(GetParam());
}
bool expected_result() const {
switch (delay_delivery_until_verdict()) {
case DELAY_NONE:
case DELAY_DOWNLOADS:
return true;
case DELAY_UPLOADS:
case DELAY_UPLOADS_AND_DOWNLOADS:
return false;
}
}
};
IN_PROC_BROWSER_TEST_P(DeepScanningDialogDelegateDelayDeliveryUntilVerdictTest,
Test) {
base::ScopedAllowBlockingForTesting allow_blocking;
// Set up delegate and upload service.
EnableUploadsScanningAndReporting();
SetWaitPolicy(delay_delivery_until_verdict());
DeepScanningDialogDelegate::SetFactoryForTesting(
base::BindRepeating(&MinimalFakeDeepScanningDialogDelegate::Create));
FakeBinaryUploadServiceStorage()->SetAuthorized(true);
FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
// Create a file.
DeepScanningDialogDelegate::Data data;
data.do_dlp_scan = true;
data.do_malware_scan = true;
CreateFilesForTest({"foo.doc"}, {"foo content"}, &data);
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(
browser()->profile(), GURL(kTestUrl), &data,
enterprise_connectors::AnalysisConnector::FILE_ATTACHED));
// The file should be reported as malware and sensitive content.
EventReportValidator validator(client());
ContentAnalysisScanResult dlp_verdict;
if (use_legacy_protos()) {
DeepScanningClientResponse response;
response.mutable_malware_scan_verdict()->set_verdict(
MalwareDeepScanningVerdict::MALWARE);
response.mutable_dlp_scan_verdict()->set_status(
DlpDeepScanningVerdict::SUCCESS);
response.mutable_dlp_scan_verdict()->add_triggered_rules()->set_action(
DlpDeepScanningVerdict::TriggeredRule::BLOCK);
FakeBinaryUploadServiceStorage()->SetResponseForFile(
"foo.doc", BinaryUploadService::Result::SUCCESS, response);
dlp_verdict = SensitiveDataVerdictToResult(response.dlp_scan_verdict());
} else {
enterprise_connectors::ContentAnalysisResponse response;
auto* malware_result = response.add_results();
malware_result->set_status(
enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS);
malware_result->set_tag("malware");
auto* malware_rule = malware_result->add_triggered_rules();
malware_rule->set_action(enterprise_connectors::ContentAnalysisResponse::
Result::TriggeredRule::BLOCK);
malware_rule->set_rule_name("MALWARE");
auto* dlp_result = response.add_results();
dlp_result->set_status(
enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS);
dlp_result->set_tag("dlp");
auto* dlp_rule = dlp_result->add_triggered_rules();
dlp_rule->set_action(enterprise_connectors::ContentAnalysisResponse::
Result::TriggeredRule::BLOCK);
dlp_rule->set_rule_id("0");
dlp_rule->set_rule_name("some_dlp_rule");
FakeBinaryUploadServiceStorage()->SetResponseForFile(
"foo.doc", BinaryUploadService::Result::SUCCESS, response);
dlp_verdict = ContentAnalysisResultToResult(*dlp_result);
}
validator.ExpectDangerousDeepScanningResultAndSensitiveDataEvent(
/*url*/ "about:blank",
/*filename*/ created_file_paths()[0].AsUTF8Unsafe(),
// printf "foo content" | sha256sum | tr '[:lower:]' '[:upper:]'
/*sha*/
"B3A2E2EDBAA3C798B4FC267792B1641B94793DE02D870124E5CBE663750B4CFC",
/*threat_type*/ "DANGEROUS",
/*trigger*/
extensions::SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
/*dlp_verdict*/ dlp_verdict,
/*mimetypes*/ DocMimeTypes(),
/*size*/ std::string("foo content").size());
bool called = false;
base::RunLoop run_loop;
// If the delivery is not delayed, put the quit closure right after the events
// are reported instead of when the dialog closes.
if (expected_result())
validator.SetDoneClosure(run_loop.QuitClosure());
else
SetQuitClosure(run_loop.QuitClosure());
// Start test.
DeepScanningDialogDelegate::ShowForWebContents(
browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
base::BindLambdaForTesting(
[this, &called](const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
ASSERT_TRUE(result.text_results.empty());
ASSERT_EQ(result.paths_results.size(), 1u);
ASSERT_EQ(result.paths_results[0], expected_result());
called = true;
}),
DeepScanAccessPoint::UPLOAD);
run_loop.Run();
EXPECT_TRUE(called);
// Expect 1 request for authentication and 1 to scan the file in all cases.
ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 2);
}
INSTANTIATE_TEST_SUITE_P(
,
DeepScanningDialogDelegateDelayDeliveryUntilVerdictTest,
testing::Combine(testing::Values(DELAY_NONE,
DELAY_DOWNLOADS,
DELAY_UPLOADS,
DELAY_UPLOADS_AND_DOWNLOADS),
testing::Bool()));
} // namespace safe_browsing