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/content_settings/host_content_settings_map_factory.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/browser/cookie_settings.h"
11 #include "components/content_settings/core/common/content_settings.h"
12 #include "components/content_settings/core/common/content_settings_types.h"
13 #include "content/public/test/test_browser_thread.h"
14 #include "content/public/test/test_browser_thread_bundle.h"
15 #include "extensions/common/extension.h"
16 #include "extensions/common/extension_set.h"
17 #include "extensions/common/manifest.h"
18 #include "extensions/common/manifest_constants.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using content::BrowserThread
;
22 using extensions::Extension
;
23 using extensions::ExtensionSet
;
24 using extensions::Manifest
;
25 using storage::SpecialStoragePolicy
;
27 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy
;
29 namespace keys
= extensions::manifest_keys
;
31 class ExtensionSpecialStoragePolicyTest
: public testing::Test
{
33 class PolicyChangeObserver
: public SpecialStoragePolicy::Observer
{
35 PolicyChangeObserver()
36 : expected_type_(NOTIFICATION_TYPE_NONE
),
37 expected_change_flags_(0) {
40 void OnGranted(const GURL
& origin
, int change_flags
) override
{
41 EXPECT_EQ(expected_type_
, NOTIFICATION_TYPE_GRANT
);
42 EXPECT_EQ(expected_origin_
, origin
);
43 EXPECT_EQ(expected_change_flags_
, change_flags
);
44 expected_type_
= NOTIFICATION_TYPE_NONE
;
47 void OnRevoked(const GURL
& origin
, 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 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 void SetUp() override
{ policy_
= new ExtensionSpecialStoragePolicy(NULL
); }
97 scoped_refptr
<Extension
> CreateProtectedApp() {
99 base::FilePath
path(FILE_PATH_LITERAL("c:\\foo"));
100 #elif defined(OS_POSIX)
101 base::FilePath
path(FILE_PATH_LITERAL("/foo"));
103 base::DictionaryValue manifest
;
104 manifest
.SetString(keys::kName
, "Protected");
105 manifest
.SetString(keys::kVersion
, "1");
106 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/protected/start");
107 base::ListValue
* list
= new base::ListValue();
108 list
->Append(new base::StringValue("http://explicit/protected"));
109 list
->Append(new base::StringValue("*://*.wildcards/protected"));
110 manifest
.Set(keys::kWebURLs
, list
);
112 scoped_refptr
<Extension
> protected_app
= Extension::Create(
113 path
, Manifest::INVALID_LOCATION
, manifest
,
114 Extension::NO_FLAGS
, &error
);
115 EXPECT_TRUE(protected_app
.get()) << error
;
116 return protected_app
;
119 scoped_refptr
<Extension
> CreateUnlimitedApp() {
121 base::FilePath
path(FILE_PATH_LITERAL("c:\\bar"));
122 #elif defined(OS_POSIX)
123 base::FilePath
path(FILE_PATH_LITERAL("/bar"));
125 base::DictionaryValue manifest
;
126 manifest
.SetString(keys::kName
, "Unlimited");
127 manifest
.SetString(keys::kVersion
, "1");
128 manifest
.SetString(keys::kLaunchWebURL
, "http://explicit/unlimited/start");
129 base::ListValue
* list
= new base::ListValue();
130 list
->Append(new base::StringValue("unlimitedStorage"));
131 manifest
.Set(keys::kPermissions
, list
);
132 list
= new base::ListValue();
133 list
->Append(new base::StringValue("http://explicit/unlimited"));
134 list
->Append(new base::StringValue("*://*.wildcards/unlimited"));
135 manifest
.Set(keys::kWebURLs
, list
);
137 scoped_refptr
<Extension
> unlimited_app
= Extension::Create(
138 path
, Manifest::INVALID_LOCATION
, manifest
,
139 Extension::NO_FLAGS
, &error
);
140 EXPECT_TRUE(unlimited_app
.get()) << error
;
141 return unlimited_app
;
144 scoped_refptr
<Extension
> CreateRegularApp() {
146 base::FilePath
path(FILE_PATH_LITERAL("c:\\app"));
147 #elif defined(OS_POSIX)
148 base::FilePath
path(FILE_PATH_LITERAL("/app"));
150 base::DictionaryValue manifest
;
151 manifest
.SetString(keys::kName
, "App");
152 manifest
.SetString(keys::kVersion
, "1");
153 manifest
.SetString(keys::kPlatformAppBackgroundPage
, "background.html");
155 scoped_refptr
<Extension
> app
= Extension::Create(
156 path
, Manifest::INVALID_LOCATION
, manifest
,
157 Extension::NO_FLAGS
, &error
);
158 EXPECT_TRUE(app
.get()) << error
;
162 // Verifies that the set of extensions protecting |url| is *exactly* equal to
163 // |expected_extensions|. Pass in an empty set to verify that an origin is not
165 void ExpectProtectedBy(const ExtensionSet
& expected_extensions
,
167 const ExtensionSet
* extensions
= policy_
->ExtensionsProtectingOrigin(url
);
168 EXPECT_EQ(expected_extensions
.size(), extensions
->size());
169 for (ExtensionSet::const_iterator it
= expected_extensions
.begin();
170 it
!= expected_extensions
.end(); ++it
) {
171 EXPECT_TRUE(extensions
->Contains((*it
)->id()))
172 << "Origin " << url
<< "not protected by extension ID "
177 content::TestBrowserThreadBundle thread_bundle_
;
178 scoped_refptr
<ExtensionSpecialStoragePolicy
> policy_
;
181 TEST_F(ExtensionSpecialStoragePolicyTest
, EmptyPolicy
) {
182 const GURL
kHttpUrl("http://foo");
183 const GURL
kExtensionUrl("chrome-extension://bar");
184 scoped_refptr
<Extension
> app(CreateRegularApp());
186 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
));
187 EXPECT_FALSE(policy_
->IsStorageUnlimited(kHttpUrl
)); // test cached result
188 EXPECT_FALSE(policy_
->IsStorageUnlimited(kExtensionUrl
));
189 EXPECT_FALSE(policy_
->IsStorageUnlimited(app
->url()));
190 ExtensionSet empty_set
;
191 ExpectProtectedBy(empty_set
, kHttpUrl
);
193 // This one is just based on the scheme.
194 EXPECT_TRUE(policy_
->IsStorageProtected(kExtensionUrl
));
195 EXPECT_TRUE(policy_
->IsStorageProtected(app
->url()));
198 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithProtectedStorage
) {
199 scoped_refptr
<Extension
> extension(CreateProtectedApp());
200 policy_
->GrantRightsForExtension(extension
.get(), NULL
);
201 ExtensionSet protecting_extensions
;
202 protecting_extensions
.Insert(extension
);
203 ExtensionSet empty_set
;
205 EXPECT_FALSE(policy_
->IsStorageUnlimited(extension
->url()));
206 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
207 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
208 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
209 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
210 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
211 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
213 policy_
->RevokeRightsForExtension(extension
.get());
214 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
215 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
216 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
219 TEST_F(ExtensionSpecialStoragePolicyTest
, AppWithUnlimitedStorage
) {
220 scoped_refptr
<Extension
> extension(CreateUnlimitedApp());
221 policy_
->GrantRightsForExtension(extension
.get(), NULL
);
222 ExtensionSet protecting_extensions
;
223 protecting_extensions
.Insert(extension
);
224 ExtensionSet empty_set
;
226 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
227 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
228 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
229 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
230 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
231 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
232 EXPECT_TRUE(policy_
->IsStorageUnlimited(extension
->url()));
233 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
234 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
235 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
236 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
237 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
239 policy_
->RevokeRightsForExtension(extension
.get());
240 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
241 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
242 ExpectProtectedBy(empty_set
, GURL("https://foo.wildcards/"));
243 ExpectProtectedBy(empty_set
, GURL("http://bar.wildcards/"));
244 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
245 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
246 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
249 TEST_F(ExtensionSpecialStoragePolicyTest
, CanQueryDiskSize
) {
250 const GURL
kHttpUrl("http://foo");
251 const GURL
kExtensionUrl("chrome-extension://bar");
252 scoped_refptr
<Extension
> regular_app(CreateRegularApp());
253 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
254 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
255 policy_
->GrantRightsForExtension(regular_app
.get(), NULL
);
256 policy_
->GrantRightsForExtension(protected_app
.get(), NULL
);
257 policy_
->GrantRightsForExtension(unlimited_app
.get(), NULL
);
259 EXPECT_FALSE(policy_
->CanQueryDiskSize(kHttpUrl
));
260 EXPECT_FALSE(policy_
->CanQueryDiskSize(kExtensionUrl
));
261 EXPECT_TRUE(policy_
->CanQueryDiskSize(regular_app
->url()));
262 EXPECT_TRUE(policy_
->CanQueryDiskSize(protected_app
->url()));
263 EXPECT_TRUE(policy_
->CanQueryDiskSize(unlimited_app
->url()));
266 TEST_F(ExtensionSpecialStoragePolicyTest
, HasIsolatedStorage
) {
267 const GURL
kHttpUrl("http://foo");
268 const GURL
kExtensionUrl("chrome-extension://bar");
269 scoped_refptr
<Extension
> app(CreateRegularApp());
270 policy_
->GrantRightsForExtension(app
.get(), NULL
);
272 EXPECT_FALSE(policy_
->HasIsolatedStorage(kHttpUrl
));
273 EXPECT_FALSE(policy_
->HasIsolatedStorage(kExtensionUrl
));
274 EXPECT_TRUE(policy_
->HasIsolatedStorage(app
->url()));
277 TEST_F(ExtensionSpecialStoragePolicyTest
, OverlappingApps
) {
278 scoped_refptr
<Extension
> protected_app(CreateProtectedApp());
279 scoped_refptr
<Extension
> unlimited_app(CreateUnlimitedApp());
280 policy_
->GrantRightsForExtension(protected_app
.get(), NULL
);
281 policy_
->GrantRightsForExtension(unlimited_app
.get(), NULL
);
282 ExtensionSet protecting_extensions
;
283 ExtensionSet empty_set
;
284 protecting_extensions
.Insert(protected_app
);
285 protecting_extensions
.Insert(unlimited_app
);
287 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
288 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit:6000/"));
289 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
290 ExpectProtectedBy(protecting_extensions
, GURL("https://foo.wildcards/"));
291 ExpectProtectedBy(protecting_extensions
, GURL("http://bar.wildcards/"));
292 ExpectProtectedBy(empty_set
, GURL("http://not_listed/"));
293 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
294 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("http://explicit:6000/")));
295 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
296 EXPECT_TRUE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
297 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://not_listed/")));
299 policy_
->RevokeRightsForExtension(unlimited_app
.get());
300 protecting_extensions
.Remove(unlimited_app
->id());
301 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("http://explicit/")));
302 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://foo.wildcards/")));
303 EXPECT_FALSE(policy_
->IsStorageUnlimited(GURL("https://bar.wildcards/")));
304 ExpectProtectedBy(protecting_extensions
, GURL("http://explicit/"));
305 ExpectProtectedBy(protecting_extensions
, GURL("http://foo.wildcards/"));
306 ExpectProtectedBy(protecting_extensions
, GURL("https://bar.wildcards/"));
308 policy_
->RevokeRightsForExtension(protected_app
.get());
309 ExpectProtectedBy(empty_set
, GURL("http://explicit/"));
310 ExpectProtectedBy(empty_set
, GURL("http://foo.wildcards/"));
311 ExpectProtectedBy(empty_set
, GURL("https://bar.wildcards/"));
314 TEST_F(ExtensionSpecialStoragePolicyTest
, HasSessionOnlyOrigins
) {
315 TestingProfile profile
;
316 content_settings::CookieSettings
* cookie_settings
=
317 CookieSettingsFactory::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
, IsStorageDurableTest
) {
347 TestingProfile profile
;
348 content_settings::CookieSettings
* cookie_settings
=
349 CookieSettingsFactory::GetForProfile(&profile
).get();
350 policy_
= new ExtensionSpecialStoragePolicy(cookie_settings
);
351 const GURL
kHttpUrl("http://foo.com");
353 EXPECT_FALSE(policy_
->IsStorageDurable(kHttpUrl
));
355 HostContentSettingsMap
* content_settings_map
=
356 HostContentSettingsMapFactory::GetForProfile(&profile
);
357 content_settings_map
->SetContentSetting(
358 ContentSettingsPattern::FromString("foo.com"),
359 ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_DURABLE_STORAGE
,
360 std::string(), CONTENT_SETTING_ALLOW
);
362 EXPECT_TRUE(policy_
->IsStorageDurable(kHttpUrl
));
365 TEST_F(ExtensionSpecialStoragePolicyTest
, NotificationTest
) {
366 PolicyChangeObserver observer
;
367 policy_
->AddObserver(&observer
);
369 scoped_refptr
<Extension
> apps
[] = {
370 CreateProtectedApp(),
371 CreateUnlimitedApp(),
374 int change_flags
[] = {
375 SpecialStoragePolicy::STORAGE_PROTECTED
,
377 SpecialStoragePolicy::STORAGE_PROTECTED
|
378 SpecialStoragePolicy::STORAGE_UNLIMITED
,
381 ASSERT_EQ(arraysize(apps
), arraysize(change_flags
));
382 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
383 SCOPED_TRACE(testing::Message() << "i: " << i
);
384 observer
.ExpectGrant(apps
[i
]->id(), change_flags
[i
]);
385 policy_
->GrantRightsForExtension(apps
[i
].get(), NULL
);
386 base::MessageLoop::current()->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_
->GrantRightsForExtension(apps
[i
].get(), NULL
);
393 base::MessageLoop::current()->RunUntilIdle();
394 EXPECT_TRUE(observer
.IsCompleted());
397 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
398 SCOPED_TRACE(testing::Message() << "i: " << i
);
399 observer
.ExpectRevoke(apps
[i
]->id(), change_flags
[i
]);
400 policy_
->RevokeRightsForExtension(apps
[i
].get());
401 base::MessageLoop::current()->RunUntilIdle();
402 EXPECT_TRUE(observer
.IsCompleted());
405 for (size_t i
= 0; i
< arraysize(apps
); ++i
) {
406 SCOPED_TRACE(testing::Message() << "i: " << i
);
407 policy_
->RevokeRightsForExtension(apps
[i
].get());
408 base::MessageLoop::current()->RunUntilIdle();
409 EXPECT_TRUE(observer
.IsCompleted());
412 observer
.ExpectClear();
413 policy_
->RevokeRightsForAllExtensions();
414 base::MessageLoop::current()->RunUntilIdle();
415 EXPECT_TRUE(observer
.IsCompleted());
417 policy_
->RemoveObserver(&observer
);