extension_special_storage_policy_unittest.cc revision 3551c9c881056c480085172ff9840cab31610854
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.
4
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/common/extensions/extension.h"
12#include "chrome/test/base/testing_profile.h"
13#include "content/public/test/test_browser_thread.h"
14#include "extensions/common/manifest.h"
15#include "extensions/common/manifest_constants.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using content::BrowserThread;
19using extensions::Extension;
20using extensions::Manifest;
21using quota::SpecialStoragePolicy;
22
23typedef SpecialStoragePolicy::StoragePolicy StoragePolicy;
24
25namespace keys = extensions::manifest_keys;
26
27class ExtensionSpecialStoragePolicyTest : public testing::Test {
28 protected:
29  class PolicyChangeObserver : public SpecialStoragePolicy::Observer {
30   public:
31    PolicyChangeObserver()
32        : expected_type_(NOTIFICATION_TYPE_NONE),
33          expected_change_flags_(0) {
34    }
35
36    virtual void OnGranted(const GURL& origin,
37                           int change_flags) OVERRIDE {
38      EXPECT_EQ(expected_type_, NOTIFICATION_TYPE_GRANT);
39      EXPECT_EQ(expected_origin_, origin);
40      EXPECT_EQ(expected_change_flags_, change_flags);
41      expected_type_ = NOTIFICATION_TYPE_NONE;
42    }
43
44    virtual void OnRevoked(const GURL& origin,
45                           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;
50    }
51
52    virtual void OnCleared() OVERRIDE {
53      EXPECT_EQ(expected_type_, NOTIFICATION_TYPE_CLEAR);
54      expected_type_ = NOTIFICATION_TYPE_NONE;
55    }
56
57    void ExpectGrant(const std::string& extension_id,
58                     int change_flags) {
59      expected_type_ = NOTIFICATION_TYPE_GRANT;
60      expected_origin_ = Extension::GetBaseURLFromExtensionId(extension_id);
61      expected_change_flags_ = change_flags;
62    }
63
64    void ExpectRevoke(const std::string& extension_id,
65                      int change_flags) {
66      expected_type_ = NOTIFICATION_TYPE_REVOKE;
67      expected_origin_ = Extension::GetBaseURLFromExtensionId(extension_id);
68      expected_change_flags_ = change_flags;
69    }
70
71    void ExpectClear() {
72      expected_type_ = NOTIFICATION_TYPE_CLEAR;
73    }
74
75    bool IsCompleted() {
76      return expected_type_ == NOTIFICATION_TYPE_NONE;
77    }
78
79   private:
80    enum {
81      NOTIFICATION_TYPE_NONE,
82      NOTIFICATION_TYPE_GRANT,
83      NOTIFICATION_TYPE_REVOKE,
84      NOTIFICATION_TYPE_CLEAR,
85    } expected_type_;
86
87    GURL expected_origin_;
88    int expected_change_flags_;
89
90    DISALLOW_COPY_AND_ASSIGN(PolicyChangeObserver);
91  };
92
93  virtual void SetUp() OVERRIDE {
94    policy_ = new ExtensionSpecialStoragePolicy(NULL);
95  }
96
97  scoped_refptr<Extension> CreateProtectedApp() {
98#if defined(OS_WIN)
99    base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
100#elif defined(OS_POSIX)
101    base::FilePath path(FILE_PATH_LITERAL("/foo"));
102#endif
103    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);
111    std::string error;
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;
117  }
118
119  scoped_refptr<Extension> CreateUnlimitedApp() {
120#if defined(OS_WIN)
121    base::FilePath path(FILE_PATH_LITERAL("c:\\bar"));
122#elif defined(OS_POSIX)
123    base::FilePath path(FILE_PATH_LITERAL("/bar"));
124#endif
125    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);
136    std::string error;
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;
142  }
143
144  scoped_refptr<Extension> CreateRegularApp() {
145#if defined(OS_WIN)
146    base::FilePath path(FILE_PATH_LITERAL("c:\\app"));
147#elif defined(OS_POSIX)
148    base::FilePath path(FILE_PATH_LITERAL("/app"));
149#endif
150    DictionaryValue manifest;
151    manifest.SetString(keys::kName, "App");
152    manifest.SetString(keys::kVersion, "1");
153    manifest.SetString(keys::kPlatformAppBackgroundPage, "background.html");
154    std::string error;
155    scoped_refptr<Extension> app = Extension::Create(
156        path, Manifest::INVALID_LOCATION, manifest,
157        Extension::NO_FLAGS, &error);
158    EXPECT_TRUE(app.get()) << error;
159    return app;
160  }
161
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
164  // protected.
165  void ExpectProtectedBy(const ExtensionSet& expected_extensions,
166                         const GURL& url) {
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 "
173          << (*it)->id();
174    }
175  }
176
177  scoped_refptr<ExtensionSpecialStoragePolicy> policy_;
178};
179
180TEST_F(ExtensionSpecialStoragePolicyTest, EmptyPolicy) {
181  const GURL kHttpUrl("http://foo");
182  const GURL kExtensionUrl("chrome-extension://bar");
183  scoped_refptr<Extension> app(CreateRegularApp());
184
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);
191
192  // This one is just based on the scheme.
193  EXPECT_TRUE(policy_->IsStorageProtected(kExtensionUrl));
194  EXPECT_TRUE(policy_->IsStorageProtected(app->url()));
195}
196
197TEST_F(ExtensionSpecialStoragePolicyTest, AppWithProtectedStorage) {
198  scoped_refptr<Extension> extension(CreateProtectedApp());
199  policy_->GrantRightsForExtension(extension.get());
200  ExtensionSet protecting_extensions;
201  protecting_extensions.Insert(extension);
202  ExtensionSet empty_set;
203
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/"));
211
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/"));
216}
217
218TEST_F(ExtensionSpecialStoragePolicyTest, AppWithUnlimitedStorage) {
219  scoped_refptr<Extension> extension(CreateUnlimitedApp());
220  policy_->GrantRightsForExtension(extension.get());
221  ExtensionSet protecting_extensions;
222  protecting_extensions.Insert(extension);
223  ExtensionSet empty_set;
224
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/")));
237
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/")));
246}
247
248TEST_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());
255  policy_->GrantRightsForExtension(protected_app.get());
256  policy_->GrantRightsForExtension(unlimited_app.get());
257
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()));
263}
264
265TEST_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());
270
271  EXPECT_FALSE(policy_->HasIsolatedStorage(kHttpUrl));
272  EXPECT_FALSE(policy_->HasIsolatedStorage(kExtensionUrl));
273  EXPECT_TRUE(policy_->HasIsolatedStorage(app->url()));
274}
275
276TEST_F(ExtensionSpecialStoragePolicyTest, OverlappingApps) {
277  scoped_refptr<Extension> protected_app(CreateProtectedApp());
278  scoped_refptr<Extension> unlimited_app(CreateUnlimitedApp());
279  policy_->GrantRightsForExtension(protected_app.get());
280  policy_->GrantRightsForExtension(unlimited_app.get());
281  ExtensionSet protecting_extensions;
282  ExtensionSet empty_set;
283  protecting_extensions.Insert(protected_app);
284  protecting_extensions.Insert(unlimited_app);
285
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/")));
297
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/"));
306
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/"));
311}
312
313TEST_F(ExtensionSpecialStoragePolicyTest, HasSessionOnlyOrigins) {
314  base::MessageLoop message_loop;
315  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
316
317  TestingProfile profile;
318  CookieSettings* cookie_settings =
319      CookieSettings::Factory::GetForProfile(&profile).get();
320  policy_ = new ExtensionSpecialStoragePolicy(cookie_settings);
321
322  EXPECT_FALSE(policy_->HasSessionOnlyOrigins());
323
324  // The default setting can be session-only.
325  cookie_settings->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
326  EXPECT_TRUE(policy_->HasSessionOnlyOrigins());
327
328  cookie_settings->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW);
329  EXPECT_FALSE(policy_->HasSessionOnlyOrigins());
330
331  // Or the session-onlyness can affect individual origins.
332  ContentSettingsPattern pattern =
333      ContentSettingsPattern::FromString("pattern.com");
334
335  cookie_settings->SetCookieSetting(pattern,
336                                    ContentSettingsPattern::Wildcard(),
337                                    CONTENT_SETTING_SESSION_ONLY);
338
339  EXPECT_TRUE(policy_->HasSessionOnlyOrigins());
340
341  // Clearing an origin-specific rule.
342  cookie_settings->ResetCookieSetting(pattern,
343                                      ContentSettingsPattern::Wildcard());
344
345  EXPECT_FALSE(policy_->HasSessionOnlyOrigins());
346}
347
348TEST_F(ExtensionSpecialStoragePolicyTest, NotificationTest) {
349  base::MessageLoop message_loop;
350  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
351  content::TestBrowserThread io_thread(BrowserThread::IO, &message_loop);
352
353  PolicyChangeObserver observer;
354  policy_->AddObserver(&observer);
355
356  scoped_refptr<Extension> apps[] = {
357    CreateProtectedApp(),
358    CreateUnlimitedApp(),
359  };
360
361  int change_flags[] = {
362    SpecialStoragePolicy::STORAGE_PROTECTED,
363
364    SpecialStoragePolicy::STORAGE_PROTECTED |
365    SpecialStoragePolicy::STORAGE_UNLIMITED,
366  };
367
368  ASSERT_EQ(arraysize(apps), arraysize(change_flags));
369  for (size_t i = 0; i < arraysize(apps); ++i) {
370    SCOPED_TRACE(testing::Message() << "i: " << i);
371    observer.ExpectGrant(apps[i]->id(), change_flags[i]);
372    policy_->GrantRightsForExtension(apps[i].get());
373    message_loop.RunUntilIdle();
374    EXPECT_TRUE(observer.IsCompleted());
375  }
376
377  for (size_t i = 0; i < arraysize(apps); ++i) {
378    SCOPED_TRACE(testing::Message() << "i: " << i);
379    policy_->GrantRightsForExtension(apps[i].get());
380    message_loop.RunUntilIdle();
381    EXPECT_TRUE(observer.IsCompleted());
382  }
383
384  for (size_t i = 0; i < arraysize(apps); ++i) {
385    SCOPED_TRACE(testing::Message() << "i: " << i);
386    observer.ExpectRevoke(apps[i]->id(), change_flags[i]);
387    policy_->RevokeRightsForExtension(apps[i].get());
388    message_loop.RunUntilIdle();
389    EXPECT_TRUE(observer.IsCompleted());
390  }
391
392  for (size_t i = 0; i < arraysize(apps); ++i) {
393    SCOPED_TRACE(testing::Message() << "i: " << i);
394    policy_->RevokeRightsForExtension(apps[i].get());
395    message_loop.RunUntilIdle();
396    EXPECT_TRUE(observer.IsCompleted());
397  }
398
399  observer.ExpectClear();
400  policy_->RevokeRightsForAllExtensions();
401  message_loop.RunUntilIdle();
402  EXPECT_TRUE(observer.IsCompleted());
403
404  policy_->RemoveObserver(&observer);
405}
406