diff options
author | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-11 17:54:59 +0000 |
---|---|---|
committer | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-11 17:54:59 +0000 |
commit | 8a87a533efa7ac622a839499ada717f35f14dda2 (patch) | |
tree | 1fe7265c6ab1af6a488240ad291c6c66be8df3f4 /chrome | |
parent | ba0b53cfe7abf74b8c3d667a52c666350b757035 (diff) | |
download | chromium_src-8a87a533efa7ac622a839499ada717f35f14dda2.zip chromium_src-8a87a533efa7ac622a839499ada717f35f14dda2.tar.gz chromium_src-8a87a533efa7ac622a839499ada717f35f14dda2.tar.bz2 |
Extensions installed by policy overrun previously installed extensions.
BUG=86519
TEST=Extensions tests, should all work as before. The test described in the bug should now work as expected.
Review URL: http://codereview.chromium.org/7605001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96420 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
5 files changed, 178 insertions, 23 deletions
diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc index cace228..cd018a42 100644 --- a/chrome/browser/extensions/extension_management_browsertest.cc +++ b/chrome/browser/extensions/extension_management_browsertest.cc @@ -442,6 +442,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) { << "Uninstalling non-external extension should not set kill bit."; } +namespace { + +const char* kForceInstallNotEmptyHelp = + "A policy may already be controlling the list of force-installed " + "extensions. Please remove all policy settings from your computer " + "before running tests. E.g. from /etc/chromium/policies Linux or " + "from the registry on Windows, etc."; + +} + // See http://crbug.com/57378 for flakiness details. IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { ExtensionService* service = browser()->profile()->GetExtensionService(); @@ -466,11 +476,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { PrefService* prefs = browser()->profile()->GetPrefs(); const ListValue* forcelist = prefs->GetList(prefs::kExtensionInstallForceList); - ASSERT_TRUE(forcelist->empty()) - << "A policy may already be controlling the list of force-installed " - << "extensions. Please remove all policy settings from your computer " - << "before running tests. E.g. from /etc/chromium/policies Linux or " - << "from the registry on Windows, etc."; + ASSERT_TRUE(forcelist->empty()) << kForceInstallNotEmptyHelp; { // Set the policy as a user preference and fire notification observers. @@ -516,3 +522,100 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { for (i = extensions->begin(); i != extensions->end(); ++i) EXPECT_NE(kExtensionId, (*i)->id()); } + +IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, PolicyOverridesUserInstall) { + ExtensionService* service = browser()->profile()->GetExtensionService(); + const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf"; + service->updater()->set_blacklist_checks_enabled(false); + const size_t size_before = service->extensions()->size(); + FilePath basedir = test_data_dir_.AppendASCII("autoupdate"); + ASSERT_TRUE(service->disabled_extensions()->empty()); + + // Note: This interceptor gets requests on the IO thread. + scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor()); + URLFetcher::enable_interception_for_tests(true); + + interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest", + basedir.AppendASCII("manifest_v2.xml")); + interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx", + basedir.AppendASCII("v2.crx")); + + // Check that the policy is initially empty. + PrefService* prefs = browser()->profile()->GetPrefs(); + const ListValue* forcelist = + prefs->GetList(prefs::kExtensionInstallForceList); + ASSERT_TRUE(forcelist->empty()) << kForceInstallNotEmptyHelp; + + // User install of the extension. + ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1)); + const ExtensionList* extensions = service->extensions(); + ASSERT_EQ(size_before + 1, extensions->size()); + const Extension* extension = extensions->at(size_before); + ASSERT_EQ(kExtensionId, extension->id()); + EXPECT_EQ(Extension::INTERNAL, extension->location()); + EXPECT_TRUE(service->IsExtensionEnabled(kExtensionId)); + + // Setup the force install policy. It should override the location. + { + ListPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList); + ListValue* forcelist = pref_update.Get(); + ASSERT_TRUE(forcelist->empty()); + forcelist->Append(Value::CreateStringValue( + std::string(kExtensionId) + ";http://localhost/autoupdate/manifest")); + } + ASSERT_TRUE(WaitForExtensionInstall()); + extensions = service->extensions(); + ASSERT_EQ(size_before + 1, extensions->size()); + extension = extensions->at(size_before); + ASSERT_EQ(kExtensionId, extension->id()); + EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, extension->location()); + EXPECT_TRUE(service->IsExtensionEnabled(kExtensionId)); + + // Remove the policy, and verify that the extension was uninstalled. + // TODO(joaodasilva): it would be nicer if the extension was kept instead, + // and reverted location to INTERNAL or whatever it was before the policy + // was applied. + { + ListPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList); + ListValue* forcelist = pref_update.Get(); + ASSERT_TRUE(!forcelist->empty()); + forcelist->Clear(); + } + extensions = service->extensions(); + ASSERT_EQ(size_before, extensions->size()); + extension = service->GetExtensionById(kExtensionId, true); + EXPECT_TRUE(extension == NULL); + + // User install again, but have it disabled too before setting the policy. + ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1)); + extensions = service->extensions(); + ASSERT_EQ(size_before + 1, extensions->size()); + extension = extensions->at(size_before); + ASSERT_EQ(kExtensionId, extension->id()); + EXPECT_EQ(Extension::INTERNAL, extension->location()); + EXPECT_TRUE(service->IsExtensionEnabled(kExtensionId)); + EXPECT_TRUE(service->disabled_extensions()->empty()); + + service->DisableExtension(kExtensionId); + EXPECT_EQ(1u, service->disabled_extensions()->size()); + EXPECT_EQ(kExtensionId, service->disabled_extensions()->at(0)->id()); + EXPECT_FALSE(service->IsExtensionEnabled(kExtensionId)); + + // Install the policy again. It should overwrite the extension's location, + // and force enable it too. + { + ListPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList); + ListValue* forcelist = pref_update.Get(); + ASSERT_TRUE(forcelist->empty()); + forcelist->Append(Value::CreateStringValue( + std::string(kExtensionId) + ";http://localhost/autoupdate/manifest")); + } + ASSERT_TRUE(WaitForExtensionInstall()); + extensions = service->extensions(); + ASSERT_EQ(size_before + 1, extensions->size()); + extension = extensions->at(size_before); + ASSERT_EQ(kExtensionId, extension->id()); + EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, extension->location()); + EXPECT_TRUE(service->IsExtensionEnabled(kExtensionId)); + EXPECT_TRUE(service->disabled_extensions()->empty()); +} diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index c729867..b49f5bd 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -415,9 +415,14 @@ void ExtensionService::OnExternalExtensionUpdateUrlFound( CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CHECK(Extension::IdIsValid(id)); - if (GetExtensionById(id, true)) { - // Already installed. Do not change the update URL that the extension set. - return; + const Extension* extension = GetExtensionById(id, true); + if (extension) { + // Already installed. Skip this install if the current location has + // higher priority than |location|. + Extension::Location current = extension->location(); + if (current == Extension::GetHigherPriorityLocation(current, location)) + return; + // Otherwise, overwrite the current installation. } pending_extension_manager()->AddFromExternalUpdateUrl( id, update_url, location); @@ -2163,7 +2168,11 @@ void ExtensionService::OnExtensionInstalled( // Ensure extension is deleted unless we transfer ownership. scoped_refptr<const Extension> scoped_extension(extension); const std::string& id = extension->id(); - bool initial_enable = !extension_prefs_->IsExtensionDisabled(id); + // Extensions installed by policy can't be disabled. So even if a previous + // installation disabled the extension, make sure it is now enabled. + bool initial_enable = + !extension_prefs_->IsExtensionDisabled(id) || + !Extension::UserMayDisable(extension->location()); PendingExtensionInfo pending_extension_info; if (pending_extension_manager()->GetById(id, &pending_extension_info)) { pending_extension_manager()->Remove(id); diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index edb7772..5111f31 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -3704,6 +3704,33 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataNotInstalled) { // TODO(akalin): Figure out a way to test |info.ShouldAllowInstall()|. } +TEST_F(ExtensionServiceTest, HigherPriorityInstall) { + InitializeEmptyExtensionService(); + + FilePath path = data_dir_.AppendASCII("good.crx"); + InstallCrx(path, true); + ValidatePrefKeyCount(1u); + ValidateIntegerPref(good_crx, "state", Extension::ENABLED); + ValidateIntegerPref(good_crx, "location", Extension::INTERNAL); + + PendingExtensionManager* pending = service_->pending_extension_manager(); + EXPECT_FALSE(pending->IsIdPending(kGoodId)); + + // Skip install when the location is the same. + service_->OnExternalExtensionUpdateUrlFound(kGoodId, GURL(kGoodUpdateURL), + Extension::INTERNAL); + EXPECT_FALSE(pending->IsIdPending(kGoodId)); + // Force install when the location has higher priority. + service_->OnExternalExtensionUpdateUrlFound(kGoodId, GURL(kGoodUpdateURL), + Extension::EXTERNAL_POLICY_DOWNLOAD); + EXPECT_TRUE(pending->IsIdPending(kGoodId)); + pending->Remove(kGoodId); + // Skip install when the location has lower priority. + service_->OnExternalExtensionUpdateUrlFound(kGoodId, GURL(kGoodUpdateURL), + Extension::INTERNAL); + EXPECT_FALSE(pending->IsIdPending(kGoodId)); +} + // Test that when multiple sources try to install an extension, // we consistently choose the right one. To make tests easy to read, // methods that fake requests to install crx files in several ways diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc index ae62dca..32679af 100644 --- a/chrome/browser/extensions/extension_updater.cc +++ b/chrome/browser/extensions/extension_updater.cc @@ -1000,14 +1000,9 @@ void ExtensionUpdater::CheckNow() { NotifyStarted(); ManifestFetchesBuilder fetches_builder(service_, extension_prefs_); - const ExtensionList* extensions = service_->extensions(); - for (ExtensionList::const_iterator iter = extensions->begin(); - iter != extensions->end(); ++iter) { - fetches_builder.AddExtension(**iter); - } - const PendingExtensionManager* pending_extension_manager = service_->pending_extension_manager(); + std::set<std::string> pending_ids; PendingExtensionManager::const_iterator iter; for (iter = pending_extension_manager->begin(); @@ -1016,8 +1011,21 @@ void ExtensionUpdater::CheckNow() { // class PendingExtensionManager. Extension::Location location = iter->second.install_source(); if (location != Extension::EXTERNAL_PREF && - location != Extension::EXTERNAL_REGISTRY) + location != Extension::EXTERNAL_REGISTRY) { fetches_builder.AddPendingExtension(iter->first, iter->second); + pending_ids.insert(iter->first); + } + } + + const ExtensionList* extensions = service_->extensions(); + for (ExtensionList::const_iterator iter = extensions->begin(); + iter != extensions->end(); ++iter) { + // An extension might be overwritten by policy, and have its update url + // changed. Make sure existing extensions aren't fetched again, if a + // pending fetch for an extension with the same id already exists. + if (!ContainsKey(pending_ids, (*iter)->id())) { + fetches_builder.AddExtension(**iter); + } } fetches_builder.ReportStats(); diff --git a/chrome/browser/extensions/pending_extension_manager.cc b/chrome/browser/extensions/pending_extension_manager.cc index d4446a9..c978415 100644 --- a/chrome/browser/extensions/pending_extension_manager.cc +++ b/chrome/browser/extensions/pending_extension_manager.cc @@ -74,13 +74,21 @@ void PendingExtensionManager::AddFromExternalUpdateUrl( const bool kIsFromSync = false; const bool kInstallSilently = true; - if (service_.IsExternalExtensionUninstalled(id)) - return; - - if (service_.GetInstalledExtension(id)) { - LOG(DFATAL) << "Trying to add extension " << id - << " by external update, but it is already installed."; - return; + const Extension* extension = service_.GetInstalledExtension(id); + if (extension && + location == Extension::GetHigherPriorityLocation(location, + extension->location())) { + // If the new location has higher priority than the location of an existing + // extension, let the update process overwrite the existing extension. + } else { + if (service_.IsExternalExtensionUninstalled(id)) { + return; + } + if (extension) { + LOG(DFATAL) << "Trying to add extension " << id + << " by external update, but it is already installed."; + return; + } } AddExtensionImpl(id, update_url, &AlwaysInstall, |