blob: 1fee3b46b559305fda150ca54e744b8a534353e2 [file] [log] [blame]
// Copyright 2017 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 <utility>
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/safe_browsing/core/browser/db/safebrowsing.pb.h"
#include "components/safe_browsing/core/browser/db/util.h"
#include "components/safe_browsing/core/browser/db/v4_embedded_test_server_util.h"
#include "components/safe_browsing/core/browser/db/v4_test_util.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "net/cookies/canonical_cookie.h"
#include "net/dns/mapped_host_resolver.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/network/public/mojom/network_context.mojom-forward.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
bool IsShowingInterstitial(content::WebContents* contents) {
security_interstitials::SecurityInterstitialTabHelper* helper =
security_interstitials::SecurityInterstitialTabHelper::FromWebContents(
contents);
return helper &&
(helper->GetBlockingPageForCurrentlyCommittedNavigationForTesting() !=
nullptr);
}
std::vector<net::CanonicalCookie> GetCookies(
network::mojom::NetworkContext* network_context) {
base::RunLoop run_loop;
std::vector<net::CanonicalCookie> cookies;
mojo::Remote<network::mojom::CookieManager> cookie_manager_remote;
network_context->GetCookieManager(
cookie_manager_remote.BindNewPipeAndPassReceiver());
cookie_manager_remote->GetAllCookies(base::BindOnce(
[](base::RunLoop* run_loop,
std::vector<net::CanonicalCookie>* out_cookies,
const std::vector<net::CanonicalCookie>& cookies) {
*out_cookies = cookies;
run_loop->Quit();
},
&run_loop, &cookies));
run_loop.Run();
return cookies;
}
} // namespace
namespace safe_browsing {
// This harness tests test-only code for correctness. This ensures that other
// test classes which want to use the V4 interceptor are testing the right
// thing.
class V4EmbeddedTestServerBrowserTest : public InProcessBrowserTest {
public:
V4EmbeddedTestServerBrowserTest() {}
V4EmbeddedTestServerBrowserTest(const V4EmbeddedTestServerBrowserTest&) =
delete;
V4EmbeddedTestServerBrowserTest& operator=(
const V4EmbeddedTestServerBrowserTest&) = delete;
~V4EmbeddedTestServerBrowserTest() override {}
void SetUp() override {
// We only need to mock a local database. The tests will use a true real V4
// protocol manager.
V4Database::RegisterStoreFactoryForTest(
std::make_unique<TestV4StoreFactory>());
auto v4_db_factory = std::make_unique<TestV4DatabaseFactory>();
v4_db_factory_ = v4_db_factory.get();
V4Database::RegisterDatabaseFactoryForTest(std::move(v4_db_factory));
secure_embedded_test_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::Type::TYPE_HTTPS);
InProcessBrowserTest::SetUp();
}
void TearDown() override {
InProcessBrowserTest::TearDown();
V4Database::RegisterStoreFactoryForTest(nullptr);
V4Database::RegisterDatabaseFactoryForTest(nullptr);
}
// Only marks the prefix as bad in the local database. The server will respond
// with the source of truth.
void LocallyMarkPrefixAsBad(const GURL& url, const ListIdentifier& list_id) {
FullHash full_hash = V4ProtocolManagerUtil::GetFullHash(url);
v4_db_factory_->MarkPrefixAsBad(list_id, full_hash);
}
protected:
std::unique_ptr<net::EmbeddedTestServer> secure_embedded_test_server_;
private:
std::unique_ptr<net::MappedHostResolver> mapped_host_resolver_;
// Owned by the V4Database.
TestV4DatabaseFactory* v4_db_factory_ = nullptr;
};
IN_PROC_BROWSER_TEST_F(V4EmbeddedTestServerBrowserTest, SimpleTest) {
ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
const char kMalwarePage[] = "/safe_browsing/malware.html";
const GURL bad_url = embedded_test_server()->GetURL(kMalwarePage);
ThreatMatch match;
FullHash full_hash = V4ProtocolManagerUtil::GetFullHash(bad_url);
LocallyMarkPrefixAsBad(bad_url, GetUrlMalwareId());
match.set_platform_type(GetUrlMalwareId().platform_type());
match.set_threat_entry_type(ThreatEntryType::URL);
match.set_threat_type(ThreatType::MALWARE_THREAT);
match.mutable_threat()->set_hash(full_hash);
match.mutable_cache_duration()->set_seconds(300);
std::map<GURL, safe_browsing::ThreatMatch> response_map{{bad_url, match}};
StartRedirectingV4RequestsForTesting(response_map, embedded_test_server());
embedded_test_server()->StartAcceptingConnections();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), bad_url));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(IsShowingInterstitial(contents));
}
IN_PROC_BROWSER_TEST_F(V4EmbeddedTestServerBrowserTest,
WrongFullHash_NoInterstitial) {
ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
const char kMalwarePage[] = "/safe_browsing/malware.html";
const GURL bad_url = embedded_test_server()->GetURL(kMalwarePage);
// Return a different full hash, so there will be no match and no
// interstitial.
ThreatMatch match;
FullHash full_hash =
V4ProtocolManagerUtil::GetFullHash(GURL("https://example.test/"));
LocallyMarkPrefixAsBad(bad_url, GetUrlMalwareId());
match.set_platform_type(GetUrlMalwareId().platform_type());
match.set_threat_entry_type(ThreatEntryType::URL);
match.set_threat_type(ThreatType::MALWARE_THREAT);
match.mutable_threat()->set_hash(full_hash);
match.mutable_cache_duration()->set_seconds(300);
std::map<GURL, safe_browsing::ThreatMatch> response_map{{bad_url, match}};
StartRedirectingV4RequestsForTesting(response_map, embedded_test_server());
embedded_test_server()->StartAcceptingConnections();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), bad_url));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_FALSE(IsShowingInterstitial(contents));
}
class V4EmbeddedTestServerWithoutCookies
: public V4EmbeddedTestServerBrowserTest {
public:
V4EmbeddedTestServerWithoutCookies() {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures({kSafeBrowsingRemoveCookies}, {});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(V4EmbeddedTestServerWithoutCookies, DoesNotSaveCookies) {
ASSERT_TRUE(secure_embedded_test_server_->InitializeAndListen());
const char kMalwarePage[] = "/safe_browsing/malware.html";
const GURL bad_url = secure_embedded_test_server_->GetURL(kMalwarePage);
ThreatMatch match;
FullHash full_hash = V4ProtocolManagerUtil::GetFullHash(bad_url);
LocallyMarkPrefixAsBad(bad_url, GetUrlMalwareId());
match.set_platform_type(GetUrlMalwareId().platform_type());
match.set_threat_entry_type(ThreatEntryType::URL);
match.set_threat_type(ThreatType::MALWARE_THREAT);
match.mutable_threat()->set_hash(full_hash);
match.mutable_cache_duration()->set_seconds(0);
std::map<GURL, safe_browsing::ThreatMatch> response_map{{bad_url, match}};
StartRedirectingV4RequestsForTesting(
response_map, secure_embedded_test_server_.get(),
/*delay_map=*/std::map<GURL, base::TimeDelta>(),
/*serve_cookies=*/true);
secure_embedded_test_server_->StartAcceptingConnections();
EXPECT_EQ(GetCookies(
g_browser_process->safe_browsing_service()->GetNetworkContext())
.size(),
0u);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), bad_url));
EXPECT_EQ(GetCookies(
g_browser_process->safe_browsing_service()->GetNetworkContext())
.size(),
0u);
}
} // namespace safe_browsing