Home | History | Annotate | Download | only in extensions
      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 <string>
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/extensions/active_tab_permission_granter.h"
     13 #include "chrome/browser/extensions/tab_helper.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/sessions/session_id.h"
     16 #include "chrome/common/extensions/features/feature_channel.h"
     17 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "content/public/browser/navigation_details.h"
     20 #include "content/public/browser/navigation_entry.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "content/public/browser/notification_types.h"
     23 #include "content/public/browser/web_contents.h"
     24 #include "content/public/common/frame_navigate_params.h"
     25 #include "content/public/common/page_transition_types.h"
     26 #include "content/public/test/test_browser_thread.h"
     27 #include "extensions/common/extension.h"
     28 #include "extensions/common/extension_builder.h"
     29 #include "extensions/common/features/feature.h"
     30 #include "extensions/common/permissions/permissions_data.h"
     31 #include "extensions/common/value_builder.h"
     32 
     33 using base::DictionaryValue;
     34 using base::ListValue;
     35 using content::BrowserThread;
     36 using content::NavigationController;
     37 
     38 namespace extensions {
     39 namespace {
     40 
     41 scoped_refptr<const Extension> CreateTestExtension(
     42     const std::string& id,
     43     bool has_active_tab_permission,
     44     bool has_tab_capture_permission) {
     45   ListBuilder permissions;
     46   if (has_active_tab_permission)
     47     permissions.Append("activeTab");
     48   if (has_tab_capture_permission)
     49     permissions.Append("tabCapture");
     50   return ExtensionBuilder()
     51       .SetManifest(DictionaryBuilder()
     52           .Set("name", "Extension with ID " + id)
     53           .Set("version", "1.0")
     54           .Set("manifest_version", 2)
     55           .Set("permissions", permissions))
     56       .SetID(id)
     57       .Build();
     58 }
     59 
     60 class ActiveTabTest : public ChromeRenderViewHostTestHarness {
     61  protected:
     62   ActiveTabTest()
     63       : current_channel(chrome::VersionInfo::CHANNEL_DEV),
     64         extension(CreateTestExtension("deadbeef", true, false)),
     65         another_extension(CreateTestExtension("feedbeef", true, false)),
     66         extension_without_active_tab(CreateTestExtension("badbeef",
     67                                                          false,
     68                                                          false)),
     69         extension_with_tab_capture(CreateTestExtension("cafebeef",
     70                                                        true,
     71                                                        true)) {}
     72 
     73   virtual void SetUp() OVERRIDE {
     74     ChromeRenderViewHostTestHarness::SetUp();
     75     TabHelper::CreateForWebContents(web_contents());
     76   }
     77 
     78   int tab_id() {
     79     return SessionID::IdForTab(web_contents());
     80   }
     81 
     82   ActiveTabPermissionGranter* active_tab_permission_granter() {
     83     return extensions::TabHelper::FromWebContents(web_contents())->
     84         active_tab_permission_granter();
     85   }
     86 
     87   bool IsAllowed(const scoped_refptr<const Extension>& extension,
     88                  const GURL& url) {
     89     return IsAllowed(extension, url, tab_id());
     90   }
     91 
     92   bool IsAllowed(const scoped_refptr<const Extension>& extension,
     93                  const GURL& url,
     94                  int tab_id) {
     95     return PermissionsData::CanExecuteScriptOnPage(
     96                extension.get(), url, url, tab_id, NULL, -1, NULL) &&
     97            PermissionsData::CanCaptureVisiblePage(
     98                extension.get(), url, tab_id, NULL) &&
     99            HasTabsPermission(extension, tab_id);
    100   }
    101 
    102   bool IsBlocked(const scoped_refptr<const Extension>& extension,
    103                  const GURL& url) {
    104     return IsBlocked(extension, url, tab_id());
    105   }
    106 
    107   bool IsBlocked(const scoped_refptr<const Extension>& extension,
    108                  const GURL& url,
    109                  int tab_id) {
    110     // Note: can't check HasTabsPermission because it isn't URL specific.
    111     return !PermissionsData::CanExecuteScriptOnPage(
    112                extension.get(), url, url, tab_id, NULL, -1, NULL) &&
    113            !PermissionsData::CanCaptureVisiblePage(
    114                extension.get(), url, tab_id, NULL);
    115   }
    116 
    117   bool HasTabsPermission(const scoped_refptr<const Extension>& extension) {
    118     return HasTabsPermission(extension, tab_id());
    119   }
    120 
    121   bool HasTabsPermission(const scoped_refptr<const Extension>& extension,
    122                          int tab_id) {
    123     return PermissionsData::HasAPIPermissionForTab(
    124         extension.get(), tab_id, APIPermission::kTab);
    125   }
    126 
    127   bool IsGrantedForTab(const Extension* extension,
    128                        const content::WebContents* web_contents) {
    129     return PermissionsData::HasAPIPermissionForTab(
    130         extension,
    131         SessionID::IdForTab(web_contents),
    132         APIPermission::kTab);
    133   }
    134 
    135   // TODO(justinlin): Remove when tabCapture is moved to stable.
    136   ScopedCurrentChannel current_channel;
    137 
    138   // An extension with the activeTab permission.
    139   scoped_refptr<const Extension> extension;
    140 
    141   // Another extension with activeTab (for good measure).
    142   scoped_refptr<const Extension> another_extension;
    143 
    144   // An extension without the activeTab permission.
    145   scoped_refptr<const Extension> extension_without_active_tab;
    146 
    147   // An extension with both the activeTab and tabCapture permission.
    148   scoped_refptr<const Extension> extension_with_tab_capture;
    149 };
    150 
    151 TEST_F(ActiveTabTest, GrantToSinglePage) {
    152   GURL google("http://www.google.com");
    153   NavigateAndCommit(google);
    154 
    155   // No access unless it's been granted.
    156   EXPECT_TRUE(IsBlocked(extension, google));
    157   EXPECT_TRUE(IsBlocked(another_extension, google));
    158   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    159 
    160   EXPECT_FALSE(HasTabsPermission(extension));
    161   EXPECT_FALSE(HasTabsPermission(another_extension));
    162   EXPECT_FALSE(HasTabsPermission(extension_without_active_tab));
    163 
    164   active_tab_permission_granter()->GrantIfRequested(extension.get());
    165   active_tab_permission_granter()->GrantIfRequested(
    166       extension_without_active_tab.get());
    167 
    168   // Granted to extension and extension_without_active_tab, but the latter
    169   // doesn't have the activeTab permission so not granted.
    170   EXPECT_TRUE(IsAllowed(extension, google));
    171   EXPECT_TRUE(IsBlocked(another_extension, google));
    172   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    173 
    174   // Other subdomains shouldn't be given access.
    175   GURL mail_google("http://mail.google.com");
    176   EXPECT_TRUE(IsBlocked(extension, mail_google));
    177   EXPECT_TRUE(IsBlocked(another_extension, mail_google));
    178   EXPECT_TRUE(IsBlocked(extension_without_active_tab, mail_google));
    179 
    180   // Reloading the page should clear the active permissions.
    181   Reload();
    182 
    183   EXPECT_TRUE(IsBlocked(extension, google));
    184   EXPECT_TRUE(IsBlocked(another_extension, google));
    185   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    186 
    187   EXPECT_FALSE(HasTabsPermission(extension));
    188   EXPECT_FALSE(HasTabsPermission(another_extension));
    189   EXPECT_FALSE(HasTabsPermission(extension_without_active_tab));
    190 
    191   // But they should still be able to be granted again.
    192   active_tab_permission_granter()->GrantIfRequested(extension.get());
    193 
    194   EXPECT_TRUE(IsAllowed(extension, google));
    195   EXPECT_TRUE(IsBlocked(another_extension, google));
    196   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    197 
    198   // And grant a few more times redundantly for good measure.
    199   active_tab_permission_granter()->GrantIfRequested(extension.get());
    200   active_tab_permission_granter()->GrantIfRequested(extension.get());
    201   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    202   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    203   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    204   active_tab_permission_granter()->GrantIfRequested(extension.get());
    205   active_tab_permission_granter()->GrantIfRequested(extension.get());
    206   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    207   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    208 
    209   EXPECT_TRUE(IsAllowed(extension, google));
    210   EXPECT_TRUE(IsAllowed(another_extension, google));
    211   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    212 
    213   // Navigating to a new URL should clear the active permissions.
    214   GURL chromium("http://www.chromium.org");
    215   NavigateAndCommit(chromium);
    216 
    217   EXPECT_TRUE(IsBlocked(extension, google));
    218   EXPECT_TRUE(IsBlocked(another_extension, google));
    219   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    220 
    221   EXPECT_TRUE(IsBlocked(extension, chromium));
    222   EXPECT_TRUE(IsBlocked(another_extension, chromium));
    223   EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium));
    224 
    225   EXPECT_FALSE(HasTabsPermission(extension));
    226   EXPECT_FALSE(HasTabsPermission(another_extension));
    227   EXPECT_FALSE(HasTabsPermission(extension_without_active_tab));
    228 
    229   // Should be able to grant to multiple extensions at the same time (if they
    230   // have the activeTab permission, of course).
    231   active_tab_permission_granter()->GrantIfRequested(extension.get());
    232   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    233   active_tab_permission_granter()->GrantIfRequested(
    234       extension_without_active_tab.get());
    235 
    236   EXPECT_TRUE(IsBlocked(extension, google));
    237   EXPECT_TRUE(IsBlocked(another_extension, google));
    238   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    239 
    240   EXPECT_TRUE(IsAllowed(extension, chromium));
    241   EXPECT_TRUE(IsAllowed(another_extension, chromium));
    242   EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium));
    243 
    244   // Should be able to go back to URLs that were previously cleared.
    245   NavigateAndCommit(google);
    246 
    247   active_tab_permission_granter()->GrantIfRequested(extension.get());
    248   active_tab_permission_granter()->GrantIfRequested(another_extension.get());
    249   active_tab_permission_granter()->GrantIfRequested(
    250       extension_without_active_tab.get());
    251 
    252   EXPECT_TRUE(IsAllowed(extension, google));
    253   EXPECT_TRUE(IsAllowed(another_extension, google));
    254   EXPECT_TRUE(IsBlocked(extension_without_active_tab, google));
    255 
    256   EXPECT_TRUE(IsBlocked(extension, chromium));
    257   EXPECT_TRUE(IsBlocked(another_extension, chromium));
    258   EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium));
    259 };
    260 
    261 TEST_F(ActiveTabTest, Uninstalling) {
    262   // Some semi-arbitrary setup.
    263   GURL google("http://www.google.com");
    264   NavigateAndCommit(google);
    265 
    266   active_tab_permission_granter()->GrantIfRequested(extension.get());
    267 
    268   EXPECT_TRUE(IsGrantedForTab(extension.get(), web_contents()));
    269   EXPECT_TRUE(IsAllowed(extension, google));
    270 
    271   // Uninstalling the extension should clear its tab permissions.
    272   UnloadedExtensionInfo details(extension.get(),
    273                                 UnloadedExtensionInfo::REASON_DISABLE);
    274   content::NotificationService::current()->Notify(
    275       chrome::NOTIFICATION_EXTENSION_UNLOADED,
    276       content::Source<Profile>(Profile::FromBrowserContext(
    277           web_contents()->GetBrowserContext())),
    278       content::Details<UnloadedExtensionInfo>(&details));
    279 
    280   // Note: can't EXPECT_FALSE(IsAllowed) here because uninstalled extensions
    281   // are just that... considered to be uninstalled, and the manager might
    282   // just ignore them from here on.
    283 
    284   // Granting the extension again should give them back.
    285   active_tab_permission_granter()->GrantIfRequested(extension.get());
    286 
    287   EXPECT_TRUE(IsGrantedForTab(extension.get(), web_contents()));
    288   EXPECT_TRUE(IsAllowed(extension, google));
    289 }
    290 
    291 TEST_F(ActiveTabTest, OnlyActiveTab) {
    292   GURL google("http://www.google.com");
    293   NavigateAndCommit(google);
    294 
    295   active_tab_permission_granter()->GrantIfRequested(extension.get());
    296 
    297   EXPECT_TRUE(IsAllowed(extension, google, tab_id()));
    298   EXPECT_TRUE(IsBlocked(extension, google, tab_id() + 1));
    299   EXPECT_FALSE(HasTabsPermission(extension, tab_id() + 1));
    300 }
    301 
    302 TEST_F(ActiveTabTest, NavigateInPage) {
    303   GURL google("http://www.google.com");
    304   NavigateAndCommit(google);
    305 
    306   active_tab_permission_granter()->GrantIfRequested(extension.get());
    307 
    308   // Perform an in-page navigation. The extension should not lose the temporary
    309   // permission.
    310   GURL google_h1("http://www.google.com#h1");
    311   NavigateAndCommit(google_h1);
    312 
    313   EXPECT_TRUE(IsAllowed(extension, google, tab_id()));
    314   EXPECT_TRUE(IsAllowed(extension, google_h1, tab_id()));
    315 
    316   GURL chromium("http://www.chromium.org");
    317   NavigateAndCommit(chromium);
    318 
    319   EXPECT_FALSE(IsAllowed(extension, google, tab_id()));
    320   EXPECT_FALSE(IsAllowed(extension, google_h1, tab_id()));
    321   EXPECT_FALSE(IsAllowed(extension, chromium, tab_id()));
    322 
    323   active_tab_permission_granter()->GrantIfRequested(extension.get());
    324 
    325   EXPECT_FALSE(IsAllowed(extension, google, tab_id()));
    326   EXPECT_FALSE(IsAllowed(extension, google_h1, tab_id()));
    327   EXPECT_TRUE(IsAllowed(extension, chromium, tab_id()));
    328 
    329   GURL chromium_h1("http://www.chromium.org#h1");
    330   NavigateAndCommit(chromium_h1);
    331 
    332   EXPECT_FALSE(IsAllowed(extension, google, tab_id()));
    333   EXPECT_FALSE(IsAllowed(extension, google_h1, tab_id()));
    334   EXPECT_TRUE(IsAllowed(extension, chromium, tab_id()));
    335   EXPECT_TRUE(IsAllowed(extension, chromium_h1, tab_id()));
    336 
    337   Reload();
    338 
    339   EXPECT_FALSE(IsAllowed(extension, google, tab_id()));
    340   EXPECT_FALSE(IsAllowed(extension, google_h1, tab_id()));
    341   EXPECT_FALSE(IsAllowed(extension, chromium, tab_id()));
    342   EXPECT_FALSE(IsAllowed(extension, chromium_h1, tab_id()));
    343 }
    344 
    345 TEST_F(ActiveTabTest, ChromeUrlGrants) {
    346   GURL internal("chrome://version");
    347   NavigateAndCommit(internal);
    348   active_tab_permission_granter()->GrantIfRequested(
    349       extension_with_tab_capture.get());
    350   // Do not grant tabs/hosts permissions for tab.
    351   EXPECT_TRUE(IsBlocked(extension_with_tab_capture, internal, tab_id()));
    352   EXPECT_TRUE(PermissionsData::HasAPIPermissionForTab(
    353       extension_with_tab_capture.get(),
    354       tab_id(),
    355       APIPermission::kTabCaptureForTab));
    356 
    357   EXPECT_TRUE(IsBlocked(extension_with_tab_capture, internal, tab_id() + 1));
    358   EXPECT_FALSE(PermissionsData::HasAPIPermissionForTab(
    359       extension_with_tab_capture.get(),
    360       tab_id() + 1,
    361       APIPermission::kTabCaptureForTab));
    362 }
    363 
    364 }  // namespace
    365 }  // namespace extensions
    366