| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/compiler_specific.h" |
| #include "base/macros.h" |
| #include "base/values.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/extensions/active_tab_permission_granter.h" |
| #include "chrome/browser/extensions/chrome_test_extension_loader.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_service_test_base.h" |
| #include "chrome/browser/extensions/extension_util.h" |
| #include "chrome/browser/extensions/tab_helper.h" |
| #include "chrome/browser/extensions/test_extension_system.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/webui_url_constants.h" |
| #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/sessions/content/session_tab_helper.h" |
| #include "components/version_info/version_info.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_details.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_types.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "content/public/test/web_contents_tester.h" |
| #include "extensions/browser/disable_reason.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/test_extension_registry_observer.h" |
| #include "extensions/common/constants.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/extension_builder.h" |
| #include "extensions/common/extensions_client.h" |
| #include "extensions/common/features/feature.h" |
| #include "extensions/common/features/feature_channel.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| #include "extensions/common/value_builder.h" |
| #include "extensions/test/test_extension_dir.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "ash/constants/ash_switches.h" |
| #include "base/run_loop.h" |
| #include "chrome/browser/ash/app_mode/kiosk_app_manager.h" |
| #include "chrome/browser/ash/login/users/chrome_user_manager_impl.h" |
| #include "chrome/browser/ash/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.h" |
| #include "chrome/browser/ui/ash/test_wallpaper_controller.h" |
| #include "chrome/browser/ui/ash/wallpaper_controller_client_impl.h" |
| #include "chrome/test/base/scoped_testing_local_state.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chromeos/login/login_state/scoped_test_public_session_login_state.h" |
| #include "components/account_id/account_id.h" |
| #include "components/sync/driver/sync_driver_switches.h" |
| #include "content/public/common/content_switches.h" |
| #include "extensions/browser/extension_dialog_auto_confirm.h" |
| #endif |
| |
| using base::DictionaryValue; |
| using base::ListValue; |
| using content::BrowserThread; |
| using content::NavigationController; |
| using extensions::mojom::APIPermissionID; |
| |
| namespace extensions { |
| namespace { |
| |
| scoped_refptr<const Extension> CreateTestExtension( |
| const std::string& name, |
| bool has_active_tab_permission, |
| bool has_tab_capture_permission) { |
| ExtensionBuilder builder(name); |
| if (has_active_tab_permission) |
| builder.AddPermission("activeTab"); |
| if (has_tab_capture_permission) |
| builder.AddPermission("tabCapture"); |
| |
| return builder.Build(); |
| } |
| |
| enum PermittedFeature { |
| PERMITTED_NONE, |
| PERMITTED_SCRIPT_ONLY, |
| PERMITTED_CAPTURE_ONLY, |
| PERMITTED_BOTH |
| }; |
| |
| class ActiveTabPermissionGranterTestDelegate |
| : public ActiveTabPermissionGranter::Delegate { |
| public: |
| ActiveTabPermissionGranterTestDelegate() {} |
| ~ActiveTabPermissionGranterTestDelegate() override {} |
| |
| // ActiveTabPermissionGranterTestDelegate::Delegate |
| bool ShouldGrantActiveTabOrPrompt(const Extension* extension, |
| content::WebContents* contents) override { |
| should_grant_call_count_++; |
| return should_grant_; |
| } |
| |
| void SetShouldGrant(bool should_grant) { |
| should_grant_ = should_grant; |
| } |
| |
| int should_grant_call_count() { return should_grant_call_count_; } |
| |
| private: |
| bool should_grant_ = false; |
| int should_grant_call_count_ = 0; |
| |
| DISALLOW_COPY_AND_ASSIGN(ActiveTabPermissionGranterTestDelegate); |
| }; |
| |
| class ActiveTabTest : public ChromeRenderViewHostTestHarness { |
| protected: |
| ActiveTabTest() |
| : current_channel(version_info::Channel::DEV), |
| extension(CreateTestExtension("deadbeef", true, false)), |
| another_extension(CreateTestExtension("feedbeef", true, false)), |
| extension_without_active_tab(CreateTestExtension("badbeef", |
| false, |
| false)), |
| extension_with_tab_capture(CreateTestExtension("cafebeef", |
| true, |
| true)) {} |
| |
| void SetUp() override { |
| ChromeRenderViewHostTestHarness::SetUp(); |
| TabHelper::CreateForWebContents(web_contents()); |
| |
| // We need to add extensions to the ExtensionService; else trying to commit |
| // any of their URLs fails and redirects to about:blank. |
| ExtensionService* service = |
| static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())) |
| ->CreateExtensionService(base::CommandLine::ForCurrentProcess(), |
| base::FilePath(), false); |
| service->AddExtension(extension.get()); |
| service->AddExtension(another_extension.get()); |
| service->AddExtension(extension_without_active_tab.get()); |
| service->AddExtension(extension_with_tab_capture.get()); |
| } |
| |
| void TearDown() override { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ash::KioskAppManager::Shutdown(); |
| #endif |
| ChromeRenderViewHostTestHarness::TearDown(); |
| } |
| |
| int tab_id() { |
| return sessions::SessionTabHelper::IdForTab(web_contents()).id(); |
| } |
| |
| ActiveTabPermissionGranter* active_tab_permission_granter() { |
| return extensions::TabHelper::FromWebContents(web_contents())-> |
| active_tab_permission_granter(); |
| } |
| |
| bool IsAllowed(const scoped_refptr<const Extension>& extension, |
| const GURL& url) { |
| return IsAllowed(extension, url, PERMITTED_BOTH, tab_id()); |
| } |
| |
| bool IsAllowed(const scoped_refptr<const Extension>& extension, |
| const GURL& url, |
| PermittedFeature feature) { |
| return IsAllowed(extension, url, feature, tab_id()); |
| } |
| |
| bool IsAllowed(const scoped_refptr<const Extension>& extension, |
| const GURL& url, |
| PermittedFeature feature, |
| int tab_id) { |
| const PermissionsData* permissions_data = extension->permissions_data(); |
| bool script = |
| permissions_data->CanAccessPage(url, tab_id, nullptr) && |
| permissions_data->CanRunContentScriptOnPage(url, tab_id, nullptr); |
| bool capture = permissions_data->CanCaptureVisiblePage( |
| url, tab_id, NULL, extensions::CaptureRequirement::kActiveTabOrAllUrls); |
| switch (feature) { |
| case PERMITTED_SCRIPT_ONLY: |
| return script && !capture; |
| case PERMITTED_CAPTURE_ONLY: |
| return capture && !script; |
| case PERMITTED_BOTH: |
| return script && capture; |
| case PERMITTED_NONE: |
| return !script && !capture; |
| } |
| NOTREACHED(); |
| return false; |
| } |
| |
| bool IsBlocked(const scoped_refptr<const Extension>& extension, |
| const GURL& url) { |
| return IsBlocked(extension, url, tab_id()); |
| } |
| |
| bool IsBlocked(const scoped_refptr<const Extension>& extension, |
| const GURL& url, |
| int tab_id) { |
| return IsAllowed(extension, url, PERMITTED_NONE, tab_id); |
| } |
| |
| bool HasTabsPermission(const scoped_refptr<const Extension>& extension) { |
| return HasTabsPermission(extension, tab_id()); |
| } |
| |
| bool HasTabsPermission(const scoped_refptr<const Extension>& extension, |
| int tab_id) { |
| return extension->permissions_data()->HasAPIPermissionForTab( |
| tab_id, APIPermissionID::kTab); |
| } |
| |
| bool IsGrantedForTab(const Extension* extension, |
| const content::WebContents* web_contents) { |
| return extension->permissions_data()->HasAPIPermissionForTab( |
| sessions::SessionTabHelper::IdForTab(web_contents).id(), |
| APIPermissionID::kTab); |
| } |
| |
| // TODO(justinlin): Remove when tabCapture is moved to stable. |
| ScopedCurrentChannel current_channel; |
| |
| // An extension with the activeTab permission. |
| scoped_refptr<const Extension> extension; |
| |
| // Another extension with activeTab (for good measure). |
| scoped_refptr<const Extension> another_extension; |
| |
| // An extension without the activeTab permission. |
| scoped_refptr<const Extension> extension_without_active_tab; |
| |
| // An extension with both the activeTab and tabCapture permission. |
| scoped_refptr<const Extension> extension_with_tab_capture; |
| }; |
| |
| TEST_F(ActiveTabTest, GrantToSinglePage) { |
| GURL google("http://www.google.com"); |
| NavigateAndCommit(google); |
| |
| // No access unless it's been granted. |
| EXPECT_TRUE(IsBlocked(extension, google)); |
| EXPECT_TRUE(IsBlocked(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| EXPECT_FALSE(HasTabsPermission(extension)); |
| EXPECT_FALSE(HasTabsPermission(another_extension)); |
| EXPECT_FALSE(HasTabsPermission(extension_without_active_tab)); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested( |
| extension_without_active_tab.get()); |
| |
| // Granted to extension and extension_without_active_tab, but the latter |
| // doesn't have the activeTab permission so not granted. |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| EXPECT_TRUE(IsBlocked(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| // Other subdomains shouldn't be given access. |
| GURL mail_google("http://mail.google.com"); |
| EXPECT_TRUE(IsBlocked(extension, mail_google)); |
| EXPECT_TRUE(IsBlocked(another_extension, mail_google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, mail_google)); |
| |
| // Reloading the page should not clear the active permissions, since the |
| // user remains on the same site. |
| content::NavigationSimulator::Reload(web_contents()); |
| |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| EXPECT_TRUE(IsBlocked(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| EXPECT_TRUE(HasTabsPermission(extension)); |
| EXPECT_FALSE(HasTabsPermission(another_extension)); |
| EXPECT_FALSE(HasTabsPermission(extension_without_active_tab)); |
| |
| // And grant a few more times redundantly for good measure. |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| EXPECT_TRUE(IsAllowed(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| // Navigating to a new URL should clear the active permissions. |
| GURL chromium("http://www.chromium.org"); |
| NavigateAndCommit(chromium); |
| |
| EXPECT_TRUE(IsBlocked(extension, google)); |
| EXPECT_TRUE(IsBlocked(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| EXPECT_TRUE(IsBlocked(extension, chromium)); |
| EXPECT_TRUE(IsBlocked(another_extension, chromium)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium)); |
| |
| EXPECT_FALSE(HasTabsPermission(extension)); |
| EXPECT_FALSE(HasTabsPermission(another_extension)); |
| EXPECT_FALSE(HasTabsPermission(extension_without_active_tab)); |
| |
| // Should be able to grant to multiple extensions at the same time (if they |
| // have the activeTab permission, of course). |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| active_tab_permission_granter()->GrantIfRequested( |
| extension_without_active_tab.get()); |
| |
| EXPECT_TRUE(IsBlocked(extension, google)); |
| EXPECT_TRUE(IsBlocked(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| EXPECT_TRUE(IsAllowed(extension, chromium)); |
| EXPECT_TRUE(IsAllowed(another_extension, chromium)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium)); |
| |
| // Should be able to go back to URLs that were previously cleared. |
| NavigateAndCommit(google); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| active_tab_permission_granter()->GrantIfRequested( |
| extension_without_active_tab.get()); |
| |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| EXPECT_TRUE(IsAllowed(another_extension, google)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); |
| |
| EXPECT_TRUE(IsBlocked(extension, chromium)); |
| EXPECT_TRUE(IsBlocked(another_extension, chromium)); |
| EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium)); |
| } |
| |
| TEST_F(ActiveTabTest, CapturingPagesWithActiveTab) { |
| std::vector<GURL> test_urls = { |
| GURL("https://example.com"), |
| GURL(chrome::kChromeUIVersionURL), |
| GURL(chrome::kChromeUINewTabURL), |
| GURL("http://[2607:f8b0:4005:805::200e]"), |
| ExtensionsClient::Get()->GetWebstoreBaseURL(), |
| extension->GetResourceURL("test.html"), |
| another_extension->GetResourceURL("test.html"), |
| }; |
| |
| const GURL kAboutBlank("about:blank"); |
| |
| for (const GURL& url : test_urls) { |
| SCOPED_TRACE(url); |
| NavigateAndCommit(url); |
| EXPECT_EQ(url, web_contents()->GetLastCommittedURL()); |
| // By default, there should be no access. |
| EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( |
| url, tab_id(), nullptr /*error*/, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| // Granting permission should allow page capture. |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| EXPECT_TRUE(extension->permissions_data()->CanCaptureVisiblePage( |
| url, tab_id(), nullptr /*error*/, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| // Navigating away should revoke access. |
| NavigateAndCommit(kAboutBlank); |
| EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( |
| url, tab_id(), nullptr /*error*/, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| } |
| } |
| |
| TEST_F(ActiveTabTest, Unloading) { |
| // Some semi-arbitrary setup. |
| GURL google("http://www.google.com"); |
| NavigateAndCommit(google); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| |
| EXPECT_TRUE(IsGrantedForTab(extension.get(), web_contents())); |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| |
| // Unloading the extension should clear its tab permissions. |
| ExtensionSystem::Get(web_contents()->GetBrowserContext()) |
| ->extension_service() |
| ->DisableExtension(extension->id(), disable_reason::DISABLE_USER_ACTION); |
| |
| // Note: can't EXPECT_FALSE(IsAllowed) here because uninstalled extensions |
| // are just that... considered to be uninstalled, and the manager might |
| // just ignore them from here on. |
| |
| // Granting the extension again should give them back. |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| |
| EXPECT_TRUE(IsGrantedForTab(extension.get(), web_contents())); |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| } |
| |
| TEST_F(ActiveTabTest, OnlyActiveTab) { |
| GURL google("http://www.google.com"); |
| NavigateAndCommit(google); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| |
| EXPECT_TRUE(IsAllowed(extension, google, PERMITTED_BOTH, tab_id())); |
| EXPECT_TRUE(IsBlocked(extension, google, tab_id() + 1)); |
| EXPECT_FALSE(HasTabsPermission(extension, tab_id() + 1)); |
| } |
| |
| TEST_F(ActiveTabTest, SameDocumentNavigations) { |
| GURL google("http://www.google.com"); |
| NavigateAndCommit(google); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| |
| // Perform a same-document navigation. The extension should not lose the |
| // temporary permission. |
| GURL google_h1("http://www.google.com#h1"); |
| NavigateAndCommit(google_h1); |
| |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| EXPECT_TRUE(IsAllowed(extension, google_h1)); |
| |
| GURL chromium("http://www.chromium.org"); |
| NavigateAndCommit(chromium); |
| |
| EXPECT_FALSE(IsAllowed(extension, google)); |
| EXPECT_FALSE(IsAllowed(extension, google_h1)); |
| EXPECT_FALSE(IsAllowed(extension, chromium)); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| |
| EXPECT_FALSE(IsAllowed(extension, google)); |
| EXPECT_FALSE(IsAllowed(extension, google_h1)); |
| EXPECT_TRUE(IsAllowed(extension, chromium)); |
| |
| GURL chromium_h1("http://www.chromium.org#h1"); |
| NavigateAndCommit(chromium_h1); |
| |
| EXPECT_FALSE(IsAllowed(extension, google)); |
| EXPECT_FALSE(IsAllowed(extension, google_h1)); |
| EXPECT_TRUE(IsAllowed(extension, chromium)); |
| EXPECT_TRUE(IsAllowed(extension, chromium_h1)); |
| |
| content::NavigationSimulator::Reload(web_contents()); |
| |
| EXPECT_FALSE(IsAllowed(extension, google)); |
| EXPECT_FALSE(IsAllowed(extension, google_h1)); |
| EXPECT_TRUE(IsAllowed(extension, chromium)); |
| EXPECT_TRUE(IsAllowed(extension, chromium_h1)); |
| } |
| |
| TEST_F(ActiveTabTest, ChromeUrlGrants) { |
| GURL internal(chrome::kChromeUIVersionURL); |
| NavigateAndCommit(internal); |
| active_tab_permission_granter()->GrantIfRequested( |
| extension_with_tab_capture.get()); |
| // Do not grant tabs/hosts permissions for tab. |
| EXPECT_TRUE(IsAllowed(extension_with_tab_capture, internal, |
| PERMITTED_CAPTURE_ONLY)); |
| const PermissionsData* permissions_data = |
| extension_with_tab_capture->permissions_data(); |
| EXPECT_TRUE(permissions_data->HasAPIPermissionForTab( |
| tab_id(), APIPermissionID::kTabCaptureForTab)); |
| |
| EXPECT_TRUE(IsBlocked(extension_with_tab_capture, internal, tab_id() + 1)); |
| EXPECT_FALSE(permissions_data->HasAPIPermissionForTab( |
| tab_id() + 1, APIPermissionID::kTabCaptureForTab)); |
| } |
| |
| class ActiveTabDelegateTest : public ActiveTabTest { |
| protected: |
| ActiveTabDelegateTest() { |
| auto delegate = std::make_unique<ActiveTabPermissionGranterTestDelegate>(); |
| test_delegate_ = delegate.get(); |
| ActiveTabPermissionGranter::SetPlatformDelegate(std::move(delegate)); |
| } |
| |
| ~ActiveTabDelegateTest() override { |
| ActiveTabPermissionGranter::SetPlatformDelegate(nullptr); |
| } |
| |
| ActiveTabPermissionGranterTestDelegate* test_delegate_; |
| }; |
| |
| // Test that the custom platform delegate works as expected. |
| TEST_F(ActiveTabDelegateTest, Delegate) { |
| GURL google("http://www.google.com"); |
| NavigateAndCommit(google); |
| |
| // Not granted because the delegate denies grant. |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| EXPECT_TRUE(IsBlocked(extension, google)); |
| |
| // This time it's granted because the delegate allows it. |
| test_delegate_->SetShouldGrant(true); |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| EXPECT_TRUE(IsAllowed(extension, google)); |
| } |
| |
| // Regression test for crbug.com/833188. |
| TEST_F(ActiveTabDelegateTest, DelegateUsedOnlyWhenNeeded) { |
| active_tab_permission_granter()->GrantIfRequested( |
| extension_without_active_tab.get()); |
| |
| EXPECT_EQ(0, test_delegate_->should_grant_call_count()); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| class ActiveTabManagedSessionTest : public ActiveTabTest { |
| protected: |
| ActiveTabManagedSessionTest() {} |
| |
| void SetUp() override { |
| ActiveTabTest::SetUp(); |
| |
| // Necessary to prevent instantiation of SyncService, which messes |
| // with our signin state below. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kDisableSync); |
| // Necessary because no ProfileManager instance exists in this test. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| chromeos::switches::kIgnoreUserProfileMappingForTests); |
| // Necessary to skip cryptohome/profile sanity check in |
| // ChromeUserManagerImpl for fake user login. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kTestType); |
| |
| // Setup, login a public account user. |
| const std::string user_id = "public@account.user"; |
| const std::string user_email = user_id; |
| const AccountId account_id = |
| AccountId::FromUserEmailGaiaId(user_email, user_id); |
| const std::string user_id_hash = |
| chromeos::ProfileHelper::Get()->GetUserIdHashByUserIdForTesting( |
| user_id); |
| |
| local_state_ = std::make_unique<ScopedTestingLocalState>( |
| TestingBrowserProcess::GetGlobal()); |
| wallpaper_controller_client_ = |
| std::make_unique<WallpaperControllerClientImpl>(); |
| wallpaper_controller_client_->InitForTesting(&test_wallpaper_controller_); |
| g_browser_process->local_state()->SetString( |
| "PublicAccountPendingDataRemoval", user_email); |
| user_manager::UserManager::Get()->UserLoggedIn(account_id, user_id_hash, |
| true /* browser_restart */, |
| false /* is_child */); |
| // Finish initialization - some things are run as separate tasks. |
| base::RunLoop().RunUntilIdle(); |
| |
| google_ = GURL("http://www.google.com"); |
| NavigateAndCommit(google_); |
| } |
| |
| void TearDown() override { |
| // This one needs to be destructed here so it deregisters itself from |
| // CrosSettings before that is destructed down the line inside |
| // ChromeRenderViewHostTestHarness::TearDown. |
| wallpaper_controller_client_.reset(); |
| |
| ash::ChromeUserManagerImpl::ResetPublicAccountDelegatesForTesting(); |
| ash::ChromeUserManager::Get()->Shutdown(); |
| |
| ActiveTabTest::TearDown(); |
| } |
| |
| std::unique_ptr<ScopedTestingLocalState> local_state_; |
| TestWallpaperController test_wallpaper_controller_; |
| std::unique_ptr<WallpaperControllerClientImpl> wallpaper_controller_client_; |
| GURL google_; |
| }; |
| |
| // Test that there's no permission prompt in Managed Sessions (Public Sessions |
| // v2) for activeTab. |
| TEST_F(ActiveTabManagedSessionTest, NoPromptInManagedSession) { |
| chromeos::ScopedTestPublicSessionLoginState login_state( |
| chromeos::LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT_MANAGED); |
| |
| active_tab_permission_granter()->GrantIfRequested( |
| extension_with_tab_capture.get()); |
| EXPECT_TRUE(IsAllowed(extension_with_tab_capture, google_)); |
| } |
| |
| // Keep the unique_ptr around until callback has been run and don't forget to |
| // unset the ActiveTabPermissionGranterDelegateChromeOS. |
| std::unique_ptr<permission_helper::RequestResolvedCallback> |
| QuitRunLoopOnRequestResolved(base::RunLoop* run_loop) { |
| auto callback = std::make_unique<permission_helper::RequestResolvedCallback>( |
| base::BindOnce([](base::RunLoop* run_loop, |
| const PermissionIDSet&) { run_loop->Quit(); }, |
| run_loop)); |
| ActiveTabPermissionGranterDelegateChromeOS:: |
| SetRequestResolvedCallbackForTesting(callback.get()); |
| return callback; |
| } |
| |
| // Test that the platform delegate is being set and the activeTab permission is |
| // prompted for in Public Sessions. |
| TEST_F(ActiveTabManagedSessionTest, |
| DelegateIsSetAndPromptIsShownInPublicSession) { |
| chromeos::ScopedTestPublicSessionLoginState login_state( |
| chromeos::LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT); |
| // Grant and verify. |
| { |
| ScopedTestDialogAutoConfirm auto_confirm( |
| ScopedTestDialogAutoConfirm::ACCEPT); |
| |
| // RunLoop needed to resolve the permission dialog. |
| base::RunLoop run_loop; |
| auto cb = QuitRunLoopOnRequestResolved(&run_loop); |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| run_loop.Run(); |
| EXPECT_TRUE(IsBlocked(extension, google_)); |
| |
| active_tab_permission_granter()->GrantIfRequested(extension.get()); |
| EXPECT_TRUE(IsAllowed(extension, google_)); |
| } |
| |
| // Deny and verify. Use a different extension so it doesn't trigger the |
| // cache. |
| { |
| ScopedTestDialogAutoConfirm auto_confirm( |
| ScopedTestDialogAutoConfirm::CANCEL); |
| |
| base::RunLoop run_loop; |
| auto cb = QuitRunLoopOnRequestResolved(&run_loop); |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| run_loop.Run(); |
| EXPECT_TRUE(IsBlocked(another_extension, google_)); |
| |
| active_tab_permission_granter()->GrantIfRequested(another_extension.get()); |
| EXPECT_TRUE(IsBlocked(another_extension, google_)); |
| } |
| |
| // Cleanup. |
| ActiveTabPermissionGranterDelegateChromeOS:: |
| SetRequestResolvedCallbackForTesting(nullptr); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // An active tab test that includes an ExtensionService. |
| class ActiveTabWithServiceTest : public ExtensionServiceTestBase { |
| public: |
| ActiveTabWithServiceTest() {} |
| |
| void SetUp() override; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ActiveTabWithServiceTest); |
| }; |
| |
| void ActiveTabWithServiceTest::SetUp() { |
| ExtensionServiceTestBase::SetUp(); |
| } |
| |
| // Tests that an extension can only capture file:// URLs with the active tab |
| // permission when it has file access granted. |
| // Regression test for https://crbug.com/810220. |
| TEST_F(ActiveTabWithServiceTest, FileURLs) { |
| InitializeEmptyExtensionService(); |
| |
| TestExtensionDir test_dir; |
| test_dir.WriteManifest(R"( |
| { |
| "name": "Active Tab Capture With File Urls", |
| "description": "Testing activeTab on file urls", |
| "version": "0.1", |
| "manifest_version": 2, |
| "permissions": ["activeTab"] |
| })"); |
| |
| ChromeTestExtensionLoader loader(profile()); |
| loader.set_allow_file_access(false); |
| scoped_refptr<const Extension> extension = |
| loader.LoadExtension(test_dir.UnpackedPath()); |
| ASSERT_TRUE(extension); |
| const std::string id = extension->id(); |
| ASSERT_TRUE(registry()->enabled_extensions().Contains(id)); |
| |
| EXPECT_FALSE(util::AllowFileAccess(id, profile())); |
| |
| std::unique_ptr<content::WebContents> web_contents( |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr)); |
| ASSERT_TRUE(web_contents); |
| |
| const GURL file_url("file:///foo"); |
| ASSERT_TRUE(content::WebContentsTester::For(web_contents.get())); |
| content::WebContentsTester::For(web_contents.get()) |
| ->NavigateAndCommit(file_url); |
| EXPECT_EQ(file_url, web_contents->GetLastCommittedURL()); |
| |
| TabHelper::CreateForWebContents(web_contents.get()); |
| ActiveTabPermissionGranter* permission_granter = |
| TabHelper::FromWebContents(web_contents.get()) |
| ->active_tab_permission_granter(); |
| ASSERT_TRUE(permission_granter); |
| const int tab_id = |
| sessions::SessionTabHelper::IdForTab(web_contents.get()).id(); |
| EXPECT_NE(extension_misc::kUnknownTabId, tab_id); |
| |
| EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( |
| web_contents->GetLastCommittedURL(), tab_id, nullptr, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| |
| permission_granter->GrantIfRequested(extension.get()); |
| EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( |
| web_contents->GetLastCommittedURL(), tab_id, nullptr, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| |
| permission_granter->RevokeForTesting(); |
| TestExtensionRegistryObserver observer(registry(), id); |
| // This will reload the extension, so we need to reset the extension pointer. |
| util::SetAllowFileAccess(id, profile(), true); |
| extension = observer.WaitForExtensionLoaded(); |
| ASSERT_TRUE(extension); |
| |
| EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( |
| web_contents->GetLastCommittedURL(), tab_id, nullptr, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| permission_granter->GrantIfRequested(extension.get()); |
| EXPECT_TRUE(extension->permissions_data()->CanCaptureVisiblePage( |
| web_contents->GetLastCommittedURL(), tab_id, nullptr, |
| extensions::CaptureRequirement::kActiveTabOrAllUrls)); |
| } |
| |
| } // namespace |
| } // namespace extensions |