Home | History | Annotate | Download | only in management
      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/files/file_path.h"
      6 #include "base/files/scoped_temp_dir.h"
      7 #include "base/strings/string_util.h"
      8 #include "base/strings/stringprintf.h"
      9 #include "chrome/browser/extensions/api/management/management_api.h"
     10 #include "chrome/browser/extensions/api/management/management_api_constants.h"
     11 #include "chrome/browser/extensions/extension_browsertest.h"
     12 #include "chrome/browser/extensions/extension_function_test_utils.h"
     13 #include "chrome/browser/extensions/extension_service.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser.h"
     16 #include "content/public/browser/notification_service.h"
     17 #include "content/public/common/url_constants.h"
     18 #include "content/public/test/browser_test_utils.h"
     19 #include "content/public/test/test_utils.h"
     20 #include "extensions/browser/extension_host.h"
     21 #include "extensions/browser/extension_prefs.h"
     22 #include "extensions/browser/extension_system.h"
     23 #include "extensions/browser/notification_types.h"
     24 #include "extensions/common/test_util.h"
     25 #include "extensions/test/extension_test_message_listener.h"
     26 
     27 namespace keys = extension_management_api_constants;
     28 namespace util = extension_function_test_utils;
     29 
     30 namespace extensions {
     31 
     32 class ExtensionManagementApiBrowserTest : public ExtensionBrowserTest {
     33  protected:
     34   bool CrashEnabledExtension(const std::string& extension_id) {
     35     ExtensionHost* background_host =
     36         ExtensionSystem::Get(browser()->profile())->
     37             process_manager()->GetBackgroundHostForExtension(extension_id);
     38     if (!background_host)
     39       return false;
     40     content::CrashTab(background_host->host_contents());
     41     return true;
     42   }
     43 };
     44 
     45 // We test this here instead of in an ExtensionApiTest because normal extensions
     46 // are not allowed to call the install function.
     47 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest, InstallEvent) {
     48   ExtensionTestMessageListener listener1("ready", false);
     49   ASSERT_TRUE(LoadExtension(
     50       test_data_dir_.AppendASCII("management/install_event")));
     51   ASSERT_TRUE(listener1.WaitUntilSatisfied());
     52 
     53   ExtensionTestMessageListener listener2("got_event", false);
     54   ASSERT_TRUE(LoadExtension(
     55       test_data_dir_.AppendASCII("api_test/management/enabled_extension")));
     56   ASSERT_TRUE(listener2.WaitUntilSatisfied());
     57 }
     58 
     59 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest, LaunchApp) {
     60   ExtensionTestMessageListener listener1("app_launched", false);
     61   ExtensionTestMessageListener listener2("got_expected_error", false);
     62   ASSERT_TRUE(LoadExtension(
     63       test_data_dir_.AppendASCII("management/simple_extension")));
     64   ASSERT_TRUE(LoadExtension(
     65       test_data_dir_.AppendASCII("management/packaged_app")));
     66   ASSERT_TRUE(LoadExtension(
     67       test_data_dir_.AppendASCII("management/launch_app")));
     68   ASSERT_TRUE(listener1.WaitUntilSatisfied());
     69   ASSERT_TRUE(listener2.WaitUntilSatisfied());
     70 }
     71 
     72 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
     73                        LaunchAppFromBackground) {
     74   ExtensionTestMessageListener listener1("success", false);
     75   ASSERT_TRUE(LoadExtension(
     76       test_data_dir_.AppendASCII("management/packaged_app")));
     77   ASSERT_TRUE(LoadExtension(
     78       test_data_dir_.AppendASCII("management/launch_app_from_background")));
     79   ASSERT_TRUE(listener1.WaitUntilSatisfied());
     80 }
     81 
     82 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
     83                        SelfUninstall) {
     84   ExtensionTestMessageListener listener1("success", false);
     85   ASSERT_TRUE(LoadExtension(
     86       test_data_dir_.AppendASCII("management/self_uninstall_helper")));
     87   ASSERT_TRUE(LoadExtension(
     88       test_data_dir_.AppendASCII("management/self_uninstall")));
     89   ASSERT_TRUE(listener1.WaitUntilSatisfied());
     90 }
     91 
     92 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
     93                        SelfUninstallNoPermissions) {
     94   ExtensionTestMessageListener listener1("success", false);
     95   ASSERT_TRUE(LoadExtension(
     96       test_data_dir_.AppendASCII("management/self_uninstall_helper")));
     97   ASSERT_TRUE(LoadExtension(
     98       test_data_dir_.AppendASCII("management/self_uninstall_noperm")));
     99   ASSERT_TRUE(listener1.WaitUntilSatisfied());
    100 }
    101 
    102 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
    103                        GetSelfNoPermissions) {
    104   ExtensionTestMessageListener listener1("success", false);
    105   ASSERT_TRUE(LoadExtension(
    106       test_data_dir_.AppendASCII("management/get_self")));
    107   ASSERT_TRUE(listener1.WaitUntilSatisfied());
    108 }
    109 
    110 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
    111                        UninstallWithConfirmDialog) {
    112   ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
    113       extension_service();
    114 
    115   // Install an extension.
    116   const Extension* extension = InstallExtension(
    117       test_data_dir_.AppendASCII("api_test/management/enabled_extension"), 1);
    118   ASSERT_TRUE(extension);
    119 
    120   const std::string id = extension->id();
    121 
    122   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
    123   // Uninstall, then cancel via the confirm dialog.
    124   scoped_refptr<ManagementUninstallFunction> uninstall_function(
    125       new ManagementUninstallFunction());
    126   uninstall_function->set_extension(empty_extension.get());
    127   uninstall_function->set_user_gesture(true);
    128   ManagementUninstallFunction::SetAutoConfirmForTest(false);
    129 
    130   EXPECT_TRUE(MatchPattern(
    131       util::RunFunctionAndReturnError(
    132           uninstall_function.get(),
    133           base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]",
    134                              id.c_str()),
    135           browser()),
    136       keys::kUninstallCanceledError));
    137 
    138   // Make sure the extension wasn't uninstalled.
    139   EXPECT_TRUE(service->GetExtensionById(id, false) != NULL);
    140 
    141   // Uninstall, then accept via the confirm dialog.
    142   uninstall_function = new ManagementUninstallFunction();
    143   uninstall_function->set_extension(empty_extension.get());
    144   ManagementUninstallFunction::SetAutoConfirmForTest(true);
    145   uninstall_function->set_user_gesture(true);
    146   util::RunFunctionAndReturnSingleResult(
    147       uninstall_function.get(),
    148       base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]", id.c_str()),
    149       browser());
    150 
    151   // Make sure the extension was uninstalled.
    152   EXPECT_TRUE(service->GetExtensionById(id, false) == NULL);
    153 }
    154 
    155 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
    156                        CreateAppShortcutConfirmDialog) {
    157   const Extension* app = InstallExtension(
    158       test_data_dir_.AppendASCII("api_test/management/packaged_app"), 1);
    159   ASSERT_TRUE(app);
    160 
    161   const std::string app_id = app->id();
    162 
    163   scoped_refptr<ManagementCreateAppShortcutFunction> create_shortcut_function(
    164       new ManagementCreateAppShortcutFunction());
    165   create_shortcut_function->set_user_gesture(true);
    166   ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(true);
    167   util::RunFunctionAndReturnSingleResult(
    168       create_shortcut_function.get(),
    169       base::StringPrintf("[\"%s\"]", app_id.c_str()),
    170       browser());
    171 
    172   create_shortcut_function = new ManagementCreateAppShortcutFunction();
    173   create_shortcut_function->set_user_gesture(true);
    174   ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(false);
    175   EXPECT_TRUE(MatchPattern(
    176       util::RunFunctionAndReturnError(
    177           create_shortcut_function.get(),
    178           base::StringPrintf("[\"%s\"]", app_id.c_str()),
    179           browser()),
    180       keys::kCreateShortcutCanceledError));
    181 }
    182 
    183 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
    184                        GetAllIncludesTerminated) {
    185   // Load an extension with a background page, so that we know it has a process
    186   // running.
    187   ExtensionTestMessageListener listener("ready", false);
    188   const Extension* extension = LoadExtension(
    189       test_data_dir_.AppendASCII("management/install_event"));
    190   ASSERT_TRUE(extension);
    191   ASSERT_TRUE(listener.WaitUntilSatisfied());
    192 
    193   // The management API should list this extension.
    194   scoped_refptr<ManagementGetAllFunction> function =
    195       new ManagementGetAllFunction();
    196   scoped_ptr<base::Value> result(util::RunFunctionAndReturnSingleResult(
    197       function.get(), "[]", browser()));
    198   base::ListValue* list;
    199   ASSERT_TRUE(result->GetAsList(&list));
    200   EXPECT_EQ(1U, list->GetSize());
    201 
    202   // And it should continue to do so even after it crashes.
    203   ASSERT_TRUE(CrashEnabledExtension(extension->id()));
    204 
    205   function = new ManagementGetAllFunction();
    206   result.reset(util::RunFunctionAndReturnSingleResult(
    207       function.get(), "[]", browser()));
    208   ASSERT_TRUE(result->GetAsList(&list));
    209   EXPECT_EQ(1U, list->GetSize());
    210 }
    211 
    212 class ExtensionManagementApiEscalationTest :
    213     public ExtensionManagementApiBrowserTest {
    214  protected:
    215   // The id of the permissions escalation test extension we use.
    216   static const char kId[];
    217 
    218   virtual void SetUpOnMainThread() OVERRIDE {
    219     EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
    220     base::FilePath pem_path = test_data_dir_.
    221         AppendASCII("permissions_increase").AppendASCII("permissions.pem");
    222     base::FilePath path_v1 = PackExtensionWithOptions(
    223         test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v1"),
    224         scoped_temp_dir_.path().AppendASCII("permissions1.crx"),
    225         pem_path,
    226         base::FilePath());
    227     base::FilePath path_v2 = PackExtensionWithOptions(
    228         test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v2"),
    229         scoped_temp_dir_.path().AppendASCII("permissions2.crx"),
    230         pem_path,
    231         base::FilePath());
    232 
    233     ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
    234         extension_service();
    235 
    236     // Install low-permission version of the extension.
    237     ASSERT_TRUE(InstallExtension(path_v1, 1));
    238     EXPECT_TRUE(service->GetExtensionById(kId, false) != NULL);
    239 
    240     // Update to a high-permission version - it should get disabled.
    241     EXPECT_FALSE(UpdateExtension(kId, path_v2, -1));
    242     EXPECT_TRUE(service->GetExtensionById(kId, false) == NULL);
    243     EXPECT_TRUE(service->GetExtensionById(kId, true) != NULL);
    244     EXPECT_TRUE(ExtensionPrefs::Get(browser()->profile())
    245                     ->DidExtensionEscalatePermissions(kId));
    246   }
    247 
    248   void SetEnabled(bool enabled, bool user_gesture,
    249                   const std::string& expected_error) {
    250     scoped_refptr<ManagementSetEnabledFunction> function(
    251         new ManagementSetEnabledFunction);
    252     const char* enabled_string = enabled ? "true" : "false";
    253     if (user_gesture)
    254       function->set_user_gesture(true);
    255     bool response = util::RunFunction(
    256         function.get(),
    257         base::StringPrintf("[\"%s\", %s]", kId, enabled_string),
    258         browser(),
    259         util::NONE);
    260     if (expected_error.empty()) {
    261       EXPECT_EQ(true, response);
    262     } else {
    263       EXPECT_TRUE(response == false);
    264       EXPECT_EQ(expected_error, function->GetError());
    265     }
    266   }
    267 
    268 
    269  private:
    270   base::ScopedTempDir scoped_temp_dir_;
    271 };
    272 
    273 const char ExtensionManagementApiEscalationTest::kId[] =
    274     "pgdpcfcocojkjfbgpiianjngphoopgmo";
    275 
    276 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,
    277                        DisabledReason) {
    278   scoped_refptr<ManagementGetFunction> function =
    279       new ManagementGetFunction();
    280   scoped_ptr<base::Value> result(util::RunFunctionAndReturnSingleResult(
    281       function.get(),
    282       base::StringPrintf("[\"%s\"]", kId),
    283       browser()));
    284   ASSERT_TRUE(result.get() != NULL);
    285   ASSERT_TRUE(result->IsType(base::Value::TYPE_DICTIONARY));
    286   base::DictionaryValue* dict =
    287       static_cast<base::DictionaryValue*>(result.get());
    288   std::string reason;
    289   EXPECT_TRUE(dict->GetStringASCII(keys::kDisabledReasonKey, &reason));
    290   EXPECT_EQ(reason, std::string(keys::kDisabledReasonPermissionsIncrease));
    291 }
    292 
    293 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,
    294                        SetEnabled) {
    295   // Expect an error about no gesture.
    296   SetEnabled(true, false, keys::kGestureNeededForEscalationError);
    297 
    298   // Expect an error that user cancelled the dialog.
    299   ExtensionInstallPrompt::g_auto_confirm_for_tests =
    300       ExtensionInstallPrompt::CANCEL;
    301   SetEnabled(true, true, keys::kUserDidNotReEnableError);
    302 
    303   // This should succeed when user accepts dialog.  We must wait for the process
    304   // to connect *and* for the channel to finish initializing before trying to
    305   // crash it.  (NOTIFICATION_RENDERER_PROCESS_CREATED does not wait for the
    306   // latter and can cause KillProcess to fail on Windows.)
    307   content::WindowedNotificationObserver observer(
    308       extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
    309       content::NotificationService::AllSources());
    310   ExtensionInstallPrompt::g_auto_confirm_for_tests =
    311       ExtensionInstallPrompt::ACCEPT;
    312   SetEnabled(true, true, std::string());
    313   observer.Wait();
    314 
    315   // Crash the extension. Mock a reload by disabling and then enabling. The
    316   // extension should be reloaded and enabled.
    317   ASSERT_TRUE(CrashEnabledExtension(kId));
    318   SetEnabled(false, true, std::string());
    319   SetEnabled(true, true, std::string());
    320   const Extension* extension = ExtensionSystem::Get(browser()->profile())
    321       ->extension_service()->GetExtensionById(kId, false);
    322   EXPECT_TRUE(extension);
    323 }
    324 
    325 }  // namespace extensions
    326