Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / active_script_controller_unittest.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <map>
6
7 #include "base/values.h"
8 #include "chrome/browser/extensions/active_script_controller.h"
9 #include "chrome/browser/extensions/active_tab_permission_granter.h"
10 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
11 #include "chrome/browser/extensions/extension_util.h"
12 #include "chrome/browser/extensions/permissions_updater.h"
13 #include "chrome/browser/extensions/tab_helper.h"
14 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "components/crx_file/id_util.h"
17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/web_contents.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_builder.h"
23 #include "extensions/common/feature_switch.h"
24 #include "extensions/common/manifest.h"
25 #include "extensions/common/user_script.h"
26 #include "extensions/common/value_builder.h"
27
28 namespace extensions {
29
30 namespace {
31
32 const char kAllHostsPermission[] = "*://*/*";
33
34 }  // namespace
35
36 // Unittests for the ActiveScriptController mostly test the internal logic
37 // of the controller itself (when to allow/deny extension script injection).
38 // Testing real injection is allowed/denied as expected (i.e., that the
39 // ActiveScriptController correctly interfaces in the system) is done in the
40 // ActiveScriptControllerBrowserTests.
41 class ActiveScriptControllerUnitTest : public ChromeRenderViewHostTestHarness {
42  protected:
43   ActiveScriptControllerUnitTest();
44   ~ActiveScriptControllerUnitTest() override;
45
46   // Creates an extension with all hosts permission and adds it to the registry.
47   const Extension* AddExtension();
48
49   // Reloads |extension_| by removing it from the registry and recreating it.
50   const Extension* ReloadExtension();
51
52   // Returns true if the |extension| requires user consent before injecting
53   // a script.
54   bool RequiresUserConsent(const Extension* extension) const;
55
56   // Request an injection for the given |extension|.
57   void RequestInjection(const Extension* extension);
58
59   // Returns the number of times a given extension has had a script execute.
60   size_t GetExecutionCountForExtension(const std::string& extension_id) const;
61
62   ActiveScriptController* controller() const {
63     return active_script_controller_;
64   }
65
66  private:
67   // Returns a closure to use as a script execution for a given extension.
68   base::Closure GetExecutionCallbackForExtension(
69       const std::string& extension_id);
70
71   // Increment the number of executions for the given |extension_id|.
72   void IncrementExecutionCount(const std::string& extension_id);
73
74   void SetUp() override;
75
76   // Since ActiveScriptController's behavior is behind a flag, override the
77   // feature switch.
78   FeatureSwitch::ScopedOverride feature_override_;
79
80   // The associated ActiveScriptController.
81   ActiveScriptController* active_script_controller_;
82
83   // The map of observed executions, keyed by extension id.
84   std::map<std::string, int> extension_executions_;
85
86   scoped_refptr<const Extension> extension_;
87 };
88
89 ActiveScriptControllerUnitTest::ActiveScriptControllerUnitTest()
90     : feature_override_(FeatureSwitch::scripts_require_action(),
91                         FeatureSwitch::OVERRIDE_ENABLED),
92       active_script_controller_(NULL) {
93 }
94
95 ActiveScriptControllerUnitTest::~ActiveScriptControllerUnitTest() {
96 }
97
98 const Extension* ActiveScriptControllerUnitTest::AddExtension() {
99   const std::string kId = crx_file::id_util::GenerateId("all_hosts_extension");
100   extension_ = ExtensionBuilder()
101                    .SetManifest(
102                        DictionaryBuilder()
103                            .Set("name", "all_hosts_extension")
104                            .Set("description", "an extension")
105                            .Set("manifest_version", 2)
106                            .Set("version", "1.0.0")
107                            .Set("permissions",
108                                 ListBuilder().Append(kAllHostsPermission)))
109                    .SetLocation(Manifest::INTERNAL)
110                    .SetID(kId)
111                    .Build();
112
113   ExtensionRegistry::Get(profile())->AddEnabled(extension_);
114   PermissionsUpdater(profile()).InitializePermissions(extension_.get());
115   return extension_.get();
116 }
117
118 const Extension* ActiveScriptControllerUnitTest::ReloadExtension() {
119   ExtensionRegistry::Get(profile())->RemoveEnabled(extension_->id());
120   return AddExtension();
121 }
122
123 bool ActiveScriptControllerUnitTest::RequiresUserConsent(
124     const Extension* extension) const {
125   PermissionsData::AccessType access_type =
126       controller()->RequiresUserConsentForScriptInjectionForTesting(
127           extension, UserScript::PROGRAMMATIC_SCRIPT);
128   // We should never downright refuse access in these tests.
129   DCHECK_NE(PermissionsData::ACCESS_DENIED, access_type);
130   return access_type == PermissionsData::ACCESS_WITHHELD;
131 }
132
133 void ActiveScriptControllerUnitTest::RequestInjection(
134     const Extension* extension) {
135   controller()->RequestScriptInjectionForTesting(
136       extension,
137       GetExecutionCallbackForExtension(extension->id()));
138 }
139
140 size_t ActiveScriptControllerUnitTest::GetExecutionCountForExtension(
141     const std::string& extension_id) const {
142   std::map<std::string, int>::const_iterator iter =
143       extension_executions_.find(extension_id);
144   if (iter != extension_executions_.end())
145     return iter->second;
146   return 0u;
147 }
148
149 base::Closure ActiveScriptControllerUnitTest::GetExecutionCallbackForExtension(
150     const std::string& extension_id) {
151   // We use base unretained here, but if this ever gets executed outside of
152   // this test's lifetime, we have a major problem anyway.
153   return base::Bind(&ActiveScriptControllerUnitTest::IncrementExecutionCount,
154                     base::Unretained(this),
155                     extension_id);
156 }
157
158 void ActiveScriptControllerUnitTest::IncrementExecutionCount(
159     const std::string& extension_id) {
160   ++extension_executions_[extension_id];
161 }
162
163 void ActiveScriptControllerUnitTest::SetUp() {
164   ChromeRenderViewHostTestHarness::SetUp();
165
166   TabHelper::CreateForWebContents(web_contents());
167   TabHelper* tab_helper = TabHelper::FromWebContents(web_contents());
168   // These should never be NULL.
169   DCHECK(tab_helper);
170   active_script_controller_ = tab_helper->active_script_controller();
171   DCHECK(active_script_controller_);
172 }
173
174 // Test that extensions with all_hosts require permission to execute, and, once
175 // that permission is granted, do execute.
176 TEST_F(ActiveScriptControllerUnitTest, RequestPermissionAndExecute) {
177   const Extension* extension = AddExtension();
178   ASSERT_TRUE(extension);
179
180   NavigateAndCommit(GURL("https://www.google.com"));
181
182   // Ensure that there aren't any executions pending.
183   ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
184   ASSERT_FALSE(controller()->WantsToRun(extension));
185
186   ExtensionActionAPI* extension_action_api =
187       ExtensionActionAPI::Get(profile());
188   ASSERT_FALSE(extension_action_api->ExtensionWantsToRun(extension,
189                                                          web_contents()));
190
191   // Since the extension requests all_hosts, we should require user consent.
192   EXPECT_TRUE(RequiresUserConsent(extension));
193
194   // Request an injection. The extension should want to run, but should not have
195   // executed.
196   RequestInjection(extension);
197   EXPECT_TRUE(controller()->WantsToRun(extension));
198   EXPECT_TRUE(extension_action_api->ExtensionWantsToRun(extension,
199                                                         web_contents()));
200   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
201
202   // Click to accept the extension executing.
203   controller()->OnClicked(extension);
204
205   // The extension should execute, and the extension shouldn't want to run.
206   EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
207   EXPECT_FALSE(controller()->WantsToRun(extension));
208   EXPECT_FALSE(extension_action_api->ExtensionWantsToRun(extension,
209                                                          web_contents()));
210
211   // Since we already executed on the given page, we shouldn't need permission
212   // for a second time.
213   EXPECT_FALSE(RequiresUserConsent(extension));
214
215   // Reloading and same-origin navigations shouldn't clear those permissions,
216   // and we shouldn't require user constent again.
217   Reload();
218   EXPECT_FALSE(RequiresUserConsent(extension));
219   NavigateAndCommit(GURL("https://www.google.com/foo"));
220   EXPECT_FALSE(RequiresUserConsent(extension));
221   NavigateAndCommit(GURL("https://www.google.com/bar"));
222   EXPECT_FALSE(RequiresUserConsent(extension));
223
224   // Cross-origin navigations should clear permissions.
225   NavigateAndCommit(GURL("https://otherdomain.google.com"));
226   EXPECT_TRUE(RequiresUserConsent(extension));
227
228   // Grant access.
229   RequestInjection(extension);
230   controller()->OnClicked(extension);
231   EXPECT_EQ(2u, GetExecutionCountForExtension(extension->id()));
232   EXPECT_FALSE(controller()->WantsToRun(extension));
233
234   // Navigating to another site should also clear the permissions.
235   NavigateAndCommit(GURL("https://www.foo.com"));
236   EXPECT_TRUE(RequiresUserConsent(extension));
237 }
238
239 // Test that injections that are not executed by the time the user navigates are
240 // ignored and never execute.
241 TEST_F(ActiveScriptControllerUnitTest, PendingInjectionsRemovedAtNavigation) {
242   const Extension* extension = AddExtension();
243   ASSERT_TRUE(extension);
244
245   NavigateAndCommit(GURL("https://www.google.com"));
246
247   ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
248
249   // Request an injection. The extension should want to run, but not execute.
250   RequestInjection(extension);
251   EXPECT_TRUE(controller()->WantsToRun(extension));
252   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
253
254   // Reload. This should remove the pending injection, and we should not
255   // execute anything.
256   Reload();
257   EXPECT_FALSE(controller()->WantsToRun(extension));
258   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
259
260   // Request and accept a new injection.
261   RequestInjection(extension);
262   controller()->OnClicked(extension);
263
264   // The extension should only have executed once, even though a grand total
265   // of two executions were requested.
266   EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
267   EXPECT_FALSE(controller()->WantsToRun(extension));
268 }
269
270 // Test that queueing multiple pending injections, and then accepting, triggers
271 // them all.
272 TEST_F(ActiveScriptControllerUnitTest, MultiplePendingInjection) {
273   const Extension* extension = AddExtension();
274   ASSERT_TRUE(extension);
275   NavigateAndCommit(GURL("https://www.google.com"));
276
277   ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
278
279   const size_t kNumInjections = 3u;
280   // Queue multiple pending injections.
281   for (size_t i = 0u; i < kNumInjections; ++i)
282     RequestInjection(extension);
283
284   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
285
286   controller()->OnClicked(extension);
287
288   // All pending injections should have executed.
289   EXPECT_EQ(kNumInjections, GetExecutionCountForExtension(extension->id()));
290   EXPECT_FALSE(controller()->WantsToRun(extension));
291 }
292
293 TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsUseActiveTabPermissions) {
294   const Extension* extension = AddExtension();
295   NavigateAndCommit(GURL("https://www.google.com"));
296
297   ActiveTabPermissionGranter* active_tab_permission_granter =
298       TabHelper::FromWebContents(web_contents())
299           ->active_tab_permission_granter();
300   ASSERT_TRUE(active_tab_permission_granter);
301   // Grant the extension active tab permissions. This normally happens, e.g.,
302   // if the user clicks on a browser action.
303   active_tab_permission_granter->GrantIfRequested(extension);
304
305   // Since we have active tab permissions, we shouldn't need user consent
306   // anymore.
307   EXPECT_FALSE(RequiresUserConsent(extension));
308
309   // Reloading and other same-origin navigations maintain the permission to
310   // execute.
311   Reload();
312   EXPECT_FALSE(RequiresUserConsent(extension));
313   NavigateAndCommit(GURL("https://www.google.com/foo"));
314   EXPECT_FALSE(RequiresUserConsent(extension));
315   NavigateAndCommit(GURL("https://www.google.com/bar"));
316   EXPECT_FALSE(RequiresUserConsent(extension));
317
318   // Navigating to a different origin will require user consent again.
319   NavigateAndCommit(GURL("https://yahoo.com"));
320   EXPECT_TRUE(RequiresUserConsent(extension));
321
322   // Back to the original origin should also re-require constent.
323   NavigateAndCommit(GURL("https://www.google.com"));
324   EXPECT_TRUE(RequiresUserConsent(extension));
325
326   RequestInjection(extension);
327   EXPECT_TRUE(controller()->WantsToRun(extension));
328   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
329
330   // Grant active tab.
331   active_tab_permission_granter->GrantIfRequested(extension);
332
333   // The pending injections should have run since active tab permission was
334   // granted.
335   EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
336   EXPECT_FALSE(controller()->WantsToRun(extension));
337 }
338
339 TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsCanHaveAllUrlsPref) {
340   const Extension* extension = AddExtension();
341   ASSERT_TRUE(extension);
342
343   NavigateAndCommit(GURL("https://www.google.com"));
344   EXPECT_TRUE(RequiresUserConsent(extension));
345
346   // Enable the extension on all urls.
347   util::SetAllowedScriptingOnAllUrls(extension->id(), profile(), true);
348
349   EXPECT_FALSE(RequiresUserConsent(extension));
350   // This should carry across navigations, and websites.
351   NavigateAndCommit(GURL("http://www.foo.com"));
352   EXPECT_FALSE(RequiresUserConsent(extension));
353
354   // Turning off the preference should have instant effect.
355   util::SetAllowedScriptingOnAllUrls(extension->id(), profile(), false);
356   EXPECT_TRUE(RequiresUserConsent(extension));
357
358   // And should also persist across navigations and websites.
359   NavigateAndCommit(GURL("http://www.bar.com"));
360   EXPECT_TRUE(RequiresUserConsent(extension));
361 }
362
363 TEST_F(ActiveScriptControllerUnitTest, TestAlwaysRun) {
364   const Extension* extension = AddExtension();
365   ASSERT_TRUE(extension);
366
367   NavigateAndCommit(GURL("https://www.google.com/?gws_rd=ssl"));
368
369   // Ensure that there aren't any executions pending.
370   ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
371   ASSERT_FALSE(controller()->WantsToRun(extension));
372
373   // Since the extension requests all_hosts, we should require user consent.
374   EXPECT_TRUE(RequiresUserConsent(extension));
375
376   // Request an injection. The extension should want to run, but not execute.
377   RequestInjection(extension);
378   EXPECT_TRUE(controller()->WantsToRun(extension));
379   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
380
381   // Allow the extension to always run on this origin.
382   controller()->AlwaysRunOnVisibleOrigin(extension);
383
384   // The extension should execute, and the extension shouldn't want to run.
385   EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
386   EXPECT_FALSE(controller()->WantsToRun(extension));
387
388   // Since we already executed on the given page, we shouldn't need permission
389   // for a second time.
390   EXPECT_FALSE(RequiresUserConsent(extension));
391
392   // Navigating to another site that hasn't been granted a persisted permission
393   // should necessitate user consent.
394   NavigateAndCommit(GURL("https://www.foo.com/bar"));
395   EXPECT_TRUE(RequiresUserConsent(extension));
396
397   // We shouldn't need user permission upon returning to the original origin.
398   NavigateAndCommit(GURL("https://www.google.com/foo/bar"));
399   EXPECT_FALSE(RequiresUserConsent(extension));
400
401   // Reloading the extension should not clear any granted host permissions.
402   extension = ReloadExtension();
403   Reload();
404   EXPECT_FALSE(RequiresUserConsent(extension));
405
406   // Different host...
407   NavigateAndCommit(GURL("https://www.foo.com/bar"));
408   EXPECT_TRUE(RequiresUserConsent(extension));
409   // Different scheme...
410   NavigateAndCommit(GURL("http://www.google.com/foo/bar"));
411   EXPECT_TRUE(RequiresUserConsent(extension));
412   // Different subdomain...
413   NavigateAndCommit(GURL("https://en.google.com/foo/bar"));
414   EXPECT_TRUE(RequiresUserConsent(extension));
415   // Only the "always run" origin should be allowed to run without user consent.
416   NavigateAndCommit(GURL("https://www.google.com/foo/bar"));
417   EXPECT_FALSE(RequiresUserConsent(extension));
418 }
419
420 }  // namespace extensions