blob: 7e38b618ab7dde48ffeacbb33591edff27648985 [file] [log] [blame]
[email protected]c333e792012-01-06 16:57:391// 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
dcheng1fc00f12015-12-26 22:18:035#include "chrome/browser/extensions/permissions_updater.h"
6
7#include <utility>
8
[email protected]57999812013-02-24 05:40:529#include "base/files/file_path.h"
[email protected]ffbec692012-02-26 20:26:4210#include "base/json/json_file_value_serializer.h"
[email protected]c333e792012-01-06 16:57:3911#include "base/memory/ref_counted.h"
[email protected]78089f02012-07-19 06:11:2812#include "base/run_loop.h"
Devlin Cronincac45cb2018-04-25 04:43:0313#include "base/test/scoped_feature_list.h"
[email protected]c333e792012-01-06 16:57:3914#include "base/values.h"
[email protected]49a01e642013-07-12 00:29:4515#include "chrome/browser/chrome_notification_types.h"
[email protected]c333e792012-01-06 16:57:3916#include "chrome/browser/extensions/extension_service.h"
[email protected]f484f8d52014-06-12 08:38:1817#include "chrome/browser/extensions/extension_service_test_base.h"
rdevlin.croninb8dffe52015-02-07 00:58:0118#include "chrome/browser/extensions/extension_util.h"
Devlin Croninf355f1de2018-05-14 15:27:2419#include "chrome/browser/extensions/scripting_permissions_modifier.h"
[email protected]c333e792012-01-06 16:57:3920#include "chrome/common/chrome_paths.h"
[email protected]04e4bbe2013-04-27 07:44:2421#include "chrome/common/extensions/extension_test_util.h"
[email protected]c333e792012-01-06 16:57:3922#include "chrome/test/base/testing_profile.h"
rdevlin.croninb8dffe52015-02-07 00:58:0123#include "components/crx_file/id_util.h"
[email protected]c333e792012-01-06 16:57:3924#include "content/public/browser/notification_observer.h"
25#include "content/public/browser/notification_registrar.h"
26#include "content/public/browser/notification_service.h"
[email protected]dccba4f82014-05-29 00:52:5627#include "extensions/browser/extension_prefs.h"
[email protected]e4452d32013-11-15 23:07:4128#include "extensions/common/extension.h"
[email protected]23a85362014-07-07 23:26:1929#include "extensions/common/extension_builder.h"
Devlin Cronincac45cb2018-04-25 04:43:0330#include "extensions/common/extension_features.h"
[email protected]5a55f3f2013-10-29 01:08:2931#include "extensions/common/permissions/permission_set.h"
[email protected]076ebeda2014-06-06 21:47:2632#include "extensions/common/permissions/permissions_data.h"
[email protected]23a85362014-07-07 23:26:1933#include "extensions/common/value_builder.h"
[email protected]c333e792012-01-06 16:57:3934#include "testing/gtest/include/gtest/gtest.h"
35
[email protected]04e4bbe2013-04-27 07:44:2436using extension_test_util::LoadManifest;
37
[email protected]c333e792012-01-06 16:57:3938namespace extensions {
39
40namespace {
41
rdevlin.cronin77cb0ef2015-09-16 17:03:4842scoped_refptr<const Extension> CreateExtensionWithOptionalPermissions(
dchengc963c7142016-04-08 03:55:2243 std::unique_ptr<base::Value> optional_permissions,
44 std::unique_ptr<base::Value> permissions,
rdevlin.cronin77cb0ef2015-09-16 17:03:4845 const std::string& name) {
46 return ExtensionBuilder()
47 .SetLocation(Manifest::INTERNAL)
dcheng794d2bd2016-02-27 03:51:3248 .SetManifest(
rdevlin.cronin77cb0ef2015-09-16 17:03:4849 DictionaryBuilder()
50 .Set("name", name)
51 .Set("description", "foo")
52 .Set("manifest_version", 2)
53 .Set("version", "0.1.2.3")
dcheng1fc00f12015-12-26 22:18:0354 .Set("permissions", std::move(permissions))
dcheng794d2bd2016-02-27 03:51:3255 .Set("optional_permissions", std::move(optional_permissions))
56 .Build())
rdevlin.cronin77cb0ef2015-09-16 17:03:4857 .SetID(crx_file::id_util::GenerateId(name))
58 .Build();
59}
60
[email protected]c333e792012-01-06 16:57:3961// A helper class that listens for NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED.
62class PermissionsUpdaterListener : public content::NotificationObserver {
63 public:
64 PermissionsUpdaterListener()
65 : received_notification_(false), waiting_(false) {
66 registrar_.Add(this,
[email protected]adf5a102014-07-31 12:44:0667 extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
[email protected]c333e792012-01-06 16:57:3968 content::NotificationService::AllSources());
69 }
70
71 void Reset() {
72 received_notification_ = false;
73 waiting_ = false;
74 extension_ = NULL;
75 permissions_ = NULL;
76 }
77
78 void Wait() {
79 if (received_notification_)
80 return;
81
82 waiting_ = true;
[email protected]78089f02012-07-19 06:11:2883 base::RunLoop run_loop;
84 run_loop.Run();
[email protected]c333e792012-01-06 16:57:3985 }
86
87 bool received_notification() const { return received_notification_; }
[email protected]dc24976f2013-06-02 21:15:0988 const Extension* extension() const { return extension_.get(); }
89 const PermissionSet* permissions() const { return permissions_.get(); }
90 UpdatedExtensionPermissionsInfo::Reason reason() const { return reason_; }
[email protected]c333e792012-01-06 16:57:3991
92 private:
dchengae36a4a2014-10-21 12:36:3693 void Observe(int type,
94 const content::NotificationSource& source,
95 const content::NotificationDetails& details) override {
[email protected]c333e792012-01-06 16:57:3996 received_notification_ = true;
97 UpdatedExtensionPermissionsInfo* info =
98 content::Details<UpdatedExtensionPermissionsInfo>(details).ptr();
99
100 extension_ = info->extension;
rdevlin.cronine2d0fd02015-09-24 22:35:49101 permissions_ = info->permissions.Clone();
[email protected]c333e792012-01-06 16:57:39102 reason_ = info->reason;
103
104 if (waiting_) {
105 waiting_ = false;
Gabriel Charette53a9ef812017-07-26 12:36:23106 base::RunLoop::QuitCurrentWhenIdleDeprecated();
[email protected]c333e792012-01-06 16:57:39107 }
108 }
109
110 bool received_notification_;
111 bool waiting_;
112 content::NotificationRegistrar registrar_;
113 scoped_refptr<const Extension> extension_;
dchengc963c7142016-04-08 03:55:22114 std::unique_ptr<const PermissionSet> permissions_;
[email protected]c333e792012-01-06 16:57:39115 UpdatedExtensionPermissionsInfo::Reason reason_;
116};
117
118class PermissionsUpdaterTest : public ExtensionServiceTestBase {
119};
120
[email protected]04e4bbe2013-04-27 07:44:24121scoped_refptr<Extension> LoadOurManifest() {
[email protected]650b2d52013-02-10 03:41:45122 base::FilePath path;
[email protected]04e4bbe2013-04-27 07:44:24123 path = path.AppendASCII("api_test")
[email protected]c333e792012-01-06 16:57:39124 .AppendASCII("permissions")
[email protected]04e4bbe2013-04-27 07:44:24125 .AppendASCII("optional");
126 return LoadManifest(path.AsUTF8Unsafe(),
127 "manifest.json",
128 Manifest::INTERNAL,
129 Extension::NO_FLAGS);
[email protected]c333e792012-01-06 16:57:39130}
131
132void AddPattern(URLPatternSet* extent, const std::string& pattern) {
133 int schemes = URLPattern::SCHEME_ALL;
134 extent->AddPattern(URLPattern(schemes, pattern));
135}
136
isandrk80e3eb92017-04-12 15:22:14137class PermissionsUpdaterTestDelegate : public PermissionsUpdater::Delegate {
138 public:
139 PermissionsUpdaterTestDelegate() {}
140 ~PermissionsUpdaterTestDelegate() override {}
141
142 // PermissionsUpdater::Delegate
143 void InitializePermissions(
144 const Extension* extension,
145 std::unique_ptr<const PermissionSet>* granted_permissions) override {
146 // Remove the cookie permission.
147 APIPermissionSet api_permission_set((*granted_permissions)->apis());
148 api_permission_set.erase(APIPermission::kCookie);
149 granted_permissions->reset(
150 new PermissionSet(api_permission_set, ManifestPermissionSet(),
151 URLPatternSet(), URLPatternSet()));
152 }
153
154 private:
155 DISALLOW_COPY_AND_ASSIGN(PermissionsUpdaterTestDelegate);
156};
157
[email protected]c333e792012-01-06 16:57:39158} // namespace
159
160// Test that the PermissionUpdater can correctly add and remove active
161// permissions. This tests all of PermissionsUpdater's public methods because
[email protected]23a85362014-07-07 23:26:19162// GrantActivePermissions and SetPermissions are used by AddPermissions.
Devlin Cronin5218d262018-07-09 20:18:05163TEST_F(PermissionsUpdaterTest, GrantAndRevokeOptionalPermissions) {
[email protected]c333e792012-01-06 16:57:39164 InitializeEmptyExtensionService();
165
166 // Load the test extension.
[email protected]04e4bbe2013-04-27 07:44:24167 scoped_refptr<Extension> extension = LoadOurManifest();
168 ASSERT_TRUE(extension.get());
[email protected]c333e792012-01-06 16:57:39169
[email protected]c2e66e12012-06-27 06:27:06170 APIPermissionSet default_apis;
171 default_apis.insert(APIPermission::kManagement);
[email protected]e737c442013-11-15 15:55:24172 ManifestPermissionSet empty_manifest_permissions;
173
[email protected]c333e792012-01-06 16:57:39174 URLPatternSet default_hosts;
175 AddPattern(&default_hosts, "http://a.com/*");
rdevlin.cronine2d0fd02015-09-24 22:35:49176 PermissionSet default_permissions(default_apis, empty_manifest_permissions,
177 default_hosts, URLPatternSet());
[email protected]c333e792012-01-06 16:57:39178
179 // Make sure it loaded properly.
rdevlin.cronine2d0fd02015-09-24 22:35:49180 ASSERT_EQ(default_permissions,
rdevlin.cronind630c302015-09-30 20:19:33181 extension->permissions_data()->active_permissions());
rdevlin.cronine2d0fd02015-09-24 22:35:49182
183 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_.get());
dchengc963c7142016-04-08 03:55:22184 std::unique_ptr<const PermissionSet> active_permissions;
185 std::unique_ptr<const PermissionSet> granted_permissions;
[email protected]c333e792012-01-06 16:57:39186
187 // Add a few permissions.
[email protected]c2e66e12012-06-27 06:27:06188 APIPermissionSet apis;
[email protected]81327f12014-07-29 04:24:11189 apis.insert(APIPermission::kNotifications);
[email protected]c333e792012-01-06 16:57:39190 URLPatternSet hosts;
191 AddPattern(&hosts, "http://*.c.com/*");
Karan Bhatia599a50b2018-02-03 04:56:30192 URLPatternSet scriptable_hosts;
193 AddPattern(&scriptable_hosts, "http://*.example.com/*");
[email protected]c333e792012-01-06 16:57:39194
rdevlin.cronine2d0fd02015-09-24 22:35:49195 {
196 PermissionSet delta(apis, empty_manifest_permissions, hosts,
Karan Bhatia599a50b2018-02-03 04:56:30197 scriptable_hosts);
[email protected]c333e792012-01-06 16:57:39198
Karan Bhatia599a50b2018-02-03 04:56:30199 PermissionsUpdaterListener listener;
Devlin Cronin5218d262018-07-09 20:18:05200 PermissionsUpdater(profile_.get())
201 .GrantOptionalPermissions(*extension, delta);
[email protected]c333e792012-01-06 16:57:39202
Karan Bhatia599a50b2018-02-03 04:56:30203 listener.Wait();
[email protected]c333e792012-01-06 16:57:39204
Karan Bhatia599a50b2018-02-03 04:56:30205 // Verify that the permission notification was sent correctly.
206 ASSERT_TRUE(listener.received_notification());
207 ASSERT_EQ(extension.get(), listener.extension());
208 ASSERT_EQ(UpdatedExtensionPermissionsInfo::ADDED, listener.reason());
209 ASSERT_EQ(delta, *listener.permissions());
[email protected]c333e792012-01-06 16:57:39210
Karan Bhatia599a50b2018-02-03 04:56:30211 // Make sure the extension's active permissions reflect the change.
212 active_permissions = PermissionSet::CreateUnion(default_permissions, delta);
213 ASSERT_EQ(*active_permissions,
214 extension->permissions_data()->active_permissions());
[email protected]c333e792012-01-06 16:57:39215
Karan Bhatia599a50b2018-02-03 04:56:30216 // Verify that the new granted and active permissions were also stored
217 // in the extension preferences. In this case, the granted permissions
218 // should be equal to the active permissions.
219 ASSERT_EQ(*active_permissions,
220 *prefs->GetActivePermissions(extension->id()));
221 granted_permissions = active_permissions->Clone();
222 ASSERT_EQ(*granted_permissions,
223 *prefs->GetGrantedPermissions(extension->id()));
rdevlin.cronine2d0fd02015-09-24 22:35:49224 }
[email protected]c333e792012-01-06 16:57:39225
rdevlin.cronine2d0fd02015-09-24 22:35:49226 {
Devlin Cronin5218d262018-07-09 20:18:05227 // In the second part of the test, we'll remove the permissions that we
228 // just added except for 'notifications'.
229 apis.erase(APIPermission::kNotifications);
230 PermissionSet delta(apis, empty_manifest_permissions, hosts,
231 scriptable_hosts);
[email protected]c333e792012-01-06 16:57:39232
Devlin Cronin5218d262018-07-09 20:18:05233 PermissionsUpdaterListener listener;
234 PermissionsUpdater(profile_.get())
235 .RevokeOptionalPermissions(*extension, delta,
236 PermissionsUpdater::REMOVE_SOFT);
237 listener.Wait();
[email protected]c333e792012-01-06 16:57:39238
Devlin Cronin5218d262018-07-09 20:18:05239 // Verify that the notification was correct.
240 ASSERT_TRUE(listener.received_notification());
241 ASSERT_EQ(extension.get(), listener.extension());
242 ASSERT_EQ(UpdatedExtensionPermissionsInfo::REMOVED, listener.reason());
243 ASSERT_EQ(delta, *listener.permissions());
[email protected]c333e792012-01-06 16:57:39244
Devlin Cronin5218d262018-07-09 20:18:05245 // Make sure the extension's active permissions reflect the change.
246 active_permissions =
247 PermissionSet::CreateDifference(*active_permissions, delta);
248 ASSERT_EQ(*active_permissions,
249 extension->permissions_data()->active_permissions());
[email protected]c333e792012-01-06 16:57:39250
Devlin Cronin5218d262018-07-09 20:18:05251 // Verify that the extension prefs hold the new active permissions and the
252 // same granted permissions.
253 ASSERT_EQ(*active_permissions,
254 *prefs->GetActivePermissions(extension->id()));
[email protected]c333e792012-01-06 16:57:39255
Devlin Cronin5218d262018-07-09 20:18:05256 ASSERT_EQ(*granted_permissions,
257 *prefs->GetGrantedPermissions(extension->id()));
rdevlin.cronine2d0fd02015-09-24 22:35:49258 }
[email protected]c333e792012-01-06 16:57:39259}
260
rdevlin.cronin77cb0ef2015-09-16 17:03:48261TEST_F(PermissionsUpdaterTest, RevokingPermissions) {
262 InitializeEmptyExtensionService();
263
264 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
265
266 auto api_permission_set = [](APIPermission::ID id) {
267 APIPermissionSet apis;
268 apis.insert(id);
Jinho Bangb5216cec2018-01-17 19:43:11269 return std::make_unique<PermissionSet>(apis, ManifestPermissionSet(),
ricea91d6fc122016-08-30 08:47:14270 URLPatternSet(), URLPatternSet());
rdevlin.cronin77cb0ef2015-09-16 17:03:48271 };
272
nrpetere33d2a5b2017-04-25 00:12:31273 auto can_access_page =
274 [](scoped_refptr<const extensions::Extension> extension,
275 const GURL& document_url) -> bool {
Devlin Cronin3e532b82018-05-03 21:27:19276 PermissionsData::PageAccess access =
Devlin Cronin5cb437832018-05-17 20:14:41277 extension->permissions_data()->GetPageAccess(document_url, -1, nullptr);
Devlin Cronin3e532b82018-05-03 21:27:19278 return access == PermissionsData::PageAccess::kAllowed;
nrpetere33d2a5b2017-04-25 00:12:31279 };
280
rdevlin.cronin77cb0ef2015-09-16 17:03:48281 {
282 // Test revoking optional permissions.
283 ListBuilder optional_permissions;
284 optional_permissions.Append("tabs").Append("cookies").Append("management");
285 ListBuilder required_permissions;
286 required_permissions.Append("topSites");
287 scoped_refptr<const Extension> extension =
288 CreateExtensionWithOptionalPermissions(optional_permissions.Build(),
289 required_permissions.Build(),
290 "My Extension");
291
292 PermissionsUpdater updater(profile());
293 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())->IsEmpty());
294
295 // Add the optional "cookies" permission.
Devlin Cronin5218d262018-07-09 20:18:05296 updater.GrantOptionalPermissions(
297 *extension, *api_permission_set(APIPermission::kCookie));
rdevlin.cronin77cb0ef2015-09-16 17:03:48298 const PermissionsData* permissions = extension->permissions_data();
299 // The extension should have the permission in its active permissions and
300 // its granted permissions (stored in prefs). And, the permission should
301 // be revokable.
302 EXPECT_TRUE(permissions->HasAPIPermission(APIPermission::kCookie));
dchengc963c7142016-04-08 03:55:22303 std::unique_ptr<const PermissionSet> granted_permissions =
rdevlin.cronin77cb0ef2015-09-16 17:03:48304 prefs->GetGrantedPermissions(extension->id());
305 EXPECT_TRUE(granted_permissions->HasAPIPermission(APIPermission::kCookie));
306 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())
307 ->HasAPIPermission(APIPermission::kCookie));
308
309 // Repeat with "tabs".
Devlin Cronin5218d262018-07-09 20:18:05310 updater.GrantOptionalPermissions(*extension,
311 *api_permission_set(APIPermission::kTab));
rdevlin.cronin77cb0ef2015-09-16 17:03:48312 EXPECT_TRUE(permissions->HasAPIPermission(APIPermission::kTab));
313 granted_permissions = prefs->GetGrantedPermissions(extension->id());
314 EXPECT_TRUE(granted_permissions->HasAPIPermission(APIPermission::kTab));
315 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())
316 ->HasAPIPermission(APIPermission::kTab));
317
318 // Remove the "tabs" permission. The extension should no longer have it
319 // in its active or granted permissions, and it shouldn't be revokable.
320 // The extension should still have the "cookies" permission.
Devlin Cronin5218d262018-07-09 20:18:05321 updater.RevokeOptionalPermissions(*extension,
322 *api_permission_set(APIPermission::kTab),
323 PermissionsUpdater::REMOVE_HARD);
rdevlin.cronin77cb0ef2015-09-16 17:03:48324 EXPECT_FALSE(permissions->HasAPIPermission(APIPermission::kTab));
325 granted_permissions = prefs->GetGrantedPermissions(extension->id());
326 EXPECT_FALSE(granted_permissions->HasAPIPermission(APIPermission::kTab));
327 EXPECT_FALSE(updater.GetRevokablePermissions(extension.get())
328 ->HasAPIPermission(APIPermission::kTab));
329 EXPECT_TRUE(permissions->HasAPIPermission(APIPermission::kCookie));
330 granted_permissions = prefs->GetGrantedPermissions(extension->id());
331 EXPECT_TRUE(granted_permissions->HasAPIPermission(APIPermission::kCookie));
332 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())
333 ->HasAPIPermission(APIPermission::kCookie));
334 }
335
336 {
nrpetere33d2a5b2017-04-25 00:12:31337 // Make sure policy restriction updates update permission data.
338 URLPatternSet default_policy_blocked_hosts;
339 URLPatternSet default_policy_allowed_hosts;
340 URLPatternSet policy_blocked_hosts;
341 URLPatternSet policy_allowed_hosts;
342 ListBuilder optional_permissions;
343 ListBuilder required_permissions;
344 required_permissions.Append("tabs").Append("http://*/*");
345 scoped_refptr<const Extension> extension =
346 CreateExtensionWithOptionalPermissions(optional_permissions.Build(),
347 required_permissions.Build(),
348 "ExtensionSettings");
349 AddPattern(&default_policy_blocked_hosts, "http://*.google.com/*");
350 PermissionsUpdater updater(profile());
351 updater.InitializePermissions(extension.get());
352 extension->permissions_data()->SetDefaultPolicyHostRestrictions(
353 default_policy_blocked_hosts, default_policy_allowed_hosts);
354
355 // By default, all subdomains of google.com should be blocked.
356 const GURL kOrigin("http://foo.com");
357 const GURL kGoogle("http://www.google.com");
358 const GURL kExampleGoogle("http://example.google.com");
359 EXPECT_TRUE(
360 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
361 EXPECT_TRUE(can_access_page(extension, kOrigin));
362 EXPECT_FALSE(can_access_page(extension, kGoogle));
363 EXPECT_FALSE(can_access_page(extension, kExampleGoogle));
364
365 AddPattern(&default_policy_allowed_hosts, "http://example.google.com/*");
366 // Give the extension access to example.google.com. Now the
367 // example.google.com should not be a runtime blocked host.
368 updater.SetDefaultPolicyHostRestrictions(default_policy_blocked_hosts,
369 default_policy_allowed_hosts);
370
371 EXPECT_TRUE(
372 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
373 EXPECT_TRUE(can_access_page(extension, kOrigin));
374 EXPECT_FALSE(can_access_page(extension, kGoogle));
375 EXPECT_TRUE(can_access_page(extension, kExampleGoogle));
376
377 // Revoke extension access to foo.com. Now, foo.com should be a runtime
378 // blocked host.
379 AddPattern(&default_policy_blocked_hosts, "*://*.foo.com/");
380 updater.SetDefaultPolicyHostRestrictions(default_policy_blocked_hosts,
381 default_policy_allowed_hosts);
382 EXPECT_TRUE(
383 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
384 EXPECT_FALSE(can_access_page(extension, kOrigin));
385 EXPECT_FALSE(can_access_page(extension, kGoogle));
386 EXPECT_TRUE(can_access_page(extension, kExampleGoogle));
387
388 // Remove foo.com from blocked hosts. The extension should no longer have
389 // be a runtime blocked host.
390 default_policy_blocked_hosts.ClearPatterns();
391 AddPattern(&default_policy_blocked_hosts, "*://*.foo.com/");
392 updater.SetDefaultPolicyHostRestrictions(default_policy_blocked_hosts,
393 default_policy_allowed_hosts);
394 EXPECT_TRUE(
395 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
396 EXPECT_FALSE(can_access_page(extension, kOrigin));
397 EXPECT_TRUE(can_access_page(extension, kGoogle));
398 EXPECT_TRUE(can_access_page(extension, kExampleGoogle));
399
400 // Set an empty individual policy, should not affect default policy.
401 updater.SetPolicyHostRestrictions(extension.get(), policy_blocked_hosts,
402 policy_allowed_hosts);
403 EXPECT_FALSE(
404 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
405 EXPECT_TRUE(can_access_page(extension, kOrigin));
406 EXPECT_TRUE(can_access_page(extension, kGoogle));
407 EXPECT_TRUE(can_access_page(extension, kExampleGoogle));
408
409 // Block google.com for the Individual scope.
410 // Whitelist example.google.com for the Indiviaul scope.
411 // Leave google.com and example.google.com off both the whitelist and
412 // blacklist for Default scope.
413 AddPattern(&policy_blocked_hosts, "*://*.google.com/*");
414 AddPattern(&policy_allowed_hosts, "*://example.google.com/*");
415 updater.SetPolicyHostRestrictions(extension.get(), policy_blocked_hosts,
416 policy_allowed_hosts);
417 EXPECT_FALSE(
418 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
419 EXPECT_TRUE(can_access_page(extension, kOrigin));
420 EXPECT_FALSE(can_access_page(extension, kGoogle));
421 EXPECT_TRUE(can_access_page(extension, kExampleGoogle));
422
423 // Switch back to default scope for extension.
424 updater.SetUsesDefaultHostRestrictions(extension.get());
425 EXPECT_TRUE(
426 extension->permissions_data()->UsesDefaultPolicyHostRestrictions());
427 default_policy_blocked_hosts.ClearPatterns();
428 default_policy_allowed_hosts.ClearPatterns();
429 updater.SetDefaultPolicyHostRestrictions(default_policy_blocked_hosts,
430 default_policy_allowed_hosts);
431 }
rdevlin.cronin77cb0ef2015-09-16 17:03:48432}
433
isandrk80e3eb92017-04-12 15:22:14434// Test that the permissions updater delegate works - in this test it removes
435// the cookies permission.
436TEST_F(PermissionsUpdaterTest, Delegate) {
437 InitializeEmptyExtensionService();
438
439 ListBuilder required_permissions;
440 required_permissions.Append("tabs").Append("management").Append("cookies");
441 scoped_refptr<const Extension> extension =
442 CreateExtensionWithOptionalPermissions(
Jinho Bangb5216cec2018-01-17 19:43:11443 std::make_unique<base::ListValue>(), required_permissions.Build(),
isandrk80e3eb92017-04-12 15:22:14444 "My Extension");
445
Ivan Sandrke2b20c62018-09-10 16:23:53446 PermissionsUpdater::SetPlatformDelegate(
447 std::make_unique<PermissionsUpdaterTestDelegate>());
isandrk80e3eb92017-04-12 15:22:14448 PermissionsUpdater updater(profile());
449 updater.InitializePermissions(extension.get());
450
451 EXPECT_TRUE(extension->permissions_data()->HasAPIPermission(
452 APIPermission::kTab));
453 EXPECT_TRUE(extension->permissions_data()->HasAPIPermission(
454 APIPermission::kManagement));
455 EXPECT_FALSE(extension->permissions_data()->HasAPIPermission(
456 APIPermission::kCookie));
457
458 // Unset the delegate.
459 PermissionsUpdater::SetPlatformDelegate(nullptr);
460}
461
Devlin Cronin5218d262018-07-09 20:18:05462TEST_F(PermissionsUpdaterTest,
463 UpdatingRuntimeGrantedPermissionsWithOptionalPermissions) {
Devlin Cronine90eacf2018-06-07 17:23:45464 InitializeEmptyExtensionService();
465
466 scoped_refptr<const Extension> extension =
467 ExtensionBuilder("extension")
468 .SetManifestKey("optional_permissions",
469 extensions::ListBuilder().Append("tabs").Build())
470 .Build();
471
472 PermissionsUpdater updater(profile());
473 updater.InitializePermissions(extension.get());
Devlin Cronin5218d262018-07-09 20:18:05474 // Grant the active permissions, as if the extension had just been installed.
475 updater.GrantActivePermissions(extension.get());
Devlin Cronine90eacf2018-06-07 17:23:45476
477 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
478
Devlin Cronin5218d262018-07-09 20:18:05479 // Initially, there should be no runtime-granted permissions or granted
480 // permissions.
Devlin Cronine90eacf2018-06-07 17:23:45481 EXPECT_TRUE(prefs->GetRuntimeGrantedPermissions(extension->id())->IsEmpty());
Devlin Cronin5218d262018-07-09 20:18:05482 EXPECT_TRUE(prefs->GetGrantedPermissions(extension->id())->IsEmpty());
Devlin Cronine90eacf2018-06-07 17:23:45483
484 APIPermissionSet apis;
485 apis.insert(APIPermission::kTab);
486 PermissionSet optional_permissions(apis, ManifestPermissionSet(),
487 URLPatternSet(), URLPatternSet());
488
Devlin Cronin5218d262018-07-09 20:18:05489 // Granting permissions should update both runtime-granted permissions and
490 // granted permissions.
491 updater.GrantOptionalPermissions(*extension, optional_permissions);
Devlin Cronine90eacf2018-06-07 17:23:45492 EXPECT_EQ(optional_permissions,
493 *prefs->GetRuntimeGrantedPermissions(extension->id()));
Devlin Cronin5218d262018-07-09 20:18:05494 EXPECT_EQ(optional_permissions,
495 *prefs->GetGrantedPermissions(extension->id()));
Devlin Cronine90eacf2018-06-07 17:23:45496
497 // Removing permissions with REMOVE_SOFT should not remove the permission
Devlin Cronin5218d262018-07-09 20:18:05498 // from runtime-granted permissions or granted permissions; this happens when
499 // the extension opts into lower privilege.
500 updater.RevokeOptionalPermissions(*extension, optional_permissions,
501 PermissionsUpdater::REMOVE_SOFT);
Devlin Cronine90eacf2018-06-07 17:23:45502 EXPECT_EQ(optional_permissions,
503 *prefs->GetRuntimeGrantedPermissions(extension->id()));
Devlin Cronin5218d262018-07-09 20:18:05504 EXPECT_EQ(optional_permissions,
505 *prefs->GetGrantedPermissions(extension->id()));
Devlin Cronine90eacf2018-06-07 17:23:45506
507 // Removing permissions with REMOVE_HARD should remove the permission from
Devlin Cronin5218d262018-07-09 20:18:05508 // runtime-granted and granted permissions; this happens when the user chooses
509 // to revoke the permission.
Devlin Cronine90eacf2018-06-07 17:23:45510 // Note: we need to add back the permission first, so it shows up as a
511 // revokable permission.
512 // TODO(devlin): Inactive, but granted, permissions should be revokable.
Devlin Cronin5218d262018-07-09 20:18:05513 updater.GrantOptionalPermissions(*extension, optional_permissions);
514 updater.RevokeOptionalPermissions(*extension, optional_permissions,
515 PermissionsUpdater::REMOVE_HARD);
Devlin Cronine90eacf2018-06-07 17:23:45516 EXPECT_TRUE(prefs->GetRuntimeGrantedPermissions(extension->id())->IsEmpty());
Devlin Cronin5218d262018-07-09 20:18:05517 EXPECT_TRUE(prefs->GetGrantedPermissions(extension->id())->IsEmpty());
518}
519
520TEST_F(PermissionsUpdaterTest,
521 UpdatingRuntimeGrantedPermissionsWithRuntimePermissions) {
522 base::test::ScopedFeatureList scoped_feature_list;
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35523 scoped_feature_list.InitAndEnableFeature(
524 extensions_features::kRuntimeHostPermissions);
Devlin Cronin5218d262018-07-09 20:18:05525
526 InitializeEmptyExtensionService();
527
528 scoped_refptr<const Extension> extension =
529 ExtensionBuilder("extension").AddPermission("*://*/*").Build();
530
531 PermissionsUpdater updater(profile());
532 updater.InitializePermissions(extension.get());
533 // Grant the active permissions, as if the extension had just been installed.
534 updater.GrantActivePermissions(extension.get());
535 ScriptingPermissionsModifier(profile(), extension)
536 .SetWithholdHostPermissions(true);
537
538 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
539
540 // Initially, there should be no runtime-granted permissions.
541 EXPECT_TRUE(prefs->GetRuntimeGrantedPermissions(extension->id())->IsEmpty());
542 std::unique_ptr<const PermissionSet> initial_granted_permissions =
543 prefs->GetGrantedPermissions(extension->id());
544 // Granted permissions should contain the required permissions from the
545 // extension.
546 EXPECT_TRUE(initial_granted_permissions->explicit_hosts().ContainsPattern(
547 URLPattern(Extension::kValidHostPermissionSchemes, "*://*/*")));
548
549 URLPatternSet explicit_hosts({URLPattern(
550 Extension::kValidHostPermissionSchemes, "https://example.com/*")});
551 PermissionSet runtime_granted_permissions(APIPermissionSet(),
552 ManifestPermissionSet(),
553 explicit_hosts, URLPatternSet());
554
555 // Granting runtime-granted permissions should update the runtime granted
556 // permissions store in preferences, but *not* granted permissions in
557 // preferences.
558 updater.GrantRuntimePermissions(*extension, runtime_granted_permissions);
559 EXPECT_EQ(runtime_granted_permissions,
560 *prefs->GetRuntimeGrantedPermissions(extension->id()));
561 EXPECT_EQ(*initial_granted_permissions,
562 *prefs->GetGrantedPermissions(extension->id()));
563
564 // Removing runtime-granted permissions should not remove the permission
565 // from runtime-granted permissions; granted permissions should remain
566 // unchanged.
567 updater.RevokeRuntimePermissions(*extension, runtime_granted_permissions);
568
569 EXPECT_TRUE(prefs->GetRuntimeGrantedPermissions(extension->id())->IsEmpty());
570 EXPECT_EQ(*initial_granted_permissions,
571 *prefs->GetGrantedPermissions(extension->id()));
Devlin Cronine90eacf2018-06-07 17:23:45572}
573
Devlin Croninc5830702018-07-03 00:26:16574TEST_F(PermissionsUpdaterTest, RevokingPermissionsWithRuntimeHostPermissions) {
575 base::test::ScopedFeatureList scoped_feature_list;
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35576 scoped_feature_list.InitAndEnableFeature(
577 extensions_features::kRuntimeHostPermissions);
Devlin Croninc5830702018-07-03 00:26:16578
579 InitializeEmptyExtensionService();
580
581 constexpr struct {
582 const char* permission;
583 const char* test_url;
584 } test_cases[] = {
585 {"http://*/*", "http://foo.com"},
586 {"http://google.com/*", "http://google.com"},
587 };
588
589 for (const auto& test_case : test_cases) {
590 std::string test_name =
591 base::StringPrintf("%s, %s", test_case.permission, test_case.test_url);
592 SCOPED_TRACE(test_name);
593 scoped_refptr<const Extension> extension =
594 CreateExtensionWithOptionalPermissions(
595 std::make_unique<base::ListValue>(),
596 ListBuilder().Append(test_case.permission).Build(), test_name);
597 PermissionsUpdater updater(profile());
598 updater.InitializePermissions(extension.get());
599
600 ScriptingPermissionsModifier(profile(), extension)
601 .SetWithholdHostPermissions(true);
602
603 // Host access was withheld, so the extension shouldn't have access to the
604 // test site.
605 const GURL kOrigin(test_case.test_url);
606
607 EXPECT_FALSE(extension->permissions_data()
608 ->active_permissions()
609 .HasExplicitAccessToOrigin(kOrigin));
610 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())->IsEmpty());
611 EXPECT_TRUE(extension->permissions_data()
612 ->withheld_permissions()
613 .HasExplicitAccessToOrigin(kOrigin));
614
615 URLPatternSet url_pattern_set;
616 url_pattern_set.AddOrigin(URLPattern::SCHEME_ALL, kOrigin);
617 const PermissionSet permission_set(APIPermissionSet(),
618 ManifestPermissionSet(), url_pattern_set,
619 URLPatternSet());
620 // Give the extension access to the test site. Now, the test site permission
621 // should be revokable.
Devlin Cronin5218d262018-07-09 20:18:05622 updater.GrantRuntimePermissions(*extension, permission_set);
Devlin Croninc5830702018-07-03 00:26:16623 EXPECT_TRUE(extension->permissions_data()
624 ->active_permissions()
625 .HasExplicitAccessToOrigin(kOrigin));
626 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())
627 ->HasExplicitAccessToOrigin(kOrigin));
628
629 // Revoke the test site permission. The extension should no longer have
630 // access to test site, and the revokable permissions should be empty.
Devlin Cronin5218d262018-07-09 20:18:05631 updater.RevokeOptionalPermissions(*extension, permission_set,
632 PermissionsUpdater::REMOVE_HARD);
Devlin Croninc5830702018-07-03 00:26:16633 EXPECT_FALSE(extension->permissions_data()
634 ->active_permissions()
635 .HasExplicitAccessToOrigin(kOrigin));
636 EXPECT_TRUE(extension->permissions_data()
637 ->withheld_permissions()
638 .HasExplicitAccessToOrigin(kOrigin));
639 EXPECT_TRUE(updater.GetRevokablePermissions(extension.get())->IsEmpty());
640 }
641}
642
643TEST_F(PermissionsUpdaterTest, ChromeFaviconIsNotARevokableHost) {
644 base::test::ScopedFeatureList scoped_feature_list;
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35645 scoped_feature_list.InitAndEnableFeature(
646 extensions_features::kRuntimeHostPermissions);
Devlin Croninc5830702018-07-03 00:26:16647
648 InitializeEmptyExtensionService();
649
650 URLPattern chrome_favicon_pattern(Extension::kValidHostPermissionSchemes,
651 "chrome://favicon/");
652
653 {
654 scoped_refptr<const Extension> extension =
655 ExtensionBuilder("favicon extension")
656 .AddPermissions({"https://example.com/*", "chrome://favicon/*"})
657 .Build();
658 URLPattern example_com_pattern(Extension::kValidHostPermissionSchemes,
659 "https://example.com/*");
660 PermissionsUpdater updater(profile());
661 updater.InitializePermissions(extension.get());
662
663 // To start, the extension should have both example.com and chrome://favicon
664 // permissions.
665 EXPECT_TRUE(extension->permissions_data()
666 ->active_permissions()
667 .explicit_hosts()
668 .ContainsPattern(chrome_favicon_pattern));
669 EXPECT_TRUE(extension->permissions_data()
670 ->active_permissions()
671 .explicit_hosts()
672 .ContainsPattern(example_com_pattern));
673
674 // Only example.com should be revokable - chrome://favicon is not a real
675 // host permission.
676 std::unique_ptr<const PermissionSet> revokable_permissions =
677 updater.GetRevokablePermissions(extension.get());
678 EXPECT_FALSE(revokable_permissions->explicit_hosts().ContainsPattern(
679 chrome_favicon_pattern));
680 EXPECT_TRUE(revokable_permissions->explicit_hosts().ContainsPattern(
681 example_com_pattern));
682
683 // Withholding host permissions shouldn't withhold example.com.
684 ScriptingPermissionsModifier(profile(), extension)
685 .SetWithholdHostPermissions(true);
686 EXPECT_TRUE(extension->permissions_data()
687 ->active_permissions()
688 .explicit_hosts()
689 .ContainsPattern(chrome_favicon_pattern));
690 EXPECT_FALSE(extension->permissions_data()
691 ->active_permissions()
692 .explicit_hosts()
693 .ContainsPattern(example_com_pattern));
694 }
695 {
696 scoped_refptr<const Extension> extension =
697 ExtensionBuilder("all urls extension")
698 .AddPermission("<all_urls>")
699 .Build();
700 URLPattern all_urls_pattern(Extension::kValidHostPermissionSchemes,
701 "<all_urls>");
702 PermissionsUpdater updater(profile());
703 updater.InitializePermissions(extension.get());
704
705 // <all_urls> (strangely) includes the chrome://favicon/ permission.
706 EXPECT_TRUE(extension->permissions_data()
707 ->active_permissions()
708 .explicit_hosts()
709 .ContainsPattern(chrome_favicon_pattern));
710 EXPECT_TRUE(extension->permissions_data()
711 ->active_permissions()
712 .explicit_hosts()
713 .ContainsPattern(all_urls_pattern));
714
715 std::unique_ptr<const PermissionSet> revokable_permissions =
716 updater.GetRevokablePermissions(extension.get());
717 // TODO(https://crbug.com/859600): <all_urls> will report containing
718 // chrome://favicon/, even though it shouldn't since the scheme doesn't
719 // match.
720 // EXPECT_FALSE(revokable_permissions->explicit_hosts().ContainsPattern(
721 // chrome_favicon_pattern));
722 EXPECT_TRUE(revokable_permissions->explicit_hosts().ContainsPattern(
723 all_urls_pattern));
724
725 ScriptingPermissionsModifier(profile(), extension)
726 .SetWithholdHostPermissions(true);
727 EXPECT_TRUE(extension->permissions_data()
728 ->active_permissions()
729 .explicit_hosts()
730 .ContainsPattern(chrome_favicon_pattern));
731 EXPECT_FALSE(extension->permissions_data()
732 ->active_permissions()
733 .explicit_hosts()
734 .ContainsPattern(all_urls_pattern));
735 }
736}
737
Devlin Cronin6b492eb2018-08-01 02:37:09738// Tests runtime-granting permissions beyond what are explicitly requested by
739// the extension.
740TEST_F(PermissionsUpdaterTest, GrantingBroadRuntimePermissions) {
741 base::test::ScopedFeatureList scoped_feature_list;
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35742 scoped_feature_list.InitAndEnableFeature(
743 extensions_features::kRuntimeHostPermissions);
Devlin Cronin6b492eb2018-08-01 02:37:09744 InitializeEmptyExtensionService();
745
746 scoped_refptr<const Extension> extension =
747 ExtensionBuilder("extension")
748 .AddPermission("https://maps.google.com/*")
749 .Build();
750
751 const URLPattern kMapsPattern(Extension::kValidHostPermissionSchemes,
752 "https://maps.google.com/*");
753 const URLPattern kAllGooglePattern(Extension::kValidHostPermissionSchemes,
754 "https://*.google.com/*");
755
756 // Withhold host permissions. Effective hosts should be empty.
757 PermissionsUpdater updater(profile());
758 updater.InitializePermissions(extension.get());
759 ScriptingPermissionsModifier(profile(), extension)
760 .SetWithholdHostPermissions(true);
761 EXPECT_TRUE(extension->permissions_data()
762 ->active_permissions()
763 .effective_hosts()
764 .is_empty());
765
766 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
767
768 {
769 // Verify initial state. The extension "active" permissions in preferences
770 // represent the permissions that would be active on the extension without
771 // the runtime host permissions feature. Thus, this should include the
772 // requested host permissions, and nothing more.
773 std::unique_ptr<const PermissionSet> active_prefs =
774 prefs->GetActivePermissions(extension->id());
775 EXPECT_TRUE(active_prefs->effective_hosts().ContainsPattern(kMapsPattern));
776 EXPECT_FALSE(
777 active_prefs->effective_hosts().ContainsPattern(kAllGooglePattern));
778
779 // Runtime granted permissions should not contain any permissions (all
780 // hosts are withheld).
781 std::unique_ptr<const PermissionSet> runtime_granted_prefs =
782 prefs->GetRuntimeGrantedPermissions(extension->id());
783 EXPECT_FALSE(
784 runtime_granted_prefs->effective_hosts().ContainsPattern(kMapsPattern));
785 EXPECT_FALSE(runtime_granted_prefs->effective_hosts().ContainsPattern(
786 kAllGooglePattern));
787 }
788
789 // Grant permission to all google.com domains.
790 const PermissionSet runtime_permissions(
791 APIPermissionSet(), ManifestPermissionSet(),
792 URLPatternSet({kAllGooglePattern}), URLPatternSet());
793 updater.GrantRuntimePermissions(*extension, runtime_permissions);
794
795 // The extension object's permission should never include un-requested
796 // permissions, so it should only include maps.google.com.
797 EXPECT_TRUE(extension->permissions_data()
798 ->active_permissions()
799 .effective_hosts()
800 .ContainsPattern(kMapsPattern));
801 EXPECT_FALSE(extension->permissions_data()
802 ->active_permissions()
803 .effective_hosts()
804 .ContainsPattern(kAllGooglePattern));
805
806 {
807 // The active permissions in preferences should reflect the extension's
808 // permission state without the runtime host permissions feature, so should
809 // still include exactly the requested permissions.
810 std::unique_ptr<const PermissionSet> active_prefs =
811 prefs->GetActivePermissions(extension->id());
812 EXPECT_TRUE(active_prefs->effective_hosts().ContainsPattern(kMapsPattern));
813 EXPECT_FALSE(
814 active_prefs->effective_hosts().ContainsPattern(kAllGooglePattern));
815 // The runtime-granted permissions should include all permissions that have
816 // been granted, which in this case includes google.com subdomains.
817 std::unique_ptr<const PermissionSet> runtime_granted_prefs =
818 prefs->GetRuntimeGrantedPermissions(extension->id());
819 EXPECT_TRUE(
820 runtime_granted_prefs->effective_hosts().ContainsPattern(kMapsPattern));
821 EXPECT_TRUE(runtime_granted_prefs->effective_hosts().ContainsPattern(
822 kAllGooglePattern));
823 }
824
825 // Revoke the host permission.
826 updater.RevokeRuntimePermissions(*extension, runtime_permissions);
827
828 EXPECT_FALSE(extension->permissions_data()
829 ->active_permissions()
830 .effective_hosts()
831 .ContainsPattern(kMapsPattern));
832
833 {
834 // Active permissions in the preferences should remain constant (unaffected
835 // by the runtime host permissions feature).
836 std::unique_ptr<const PermissionSet> active_prefs =
837 prefs->GetActivePermissions(extension->id());
838 EXPECT_TRUE(active_prefs->effective_hosts().ContainsPattern(kMapsPattern));
839 EXPECT_FALSE(
840 active_prefs->effective_hosts().ContainsPattern(kAllGooglePattern));
841 // The runtime granted preferences should be empty again.
842 std::unique_ptr<const PermissionSet> runtime_granted_prefs =
843 prefs->GetRuntimeGrantedPermissions(extension->id());
844 EXPECT_FALSE(
845 runtime_granted_prefs->effective_hosts().ContainsPattern(kMapsPattern));
846 EXPECT_FALSE(runtime_granted_prefs->effective_hosts().ContainsPattern(
847 kAllGooglePattern));
848 }
849}
850
[email protected]c333e792012-01-06 16:57:39851} // namespace extensions