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