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/common/content_settings.h"
10 #include "chrome/common/content_settings_types.h"
11 #include "chrome/test/base/testing_profile.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 quota::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 virtual void OnGranted(const GURL
& origin
,
39 int change_flags
) OVERRIDE
{
40 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_GRANT
);
41 EXPECT_EQ(expected_origin_
, origin
);
42 EXPECT_EQ(expected_change_flags_
, change_flags
);
43 expected_type_
= NOTIFICATION_TYPE_NONE
;
46 virtual void OnRevoked(const GURL
& origin
,
47 int change_flags
) OVERRIDE
{
48 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_REVOKE
);
49 EXPECT_EQ(expected_origin_
, origin
);
50 EXPECT_EQ(expected_change_flags_
, change_flags
);
51 expected_type_
= NOTIFICATION_TYPE_NONE
;
54 virtual void OnCleared() OVERRIDE
{
55 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_CLEAR
);
56 expected_type_
= NOTIFICATION_TYPE_NONE
;
59 void ExpectGrant(const std::string
& extension_id
,
61 expected_type_
= NOTIFICATION_TYPE_GRANT
;
62 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
63 expected_change_flags_
= change_flags
;
66 void ExpectRevoke(const std::string
& extension_id
,
68 expected_type_
= NOTIFICATION_TYPE_REVOKE
;
69 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
70 expected_change_flags_
= change_flags
;
74 expected_type_
= NOTIFICATION_TYPE_CLEAR
;
78 return expected_type_
== NOTIFICATION_TYPE_NONE
;
83 NOTIFICATION_TYPE_NONE
,
84 NOTIFICATION_TYPE_GRANT
,
85 NOTIFICATION_TYPE_REVOKE
,
86 NOTIFICATION_TYPE_CLEAR
,
89 GURL expected_origin_
;
90 int expected_change_flags_
;
92 DISALLOW_COPY_AND_ASSIGN(PolicyChangeObserver
);
95 virtual void SetUp() OVERRIDE
{
96 policy_
= new ExtensionSpecialStoragePolicy(NULL
);
99 scoped_refptr
<Extension
> CreateProtectedApp() {
101 base::FilePath
path(FILE_PATH_LITERAL("c:\\foo"));
102 #elif defined(OS_POSIX)
103 base::FilePath
path(FILE_PATH_LITERAL("/foo"));
105 base::DictionaryValue manifest
;
106 manifest
.SetString(keys::kName
, "Protected");
107 manifest
.SetString(keys::kVersion
, "1");
108 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/protected/start");
109 base::ListValue
* list
= new base::ListValue();
110 list
->Append(new base::StringValue("http://explicit/protected"));
111 list
->Append(new base::StringValue("*://*.wildcards/protected"));
112 manifest
.Set(keys::kWebURLs
, list
);
114 scoped_refptr
<Extension
> protected_app
= Extension::Create(
115 path
, Manifest::INVALID_LOCATION
, manifest
,
116 Extension::NO_FLAGS
, &error
);
117 EXPECT_TRUE(protected_app
.get()) << error
;
118 return protected_app
;
121 scoped_refptr
<Extension
> CreateUnlimitedApp() {
123 base::FilePath
path(FILE_PATH_LITERAL("c:\\bar"));
124 #elif defined(OS_POSIX)
125 base::FilePath
path(FILE_PATH_LITERAL("/bar"));
127 base::DictionaryValue manifest
;
128 manifest
.SetString(keys::kName
, "Unlimited");
129 manifest
.SetString(keys::kVersion
, "1");
130 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/unlimited/start");
131 base::ListValue
* list
= new base::ListValue();
132 list
->Append(new base::StringValue("unlimitedStorage"));
133 manifest
.Set(keys::kPermissions
, list
);
134 list
= new base::ListValue();
135 list
->Append(new base::StringValue("http://explicit/unlimited"));
136 list
->Append(new base::StringValue("*://*.wildcards/unlimited"));
137 manifest
.Set(keys::kWebURLs
, list
);
139 scoped_refptr
<Extension
> unlimited_app
= Extension::Create(
140 path
, Manifest::INVALID_LOCATION
, manifest
,
141 Extension::NO_FLAGS
, &error
);
142 EXPECT_TRUE(unlimited_app
.get()) << error
;
143 return unlimited_app
;
146 scoped_refptr
<Extension
> CreateRegularApp() {
148 base::FilePath
path(FILE_PATH_LITERAL("c:\\app"));
149 #elif defined(OS_POSIX)
150 base::FilePath
path(FILE_PATH_LITERAL("/app"));
152 base::DictionaryValue manifest
;
153 manifest
.SetString(keys::kName
, "App");
154 manifest
.SetString(keys::kVersion
, "1");
155 manifest
.SetString(keys::kPlatformAppBackgroundPage
, "background.html");
157 scoped_refptr
<Extension
> app
= Extension::Create(
158 path
, Manifest::INVALID_LOCATION
, manifest
,
159 Extension::NO_FLAGS
, &error
);
160 EXPECT_TRUE(app
.get()) << error
;
164 // Verifies that the set of extensions protecting |url| is *exactly* equal to
165 // |expected_extensions|. Pass in an empty set to verify that an origin is not
167 void ExpectProtectedBy(const ExtensionSet
& expected_extensions
,
169 const ExtensionSet
* extensions
= policy_
->ExtensionsProtectingOrigin(url
);
170 EXPECT_EQ(expected_extensions
.size(), extensions
->size());
171 for (ExtensionSet::const_iterator it
= expected_extensions
.begin();
172 it
!= expected_extensions
.end(); ++it
) {
173 EXPECT_TRUE(extensions
->Contains((*it
)->id()))
174 << "Origin " << url
<< "not protected by extension ID "
179 scoped_refptr
<ExtensionSpecialStoragePolicy
> policy_
;
182 TEST_F(ExtensionSpecialStoragePolicyTest
, EmptyPolicy
) {
183 const GURL
kHttpUrl("http://foo");
184 const GURL
kExtensionUrl("chrome-extension://bar");
185 scoped_refptr
<Extension
> app(CreateRegularApp());
187 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
));
188 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
)); // test cached result
189 EXPECT_FALSE(policy_
->IsStorageUnlimited(kExtensionUrl
));
190 EXPECT_FALSE(policy_
->IsStorageUnlimited(app
->url()));
191 ExtensionSet empty_set
;
192 ExpectProtectedBy(empty_set
, kHttpUrl
);
194 // This one is just based on the scheme.
195 EXPECT_TRUE(policy_
->IsStorageProtected(kExtensionUrl
));
196 EXPECT_TRUE(policy_
->IsStorageProtected(app
->url()));
199 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithProtectedStorage
) {
200 scoped_refptr
<Extension
> extension(CreateProtectedApp());
201 policy_
->GrantRightsForExtension(extension
.get());
202 ExtensionSet protecting_extensions
;
203 protecting_extensions
.Insert(extension
);
204 ExtensionSet empty_set
;
206 EXPECT_FALSE(policy_
->IsStorageUnlimited(extension
->url()));
207 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
208 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
209 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
210 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
211 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
212 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
214 policy_
->RevokeRightsForExtension(extension
.get());
215 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
216 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
217 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
220 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithUnlimitedStorage
) {
221 scoped_refptr
<Extension
> extension(CreateUnlimitedApp());
222 policy_
->GrantRightsForExtension(extension
.get());
223 ExtensionSet protecting_extensions
;
224 protecting_extensions
.Insert(extension
);
225 ExtensionSet empty_set
;
227 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
228 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
229 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
230 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
231 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
232 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
233 EXPECT_TRUE(policy_
->IsStorageUnlimited(extension
->url()));
234 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
235 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
236 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
237 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
238 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
240 policy_
->RevokeRightsForExtension(extension
.get());
241 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
242 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
243 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
244 ExpectProtectedBy(empty_set
, GURL("http://bar.wildcards/"));
245 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
246 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
247 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
250 TEST_F(ExtensionSpecialStoragePolicyTest
, CanQueryDiskSize
) {
251 const GURL
kHttpUrl("http://foo");
252 const GURL
kExtensionUrl("chrome-extension://bar");
253 scoped_refptr
<Extension
> regular_app(CreateRegularApp());
254 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
255 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
256 policy_
->GrantRightsForExtension(regular_app
.get());
257 policy_
->GrantRightsForExtension(protected_app
.get());
258 policy_
->GrantRightsForExtension(unlimited_app
.get());
260 EXPECT_FALSE(policy_
->CanQueryDiskSize(kHttpUrl
));
261 EXPECT_FALSE(policy_
->CanQueryDiskSize(kExtensionUrl
));
262 EXPECT_TRUE(policy_
->CanQueryDiskSize(regular_app
->url()));
263 EXPECT_TRUE(policy_
->CanQueryDiskSize(protected_app
->url()));
264 EXPECT_TRUE(policy_
->CanQueryDiskSize(unlimited_app
->url()));
267 TEST_F(ExtensionSpecialStoragePolicyTest
, HasIsolatedStorage
) {
268 const GURL
kHttpUrl("http://foo");
269 const GURL
kExtensionUrl("chrome-extension://bar");
270 scoped_refptr
<Extension
> app(CreateRegularApp());
271 policy_
->GrantRightsForExtension(app
.get());
273 EXPECT_FALSE(policy_
->HasIsolatedStorage(kHttpUrl
));
274 EXPECT_FALSE(policy_
->HasIsolatedStorage(kExtensionUrl
));
275 EXPECT_TRUE(policy_
->HasIsolatedStorage(app
->url()));
278 TEST_F(ExtensionSpecialStoragePolicyTest
, OverlappingApps
) {
279 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
280 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
281 policy_
->GrantRightsForExtension(protected_app
.get());
282 policy_
->GrantRightsForExtension(unlimited_app
.get());
283 ExtensionSet protecting_extensions
;
284 ExtensionSet empty_set
;
285 protecting_extensions
.Insert(protected_app
);
286 protecting_extensions
.Insert(unlimited_app
);
288 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
289 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
290 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
291 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
292 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
293 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
294 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
295 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
296 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
297 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
298 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
300 policy_
->RevokeRightsForExtension(unlimited_app
.get());
301 protecting_extensions
.Remove(unlimited_app
->id());
302 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
303 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
304 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
305 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
306 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
307 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
309 policy_
->RevokeRightsForExtension(protected_app
.get());
310 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
311 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
312 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
315 TEST_F(ExtensionSpecialStoragePolicyTest
, HasSessionOnlyOrigins
) {
316 base::MessageLoop message_loop
;
317 content::TestBrowserThread
ui_thread(BrowserThread::UI
, &message_loop
);
319 TestingProfile profile
;
320 CookieSettings
* cookie_settings
=
321 CookieSettings::Factory::GetForProfile(&profile
).get();
322 policy_
= new ExtensionSpecialStoragePolicy(cookie_settings
);
324 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
326 // The default setting can be session-only.
327 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY
);
328 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
330 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW
);
331 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
333 // Or the session-onlyness can affect individual origins.
334 ContentSettingsPattern pattern
=
335 ContentSettingsPattern::FromString("pattern.com");
337 cookie_settings
->SetCookieSetting(pattern
,
338 ContentSettingsPattern::Wildcard(),
339 CONTENT_SETTING_SESSION_ONLY
);
341 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
343 // Clearing an origin-specific rule.
344 cookie_settings
->ResetCookieSetting(pattern
,
345 ContentSettingsPattern::Wildcard());
347 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
350 TEST_F(ExtensionSpecialStoragePolicyTest
, NotificationTest
) {
351 base::MessageLoop message_loop
;
352 content::TestBrowserThread
ui_thread(BrowserThread::UI
, &message_loop
);
353 content::TestBrowserThread
io_thread(BrowserThread::IO
, &message_loop
);
355 PolicyChangeObserver observer
;
356 policy_
->AddObserver(&observer
);
358 scoped_refptr
<Extension
> apps
[] = {
359 CreateProtectedApp(),
360 CreateUnlimitedApp(),
363 int change_flags
[] = {
364 SpecialStoragePolicy::STORAGE_PROTECTED
,
366 SpecialStoragePolicy::STORAGE_PROTECTED
|
367 SpecialStoragePolicy::STORAGE_UNLIMITED
,
370 ASSERT_EQ(arraysize(apps
), arraysize(change_flags
));
371 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
372 SCOPED_TRACE(testing::Message() << "i: " << i
);
373 observer
.ExpectGrant(apps
[i
]->id(), change_flags
[i
]);
374 policy_
->GrantRightsForExtension(apps
[i
].get());
375 message_loop
.RunUntilIdle();
376 EXPECT_TRUE(observer
.IsCompleted());
379 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
380 SCOPED_TRACE(testing::Message() << "i: " << i
);
381 policy_
->GrantRightsForExtension(apps
[i
].get());
382 message_loop
.RunUntilIdle();
383 EXPECT_TRUE(observer
.IsCompleted());
386 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
387 SCOPED_TRACE(testing::Message() << "i: " << i
);
388 observer
.ExpectRevoke(apps
[i
]->id(), change_flags
[i
]);
389 policy_
->RevokeRightsForExtension(apps
[i
].get());
390 message_loop
.RunUntilIdle();
391 EXPECT_TRUE(observer
.IsCompleted());
394 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
395 SCOPED_TRACE(testing::Message() << "i: " << i
);
396 policy_
->RevokeRightsForExtension(apps
[i
].get());
397 message_loop
.RunUntilIdle();
398 EXPECT_TRUE(observer
.IsCompleted());
401 observer
.ExpectClear();
402 policy_
->RevokeRightsForAllExtensions();
403 message_loop
.RunUntilIdle();
404 EXPECT_TRUE(observer
.IsCompleted());
406 policy_
->RemoveObserver(&observer
);