1 // Copyright (c) 2011 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/memory/ref_counted.h" 6 #include "base/stl_util-inl.h" 7 #include "chrome/browser/extensions/autoupdate_interceptor.h" 8 #include "chrome/browser/extensions/extension_browsertest.h" 9 #include "chrome/browser/extensions/extension_host.h" 10 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/extension_test_message_listener.h" 12 #include "chrome/browser/extensions/extension_updater.h" 13 #include "chrome/browser/prefs/pref_service.h" 14 #include "chrome/browser/prefs/scoped_user_pref_update.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/ui/browser.h" 17 #include "chrome/common/pref_names.h" 18 #include "chrome/common/url_constants.h" 19 #include "chrome/test/ui_test_utils.h" 20 #include "content/browser/renderer_host/render_view_host.h" 21 22 class ExtensionManagementTest : public ExtensionBrowserTest { 23 protected: 24 // Helper method that returns whether the extension is at the given version. 25 // This calls version(), which must be defined in the extension's bg page, 26 // as well as asking the extension itself. 27 // 28 // Note that 'version' here means something different than the version field 29 // in the extension's manifest. We use the version as reported by the 30 // background page to test how overinstalling crx files with the same 31 // manifest version works. 32 bool IsExtensionAtVersion(const Extension* extension, 33 const std::string& expected_version) { 34 // Test that the extension's version from the manifest and reported by the 35 // background page is correct. This is to ensure that the processes are in 36 // sync with the Extension. 37 ExtensionProcessManager* manager = browser()->profile()-> 38 GetExtensionProcessManager(); 39 ExtensionHost* ext_host = manager->GetBackgroundHostForExtension(extension); 40 EXPECT_TRUE(ext_host); 41 if (!ext_host) 42 return false; 43 44 std::string version_from_bg; 45 bool exec = ui_test_utils::ExecuteJavaScriptAndExtractString( 46 ext_host->render_view_host(), L"", L"version()", &version_from_bg); 47 EXPECT_TRUE(exec); 48 if (!exec) 49 return false; 50 51 if (version_from_bg != expected_version || 52 extension->VersionString() != expected_version) 53 return false; 54 return true; 55 } 56 57 // Helper method that installs a low permission extension then updates 58 // to the second version requiring increased permissions. Returns whether 59 // the operation was completed successfully. 60 bool InstallAndUpdateIncreasingPermissionsExtension() { 61 ExtensionService* service = browser()->profile()->GetExtensionService(); 62 size_t size_before = service->extensions()->size(); 63 64 // Install the initial version, which should happen just fine. 65 if (!InstallExtension( 66 test_data_dir_.AppendASCII("permissions-low-v1.crx"), 1)) 67 return false; 68 69 // Upgrade to a version that wants more permissions. We should disable the 70 // extension and prompt the user to reenable. 71 if (service->extensions()->size() != size_before + 1) 72 return false; 73 if (!UpdateExtension( 74 service->extensions()->at(size_before)->id(), 75 test_data_dir_.AppendASCII("permissions-high-v2.crx"), -1)) 76 return false; 77 EXPECT_EQ(size_before, service->extensions()->size()); 78 if (service->disabled_extensions()->size() != 1u) 79 return false; 80 return true; 81 } 82 }; 83 84 // Tests that installing the same version overwrites. 85 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) { 86 ExtensionService* service = browser()->profile()->GetExtensionService(); 87 const size_t size_before = service->extensions()->size(); 88 ASSERT_TRUE(InstallExtension( 89 test_data_dir_.AppendASCII("install/install.crx"), 1)); 90 FilePath old_path = service->extensions()->back()->path(); 91 92 // Install an extension with the same version. The previous install should be 93 // overwritten. 94 ASSERT_TRUE(InstallExtension( 95 test_data_dir_.AppendASCII("install/install_same_version.crx"), 0)); 96 FilePath new_path = service->extensions()->back()->path(); 97 98 EXPECT_FALSE(IsExtensionAtVersion(service->extensions()->at(size_before), 99 "1.0")); 100 EXPECT_NE(old_path.value(), new_path.value()); 101 } 102 103 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) { 104 ExtensionService* service = browser()->profile()->GetExtensionService(); 105 const size_t size_before = service->extensions()->size(); 106 ASSERT_TRUE(InstallExtension( 107 test_data_dir_.AppendASCII("install/install.crx"), 1)); 108 ASSERT_TRUE(InstallExtension( 109 test_data_dir_.AppendASCII("install/install_older_version.crx"), 0)); 110 EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(size_before), 111 "1.0")); 112 } 113 114 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) { 115 ExtensionService* service = browser()->profile()->GetExtensionService(); 116 const size_t size_before = service->extensions()->size(); 117 ASSERT_TRUE(InstallExtension( 118 test_data_dir_.AppendASCII("install/install.crx"), 1)); 119 120 // Cancel this install. 121 StartInstallButCancel(test_data_dir_.AppendASCII("install/install_v2.crx")); 122 EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(size_before), 123 "1.0")); 124 } 125 126 // Tests that installing and uninstalling extensions don't crash with an 127 // incognito window open. 128 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) { 129 // Open an incognito window to the extensions management page. We just 130 // want to make sure that we don't crash while playing with extensions when 131 // this guy is around. 132 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), 133 GURL(chrome::kChromeUIExtensionsURL)); 134 135 ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 1)); 136 UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf"); 137 } 138 139 // Tests the process of updating an extension to one that requires higher 140 // permissions. 141 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) { 142 ExtensionService* service = browser()->profile()->GetExtensionService(); 143 ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension()); 144 const size_t size_before = service->extensions()->size(); 145 146 // Now try reenabling it. 147 service->EnableExtension(service->disabled_extensions()->at(0)->id()); 148 EXPECT_EQ(size_before + 1, service->extensions()->size()); 149 EXPECT_EQ(0u, service->disabled_extensions()->size()); 150 } 151 152 // Tests that we can uninstall a disabled extension. 153 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) { 154 ExtensionService* service = browser()->profile()->GetExtensionService(); 155 ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension()); 156 const size_t size_before = service->extensions()->size(); 157 158 // Now try uninstalling it. 159 UninstallExtension(service->disabled_extensions()->at(0)->id()); 160 EXPECT_EQ(size_before, service->extensions()->size()); 161 EXPECT_EQ(0u, service->disabled_extensions()->size()); 162 } 163 164 // Tests that disabling and re-enabling an extension works. 165 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) { 166 ExtensionProcessManager* manager = browser()->profile()-> 167 GetExtensionProcessManager(); 168 ExtensionService* service = browser()->profile()->GetExtensionService(); 169 const size_t size_before = service->extensions()->size(); 170 171 // Load an extension, expect the background page to be available. 172 ASSERT_TRUE(LoadExtension( 173 test_data_dir_.AppendASCII("good").AppendASCII("Extensions") 174 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa") 175 .AppendASCII("1.0"))); 176 ASSERT_EQ(size_before + 1, service->extensions()->size()); 177 EXPECT_EQ(0u, service->disabled_extensions()->size()); 178 const Extension* extension = service->extensions()->at(size_before); 179 EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension)); 180 181 // After disabling, the background page should go away. 182 service->DisableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa"); 183 EXPECT_EQ(size_before, service->extensions()->size()); 184 EXPECT_EQ(1u, service->disabled_extensions()->size()); 185 EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension)); 186 187 // And bring it back. 188 service->EnableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa"); 189 EXPECT_EQ(size_before + 1, service->extensions()->size()); 190 EXPECT_EQ(0u, service->disabled_extensions()->size()); 191 EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension)); 192 } 193 194 // Used for testing notifications sent during extension updates. 195 class NotificationListener : public NotificationObserver { 196 public: 197 NotificationListener() : started_(false), finished_(false) { 198 NotificationType::Type types[] = { 199 NotificationType::EXTENSION_UPDATING_STARTED, 200 NotificationType::EXTENSION_UPDATING_FINISHED, 201 NotificationType::EXTENSION_UPDATE_FOUND 202 }; 203 for (size_t i = 0; i < arraysize(types); i++) { 204 registrar_.Add(this, types[i], NotificationService::AllSources()); 205 } 206 } 207 ~NotificationListener() {} 208 209 bool started() { return started_; } 210 211 bool finished() { return finished_; } 212 213 const std::set<std::string>& updates() { return updates_; } 214 215 void Reset() { 216 started_ = false; 217 finished_ = false; 218 updates_.clear(); 219 } 220 221 // Implements NotificationObserver interface. 222 virtual void Observe(NotificationType type, 223 const NotificationSource& source, 224 const NotificationDetails& details) { 225 switch (type.value) { 226 case NotificationType::EXTENSION_UPDATING_STARTED: { 227 DCHECK(!started_); 228 started_ = true; 229 break; 230 } 231 case NotificationType::EXTENSION_UPDATING_FINISHED: { 232 DCHECK(!finished_); 233 finished_ = true; 234 break; 235 } 236 case NotificationType::EXTENSION_UPDATE_FOUND: { 237 const std::string* id = Details<const std::string>(details).ptr(); 238 updates_.insert(*id); 239 break; 240 } 241 default: 242 NOTREACHED(); 243 } 244 } 245 246 private: 247 NotificationRegistrar registrar_; 248 249 // Did we see EXTENSION_UPDATING_STARTED? 250 bool started_; 251 252 // Did we see EXTENSION_UPDATING_FINISHED? 253 bool finished_; 254 255 // The set of extension id's we've seen via EXTENSION_UPDATE_FOUND. 256 std::set<std::string> updates_; 257 }; 258 259 // Tests extension autoupdate. 260 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) { 261 NotificationListener notification_listener; 262 FilePath basedir = test_data_dir_.AppendASCII("autoupdate"); 263 // Note: This interceptor gets requests on the IO thread. 264 scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor()); 265 URLFetcher::enable_interception_for_tests(true); 266 267 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest", 268 basedir.AppendASCII("manifest_v2.xml")); 269 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx", 270 basedir.AppendASCII("v2.crx")); 271 272 // Install version 1 of the extension. 273 ExtensionTestMessageListener listener1("v1 installed", false); 274 ExtensionService* service = browser()->profile()->GetExtensionService(); 275 const size_t size_before = service->extensions()->size(); 276 ASSERT_TRUE(service->disabled_extensions()->empty()); 277 ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1)); 278 listener1.WaitUntilSatisfied(); 279 const ExtensionList* extensions = service->extensions(); 280 ASSERT_EQ(size_before + 1, extensions->size()); 281 ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", 282 extensions->at(size_before)->id()); 283 ASSERT_EQ("1.0", extensions->at(size_before)->VersionString()); 284 285 // We don't want autoupdate blacklist checks. 286 service->updater()->set_blacklist_checks_enabled(false); 287 288 // Run autoupdate and make sure version 2 of the extension was installed. 289 ExtensionTestMessageListener listener2("v2 installed", false); 290 service->updater()->CheckNow(); 291 ASSERT_TRUE(WaitForExtensionInstall()); 292 listener2.WaitUntilSatisfied(); 293 extensions = service->extensions(); 294 ASSERT_EQ(size_before + 1, extensions->size()); 295 ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", 296 extensions->at(size_before)->id()); 297 ASSERT_EQ("2.0", extensions->at(size_before)->VersionString()); 298 ASSERT_TRUE(notification_listener.started()); 299 ASSERT_TRUE(notification_listener.finished()); 300 ASSERT_TRUE(ContainsKey(notification_listener.updates(), 301 "ogjcoiohnmldgjemafoockdghcjciccf")); 302 notification_listener.Reset(); 303 304 // Now try doing an update to version 3, which has been incorrectly 305 // signed. This should fail. 306 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest", 307 basedir.AppendASCII("manifest_v3.xml")); 308 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v3.crx", 309 basedir.AppendASCII("v3.crx")); 310 311 service->updater()->CheckNow(); 312 ASSERT_TRUE(WaitForExtensionInstallError()); 313 ASSERT_TRUE(notification_listener.started()); 314 ASSERT_TRUE(notification_listener.finished()); 315 ASSERT_TRUE(ContainsKey(notification_listener.updates(), 316 "ogjcoiohnmldgjemafoockdghcjciccf")); 317 318 // Make sure the extension state is the same as before. 319 extensions = service->extensions(); 320 ASSERT_EQ(size_before + 1, extensions->size()); 321 ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", 322 extensions->at(size_before)->id()); 323 ASSERT_EQ("2.0", extensions->at(size_before)->VersionString()); 324 } 325 326 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) { 327 ExtensionService* service = browser()->profile()->GetExtensionService(); 328 const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf"; 329 // We don't want autoupdate blacklist checks. 330 service->updater()->set_blacklist_checks_enabled(false); 331 332 FilePath basedir = test_data_dir_.AppendASCII("autoupdate"); 333 334 // Note: This interceptor gets requests on the IO thread. 335 scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor()); 336 URLFetcher::enable_interception_for_tests(true); 337 338 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest", 339 basedir.AppendASCII("manifest_v2.xml")); 340 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx", 341 basedir.AppendASCII("v2.crx")); 342 343 const size_t size_before = service->extensions()->size(); 344 ASSERT_TRUE(service->disabled_extensions()->empty()); 345 346 PendingExtensionManager* pending_extension_manager = 347 service->pending_extension_manager(); 348 349 // The code that reads external_extensions.json uses this method to inform 350 // the ExtensionService of an extension to download. Using the real code 351 // is race-prone, because instantating the ExtensionService starts a read 352 // of external_extensions.json before this test function starts. 353 354 pending_extension_manager->AddFromExternalUpdateUrl( 355 kExtensionId, GURL("http://localhost/autoupdate/manifest"), 356 Extension::EXTERNAL_PREF_DOWNLOAD); 357 358 // Run autoupdate and make sure version 2 of the extension was installed. 359 service->updater()->CheckNow(); 360 ASSERT_TRUE(WaitForExtensionInstall()); 361 const ExtensionList* extensions = service->extensions(); 362 ASSERT_EQ(size_before + 1, extensions->size()); 363 ASSERT_EQ(kExtensionId, extensions->at(size_before)->id()); 364 ASSERT_EQ("2.0", extensions->at(size_before)->VersionString()); 365 366 // Uninstalling the extension should set a pref that keeps the extension from 367 // being installed again the next time external_extensions.json is read. 368 369 UninstallExtension(kExtensionId); 370 371 ExtensionPrefs* extension_prefs = service->extension_prefs(); 372 EXPECT_TRUE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId)) 373 << "Uninstalling should set kill bit on externaly installed extension."; 374 375 // Try to install the extension again from an external source. It should fail 376 // because of the killbit. 377 pending_extension_manager->AddFromExternalUpdateUrl( 378 kExtensionId, GURL("http://localhost/autoupdate/manifest"), 379 Extension::EXTERNAL_PREF_DOWNLOAD); 380 EXPECT_FALSE(pending_extension_manager->IsIdPending(kExtensionId)) 381 << "External reinstall of a killed extension shouldn't work."; 382 EXPECT_TRUE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId)) 383 << "External reinstall of a killed extension should leave it killed."; 384 385 // Installing from non-external source. 386 ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1)); 387 388 EXPECT_FALSE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId)) 389 << "Reinstalling should clear the kill bit."; 390 391 // Uninstalling from a non-external source should not set the kill bit. 392 UninstallExtension(kExtensionId); 393 394 EXPECT_FALSE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId)) 395 << "Uninstalling non-external extension should not set kill bit."; 396 } 397 398 // See http://crbug.com/57378 for flakiness details. 399 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { 400 ExtensionService* service = browser()->profile()->GetExtensionService(); 401 const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf"; 402 // We don't want autoupdate blacklist checks. 403 service->updater()->set_blacklist_checks_enabled(false); 404 405 FilePath basedir = test_data_dir_.AppendASCII("autoupdate"); 406 407 // Note: This interceptor gets requests on the IO thread. 408 scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor()); 409 URLFetcher::enable_interception_for_tests(true); 410 411 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest", 412 basedir.AppendASCII("manifest_v2.xml")); 413 interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx", 414 basedir.AppendASCII("v2.crx")); 415 416 const size_t size_before = service->extensions()->size(); 417 ASSERT_TRUE(service->disabled_extensions()->empty()); 418 419 PrefService* prefs = browser()->profile()->GetPrefs(); 420 { 421 // Set the policy as a user preference and fire notification observers. 422 ListPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList); 423 ListValue* forcelist = pref_update.Get(); 424 ASSERT_TRUE(forcelist->empty()); 425 forcelist->Append(Value::CreateStringValue( 426 std::string(kExtensionId) + 427 ";http://localhost/autoupdate/manifest")); 428 } 429 430 // Check if the extension got installed. 431 ASSERT_TRUE(WaitForExtensionInstall()); 432 const ExtensionList* extensions = service->extensions(); 433 ASSERT_EQ(size_before + 1, extensions->size()); 434 ASSERT_EQ(kExtensionId, extensions->at(size_before)->id()); 435 EXPECT_EQ("2.0", extensions->at(size_before)->VersionString()); 436 EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, 437 extensions->at(size_before)->location()); 438 439 // Try to disable and unstall the extension which should fail. 440 service->DisableExtension(kExtensionId); 441 EXPECT_EQ(size_before + 1, service->extensions()->size()); 442 EXPECT_EQ(0u, service->disabled_extensions()->size()); 443 UninstallExtension(kExtensionId); 444 EXPECT_EQ(size_before + 1, service->extensions()->size()); 445 EXPECT_EQ(0u, service->disabled_extensions()->size()); 446 447 // Now try to disable it through the management api. 448 ExtensionTestMessageListener listener1("ready", false); 449 ASSERT_TRUE(LoadExtension( 450 test_data_dir_.AppendASCII("management/uninstall_extension"))); 451 ASSERT_TRUE(listener1.WaitUntilSatisfied()); 452 EXPECT_EQ(size_before + 2, service->extensions()->size()); 453 EXPECT_EQ(0u, service->disabled_extensions()->size()); 454 455 // Check that emptying the list triggers uninstall. 456 { 457 prefs->ClearPref(prefs::kExtensionInstallForceList); 458 } 459 EXPECT_EQ(size_before + 1, extensions->size()); 460 ExtensionList::const_iterator i; 461 for (i = extensions->begin(); i != extensions->end(); ++i) 462 EXPECT_NE(kExtensionId, (*i)->id()); 463 } 464