[go: nahoru, domu]

blob: bab9e39be6bbdeeb1b7b992a9acb3beba9c2c3fa [file] [log] [blame]
Avi Drissman4a8573c2022-09-09 19:35:541// Copyright 2017 The Chromium Authors
michaelpgc1c49322017-06-09 18:22:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Samuel Huang5f0f93a72022-08-18 23:26:405#include "chrome/browser/extensions/api/file_system/consent_provider_impl.h"
michaelpgc1c49322017-06-09 18:22:376
Peter Boström6b701822021-04-15 03:53:087#include <memory>
michaelpgc1c49322017-06-09 18:22:378#include <string>
Samuel Huang5f0f93a72022-08-18 23:26:409#include <utility>
michaelpgc1c49322017-06-09 18:22:3710
Avi Drissman02e49e582023-01-07 01:23:1811#include "base/functional/bind.h"
Xiyuan Xiadfe3a9f2017-11-13 21:46:2612#include "base/memory/ptr_util.h"
Samuel Huang5f0f93a72022-08-18 23:26:4013#include "base/memory/raw_ptr.h"
michaelpgc1c49322017-06-09 18:22:3714#include "base/memory/ref_counted.h"
michaelpgc1c49322017-06-09 18:22:3715#include "base/run_loop.h"
Henrique Ferreiro1ab7f12f2021-03-04 19:54:4016#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
michaelpgc1c49322017-06-09 18:22:3717#include "chrome/test/base/testing_browser_process.h"
18#include "components/prefs/testing_pref_service.h"
Xiyuan Xiadfe3a9f2017-11-13 21:46:2619#include "components/user_manager/scoped_user_manager.h"
michaelpgc1c49322017-06-09 18:22:3720#include "components/user_manager/user.h"
Gabriel Charettec7108742019-08-23 03:31:4021#include "content/public/test/browser_task_environment.h"
michaelpgc1c49322017-06-09 18:22:3722#include "extensions/common/extension.h"
23#include "extensions/common/extension_builder.h"
24#include "extensions/common/manifest.h"
michaelpgc1c49322017-06-09 18:22:3725#include "testing/gtest/include/gtest/gtest.h"
26
Samuel Huang5f0f93a72022-08-18 23:26:4027using extensions::file_system_api::ConsentProviderImpl;
Gyuyoung Kimd1406582021-03-16 10:06:2228using extensions::mojom::ManifestLocation;
michaelpgc1c49322017-06-09 18:22:3729
30namespace extensions {
31namespace {
32
Samuel Huangaff2add2022-08-16 14:37:2633// Configurations and results for TestingConsentProviderDelegate, with directly
34// accessible fields.
35struct TestDelegateState {
36 // Used to assign a fake dialog response.
37 ui::DialogButton dialog_button = ui::DIALOG_BUTTON_NONE;
38
39 // Used to assign fake result of detection the auto launch kiosk mode.
40 bool is_auto_launched = false;
41
42 // Used to set allowlisted components list with a single id.
43 std::string allowlisted_component_id;
44
45 // Counters to record calls.
46 int show_dialog_counter = 0;
47 int show_notification_counter = 0;
48};
49
Samuel Huang5f0f93a72022-08-18 23:26:4050// Test implementation of ConsentProviderImpl::DelegateInterface that exposes
Samuel Huangaff2add2022-08-16 14:37:2651// states to a TestDelegateState instance.
michaelpgc1c49322017-06-09 18:22:3752class TestingConsentProviderDelegate
Samuel Huang5f0f93a72022-08-18 23:26:4053 : public ConsentProviderImpl::DelegateInterface {
michaelpgc1c49322017-06-09 18:22:3754 public:
Samuel Huangaff2add2022-08-16 14:37:2655 explicit TestingConsentProviderDelegate(TestDelegateState* state)
56 : state_(state) {}
michaelpgc1c49322017-06-09 18:22:3757
Peter Boström53c6c5952021-09-17 09:41:2658 TestingConsentProviderDelegate(const TestingConsentProviderDelegate&) =
59 delete;
60 TestingConsentProviderDelegate& operator=(
61 const TestingConsentProviderDelegate&) = delete;
62
Samuel Huang5f0f93a72022-08-18 23:26:4063 ~TestingConsentProviderDelegate() override = default;
michaelpgc1c49322017-06-09 18:22:3764
65 private:
Samuel Huang5f0f93a72022-08-18 23:26:4066 // ConsentProviderImpl::DelegateInterface:
Samuel Huang43a337802022-07-18 19:35:5467 void ShowDialog(content::RenderFrameHost* host,
68 const extensions::ExtensionId& extension_id,
69 const std::string& extension_name,
70 const std::string& volume_id,
71 const std::string& volume_label,
Clark DuVall18fd85d92020-07-09 12:19:4872 bool writable,
Samuel Huang5f0f93a72022-08-18 23:26:4073 ConsentProviderImpl::ShowDialogCallback callback) override {
Samuel Huangaff2add2022-08-16 14:37:2674 ++state_->show_dialog_counter;
75 std::move(callback).Run(state_->dialog_button);
michaelpgc1c49322017-06-09 18:22:3776 }
77
Samuel Huang5f0f93a72022-08-18 23:26:4078 // ConsentProviderImpl::DelegateInterface:
Samuel Huang43a337802022-07-18 19:35:5479 void ShowNotification(const extensions::ExtensionId& extension_id,
80 const std::string& extension_name,
81 const std::string& volume_id,
82 const std::string& volume_label,
michaelpgc1c49322017-06-09 18:22:3783 bool writable) override {
Samuel Huangaff2add2022-08-16 14:37:2684 ++state_->show_notification_counter;
michaelpgc1c49322017-06-09 18:22:3785 }
86
Samuel Huang5f0f93a72022-08-18 23:26:4087 // ConsentProviderImpl::DelegateInterface:
michaelpgc1c49322017-06-09 18:22:3788 bool IsAutoLaunched(const extensions::Extension& extension) override {
Samuel Huangaff2add2022-08-16 14:37:2689 return state_->is_auto_launched;
michaelpgc1c49322017-06-09 18:22:3790 }
91
Samuel Huang5f0f93a72022-08-18 23:26:4092 // ConsentProviderImpl::DelegateInterface:
Alex Daniloa8ed6172020-09-15 12:03:0493 bool IsAllowlistedComponent(const extensions::Extension& extension) override {
Samuel Huangaff2add2022-08-16 14:37:2694 return state_->allowlisted_component_id.compare(extension.id()) == 0;
michaelpgc1c49322017-06-09 18:22:3795 }
96
Samuel Huangaff2add2022-08-16 14:37:2697 // Use raw_ptr since |state| is owned by owner.
98 base::raw_ptr<TestDelegateState> state_;
michaelpgc1c49322017-06-09 18:22:3799};
100
101// Rewrites result of a consent request from |result| to |log|.
Samuel Huang5f0f93a72022-08-18 23:26:40102void OnConsentReceived(ConsentProviderImpl::Consent* log,
103 const ConsentProviderImpl::Consent result) {
michaelpgc1c49322017-06-09 18:22:37104 *log = result;
105}
106
107} // namespace
108
109class FileSystemApiConsentProviderTest : public testing::Test {
110 public:
111 FileSystemApiConsentProviderTest() {}
112
113 void SetUp() override {
Peter Boström6b701822021-04-15 03:53:08114 testing_pref_service_ = std::make_unique<TestingPrefServiceSimple>();
michaelpgc1c49322017-06-09 18:22:37115 TestingBrowserProcess::GetGlobal()->SetLocalState(
116 testing_pref_service_.get());
Henrique Ferreiro4c2fc0a2021-03-26 10:42:47117 user_manager_ = new ash::FakeChromeUserManager;
Xiyuan Xiadfe3a9f2017-11-13 21:46:26118 scoped_user_manager_enabler_ =
119 std::make_unique<user_manager::ScopedUserManager>(
Arthur Sonzogni39396932023-04-24 09:41:33120 base::WrapUnique(user_manager_.get()));
michaelpgc1c49322017-06-09 18:22:37121 }
122
123 void TearDown() override {
124 scoped_user_manager_enabler_.reset();
125 user_manager_ = nullptr;
126 testing_pref_service_.reset();
127 TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
128 }
129
130 protected:
michaelpgc1c49322017-06-09 18:22:37131 std::unique_ptr<TestingPrefServiceSimple> testing_pref_service_;
Arthur Sonzogni39396932023-04-24 09:41:33132 raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh>
133 user_manager_; // Owned by the scope enabler.
Xiyuan Xiadfe3a9f2017-11-13 21:46:26134 std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_enabler_;
Gabriel Charette798fde72019-08-20 22:24:04135 content::BrowserTaskEnvironment task_environment_;
michaelpgc1c49322017-06-09 18:22:37136};
137
138TEST_F(FileSystemApiConsentProviderTest, ForNonKioskApps) {
Alex Daniloa8ed6172020-09-15 12:03:04139 // Component apps are not granted unless they are allowlisted.
michaelpgc1c49322017-06-09 18:22:37140 {
Devlin Cronin8e5892f2018-10-04 00:13:43141 scoped_refptr<const Extension> component_extension(
Devlin Croninef4a7b22017-08-21 20:23:58142 ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
Gyuyoung Kimd1406582021-03-16 10:06:22143 .SetLocation(ManifestLocation::kComponent)
michaelpgc1c49322017-06-09 18:22:37144 .Build());
Samuel Huangaff2add2022-08-16 14:37:26145 TestDelegateState state;
Samuel Huang5f0f93a72022-08-18 23:26:40146 ConsentProviderImpl provider(
147 std::make_unique<TestingConsentProviderDelegate>(&state));
Wei Lee3ddd5942022-07-04 07:50:29148 EXPECT_FALSE(provider.IsGrantable(*component_extension));
michaelpgc1c49322017-06-09 18:22:37149 }
150
Alex Daniloa8ed6172020-09-15 12:03:04151 // Allowlisted component apps are instantly granted access without asking
michaelpgc1c49322017-06-09 18:22:37152 // user.
153 {
Alex Daniloa8ed6172020-09-15 12:03:04154 scoped_refptr<const Extension> allowlisted_component_extension(
Devlin Croninef4a7b22017-08-21 20:23:58155 ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
Gyuyoung Kimd1406582021-03-16 10:06:22156 .SetLocation(ManifestLocation::kComponent)
michaelpgc1c49322017-06-09 18:22:37157 .Build());
Samuel Huangaff2add2022-08-16 14:37:26158 TestDelegateState state;
159 state.allowlisted_component_id = allowlisted_component_extension->id();
Samuel Huang5f0f93a72022-08-18 23:26:40160 ConsentProviderImpl provider(
161 std::make_unique<TestingConsentProviderDelegate>(&state));
Wei Lee3ddd5942022-07-04 07:50:29162 EXPECT_TRUE(provider.IsGrantable(*allowlisted_component_extension));
michaelpgc1c49322017-06-09 18:22:37163
Samuel Huang5f0f93a72022-08-18 23:26:40164 ConsentProviderImpl::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
Samuel Huang43a337802022-07-18 19:35:54165 provider.RequestConsent(nullptr, *allowlisted_component_extension.get(),
166 "Volume ID 1", "Volume Label 1",
167 true /* writable */,
Clark DuVall18fd85d92020-07-09 12:19:48168 base::BindOnce(&OnConsentReceived, &result));
michaelpgc1c49322017-06-09 18:22:37169 base::RunLoop().RunUntilIdle();
170
Samuel Huangaff2add2022-08-16 14:37:26171 EXPECT_EQ(0, state.show_dialog_counter);
172 EXPECT_EQ(0, state.show_notification_counter);
michaelpgc1c49322017-06-09 18:22:37173 EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
174 }
175
176 // Non-component apps in non-kiosk mode will be rejected instantly, without
177 // asking for user consent.
178 {
Devlin Cronin8e5892f2018-10-04 00:13:43179 scoped_refptr<const Extension> non_component_extension(
Devlin Croninc89373f2017-08-21 22:08:33180 ExtensionBuilder("Test").Build());
Samuel Huangaff2add2022-08-16 14:37:26181 TestDelegateState state;
Samuel Huang5f0f93a72022-08-18 23:26:40182 ConsentProviderImpl provider(
183 std::make_unique<TestingConsentProviderDelegate>(&state));
Wei Lee3ddd5942022-07-04 07:50:29184 EXPECT_FALSE(provider.IsGrantable(*non_component_extension));
michaelpgc1c49322017-06-09 18:22:37185 }
186}
187
188TEST_F(FileSystemApiConsentProviderTest, ForKioskApps) {
189 // Non-component apps in auto-launch kiosk mode will be granted access
190 // instantly without asking for user consent, but with a notification.
191 {
Devlin Cronin8e5892f2018-10-04 00:13:43192 scoped_refptr<const Extension> auto_launch_kiosk_app(
Devlin Croninef4a7b22017-08-21 20:23:58193 ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
Devlin Cronin98cd6582018-05-08 19:18:12194 .SetManifestKey("kiosk_enabled", true)
195 .SetManifestKey("kiosk_only", true)
michaelpgc1c49322017-06-09 18:22:37196 .Build());
197 user_manager_->AddKioskAppUser(
198 AccountId::FromUserEmail(auto_launch_kiosk_app->id()));
199 user_manager_->LoginUser(
200 AccountId::FromUserEmail(auto_launch_kiosk_app->id()));
201
Samuel Huangaff2add2022-08-16 14:37:26202 TestDelegateState state;
203 state.is_auto_launched = true;
Samuel Huang5f0f93a72022-08-18 23:26:40204 ConsentProviderImpl provider(
205 std::make_unique<TestingConsentProviderDelegate>(&state));
Wei Lee3ddd5942022-07-04 07:50:29206 EXPECT_TRUE(provider.IsGrantable(*auto_launch_kiosk_app));
michaelpgc1c49322017-06-09 18:22:37207
Samuel Huang5f0f93a72022-08-18 23:26:40208 ConsentProviderImpl::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
Samuel Huang43a337802022-07-18 19:35:54209 provider.RequestConsent(
210 nullptr, *auto_launch_kiosk_app.get(), "Volume ID 2", "Volume Label 2",
211 true /* writable */, base::BindOnce(&OnConsentReceived, &result));
michaelpgc1c49322017-06-09 18:22:37212 base::RunLoop().RunUntilIdle();
213
Samuel Huangaff2add2022-08-16 14:37:26214 EXPECT_EQ(0, state.show_dialog_counter);
215 EXPECT_EQ(1, state.show_notification_counter);
michaelpgc1c49322017-06-09 18:22:37216 EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
217 }
218
219 // Non-component apps in manual-launch kiosk mode will be granted access after
220 // receiving approval from the user.
Devlin Cronin8e5892f2018-10-04 00:13:43221 scoped_refptr<const Extension> manual_launch_kiosk_app(
Devlin Croninef4a7b22017-08-21 20:23:58222 ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
Devlin Cronin98cd6582018-05-08 19:18:12223 .SetManifestKey("kiosk_enabled", true)
224 .SetManifestKey("kiosk_only", true)
michaelpgc1c49322017-06-09 18:22:37225 .Build());
226 user_manager::User* const manual_kiosk_app_user =
227 user_manager_->AddKioskAppUser(
228 AccountId::FromUserEmail(manual_launch_kiosk_app->id()));
229 user_manager_->KioskAppLoggedIn(manual_kiosk_app_user);
230 {
Samuel Huangaff2add2022-08-16 14:37:26231 TestDelegateState state;
232 state.dialog_button = ui::DIALOG_BUTTON_OK;
Samuel Huang5f0f93a72022-08-18 23:26:40233 ConsentProviderImpl provider(
234 std::make_unique<TestingConsentProviderDelegate>(&state));
Wei Lee3ddd5942022-07-04 07:50:29235 EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
michaelpgc1c49322017-06-09 18:22:37236
Samuel Huang5f0f93a72022-08-18 23:26:40237 ConsentProviderImpl::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
Samuel Huang43a337802022-07-18 19:35:54238 provider.RequestConsent(nullptr, *manual_launch_kiosk_app.get(),
239 "Volume ID 3", "Volume Label 3",
michaelpgc1c49322017-06-09 18:22:37240 true /* writable */,
Clark DuVall18fd85d92020-07-09 12:19:48241 base::BindOnce(&OnConsentReceived, &result));
michaelpgc1c49322017-06-09 18:22:37242 base::RunLoop().RunUntilIdle();
243
Samuel Huangaff2add2022-08-16 14:37:26244 EXPECT_EQ(1, state.show_dialog_counter);
245 EXPECT_EQ(0, state.show_notification_counter);
michaelpgc1c49322017-06-09 18:22:37246 EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
247 }
248
249 // Non-component apps in manual-launch kiosk mode will be rejected access
250 // after rejecting by a user.
251 {
Samuel Huangaff2add2022-08-16 14:37:26252 TestDelegateState state;
253 state.dialog_button = ui::DIALOG_BUTTON_CANCEL;
Samuel Huang5f0f93a72022-08-18 23:26:40254 ConsentProviderImpl provider(
255 std::make_unique<TestingConsentProviderDelegate>(&state));
Wei Lee3ddd5942022-07-04 07:50:29256 EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
michaelpgc1c49322017-06-09 18:22:37257
Samuel Huang5f0f93a72022-08-18 23:26:40258 ConsentProviderImpl::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
Samuel Huang43a337802022-07-18 19:35:54259 provider.RequestConsent(nullptr, *manual_launch_kiosk_app.get(),
260 "Volume ID 4", "Volume Label 4",
michaelpgc1c49322017-06-09 18:22:37261 true /* writable */,
Clark DuVall18fd85d92020-07-09 12:19:48262 base::BindOnce(&OnConsentReceived, &result));
michaelpgc1c49322017-06-09 18:22:37263 base::RunLoop().RunUntilIdle();
264
Samuel Huangaff2add2022-08-16 14:37:26265 EXPECT_EQ(1, state.show_dialog_counter);
266 EXPECT_EQ(0, state.show_notification_counter);
michaelpgc1c49322017-06-09 18:22:37267 EXPECT_EQ(ConsentProvider::CONSENT_REJECTED, result);
268 }
269}
270
271} // namespace extensions