diff options
Diffstat (limited to 'chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc')
-rw-r--r-- | chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc | 201 |
1 files changed, 191 insertions, 10 deletions
diff --git a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc index 3ae612a992c..7efb7086919 100644 --- a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc +++ b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc @@ -41,10 +41,13 @@ #include "extensions/browser/extension_util.h" #include "extensions/common/api/declarative_net_request/constants.h" #include "extensions/common/api/declarative_net_request/test_utils.h" +#include "extensions/common/constants.h" #include "extensions/common/extension_id.h" +#include "extensions/common/url_pattern.h" #include "net/dns/mock_host_resolver.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "net/test/test_data_directory.h" +#include "services/network/public/cpp/features.h" namespace extensions { namespace declarative_net_request { @@ -154,8 +157,11 @@ class DeclarativeNetRequestBrowserTest // Loads an extension with the given declarative |rules| in the given // |directory|. Generates a fatal failure if the extension failed to load. + // |hosts| specifies the host permissions, the extensions should + // have. void LoadExtensionWithRules(const std::vector<TestRule>& rules, - const std::string& directory) { + const std::string& directory, + const std::vector<std::string>& hosts) { base::ScopedAllowBlockingForTesting scoped_allow_blocking; base::HistogramTester tester; @@ -163,12 +169,13 @@ class DeclarativeNetRequestBrowserTest EXPECT_TRUE(base::CreateDirectory(extension_dir)); WriteManifestAndRuleset(extension_dir, kJSONRulesetFilepath, - kJSONRulesFilename, rules); + kJSONRulesFilename, rules, hosts); const Extension* extension = nullptr; switch (GetParam()) { case ExtensionLoadType::PACKED: - extension = InstallExtension(extension_dir, 1 /* expected_change */); + extension = InstallExtensionWithPermissionsGranted( + extension_dir, 1 /* expected_change */); break; case ExtensionLoadType::UNPACKED: extension = LoadExtension(extension_dir); @@ -196,7 +203,8 @@ class DeclarativeNetRequestBrowserTest } void LoadExtensionWithRules(const std::vector<TestRule>& rules) { - LoadExtensionWithRules(rules, "test_extension"); + LoadExtensionWithRules(rules, "test_extension", + {URLPattern::kAllUrlsPattern}); } private: @@ -635,8 +643,10 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, rules_2.push_back(rule); } - ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(rules_1, "extension_1")); - ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(rules_2, "extension_2")); + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules( + rules_1, "extension_1", {URLPattern::kAllUrlsPattern})); + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules( + rules_2, "extension_2", {URLPattern::kAllUrlsPattern})); struct { std::string host; @@ -688,7 +698,8 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, // url. for (size_t i = 1; i <= kNumExtensions; ++i) { rule.action->redirect_url = redirect_url_for_extension_number(i); - ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules({rule}, std::to_string(i))); + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules( + {rule}, std::to_string(i), {URLPattern::kAllUrlsPattern})); // Verify that the install time of this extension is greater than the last // extension. @@ -906,7 +917,8 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, } } -// Ensure extensions can't intercept chrome:// urls. +// Ensure extensions can't intercept chrome:// urls, even after explicitly +// requesting access to <all_urls>. IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, ChromeURLS) { // Have the extension block all chrome:// urls. TestRule rule = CreateGenericRule(); @@ -976,7 +988,12 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, RendererCacheCleared) { ui_test_utils::NavigateToURL(browser(), url); EXPECT_EQ(content::PAGE_TYPE_NORMAL, GetPageType()); EXPECT_TRUE(WasFrameWithScriptLoaded(GetMainFrame())); - EXPECT_TRUE(script_monitor.GetAndResetRequestSeen(false)); + + // NOTE: When the Network Service is enabled, the RulesetMatcher will not see + // network requests if no rulesets are active. + EXPECT_TRUE( + base::FeatureList::IsEnabled(network::features::kNetworkService) || + script_monitor.GetAndResetRequestSeen(false)); // Another request to |url| should not cause a network request for // script.js since it will be served by the renderer's in-memory @@ -1010,7 +1027,9 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, RendererCacheCleared) { ui_test_utils::NavigateToURL(browser(), url); EXPECT_EQ(content::PAGE_TYPE_NORMAL, GetPageType()); EXPECT_TRUE(WasFrameWithScriptLoaded(GetMainFrame())); - EXPECT_TRUE(script_monitor.GetAndResetRequestSeen(false)); + EXPECT_TRUE( + base::FeatureList::IsEnabled(network::features::kNetworkService) || + script_monitor.GetAndResetRequestSeen(false)); // Clear RulesetManager's observer. content::BrowserThread::PostTask( @@ -1049,6 +1068,164 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, EXPECT_EQ(content::PAGE_TYPE_NORMAL, GetPageType()); } +// Ensure that an extension can intercept its own resources, but not those of +// other extensions. +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, + InterceptExtensionScheme) { + // Load two extensions. One blocks all urls, and the other blocks urls with + // "google.com" as a substring. + std::vector<TestRule> rules_1; + TestRule rule = CreateGenericRule(); + rule.condition->url_filter = std::string("*"); + rules_1.push_back(rule); + + std::vector<TestRule> rules_2; + rule = CreateGenericRule(); + rule.condition->url_filter = std::string("google.com"); + rules_2.push_back(rule); + + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules( + rules_1, "extension_1", {URLPattern::kAllUrlsPattern})); + const std::string extension_id_1 = last_loaded_extension_id(); + + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules( + rules_2, "extension_2", {URLPattern::kAllUrlsPattern})); + const std::string extension_id_2 = last_loaded_extension_id(); + + auto get_manifest_url = [](const std::string& extension_id) { + return GURL(base::StringPrintf("%s://%s/manifest.json", + extensions::kExtensionScheme, + extension_id.c_str())); + }; + + // Extension 1 should be able to block the request to its own + // manifest.json. + ui_test_utils::NavigateToURL(browser(), get_manifest_url(extension_id_1)); + GURL final_url = web_contents()->GetLastCommittedURL(); + EXPECT_EQ(content::PAGE_TYPE_ERROR, GetPageType()); + + // But it should not be able to intercept requests to the second extensions's + // resources, even with "<all_urls>" host permissions. + ui_test_utils::NavigateToURL(browser(), get_manifest_url(extension_id_2)); + EXPECT_EQ(content::PAGE_TYPE_NORMAL, GetPageType()); +} + +// Test fixture to verify that host permissions for the request url and the +// request initiator are properly checked. Loads an example.com url with four +// sub-frames named frame_[1..4] from hosts frame_[1..4].com. The initiator for +// these frames will be example.com. Loads an extension set to block all sub- +// frames. Verifies that the correct frames are blocked depending on the host +// permissions for the extension. +class DeclarativeNetRequestHostPermissionsBrowserTest + : public DeclarativeNetRequestBrowserTest { + public: + DeclarativeNetRequestHostPermissionsBrowserTest() {} + + protected: + struct FrameLoadResult { + std::string child_frame_name; + bool expect_frame_loaded; + }; + + void LoadExtensionWithHostPermissions(const std::vector<std::string>& hosts) { + std::vector<TestRule> rules; + + // Block all sub-frame requests. + TestRule rule = CreateGenericRule(); + rule.condition->url_filter = std::string("*"); + rule.condition->resource_types = std::vector<std::string>({"sub_frame"}); + rules.push_back(rule); + + ASSERT_NO_FATAL_FAILURE( + LoadExtensionWithRules(rules, "test_extension", hosts)); + } + + void RunTests(const std::vector<FrameLoadResult>& expected_results) { + ASSERT_EQ(4u, expected_results.size()); + + GURL url = embedded_test_server()->GetURL("example.com", + "/page_with_four_frames.html"); + ui_test_utils::NavigateToURL(browser(), url); + ASSERT_TRUE(WasFrameWithScriptLoaded(GetMainFrame())); + + for (const auto& frame_result : expected_results) { + SCOPED_TRACE(base::StringPrintf("Testing child frame named %s", + frame_result.child_frame_name.c_str())); + + content::RenderFrameHost* child = + GetFrameByName(frame_result.child_frame_name); + EXPECT_TRUE(child); + EXPECT_EQ(frame_result.expect_frame_loaded, + WasFrameWithScriptLoaded(child)); + } + } + + std::string GetMatchPatternForDomain(const std::string& domain) const { + return "*://*." + domain + ".com/*"; + } + + private: + DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestHostPermissionsBrowserTest); +}; + +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestHostPermissionsBrowserTest, + AllURLs1) { + // All frames should be blocked since the extension has access to all hosts. + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithHostPermissions({"<all_urls>"})); + RunTests({{"frame_1", false}, + {"frame_2", false}, + {"frame_3", false}, + {"frame_4", false}}); +} + +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestHostPermissionsBrowserTest, + AllURLs2) { + // All frames should be blocked since the extension has access to all hosts. + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithHostPermissions({"*://*/*"})); + RunTests({{"frame_1", false}, + {"frame_2", false}, + {"frame_3", false}, + {"frame_4", false}}); +} + +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestHostPermissionsBrowserTest, + NoPermissions) { + // The extension has no host permissions. No frames should be blocked. + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithHostPermissions({})); + RunTests({{"frame_1", true}, + {"frame_2", true}, + {"frame_3", true}, + {"frame_4", true}}); +} + +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestHostPermissionsBrowserTest, + SubframesWithNoInitiatorPermissions) { + // The extension has access to requests to "frame_1.com" and "frame_2.com", + // but not the initiator of those requests (example.com). No frames should be + // blocked. + ASSERT_NO_FATAL_FAILURE( + LoadExtensionWithHostPermissions({GetMatchPatternForDomain("frame_1"), + GetMatchPatternForDomain("frame_2")})); + RunTests({{"frame_1", true}, + {"frame_2", true}, + {"frame_3", true}, + {"frame_4", true}}); +} + +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestHostPermissionsBrowserTest, + SubframesWithInitiatorPermission) { + // The extension has access to requests to "frame_1.com" and "frame_4.com", + // and also the initiator of those requests (example.com). Hence |frame_1| and + // |frame_4| should be blocked. + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithHostPermissions( + {GetMatchPatternForDomain("frame_1"), GetMatchPatternForDomain("frame_4"), + GetMatchPatternForDomain("example")})); + RunTests({{"frame_1", false}, + {"frame_2", true}, + {"frame_3", true}, + {"frame_4", false}}); +} + // Fixture to test the "resourceTypes" and "excludedResourceTypes" fields of a // declarative rule condition. class DeclarativeNetRequestResourceTypeBrowserTest @@ -1220,6 +1397,10 @@ INSTANTIATE_TEST_CASE_P(, ExtensionLoadType::UNPACKED)); INSTANTIATE_TEST_CASE_P(, + DeclarativeNetRequestHostPermissionsBrowserTest, + ::testing::Values(ExtensionLoadType::PACKED, + ExtensionLoadType::UNPACKED)); +INSTANTIATE_TEST_CASE_P(, DeclarativeNetRequestResourceTypeBrowserTest, ::testing::Values(ExtensionLoadType::PACKED, ExtensionLoadType::UNPACKED)); |