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/values.h"
6 #include "chrome/browser/content_settings/cookie_settings_factory.h"
7 #include "chrome/browser/extensions/extension_special_storage_policy.h"
8 #include "chrome/test/base/testing_profile.h"
9 #include "components/content_settings/core/browser/cookie_settings.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 "content/public/test/test_browser_thread_bundle.h"
14 #include "extensions/common/extension.h"
15 #include "extensions/common/extension_set.h"
16 #include "extensions/common/manifest.h"
17 #include "extensions/common/manifest_constants.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using content::BrowserThread
;
21 using extensions::Extension
;
22 using extensions::ExtensionSet
;
23 using extensions::Manifest
;
24 using storage::SpecialStoragePolicy
;
26 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy
;
28 namespace keys
= extensions::manifest_keys
;
30 class ExtensionSpecialStoragePolicyTest
: public testing::Test
{
32 class PolicyChangeObserver
: public SpecialStoragePolicy::Observer
{
34 PolicyChangeObserver()
35 : expected_type_(NOTIFICATION_TYPE_NONE
),
36 expected_change_flags_(0) {
39 void OnGranted(const GURL
& origin
, 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 void OnRevoked(const GURL
& origin
, int change_flags
) override
{
47 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_REVOKE
);
48 EXPECT_EQ(expected_origin_
, origin
);
49 EXPECT_EQ(expected_change_flags_
, change_flags
);
50 expected_type_
= NOTIFICATION_TYPE_NONE
;
53 void OnCleared() override
{
54 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_CLEAR
);
55 expected_type_
= NOTIFICATION_TYPE_NONE
;
58 void ExpectGrant(const std::string
& extension_id
,
60 expected_type_
= NOTIFICATION_TYPE_GRANT
;
61 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
62 expected_change_flags_
= change_flags
;
65 void ExpectRevoke(const std::string
& extension_id
,
67 expected_type_
= NOTIFICATION_TYPE_REVOKE
;
68 expected_origin_
= Extension::GetBaseURLFromExtensionId(extension_id
);
69 expected_change_flags_
= change_flags
;
73 expected_type_
= NOTIFICATION_TYPE_CLEAR
;
77 return expected_type_
== NOTIFICATION_TYPE_NONE
;
82 NOTIFICATION_TYPE_NONE
,
83 NOTIFICATION_TYPE_GRANT
,
84 NOTIFICATION_TYPE_REVOKE
,
85 NOTIFICATION_TYPE_CLEAR
,
88 GURL expected_origin_
;
89 int expected_change_flags_
;
91 DISALLOW_COPY_AND_ASSIGN(PolicyChangeObserver
);
94 void SetUp() override
{ policy_
= new ExtensionSpecialStoragePolicy(NULL
); }
96 scoped_refptr
<Extension
> CreateProtectedApp() {
98 base::FilePath
path(FILE_PATH_LITERAL("c:\\foo"));
99 #elif defined(OS_POSIX)
100 base::FilePath
path(FILE_PATH_LITERAL("/foo"));
102 base::DictionaryValue manifest
;
103 manifest
.SetString(keys::kName
, "Protected");
104 manifest
.SetString(keys::kVersion
, "1");
105 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/protected/start");
106 base::ListValue
* list
= new base::ListValue();
107 list
->Append(new base::StringValue("http://explicit/protected"));
108 list
->Append(new base::StringValue("*://*.wildcards/protected"));
109 manifest
.Set(keys::kWebURLs
, list
);
111 scoped_refptr
<Extension
> protected_app
= Extension::Create(
112 path
, Manifest::INVALID_LOCATION
, manifest
,
113 Extension::NO_FLAGS
, &error
);
114 EXPECT_TRUE(protected_app
.get()) << error
;
115 return protected_app
;
118 scoped_refptr
<Extension
> CreateUnlimitedApp() {
120 base::FilePath
path(FILE_PATH_LITERAL("c:\\bar"));
121 #elif defined(OS_POSIX)
122 base::FilePath
path(FILE_PATH_LITERAL("/bar"));
124 base::DictionaryValue manifest
;
125 manifest
.SetString(keys::kName
, "Unlimited");
126 manifest
.SetString(keys::kVersion
, "1");
127 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/unlimited/start");
128 base::ListValue
* list
= new base::ListValue();
129 list
->Append(new base::StringValue("unlimitedStorage"));
130 manifest
.Set(keys::kPermissions
, list
);
131 list
= new base::ListValue();
132 list
->Append(new base::StringValue("http://explicit/unlimited"));
133 list
->Append(new base::StringValue("*://*.wildcards/unlimited"));
134 manifest
.Set(keys::kWebURLs
, list
);
136 scoped_refptr
<Extension
> unlimited_app
= Extension::Create(
137 path
, Manifest::INVALID_LOCATION
, manifest
,
138 Extension::NO_FLAGS
, &error
);
139 EXPECT_TRUE(unlimited_app
.get()) << error
;
140 return unlimited_app
;
143 scoped_refptr
<Extension
> CreateRegularApp() {
145 base::FilePath
path(FILE_PATH_LITERAL("c:\\app"));
146 #elif defined(OS_POSIX)
147 base::FilePath
path(FILE_PATH_LITERAL("/app"));
149 base::DictionaryValue manifest
;
150 manifest
.SetString(keys::kName
, "App");
151 manifest
.SetString(keys::kVersion
, "1");
152 manifest
.SetString(keys::kPlatformAppBackgroundPage
, "background.html");
154 scoped_refptr
<Extension
> app
= Extension::Create(
155 path
, Manifest::INVALID_LOCATION
, manifest
,
156 Extension::NO_FLAGS
, &error
);
157 EXPECT_TRUE(app
.get()) << error
;
161 // Verifies that the set of extensions protecting |url| is *exactly* equal to
162 // |expected_extensions|. Pass in an empty set to verify that an origin is not
164 void ExpectProtectedBy(const ExtensionSet
& expected_extensions
,
166 const ExtensionSet
* extensions
= policy_
->ExtensionsProtectingOrigin(url
);
167 EXPECT_EQ(expected_extensions
.size(), extensions
->size());
168 for (ExtensionSet::const_iterator it
= expected_extensions
.begin();
169 it
!= expected_extensions
.end(); ++it
) {
170 EXPECT_TRUE(extensions
->Contains((*it
)->id()))
171 << "Origin " << url
<< "not protected by extension ID "
176 content::TestBrowserThreadBundle thread_bundle_
;
177 scoped_refptr
<ExtensionSpecialStoragePolicy
> policy_
;
180 TEST_F(ExtensionSpecialStoragePolicyTest
, EmptyPolicy
) {
181 const GURL
kHttpUrl("http://foo");
182 const GURL
kExtensionUrl("chrome-extension://bar");
183 scoped_refptr
<Extension
> app(CreateRegularApp());
185 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
));
186 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
)); // test cached result
187 EXPECT_FALSE(policy_
->IsStorageUnlimited(kExtensionUrl
));
188 EXPECT_FALSE(policy_
->IsStorageUnlimited(app
->url()));
189 ExtensionSet empty_set
;
190 ExpectProtectedBy(empty_set
, kHttpUrl
);
192 // This one is just based on the scheme.
193 EXPECT_TRUE(policy_
->IsStorageProtected(kExtensionUrl
));
194 EXPECT_TRUE(policy_
->IsStorageProtected(app
->url()));
197 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithProtectedStorage
) {
198 scoped_refptr
<Extension
> extension(CreateProtectedApp());
199 policy_
->GrantRightsForExtension(extension
.get(), NULL
);
200 ExtensionSet protecting_extensions
;
201 protecting_extensions
.Insert(extension
);
202 ExtensionSet empty_set
;
204 EXPECT_FALSE(policy_
->IsStorageUnlimited(extension
->url()));
205 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
206 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
207 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
208 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
209 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
210 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
212 policy_
->RevokeRightsForExtension(extension
.get());
213 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
214 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
215 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
218 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithUnlimitedStorage
) {
219 scoped_refptr
<Extension
> extension(CreateUnlimitedApp());
220 policy_
->GrantRightsForExtension(extension
.get(), NULL
);
221 ExtensionSet protecting_extensions
;
222 protecting_extensions
.Insert(extension
);
223 ExtensionSet empty_set
;
225 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
226 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
227 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
228 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
229 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
230 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
231 EXPECT_TRUE(policy_
->IsStorageUnlimited(extension
->url()));
232 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
233 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
234 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
235 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
236 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
238 policy_
->RevokeRightsForExtension(extension
.get());
239 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
240 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
241 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
242 ExpectProtectedBy(empty_set
, GURL("http://bar.wildcards/"));
243 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
244 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
245 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
248 TEST_F(ExtensionSpecialStoragePolicyTest
, CanQueryDiskSize
) {
249 const GURL
kHttpUrl("http://foo");
250 const GURL
kExtensionUrl("chrome-extension://bar");
251 scoped_refptr
<Extension
> regular_app(CreateRegularApp());
252 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
253 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
254 policy_
->GrantRightsForExtension(regular_app
.get(), NULL
);
255 policy_
->GrantRightsForExtension(protected_app
.get(), NULL
);
256 policy_
->GrantRightsForExtension(unlimited_app
.get(), NULL
);
258 EXPECT_FALSE(policy_
->CanQueryDiskSize(kHttpUrl
));
259 EXPECT_FALSE(policy_
->CanQueryDiskSize(kExtensionUrl
));
260 EXPECT_TRUE(policy_
->CanQueryDiskSize(regular_app
->url()));
261 EXPECT_TRUE(policy_
->CanQueryDiskSize(protected_app
->url()));
262 EXPECT_TRUE(policy_
->CanQueryDiskSize(unlimited_app
->url()));
265 TEST_F(ExtensionSpecialStoragePolicyTest
, HasIsolatedStorage
) {
266 const GURL
kHttpUrl("http://foo");
267 const GURL
kExtensionUrl("chrome-extension://bar");
268 scoped_refptr
<Extension
> app(CreateRegularApp());
269 policy_
->GrantRightsForExtension(app
.get(), NULL
);
271 EXPECT_FALSE(policy_
->HasIsolatedStorage(kHttpUrl
));
272 EXPECT_FALSE(policy_
->HasIsolatedStorage(kExtensionUrl
));
273 EXPECT_TRUE(policy_
->HasIsolatedStorage(app
->url()));
276 TEST_F(ExtensionSpecialStoragePolicyTest
, OverlappingApps
) {
277 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
278 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
279 policy_
->GrantRightsForExtension(protected_app
.get(), NULL
);
280 policy_
->GrantRightsForExtension(unlimited_app
.get(), NULL
);
281 ExtensionSet protecting_extensions
;
282 ExtensionSet empty_set
;
283 protecting_extensions
.Insert(protected_app
);
284 protecting_extensions
.Insert(unlimited_app
);
286 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
287 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
288 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
289 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
290 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
291 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
292 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
293 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
294 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
295 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
296 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
298 policy_
->RevokeRightsForExtension(unlimited_app
.get());
299 protecting_extensions
.Remove(unlimited_app
->id());
300 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
301 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
302 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
303 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
304 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
305 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
307 policy_
->RevokeRightsForExtension(protected_app
.get());
308 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
309 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
310 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
313 TEST_F(ExtensionSpecialStoragePolicyTest
, HasSessionOnlyOrigins
) {
314 TestingProfile profile
;
315 content_settings::CookieSettings
* cookie_settings
=
316 CookieSettingsFactory::GetForProfile(&profile
).get();
317 policy_
= new ExtensionSpecialStoragePolicy(cookie_settings
);
319 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
321 // The default setting can be session-only.
322 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY
);
323 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
325 cookie_settings
->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW
);
326 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
328 // Or the session-onlyness can affect individual origins.
329 ContentSettingsPattern pattern
=
330 ContentSettingsPattern::FromString("pattern.com");
332 cookie_settings
->SetCookieSetting(pattern
,
333 ContentSettingsPattern::Wildcard(),
334 CONTENT_SETTING_SESSION_ONLY
);
336 EXPECT_TRUE(policy_
->HasSessionOnlyOrigins());
338 // Clearing an origin-specific rule.
339 cookie_settings
->ResetCookieSetting(pattern
,
340 ContentSettingsPattern::Wildcard());
342 EXPECT_FALSE(policy_
->HasSessionOnlyOrigins());
345 TEST_F(ExtensionSpecialStoragePolicyTest
, IsStorageDurableTest
) {
346 TestingProfile profile
;
347 content_settings::CookieSettings
* cookie_settings
=
348 CookieSettingsFactory::GetForProfile(&profile
).get();
349 policy_
= new ExtensionSpecialStoragePolicy(cookie_settings
);
350 const GURL
kHttpUrl("http://foo.com");
352 EXPECT_FALSE(policy_
->IsStorageDurable(kHttpUrl
));
354 HostContentSettingsMap
* content_settings_map
=
355 profile
.GetHostContentSettingsMap();
356 content_settings_map
->SetContentSetting(
357 ContentSettingsPattern::FromString("foo.com"),
358 ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_DURABLE_STORAGE
,
359 std::string(), CONTENT_SETTING_ALLOW
);
361 EXPECT_TRUE(policy_
->IsStorageDurable(kHttpUrl
));
364 TEST_F(ExtensionSpecialStoragePolicyTest
, NotificationTest
) {
365 PolicyChangeObserver observer
;
366 policy_
->AddObserver(&observer
);
368 scoped_refptr
<Extension
> apps
[] = {
369 CreateProtectedApp(),
370 CreateUnlimitedApp(),
373 int change_flags
[] = {
374 SpecialStoragePolicy::STORAGE_PROTECTED
,
376 SpecialStoragePolicy::STORAGE_PROTECTED
|
377 SpecialStoragePolicy::STORAGE_UNLIMITED
,
380 ASSERT_EQ(arraysize(apps
), arraysize(change_flags
));
381 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
382 SCOPED_TRACE(testing::Message() << "i: " << i
);
383 observer
.ExpectGrant(apps
[i
]->id(), change_flags
[i
]);
384 policy_
->GrantRightsForExtension(apps
[i
].get(), NULL
);
385 base::MessageLoop::current()->RunUntilIdle();
386 EXPECT_TRUE(observer
.IsCompleted());
389 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
390 SCOPED_TRACE(testing::Message() << "i: " << i
);
391 policy_
->GrantRightsForExtension(apps
[i
].get(), NULL
);
392 base::MessageLoop::current()->RunUntilIdle();
393 EXPECT_TRUE(observer
.IsCompleted());
396 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
397 SCOPED_TRACE(testing::Message() << "i: " << i
);
398 observer
.ExpectRevoke(apps
[i
]->id(), change_flags
[i
]);
399 policy_
->RevokeRightsForExtension(apps
[i
].get());
400 base::MessageLoop::current()->RunUntilIdle();
401 EXPECT_TRUE(observer
.IsCompleted());
404 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
405 SCOPED_TRACE(testing::Message() << "i: " << i
);
406 policy_
->RevokeRightsForExtension(apps
[i
].get());
407 base::MessageLoop::current()->RunUntilIdle();
408 EXPECT_TRUE(observer
.IsCompleted());
411 observer
.ExpectClear();
412 policy_
->RevokeRightsForAllExtensions();
413 base::MessageLoop::current()->RunUntilIdle();
414 EXPECT_TRUE(observer
.IsCompleted());
416 policy_
->RemoveObserver(&observer
);