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