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