Index: chrome/browser/extensions/api/web_request/web_request_apitest.cc |
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc |
index 689edf0961772cf262738164502912176a36e5bb..8f1aa9c4cd46c3a5d22cf55f133111005d101bd3 100644 |
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc |
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc |
@@ -15,6 +15,7 @@ |
#include "chrome/browser/extensions/extension_action_runner.h" |
#include "chrome/browser/extensions/extension_apitest.h" |
#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_with_management_policy_apitest.h" |
#include "chrome/browser/extensions/tab_helper.h" |
#include "chrome/browser/extensions/test_extension_dir.h" |
#include "chrome/browser/profiles/profile.h" |
@@ -46,6 +47,7 @@ |
#include "extensions/test/result_catcher.h" |
#include "net/dns/mock_host_resolver.h" |
#include "net/test/embedded_test_server/embedded_test_server.h" |
+#include "net/test/embedded_test_server/http_request.h" |
#include "net/test/test_data_directory.h" |
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
#include "net/url_request/test_url_fetcher_factory.h" |
@@ -85,7 +87,7 @@ class CancelLoginDialog : public content::NotificationObserver { |
private: |
content::NotificationRegistrar registrar_; |
- DISALLOW_COPY_AND_ASSIGN(CancelLoginDialog); |
+ DISALLOW_COPY_AND_ASSIGN(CancelLoginDialog); |
}; |
// Sends an XHR request to the provided host, port, and path, and responds when |
@@ -115,11 +117,11 @@ void PerformXhrInFrame(content::RenderFrameHost* frame, |
EXPECT_TRUE(success); |
} |
-// Returns the current count of webRequests received by the |extension| in |
-// the background page (assumes the extension stores a value on the window |
-// object). Returns -1 if something goes awry. |
-int GetWebRequestCountFromBackgroundPage(const Extension* extension, |
- content::BrowserContext* context) { |
+// Returns the current count of a variable stored in the |extension| background |
+// page. Returns -1 if something goes awry. |
+int GetCountFromBackgroundPage(const Extension* extension, |
+ content::BrowserContext* context, |
+ const std::string& variable_name) { |
ExtensionHost* host = |
ProcessManager::Get(context)->GetBackgroundHostForExtension( |
extension->id()); |
@@ -129,12 +131,20 @@ int GetWebRequestCountFromBackgroundPage(const Extension* extension, |
int count = -1; |
if (!ExecuteScriptAndExtractInt( |
host->host_contents(), |
- "window.domAutomationController.send(window.webRequestCount)", |
- &count)) |
+ "window.domAutomationController.send(" + variable_name + ")", &count)) |
return -1; |
return count; |
} |
+// Returns the current count of webRequests received by the |extension| in |
+// the background page (assumes the extension stores a value on the window |
+// object). Returns -1 if something goes awry. |
+int GetWebRequestCountFromBackgroundPage(const Extension* extension, |
+ content::BrowserContext* context) { |
+ return GetCountFromBackgroundPage(extension, context, |
+ "window.webRequestCount"); |
+} |
+ |
// A test delegate to wait allow waiting for responses to complete with an |
// expected status and given content. |
// TODO(devlin): Other similar classes exist elsewhere. Pull this into a common |
@@ -954,4 +964,204 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, |
} |
} |
+// Tests that the webRequest events aren't dispatched when the request initiator |
+// is protected by policy. |
+IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy, |
+ InitiatorProtectedByPolicy) { |
+ // We expect that no request will be hidden or modification blocked. This |
+ // means that the request to example.com will be seen by the extension. |
+ { |
+ ExtensionManagementPolicyUpdater pref(&policy_provider_); |
+ pref.AddRuntimeBlockedHost("*", "*://notexample.com"); |
+ } |
+ |
+ ASSERT_TRUE(StartEmbeddedTestServer()); |
+ |
+ // Host navigated to. |
+ const std::string example_com = "example.com"; |
+ |
+ // URL of a page that initiates a cross domain requests when navigated to. |
+ const GURL extension_test_url = embedded_test_server()->GetURL( |
+ example_com, |
+ "/extensions/api_test/webrequest/policy_blocked/ref_remote_js.html"); |
+ |
+ ExtensionTestMessageListener listener("ready", false); |
+ const Extension* extension = |
+ LoadExtension(test_data_dir_.AppendASCII("webrequest/policy_blocked")); |
+ ASSERT_TRUE(extension) << message_; |
+ EXPECT_TRUE(listener.WaitUntilSatisfied()); |
+ |
+ // Extension communicates back using this listener name. |
+ const std::string listener_message = "protected_origin"; |
+ |
+ // The number of requests initiated by a protected origin is tracked in |
+ // the extension's background page under this variable name. |
+ const std::string request_counter_name = "window.protectedOriginCount"; |
+ |
+ EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(), |
+ request_counter_name)); |
+ |
+ // Wait until all remote Javascript files have been blocked / pulled down. |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser(), extension_test_url, WindowOpenDisposition::CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
+ |
+ // Domain that hosts javascript file referenced by example_com. |
+ const std::string example2_com = "example2.com"; |
+ |
+ // The server saw a request for the remote Javascript file. |
+ EXPECT_TRUE(BrowsedTo(example2_com)); |
+ |
+ // The request was seen by the extension. |
+ EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(), |
+ request_counter_name)); |
+ |
+ // Clear the list of domains the server has seen. |
+ ClearRequestLog(); |
+ |
+ // Make sure we've cleared the embedded server history. |
+ EXPECT_FALSE(BrowsedTo(example2_com)); |
+ |
+ // Set the policy to hide requests to example.com or any resource |
+ // it includes. We expect that in this test, the request to example2.com |
+ // will not be seen by the extension. |
+ { |
+ ExtensionManagementPolicyUpdater pref(&policy_provider_); |
+ pref.AddRuntimeBlockedHost("*", "*://" + example_com); |
+ } |
+ |
+ // Wait until all remote Javascript files have been pulled down. |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser(), extension_test_url, WindowOpenDisposition::CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
+ |
+ // The server saw a request for the remote Javascript file. |
+ EXPECT_TRUE(BrowsedTo(example2_com)); |
+ |
+ // The request was hidden from the extension. |
+ EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(), |
+ request_counter_name)); |
+} |
+ |
+// Tests that the webRequest events aren't dispatched when the URL of the |
+// request is protected by policy. |
+IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy, |
+ UrlProtectedByPolicy) { |
+ // Host protected by policy. |
+ const std::string protected_domain = "example.com"; |
+ |
+ { |
+ ExtensionManagementPolicyUpdater pref(&policy_provider_); |
+ pref.AddRuntimeBlockedHost("*", "*://" + protected_domain); |
+ } |
+ |
+ ASSERT_TRUE(StartEmbeddedTestServer()); |
+ |
+ LoadExtension(test_data_dir_.AppendASCII("webrequest/policy_blocked")); |
+ |
+ // Listen in case extension sees the requst. |
+ ExtensionTestMessageListener before_request_listener("protected_url", false); |
+ |
+ // Path to resolve during test navigations. |
+ const std::string test_path = "/defaultresponse?protected_url"; |
+ |
+ // Navigate to the protected domain and wait until page fully loads. |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser(), embedded_test_server()->GetURL(protected_domain, test_path), |
+ WindowOpenDisposition::CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
+ |
+ // The server saw a request for the protected site. |
+ EXPECT_TRUE(BrowsedTo(protected_domain)); |
+ |
+ // The request was hidden from the extension. |
+ EXPECT_FALSE(before_request_listener.was_satisfied()); |
+ |
+ // Host not protected by policy. |
+ const std::string unprotected_domain = "notblockedexample.com"; |
+ |
+ // Now we'll test browsing to a non-protected website where we expect the |
+ // extension to see the request. |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser(), embedded_test_server()->GetURL(unprotected_domain, test_path), |
+ WindowOpenDisposition::CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
+ |
+ // The server saw a request for the non-protected site. |
+ EXPECT_TRUE(BrowsedTo(unprotected_domain)); |
+ |
+ // The request was visible from the extension. |
+ EXPECT_TRUE(before_request_listener.was_satisfied()); |
+} |
+ |
+// Test that no webRequest events are seen for a protected host during normal |
+// navigation. This replicates most of the tests from |
+// WebRequestWithWithheldPermissions with a protected host. Granting a tab |
+// specific permission shouldn't bypass our policy. |
+IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy, |
+ WebRequestProtectedByPolicy) { |
+ FeatureSwitch::ScopedOverride enable_scripts_require_action( |
+ FeatureSwitch::scripts_require_action(), true); |
+ |
+ // Host protected by policy. |
+ const std::string protected_domain = "example.com"; |
+ |
+ { |
+ ExtensionManagementPolicyUpdater pref(&policy_provider_); |
+ pref.AddRuntimeBlockedHost("*", "*://" + protected_domain); |
+ } |
+ |
+ ASSERT_TRUE(StartEmbeddedTestServer()); |
+ |
+ ExtensionTestMessageListener listener("ready", false); |
+ const Extension* extension = |
+ LoadExtension(test_data_dir_.AppendASCII("webrequest_activetab")); |
+ ASSERT_TRUE(extension) << message_; |
+ EXPECT_TRUE(listener.WaitUntilSatisfied()); |
+ |
+ // Navigate the browser to a page in a new tab. |
+ GURL url = embedded_test_server()->GetURL(protected_domain, "/empty.html"); |
+ chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); |
+ params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; |
+ ui_test_utils::NavigateToURL(¶ms); |
+ |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ ASSERT_TRUE(web_contents); |
+ ExtensionActionRunner* runner = |
+ ExtensionActionRunner::GetForWebContents(web_contents); |
+ ASSERT_TRUE(runner); |
+ |
+ int port = embedded_test_server()->port(); |
+ const std::string kXhrPath = "simple.html"; |
+ |
+ // The extension shouldn't have currently received any webRequest events, |
+ // since it doesn't have permission (and shouldn't receive any from an XHR). |
+ EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); |
+ PerformXhrInFrame(web_contents->GetMainFrame(), protected_domain, port, |
+ kXhrPath); |
+ EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); |
+ |
+ // Grant activeTab permission, and perform another XHR. The extension should |
+ // still be blocked due to ExtensionSettings policy on example.com. |
+ // Only records ACCESS_WITHHELD, not ACCESS_DENIED, this is why it matches |
+ // BLOCKED_ACTION_NONE. |
+ EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension)); |
+ runner->set_default_bubble_close_action_for_testing( |
+ base::WrapUnique(new ToolbarActionsBarBubbleDelegate::CloseAction( |
+ ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE))); |
+ runner->RunAction(extension, true); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_TRUE(content::WaitForLoadStop(web_contents)); |
+ EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension)); |
+ int xhr_count = GetWebRequestCountFromBackgroundPage(extension, profile()); |
+ // ... which means that we should have a non-zero xhr count if the policy |
+ // didn't block the events. |
+ EXPECT_EQ(0, xhr_count); |
+ // And the extension should also block future events. |
+ PerformXhrInFrame(web_contents->GetMainFrame(), protected_domain, port, |
+ kXhrPath); |
+ EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); |
+} |
+ |
} // namespace extensions |