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