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/test/base/testing_profile.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 "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"
     18 
     19 using content::BrowserThread;
     20 using extensions::Extension;
     21 using extensions::ExtensionSet;
     22 using extensions::Manifest;
     23 using storage::SpecialStoragePolicy;
     24 
     25 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy;
     26 
     27 namespace keys = extensions::manifest_keys;
     28 
     29 class ExtensionSpecialStoragePolicyTest : public testing::Test {
     30  protected:
     31   class PolicyChangeObserver : public SpecialStoragePolicy::Observer {
     32    public:
     33     PolicyChangeObserver()
     34         : expected_type_(NOTIFICATION_TYPE_NONE),
     35           expected_change_flags_(0) {
     36     }
     37 
     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;
     44     }
     45 
     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;
     52     }
     53 
     54     virtual void OnCleared() OVERRIDE {
     55       EXPECT_EQ(expected_type_, NOTIFICATION_TYPE_CLEAR);
     56       expected_type_ = NOTIFICATION_TYPE_NONE;
     57     }
     58 
     59     void ExpectGrant(const std::string& extension_id,
     60                      int change_flags) {
     61       expected_type_ = NOTIFICATION_TYPE_GRANT;
     62       expected_origin_ = Extension::GetBaseURLFromExtensionId(extension_id);
     63       expected_change_flags_ = change_flags;
     64     }
     65 
     66     void ExpectRevoke(const std::string& extension_id,
     67                       int change_flags) {
     68       expected_type_ = NOTIFICATION_TYPE_REVOKE;
     69       expected_origin_ = Extension::GetBaseURLFromExtensionId(extension_id);
     70       expected_change_flags_ = change_flags;
     71     }
     72 
     73     void ExpectClear() {
     74       expected_type_ = NOTIFICATION_TYPE_CLEAR;
     75     }
     76 
     77     bool IsCompleted() {
     78       return expected_type_ == NOTIFICATION_TYPE_NONE;
     79     }
     80 
     81    private:
     82     enum {
     83       NOTIFICATION_TYPE_NONE,
     84       NOTIFICATION_TYPE_GRANT,
     85       NOTIFICATION_TYPE_REVOKE,
     86       NOTIFICATION_TYPE_CLEAR,
     87     } expected_type_;
     88 
     89     GURL expected_origin_;
     90     int expected_change_flags_;
     91 
     92     DISALLOW_COPY_AND_ASSIGN(PolicyChangeObserver);
     93   };
     94 
     95   virtual void SetUp() OVERRIDE {
     96     policy_ = new ExtensionSpecialStoragePolicy(NULL);
     97   }
     98 
     99   scoped_refptr<Extension> CreateProtectedApp() {
    100 #if defined(OS_WIN)
    101     base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
    102 #elif defined(OS_POSIX)
    103     base::FilePath path(FILE_PATH_LITERAL("/foo"));
    104 #endif
    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);
    113     std::string error;
    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;
    119   }
    120 
    121   scoped_refptr<Extension> CreateUnlimitedApp() {
    122 #if defined(OS_WIN)
    123     base::FilePath path(FILE_PATH_LITERAL("c:\\bar"));
    124 #elif defined(OS_POSIX)
    125     base::FilePath path(FILE_PATH_LITERAL("/bar"));
    126 #endif
    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);
    138     std::string error;
    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;
    144   }
    145 
    146   scoped_refptr<Extension> CreateRegularApp() {
    147 #if defined(OS_WIN)
    148     base::FilePath path(FILE_PATH_LITERAL("c:\\app"));
    149 #elif defined(OS_POSIX)
    150     base::FilePath path(FILE_PATH_LITERAL("/app"));
    151 #endif
    152     base::DictionaryValue manifest;
    153     manifest.SetString(keys::kName, "App");
    154     manifest.SetString(keys::kVersion, "1");
    155     manifest.SetString(keys::kPlatformAppBackgroundPage, "background.html");
    156     std::string error;
    157     scoped_refptr<Extension> app = Extension::Create(
    158         path, Manifest::INVALID_LOCATION, manifest,
    159         Extension::NO_FLAGS, &error);
    160     EXPECT_TRUE(app.get()) << error;
    161     return app;
    162   }
    163 
    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
    166   // protected.
    167   void ExpectProtectedBy(const ExtensionSet& expected_extensions,
    168                          const GURL& url) {
    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 "
    175           << (*it)->id();
    176     }
    177   }
    178 
    179   scoped_refptr<ExtensionSpecialStoragePolicy> policy_;
    180 };
    181 
    182 TEST_F(ExtensionSpecialStoragePolicyTest, EmptyPolicy) {
    183   const GURL kHttpUrl("http://foo");
    184   const GURL kExtensionUrl("chrome-extension://bar");
    185   scoped_refptr<Extension> app(CreateRegularApp());
    186 
    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);
    193 
    194   // This one is just based on the scheme.
    195   EXPECT_TRUE(policy_->IsStorageProtected(kExtensionUrl));
    196   EXPECT_TRUE(policy_->IsStorageProtected(app->url()));
    197 }
    198 
    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;
    205 
    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/"));
    213 
    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/"));
    218 }
    219 
    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;
    226 
    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/")));
    239 
    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/")));
    248 }
    249 
    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());
    259 
    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()));
    265 }
    266 
    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());
    272 
    273   EXPECT_FALSE(policy_->HasIsolatedStorage(kHttpUrl));
    274   EXPECT_FALSE(policy_->HasIsolatedStorage(kExtensionUrl));
    275   EXPECT_TRUE(policy_->HasIsolatedStorage(app->url()));
    276 }
    277 
    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);
    287 
    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/")));
    299 
    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/"));
    308 
    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/"));
    313 }
    314 
    315 TEST_F(ExtensionSpecialStoragePolicyTest, HasSessionOnlyOrigins) {
    316   base::MessageLoop message_loop;
    317   content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
    318 
    319   TestingProfile profile;
    320   CookieSettings* cookie_settings =
    321       CookieSettings::Factory::GetForProfile(&profile).get();
    322   policy_ = new ExtensionSpecialStoragePolicy(cookie_settings);
    323 
    324   EXPECT_FALSE(policy_->HasSessionOnlyOrigins());
    325 
    326   // The default setting can be session-only.
    327   cookie_settings->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
    328   EXPECT_TRUE(policy_->HasSessionOnlyOrigins());
    329 
    330   cookie_settings->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW);
    331   EXPECT_FALSE(policy_->HasSessionOnlyOrigins());
    332 
    333   // Or the session-onlyness can affect individual origins.
    334   ContentSettingsPattern pattern =
    335       ContentSettingsPattern::FromString("pattern.com");
    336 
    337   cookie_settings->SetCookieSetting(pattern,
    338                                     ContentSettingsPattern::Wildcard(),
    339                                     CONTENT_SETTING_SESSION_ONLY);
    340 
    341   EXPECT_TRUE(policy_->HasSessionOnlyOrigins());
    342 
    343   // Clearing an origin-specific rule.
    344   cookie_settings->ResetCookieSetting(pattern,
    345                                       ContentSettingsPattern::Wildcard());
    346 
    347   EXPECT_FALSE(policy_->HasSessionOnlyOrigins());
    348 }
    349 
    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);
    354 
    355   PolicyChangeObserver observer;
    356   policy_->AddObserver(&observer);
    357 
    358   scoped_refptr<Extension> apps[] = {
    359     CreateProtectedApp(),
    360     CreateUnlimitedApp(),
    361   };
    362 
    363   int change_flags[] = {
    364     SpecialStoragePolicy::STORAGE_PROTECTED,
    365 
    366     SpecialStoragePolicy::STORAGE_PROTECTED |
    367     SpecialStoragePolicy::STORAGE_UNLIMITED,
    368   };
    369 
    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());
    377   }
    378 
    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());
    384   }
    385 
    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());
    392   }
    393 
    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());
    399   }
    400 
    401   observer.ExpectClear();
    402   policy_->RevokeRightsForAllExtensions();
    403   message_loop.RunUntilIdle();
    404   EXPECT_TRUE(observer.IsCompleted());
    405 
    406   policy_->RemoveObserver(&observer);
    407 }
    408