• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "base/files/file_path.h"
6 #include "base/json/json_file_value_serializer.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/path_service.h"
9 #include "base/run_loop.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/extension_service_test_base.h"
15 #include "chrome/browser/extensions/permissions_updater.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "chrome/common/extensions/extension_test_util.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "content/public/browser/notification_observer.h"
20 #include "content/public/browser/notification_registrar.h"
21 #include "content/public/browser/notification_service.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_builder.h"
25 #include "extensions/common/feature_switch.h"
26 #include "extensions/common/permissions/permission_set.h"
27 #include "extensions/common/permissions/permissions_data.h"
28 #include "extensions/common/value_builder.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 
31 using extension_test_util::LoadManifest;
32 
33 namespace extensions {
34 
35 namespace {
36 
CreateExtensionWithPermissions(const std::set<URLPattern> & scriptable_hosts,const std::set<URLPattern> & explicit_hosts,Manifest::Location location)37 scoped_refptr<const Extension> CreateExtensionWithPermissions(
38     const std::set<URLPattern>& scriptable_hosts,
39     const std::set<URLPattern>& explicit_hosts,
40     Manifest::Location location) {
41   ListBuilder scriptable_host_list;
42   for (std::set<URLPattern>::const_iterator pattern = scriptable_hosts.begin();
43        pattern != scriptable_hosts.end();
44        ++pattern) {
45     scriptable_host_list.Append(pattern->GetAsString());
46   }
47 
48   ListBuilder explicit_host_list;
49   for (std::set<URLPattern>::const_iterator pattern = explicit_hosts.begin();
50        pattern != explicit_hosts.end();
51        ++pattern) {
52     explicit_host_list.Append(pattern->GetAsString());
53   }
54 
55   DictionaryBuilder script;
56   script.Set("matches", scriptable_host_list.Pass())
57       .Set("js", ListBuilder().Append("foo.js"));
58 
59   return ExtensionBuilder()
60       .SetLocation(location)
61       .SetManifest(
62            DictionaryBuilder()
63                .Set("name", "extension")
64                .Set("description", "foo")
65                .Set("manifest_version", 2)
66                .Set("version", "0.1.2.3")
67                .Set("content_scripts", ListBuilder().Append(script.Pass()))
68                .Set("permissions", explicit_host_list.Pass()))
69       .Build();
70 }
71 
SetsAreEqual(const std::set<URLPattern> & set1,const std::set<URLPattern> & set2)72 testing::AssertionResult SetsAreEqual(const std::set<URLPattern>& set1,
73                                       const std::set<URLPattern>& set2) {
74   // Take the (set1 - set2) U (set2 - set1). This is then the set of all
75   // elements which are in either set1 or set2, but not both.
76   // If the sets are equal, this is none.
77   std::set<URLPattern> difference = base::STLSetUnion<std::set<URLPattern> >(
78       base::STLSetDifference<std::set<URLPattern> >(set1, set2),
79       base::STLSetDifference<std::set<URLPattern> >(set2, set1));
80 
81   std::string error;
82   for (std::set<URLPattern>::const_iterator iter = difference.begin();
83        iter != difference.end();
84        ++iter) {
85     if (iter->GetAsString() == "chrome://favicon/*")
86       continue;  // Grr... This is auto-added for extensions with <all_urls>
87     error = base::StringPrintf("%s\n%s contains %s and the other does not.",
88                                error.c_str(),
89                                (set1.count(*iter) ? "Set1" : "Set2"),
90                                iter->GetAsString().c_str());
91   }
92 
93   if (!error.empty())
94     return testing::AssertionFailure() << error;
95   return testing::AssertionSuccess();
96 }
97 
98 // A helper class that listens for NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED.
99 class PermissionsUpdaterListener : public content::NotificationObserver {
100  public:
PermissionsUpdaterListener()101   PermissionsUpdaterListener()
102       : received_notification_(false), waiting_(false) {
103     registrar_.Add(this,
104                    extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
105                    content::NotificationService::AllSources());
106   }
107 
Reset()108   void Reset() {
109     received_notification_ = false;
110     waiting_ = false;
111     extension_ = NULL;
112     permissions_ = NULL;
113   }
114 
Wait()115   void Wait() {
116     if (received_notification_)
117       return;
118 
119     waiting_ = true;
120     base::RunLoop run_loop;
121     run_loop.Run();
122   }
123 
received_notification() const124   bool received_notification() const { return received_notification_; }
extension() const125   const Extension* extension() const { return extension_.get(); }
permissions() const126   const PermissionSet* permissions() const { return permissions_.get(); }
reason() const127   UpdatedExtensionPermissionsInfo::Reason reason() const { return reason_; }
128 
129  private:
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)130   virtual void Observe(int type,
131                        const content::NotificationSource& source,
132                        const content::NotificationDetails& details) OVERRIDE {
133     received_notification_ = true;
134     UpdatedExtensionPermissionsInfo* info =
135         content::Details<UpdatedExtensionPermissionsInfo>(details).ptr();
136 
137     extension_ = info->extension;
138     permissions_ = info->permissions;
139     reason_ = info->reason;
140 
141     if (waiting_) {
142       waiting_ = false;
143       base::MessageLoopForUI::current()->Quit();
144     }
145   }
146 
147   bool received_notification_;
148   bool waiting_;
149   content::NotificationRegistrar registrar_;
150   scoped_refptr<const Extension> extension_;
151   scoped_refptr<const PermissionSet> permissions_;
152   UpdatedExtensionPermissionsInfo::Reason reason_;
153 };
154 
155 class PermissionsUpdaterTest : public ExtensionServiceTestBase {
156 };
157 
LoadOurManifest()158 scoped_refptr<Extension> LoadOurManifest() {
159   base::FilePath path;
160   path = path.AppendASCII("api_test")
161       .AppendASCII("permissions")
162       .AppendASCII("optional");
163   return LoadManifest(path.AsUTF8Unsafe(),
164                       "manifest.json",
165                       Manifest::INTERNAL,
166                       Extension::NO_FLAGS);
167 }
168 
AddPattern(URLPatternSet * extent,const std::string & pattern)169 void AddPattern(URLPatternSet* extent, const std::string& pattern) {
170   int schemes = URLPattern::SCHEME_ALL;
171   extent->AddPattern(URLPattern(schemes, pattern));
172 }
173 
174 }  // namespace
175 
176 // Test that the PermissionUpdater can correctly add and remove active
177 // permissions. This tests all of PermissionsUpdater's public methods because
178 // GrantActivePermissions and SetPermissions are used by AddPermissions.
TEST_F(PermissionsUpdaterTest,AddAndRemovePermissions)179 TEST_F(PermissionsUpdaterTest, AddAndRemovePermissions) {
180   InitializeEmptyExtensionService();
181 
182   // Load the test extension.
183   scoped_refptr<Extension> extension = LoadOurManifest();
184   ASSERT_TRUE(extension.get());
185 
186   APIPermissionSet default_apis;
187   default_apis.insert(APIPermission::kManagement);
188   ManifestPermissionSet empty_manifest_permissions;
189 
190   URLPatternSet default_hosts;
191   AddPattern(&default_hosts, "http://a.com/*");
192   scoped_refptr<PermissionSet> default_permissions =
193       new PermissionSet(default_apis, empty_manifest_permissions,
194                         default_hosts, URLPatternSet());
195 
196   // Make sure it loaded properly.
197   scoped_refptr<const PermissionSet> permissions =
198       extension->permissions_data()->active_permissions();
199   ASSERT_EQ(*default_permissions.get(),
200             *extension->permissions_data()->active_permissions().get());
201 
202   // Add a few permissions.
203   APIPermissionSet apis;
204   apis.insert(APIPermission::kTab);
205   apis.insert(APIPermission::kNotifications);
206   URLPatternSet hosts;
207   AddPattern(&hosts, "http://*.c.com/*");
208 
209   scoped_refptr<PermissionSet> delta =
210       new PermissionSet(apis, empty_manifest_permissions,
211                         hosts, URLPatternSet());
212 
213   PermissionsUpdaterListener listener;
214   PermissionsUpdater updater(profile_.get());
215   updater.AddPermissions(extension.get(), delta.get());
216 
217   listener.Wait();
218 
219   // Verify that the permission notification was sent correctly.
220   ASSERT_TRUE(listener.received_notification());
221   ASSERT_EQ(extension.get(), listener.extension());
222   ASSERT_EQ(UpdatedExtensionPermissionsInfo::ADDED, listener.reason());
223   ASSERT_EQ(*delta.get(), *listener.permissions());
224 
225   // Make sure the extension's active permissions reflect the change.
226   scoped_refptr<PermissionSet> active_permissions =
227       PermissionSet::CreateUnion(default_permissions.get(), delta.get());
228   ASSERT_EQ(*active_permissions.get(),
229             *extension->permissions_data()->active_permissions().get());
230 
231   // Verify that the new granted and active permissions were also stored
232   // in the extension preferences. In this case, the granted permissions should
233   // be equal to the active permissions.
234   ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_.get());
235   scoped_refptr<PermissionSet> granted_permissions =
236       active_permissions;
237 
238   scoped_refptr<PermissionSet> from_prefs =
239       prefs->GetActivePermissions(extension->id());
240   ASSERT_EQ(*active_permissions.get(), *from_prefs.get());
241 
242   from_prefs = prefs->GetGrantedPermissions(extension->id());
243   ASSERT_EQ(*active_permissions.get(), *from_prefs.get());
244 
245   // In the second part of the test, we'll remove the permissions that we
246   // just added except for 'notifications'.
247   apis.erase(APIPermission::kNotifications);
248   delta = new PermissionSet(apis, empty_manifest_permissions,
249                             hosts, URLPatternSet());
250 
251   listener.Reset();
252   updater.RemovePermissions(extension.get(), delta.get());
253   listener.Wait();
254 
255   // Verify that the notification was correct.
256   ASSERT_TRUE(listener.received_notification());
257   ASSERT_EQ(extension.get(), listener.extension());
258   ASSERT_EQ(UpdatedExtensionPermissionsInfo::REMOVED, listener.reason());
259   ASSERT_EQ(*delta.get(), *listener.permissions());
260 
261   // Make sure the extension's active permissions reflect the change.
262   active_permissions =
263       PermissionSet::CreateDifference(active_permissions.get(), delta.get());
264   ASSERT_EQ(*active_permissions.get(),
265             *extension->permissions_data()->active_permissions().get());
266 
267   // Verify that the extension prefs hold the new active permissions and the
268   // same granted permissions.
269   from_prefs = prefs->GetActivePermissions(extension->id());
270   ASSERT_EQ(*active_permissions.get(), *from_prefs.get());
271 
272   from_prefs = prefs->GetGrantedPermissions(extension->id());
273   ASSERT_EQ(*granted_permissions.get(), *from_prefs.get());
274 }
275 
TEST_F(PermissionsUpdaterTest,WithholdAllHosts)276 TEST_F(PermissionsUpdaterTest, WithholdAllHosts) {
277   InitializeEmptyExtensionService();
278 
279   // Permissions are only withheld with the appropriate switch turned on.
280   scoped_ptr<FeatureSwitch::ScopedOverride> switch_override(
281       new FeatureSwitch::ScopedOverride(FeatureSwitch::scripts_require_action(),
282                                         FeatureSwitch::OVERRIDE_ENABLED));
283 
284   URLPattern google(URLPattern::SCHEME_ALL, "http://www.google.com/*");
285   URLPattern sub_google(URLPattern::SCHEME_ALL, "http://*.google.com/*");
286   URLPattern all_http(URLPattern::SCHEME_ALL, "http://*/*");
287   URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>");
288   URLPattern all_com(URLPattern::SCHEME_ALL, "http://*.com/*");
289 
290   std::set<URLPattern> all_host_patterns;
291   std::set<URLPattern> safe_patterns;
292 
293   all_host_patterns.insert(all_http);
294   all_host_patterns.insert(all_hosts);
295   all_host_patterns.insert(all_com);
296 
297   safe_patterns.insert(google);
298   safe_patterns.insert(sub_google);
299 
300   std::set<URLPattern> all_patterns = base::STLSetUnion<std::set<URLPattern> >(
301       all_host_patterns, safe_patterns);
302 
303   scoped_refptr<const Extension> extension = CreateExtensionWithPermissions(
304       all_patterns, all_patterns, Manifest::INTERNAL);
305   const PermissionsData* permissions_data = extension->permissions_data();
306   PermissionsUpdater updater(profile_.get());
307   updater.InitializePermissions(extension.get());
308 
309   // At first, the active permissions should have only the safe patterns and
310   // the withheld permissions should have only the all host patterns.
311   EXPECT_TRUE(SetsAreEqual(
312       permissions_data->active_permissions()->scriptable_hosts().patterns(),
313       safe_patterns));
314   EXPECT_TRUE(SetsAreEqual(
315       permissions_data->active_permissions()->explicit_hosts().patterns(),
316       safe_patterns));
317   EXPECT_TRUE(SetsAreEqual(
318       permissions_data->withheld_permissions()->scriptable_hosts().patterns(),
319       all_host_patterns));
320   EXPECT_TRUE(SetsAreEqual(
321       permissions_data->withheld_permissions()->explicit_hosts().patterns(),
322       all_host_patterns));
323 
324   // Then, we grant the withheld all-hosts permissions.
325   updater.GrantWithheldImpliedAllHosts(extension.get());
326   // Now, active permissions should have all patterns, and withheld permissions
327   // should have none.
328   EXPECT_TRUE(SetsAreEqual(
329       permissions_data->active_permissions()->scriptable_hosts().patterns(),
330       all_patterns));
331   EXPECT_TRUE(permissions_data->withheld_permissions()
332                   ->scriptable_hosts()
333                   .patterns()
334                   .empty());
335   EXPECT_TRUE(SetsAreEqual(
336       permissions_data->active_permissions()->explicit_hosts().patterns(),
337       all_patterns));
338   EXPECT_TRUE(permissions_data->withheld_permissions()
339                   ->explicit_hosts()
340                   .patterns()
341                   .empty());
342 
343   // Finally, we revoke the all hosts permissions.
344   updater.WithholdImpliedAllHosts(extension.get());
345 
346   // We should be back to our initial state - all_hosts should be withheld, and
347   // the safe patterns should be granted.
348   EXPECT_TRUE(SetsAreEqual(
349       permissions_data->active_permissions()->scriptable_hosts().patterns(),
350       safe_patterns));
351   EXPECT_TRUE(SetsAreEqual(
352       permissions_data->active_permissions()->explicit_hosts().patterns(),
353       safe_patterns));
354   EXPECT_TRUE(SetsAreEqual(
355       permissions_data->withheld_permissions()->scriptable_hosts().patterns(),
356       all_host_patterns));
357   EXPECT_TRUE(SetsAreEqual(
358       permissions_data->withheld_permissions()->explicit_hosts().patterns(),
359       all_host_patterns));
360 
361   // Creating a component extension should result in no withheld permissions.
362   extension = CreateExtensionWithPermissions(
363       all_patterns, all_patterns, Manifest::COMPONENT);
364   permissions_data = extension->permissions_data();
365   updater.InitializePermissions(extension.get());
366   EXPECT_TRUE(SetsAreEqual(
367       permissions_data->active_permissions()->scriptable_hosts().patterns(),
368       all_patterns));
369   EXPECT_TRUE(permissions_data->withheld_permissions()
370                   ->scriptable_hosts()
371                   .patterns()
372                   .empty());
373   EXPECT_TRUE(SetsAreEqual(
374       permissions_data->active_permissions()->explicit_hosts().patterns(),
375       all_patterns));
376   EXPECT_TRUE(permissions_data->withheld_permissions()
377                   ->explicit_hosts()
378                   .patterns()
379                   .empty());
380 
381   // Without the switch, we shouldn't withhold anything.
382   switch_override.reset();
383   extension = CreateExtensionWithPermissions(
384       all_patterns, all_patterns, Manifest::INTERNAL);
385   permissions_data = extension->permissions_data();
386   updater.InitializePermissions(extension.get());
387   EXPECT_TRUE(SetsAreEqual(
388       permissions_data->active_permissions()->scriptable_hosts().patterns(),
389       all_patterns));
390   EXPECT_TRUE(permissions_data->withheld_permissions()
391                   ->scriptable_hosts()
392                   .patterns()
393                   .empty());
394   EXPECT_TRUE(SetsAreEqual(
395       permissions_data->active_permissions()->explicit_hosts().patterns(),
396       all_patterns));
397   EXPECT_TRUE(permissions_data->withheld_permissions()
398                   ->explicit_hosts()
399                   .patterns()
400                   .empty());
401 }
402 
403 }  // namespace extensions
404