Home | History | Annotate | Download | only in extensions
      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/common/extensions/extension_manifest_constants.h"
     13 #include "chrome/common/extensions/manifest.h"
     14 #include "chrome/test/base/testing_profile.h"
     15 #include "content/public/test/test_browser_thread.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 using content::BrowserThread;
     19 using extensions::Extension;
     20 using extensions::Manifest;
     21 using quota::SpecialStoragePolicy;
     22 
     23 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy;
     24 
     25 namespace keys = extension_manifest_keys;
     26 
     27 class 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(Value::CreateStringValue("http://explicit/protected"));
    109     list->Append(Value::CreateStringValue("*://*.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(Value::CreateStringValue("unlimitedStorage"));
    131     manifest.Set(keys::kPermissions, list);
    132     list = new base::ListValue();
    133     list->Append(Value::CreateStringValue("http://explicit/unlimited"));
    134     list->Append(Value::CreateStringValue("*://*.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 
    180 TEST_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 
    197 TEST_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 
    218 TEST_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 
    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());
    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 
    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());
    270 
    271   EXPECT_FALSE(policy_->HasIsolatedStorage(kHttpUrl));
    272   EXPECT_FALSE(policy_->HasIsolatedStorage(kExtensionUrl));
    273   EXPECT_TRUE(policy_->HasIsolatedStorage(app->url()));
    274 }
    275 
    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());
    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 
    313 TEST_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 
    348 TEST_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