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.
5 #include "base/message_loop/message_loop.h"
6 #include "base/values.h"
7 #include "chrome/browser/content_settings/cookie_settings.h"
8 #include "chrome/browser/extensions/extension_special_storage_policy.h"
9 #include "chrome/test/base/testing_profile.h"
10 #include "components/content_settings/core/common/content_settings.h"
11 #include "components/content_settings/core/common/content_settings_types.h"
12 #include "content/public/test/test_browser_thread.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/extension_set.h"
15 #include "extensions/common/manifest.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 using content::BrowserThread
;
20 using extensions::Extension
;
21 using extensions::ExtensionSet
;
22 using extensions::Manifest
;
23 using storage::SpecialStoragePolicy
;
25 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy
;
27 namespace keys
= extensions::manifest_keys
;
29 class ExtensionSpecialStoragePolicyTest
: public testing::Test
{
31 class PolicyChangeObserver
: public SpecialStoragePolicy::Observer
{
33 PolicyChangeObserver()
34 : expected_type_(NOTIFICATION_TYPE_NONE
),
35 expected_change_flags_(0) {
38 void OnGranted(const GURL
& origin
, int change_flags
) override
{
39 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_GRANT
);
40 EXPECT_EQ(expected_origin_
, origin
);
41 EXPECT_EQ(expected_change_flags_
, change_flags
);
42 expected_type_
= NOTIFICATION_TYPE_NONE
;
45 void OnRevoked(const GURL
& origin
, int change_flags
) override
{
46 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_REVOKE
);
47 EXPECT_EQ(expected_origin_
, origin
);
48 EXPECT_EQ(expected_change_flags_
, change_flags
);
49 expected_type_
= NOTIFICATION_TYPE_NONE
;
52 void OnCleared() override
{
53 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_CLEAR
);
54 expected_type_
= NOTIFICATION_TYPE_NONE
;
57 void ExpectGrant(const std::string
& extension_id
,
59 expected_type_
= NOTIFICATION_TYPE_GRANT
;
60 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
61 expected_change_flags_
= change_flags
;
64 void ExpectRevoke(const std::string
& extension_id
,
66 expected_type_
= NOTIFICATION_TYPE_REVOKE
;
67 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
68 expected_change_flags_
= change_flags
;
72 expected_type_
= NOTIFICATION_TYPE_CLEAR
;
76 return expected_type_
== NOTIFICATION_TYPE_NONE
;
81 NOTIFICATION_TYPE_NONE
,
82 NOTIFICATION_TYPE_GRANT
,
83 NOTIFICATION_TYPE_REVOKE
,
84 NOTIFICATION_TYPE_CLEAR
,
87 GURL expected_origin_
;
88 int expected_change_flags_
;
90 DISALLOW_COPY_AND_ASSIGN(PolicyChangeObserver
);
93 void SetUp() override
{ policy_
= new ExtensionSpecialStoragePolicy(NULL
); }
95 scoped_refptr
<Extension
> CreateProtectedApp() {
97 base::FilePath
path(FILE_PATH_LITERAL("c:\\foo"));
98 #elif defined(OS_POSIX)
99 base::FilePath
path(FILE_PATH_LITERAL("/foo"));
101 base::DictionaryValue manifest
;
102 manifest
.SetString(keys::kName
, "Protected");
103 manifest
.SetString(keys::kVersion
, "1");
104 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/protected/start");
105 base::ListValue
* list
= new base::ListValue();
106 list
->Append(new base::StringValue("http://explicit/protected"));
107 list
->Append(new base::StringValue("*://*.wildcards/protected"));
108 manifest
.Set(keys::kWebURLs
, list
);
110 scoped_refptr
<Extension
> protected_app
= Extension::Create(
111 path
, Manifest::INVALID_LOCATION
, manifest
,
112 Extension::NO_FLAGS
, &error
);
113 EXPECT_TRUE(protected_app
.get()) << error
;
114 return protected_app
;
117 scoped_refptr
<Extension
> CreateUnlimitedApp() {
119 base::FilePath
path(FILE_PATH_LITERAL("c:\\bar"));
120 #elif defined(OS_POSIX)
121 base::FilePath
path(FILE_PATH_LITERAL("/bar"));
123 base::DictionaryValue manifest
;
124 manifest
.SetString(keys::kName
, "Unlimited");
125 manifest
.SetString(keys::kVersion
, "1");
126 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/unlimited/start");
127 base::ListValue
* list
= new base::ListValue();
128 list
->Append(new base::StringValue("unlimitedStorage"));
129 manifest
.Set(keys::kPermissions
, list
);
130 list
= new base::ListValue();
131 list
->Append(new base::StringValue("http://explicit/unlimited"));
132 list
->Append(new base::StringValue("*://*.wildcards/unlimited"));
133 manifest
.Set(keys::kWebURLs
, list
);
135 scoped_refptr
<Extension
> unlimited_app
= Extension::Create(
136 path
, Manifest::INVALID_LOCATION
, manifest
,
137 Extension::NO_FLAGS
, &error
);
138 EXPECT_TRUE(unlimited_app
.get()) << error
;
139 return unlimited_app
;
142 scoped_refptr
<Extension
> CreateRegularApp() {
144 base::FilePath
path(FILE_PATH_LITERAL("c:\\app"));
145 #elif defined(OS_POSIX)
146 base::FilePath
path(FILE_PATH_LITERAL("/app"));
148 base::DictionaryValue manifest
;
149 manifest
.SetString(keys::kName
, "App");
150 manifest
.SetString(keys::kVersion
, "1");
151 manifest
.SetString(keys::kPlatformAppBackgroundPage
, "background.html");
153 scoped_refptr
<Extension
> app
= Extension::Create(
154 path
, Manifest::INVALID_LOCATION
, manifest
,
155 Extension::NO_FLAGS
, &error
);
156 EXPECT_TRUE(app
.get()) << error
;
160 // Verifies that the set of extensions protecting |url| is *exactly* equal to
161 // |expected_extensions|. Pass in an empty set to verify that an origin is not
163 void ExpectProtectedBy(const ExtensionSet
& expected_extensions
,
165 const ExtensionSet
* extensions
= policy_
->ExtensionsProtectingOrigin(url
);
166 EXPECT_EQ(expected_extensions
.size(), extensions
->size());
167 for (ExtensionSet::const_iterator it
= expected_extensions
.begin();
168 it
!= expected_extensions
.end(); ++it
) {
169 EXPECT_TRUE(extensions
->Contains((*it
)->id()))
170 << "Origin " << url
<< "not protected by extension ID "
175 scoped_refptr
<ExtensionSpecialStoragePolicy
> policy_
;
178 TEST_F(ExtensionSpecialStoragePolicyTest
, EmptyPolicy
) {
179 const GURL
kHttpUrl("http://foo");
180 const GURL
kExtensionUrl("chrome-extension://bar");
181 scoped_refptr
<Extension
> app(CreateRegularApp());
183 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
));
184 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
)); // test cached result
185 EXPECT_FALSE(policy_
->IsStorageUnlimited(kExtensionUrl
));
186 EXPECT_FALSE(policy_
->IsStorageUnlimited(app
->url()));
187 ExtensionSet empty_set
;
188 ExpectProtectedBy(empty_set
, kHttpUrl
);
190 // This one is just based on the scheme.
191 EXPECT_TRUE(policy_
->IsStorageProtected(kExtensionUrl
));
192 EXPECT_TRUE(policy_
->IsStorageProtected(app
->url()));
195 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithProtectedStorage
) {
196 scoped_refptr
<Extension
> extension(CreateProtectedApp());
197 policy_
->GrantRightsForExtension(extension
.get(), NULL
);
198 ExtensionSet protecting_extensions
;
199 protecting_extensions
.Insert(extension
);
200 ExtensionSet empty_set
;
202 EXPECT_FALSE(policy_
->IsStorageUnlimited(extension
->url()));
203 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
204 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
205 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
206 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
207 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
208 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
210 policy_
->RevokeRightsForExtension(extension
.get());
211 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
212 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
213 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
216 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithUnlimitedStorage
) {
217 scoped_refptr
<Extension
> extension(CreateUnlimitedApp());
218 policy_
->GrantRightsForExtension(extension
.get(), NULL
);
219 ExtensionSet protecting_extensions
;
220 protecting_extensions
.Insert(extension
);
221 ExtensionSet empty_set
;
223 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
224 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
225 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
226 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
227 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
228 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
229 EXPECT_TRUE(policy_
->IsStorageUnlimited(extension
->url()));
230 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
231 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
232 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
233 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
234 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
236 policy_
->RevokeRightsForExtension(extension
.get());
237 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
238 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
239 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
240 ExpectProtectedBy(empty_set
, GURL("http://bar.wildcards/"));
241 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
242 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
243 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
246 TEST_F(ExtensionSpecialStoragePolicyTest
, CanQueryDiskSize
) {
247 const GURL
kHttpUrl("http://foo");
248 const GURL
kExtensionUrl("chrome-extension://bar");
249 scoped_refptr
<Extension
> regular_app(CreateRegularApp());
250 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
251 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
252 policy_
->GrantRightsForExtension(regular_app
.get(), NULL
);
253 policy_
->GrantRightsForExtension(protected_app
.get(), NULL
);
254 policy_
->GrantRightsForExtension(unlimited_app
.get(), NULL
);
256 EXPECT_FALSE(policy_
->CanQueryDiskSize(kHttpUrl
));
257 EXPECT_FALSE(policy_
->CanQueryDiskSize(kExtensionUrl
));
258 EXPECT_TRUE(policy_
->CanQueryDiskSize(regular_app
->url()));
259 EXPECT_TRUE(policy_
->CanQueryDiskSize(protected_app
->url()));
260 EXPECT_TRUE(policy_
->CanQueryDiskSize(unlimited_app
->url()));
263 TEST_F(ExtensionSpecialStoragePolicyTest
, HasIsolatedStorage
) {
264 const GURL
kHttpUrl("http://foo");
265 const GURL
kExtensionUrl("chrome-extension://bar");
266 scoped_refptr
<Extension
> app(CreateRegularApp());
267 policy_
->GrantRightsForExtension(app
.get(), NULL
);
269 EXPECT_FALSE(policy_
->HasIsolatedStorage(kHttpUrl
));
270 EXPECT_FALSE(policy_
->HasIsolatedStorage(kExtensionUrl
));
271 EXPECT_TRUE(policy_
->HasIsolatedStorage(app
->url()));
274 TEST_F(ExtensionSpecialStoragePolicyTest
, OverlappingApps
) {
275 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
276 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
277 policy_
->GrantRightsForExtension(protected_app
.get(), NULL
);
278 policy_
->GrantRightsForExtension(unlimited_app
.get(), NULL
);
279 ExtensionSet protecting_extensions
;
280 ExtensionSet empty_set
;
281 protecting_extensions
.Insert(protected_app
);
282 protecting_extensions
.Insert(unlimited_app
);
284 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
285 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
286 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
287 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
288 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
289 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
290 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
291 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
292 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
293 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
294 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
296 policy_
->RevokeRightsForExtension(unlimited_app
.get());
297 protecting_extensions
.Remove(unlimited_app
->id());
298 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
299 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
300 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
301 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
302 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
303 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
305 policy_
->RevokeRightsForExtension(protected_app
.get());
306 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
307 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
308 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
311 TEST_F(ExtensionSpecialStoragePolicyTest
, HasSessionOnlyOrigins
) {
312 base::MessageLoop message_loop
;
313 content::TestBrowserThread
ui_thread(BrowserThread::UI
, &message_loop
);
315 TestingProfile profile
;
316 CookieSettings
* cookie_settings
=
317 CookieSettings::Factory::GetForProfile(&profile
).get();
318 policy_
= new ExtensionSpecialStoragePolicy(cookie_settings
);
320 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
322 // The default setting can be session-only.
323 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY
);
324 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
326 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW
);
327 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
329 // Or the session-onlyness can affect individual origins.
330 ContentSettingsPattern pattern
=
331 ContentSettingsPattern::FromString("pattern.com");
333 cookie_settings
->SetCookieSetting(pattern
,
334 ContentSettingsPattern::Wildcard(),
335 CONTENT_SETTING_SESSION_ONLY
);
337 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
339 // Clearing an origin-specific rule.
340 cookie_settings
->ResetCookieSetting(pattern
,
341 ContentSettingsPattern::Wildcard());
343 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
346 TEST_F(ExtensionSpecialStoragePolicyTest
, NotificationTest
) {
347 base::MessageLoop message_loop
;
348 content::TestBrowserThread
ui_thread(BrowserThread::UI
, &message_loop
);
349 content::TestBrowserThread
io_thread(BrowserThread::IO
, &message_loop
);
351 PolicyChangeObserver observer
;
352 policy_
->AddObserver(&observer
);
354 scoped_refptr
<Extension
> apps
[] = {
355 CreateProtectedApp(),
356 CreateUnlimitedApp(),
359 int change_flags
[] = {
360 SpecialStoragePolicy::STORAGE_PROTECTED
,
362 SpecialStoragePolicy::STORAGE_PROTECTED
|
363 SpecialStoragePolicy::STORAGE_UNLIMITED
,
366 ASSERT_EQ(arraysize(apps
), arraysize(change_flags
));
367 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
368 SCOPED_TRACE(testing::Message() << "i: " << i
);
369 observer
.ExpectGrant(apps
[i
]->id(), change_flags
[i
]);
370 policy_
->GrantRightsForExtension(apps
[i
].get(), NULL
);
371 message_loop
.RunUntilIdle();
372 EXPECT_TRUE(observer
.IsCompleted());
375 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
376 SCOPED_TRACE(testing::Message() << "i: " << i
);
377 policy_
->GrantRightsForExtension(apps
[i
].get(), NULL
);
378 message_loop
.RunUntilIdle();
379 EXPECT_TRUE(observer
.IsCompleted());
382 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
383 SCOPED_TRACE(testing::Message() << "i: " << i
);
384 observer
.ExpectRevoke(apps
[i
]->id(), change_flags
[i
]);
385 policy_
->RevokeRightsForExtension(apps
[i
].get());
386 message_loop
.RunUntilIdle();
387 EXPECT_TRUE(observer
.IsCompleted());
390 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
391 SCOPED_TRACE(testing::Message() << "i: " << i
);
392 policy_
->RevokeRightsForExtension(apps
[i
].get());
393 message_loop
.RunUntilIdle();
394 EXPECT_TRUE(observer
.IsCompleted());
397 observer
.ExpectClear();
398 policy_
->RevokeRightsForAllExtensions();
399 message_loop
.RunUntilIdle();
400 EXPECT_TRUE(observer
.IsCompleted());
402 policy_
->RemoveObserver(&observer
);