1 // Copyright 2019 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 "chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h"
6
7 #include <memory>
8 #include <ostream>
9
10 #include "base/test/bind_test_util.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/browser_process_platform_part.h"
13 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
14 #include "chrome/browser/chromeos/profiles/profile_helper.h"
15 #include "chrome/browser/signin/identity_manager_factory.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "chromeos/components/account_manager/account_manager.h"
19 #include "chromeos/components/account_manager/account_manager_factory.h"
20 #include "components/signin/public/identity_manager/identity_manager.h"
21 #include "components/signin/public/identity_manager/identity_test_utils.h"
22 #include "components/user_manager/scoped_user_manager.h"
23 #include "components/user_manager/user_type.h"
24 #include "content/public/test/test_web_ui.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace {
28 constexpr char kGetAccountsMessage[] = "getAccounts";
29 constexpr char kHandleFunctionName[] = "handleFunctionName";
30
31 struct DeviceAccountInfo {
32 std::string id;
33 std::string email;
34 std::string fullName;
35 std::string organization;
36
37 user_manager::UserType user_type;
38 chromeos::account_manager::AccountType account_type;
39 std::string token;
40
41 friend std::ostream& operator<<(std::ostream& stream,
42 const DeviceAccountInfo& device_account_info);
43 };
44
operator <<(std::ostream & stream,const DeviceAccountInfo & device_account_info)45 std::ostream& operator<<(std::ostream& stream,
46 const DeviceAccountInfo& device_account_info) {
47 return stream << "{email: " << device_account_info.email
48 << ", user_type: " << device_account_info.user_type << "}";
49 }
50
GetActiveDirectoryDeviceAccountInfo()51 DeviceAccountInfo GetActiveDirectoryDeviceAccountInfo() {
52 return {"fake-ad-id" /*id*/,
53 "primary@example.com" /*email*/,
54 "primary" /*fullName*/,
55 "example.com" /*organization*/,
56 user_manager::USER_TYPE_ACTIVE_DIRECTORY /*user_type*/,
57 chromeos::account_manager::AccountType::
58 ACCOUNT_TYPE_ACTIVE_DIRECTORY /*account_type*/,
59 chromeos::AccountManager::kActiveDirectoryDummyToken /*token*/};
60 }
61
GetGaiaDeviceAccountInfo()62 DeviceAccountInfo GetGaiaDeviceAccountInfo() {
63 return {signin::GetTestGaiaIdForEmail("primary@example.com") /*id*/,
64 "primary@example.com" /*email*/,
65 "primary" /*fullName*/,
66 "" /*organization*/,
67 user_manager::USER_TYPE_REGULAR /*user_type*/,
68 chromeos::account_manager::AccountType::
69 ACCOUNT_TYPE_GAIA /*account_type*/,
70 "device-account-token" /*token*/};
71 }
72
GetAccountByKey(std::vector<chromeos::AccountManager::Account> accounts,chromeos::AccountManager::AccountKey key)73 chromeos::AccountManager::Account GetAccountByKey(
74 std::vector<chromeos::AccountManager::Account> accounts,
75 chromeos::AccountManager::AccountKey key) {
76 for (const chromeos::AccountManager::Account& account : accounts) {
77 if (account.key == key) {
78 return account;
79 }
80 }
81 return chromeos::AccountManager::Account();
82 }
83
ValueOrEmpty(const std::string * str)84 std::string ValueOrEmpty(const std::string* str) {
85 return str ? *str : std::string();
86 }
87
88 } // namespace
89
90 namespace chromeos {
91 namespace settings {
92
93 class TestingAccountManagerUIHandler : public AccountManagerUIHandler {
94 public:
TestingAccountManagerUIHandler(AccountManager * account_manager,signin::IdentityManager * identity_manager,content::WebUI * web_ui)95 TestingAccountManagerUIHandler(AccountManager* account_manager,
96 signin::IdentityManager* identity_manager,
97 content::WebUI* web_ui)
98 : AccountManagerUIHandler(account_manager, identity_manager) {
99 set_web_ui(web_ui);
100 }
101
102 private:
103 DISALLOW_COPY_AND_ASSIGN(TestingAccountManagerUIHandler);
104 };
105
106 class AccountManagerUIHandlerTest
107 : public InProcessBrowserTest,
108 public testing::WithParamInterface<DeviceAccountInfo> {
109 public:
110 AccountManagerUIHandlerTest() = default;
111 AccountManagerUIHandlerTest(const AccountManagerUIHandlerTest&) = delete;
112 AccountManagerUIHandlerTest& operator=(const AccountManagerUIHandlerTest&) =
113 delete;
114
SetUpOnMainThread()115 void SetUpOnMainThread() override {
116 user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
117 std::make_unique<chromeos::FakeChromeUserManager>());
118 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
119 TestingProfile::Builder profile_builder;
120 profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestProfile"));
121 profile_builder.SetProfileName(GetDeviceAccountInfo().email);
122 profile_ = profile_builder.Build();
123
124 const user_manager::User* user;
125 if (GetDeviceAccountInfo().user_type ==
126 user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY) {
127 user = GetFakeUserManager()->AddUserWithAffiliationAndTypeAndProfile(
128 AccountId::AdFromUserEmailObjGuid(GetDeviceAccountInfo().email,
129 GetDeviceAccountInfo().id),
130 true, user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
131 profile_.get());
132 } else {
133 user = GetFakeUserManager()->AddUserWithAffiliationAndTypeAndProfile(
134 AccountId::FromUserEmailGaiaId(GetDeviceAccountInfo().email,
135 GetDeviceAccountInfo().id),
136 true, GetDeviceAccountInfo().user_type, profile_.get());
137 }
138
139 identity_manager_ = IdentityManagerFactory::GetForProfile(profile_.get());
140
141 chromeos::AccountManagerFactory* factory =
142 g_browser_process->platform_part()->GetAccountManagerFactory();
143 account_manager_ = factory->GetAccountManager(profile_->GetPath().value());
144
145 account_manager_->UpsertAccount(
146 AccountManager::AccountKey{GetDeviceAccountInfo().id,
147 GetDeviceAccountInfo().account_type},
148 GetDeviceAccountInfo().email, GetDeviceAccountInfo().token);
149
150 handler_ = std::make_unique<TestingAccountManagerUIHandler>(
151 account_manager_, identity_manager_, &web_ui_);
152 handler_->SetProfileForTesting(profile_.get());
153 handler_->RegisterMessages();
154 handler_->AllowJavascriptForTesting();
155 base::RunLoop().RunUntilIdle();
156 }
157
TearDownOnMainThread()158 void TearDownOnMainThread() override {
159 handler_.reset();
160 profile_.reset();
161 user_manager_enabler_.reset();
162 }
163
UpsertAccount(std::string email)164 void UpsertAccount(std::string email) {
165 account_manager_->UpsertAccount(
166 AccountManager::AccountKey{
167 signin::GetTestGaiaIdForEmail(email),
168 chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA},
169 email, AccountManager::kInvalidToken);
170 }
171
GetAccountsFromAccountManager() const172 std::vector<AccountManager::Account> GetAccountsFromAccountManager() const {
173 std::vector<AccountManager::Account> accounts;
174
175 base::RunLoop run_loop;
176 account_manager_->GetAccounts(base::BindLambdaForTesting(
177 [&accounts, &run_loop](
178 const std::vector<AccountManager::Account>& stored_accounts) {
179 accounts = stored_accounts;
180 run_loop.Quit();
181 }));
182 run_loop.Run();
183
184 return accounts;
185 }
186
GetDeviceAccountInfo() const187 DeviceAccountInfo GetDeviceAccountInfo() const { return GetParam(); }
188
web_ui()189 content::TestWebUI* web_ui() { return &web_ui_; }
identity_manager()190 signin::IdentityManager* identity_manager() { return identity_manager_; }
account_manager()191 chromeos::AccountManager* account_manager() { return account_manager_; }
192
193 private:
GetFakeUserManager() const194 chromeos::FakeChromeUserManager* GetFakeUserManager() const {
195 return static_cast<chromeos::FakeChromeUserManager*>(
196 user_manager::UserManager::Get());
197 }
198
199 std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
200 base::ScopedTempDir temp_dir_;
201 std::unique_ptr<TestingProfile> profile_;
202 chromeos::AccountManager* account_manager_ = nullptr;
203 signin::IdentityManager* identity_manager_ = nullptr;
204 content::TestWebUI web_ui_;
205 std::unique_ptr<TestingAccountManagerUIHandler> handler_;
206 };
207
IN_PROC_BROWSER_TEST_P(AccountManagerUIHandlerTest,OnGetAccountsNoSecondaryAccounts)208 IN_PROC_BROWSER_TEST_P(AccountManagerUIHandlerTest,
209 OnGetAccountsNoSecondaryAccounts) {
210 const std::vector<AccountManager::Account> account_manager_accounts =
211 GetAccountsFromAccountManager();
212 // Only Primary account.
213 ASSERT_EQ(1UL, account_manager_accounts.size());
214
215 // Call "getAccounts".
216 base::ListValue args;
217 args.AppendString(kHandleFunctionName);
218 web_ui()->HandleReceivedMessage(kGetAccountsMessage, &args);
219
220 const content::TestWebUI::CallData& call_data = *web_ui()->call_data().back();
221 EXPECT_EQ("cr.webUIResponse", call_data.function_name());
222 EXPECT_EQ(kHandleFunctionName, call_data.arg1()->GetString());
223 ASSERT_TRUE(call_data.arg2()->GetBool());
224
225 // Get results from JS callback.
226 const base::span<const base::Value> result = call_data.arg3()->GetList();
227 ASSERT_EQ(account_manager_accounts.size(), result.size());
228
229 // Check first (device) account.
230 const base::Value& device_account = result[0];
231 EXPECT_TRUE(device_account.FindBoolKey("isDeviceAccount").value());
232 EXPECT_TRUE(device_account.FindBoolKey("isSignedIn").value());
233 EXPECT_FALSE(device_account.FindBoolKey("unmigrated").value());
234 EXPECT_EQ(GetDeviceAccountInfo().account_type,
235 device_account.FindIntKey("accountType"));
236 EXPECT_EQ(GetDeviceAccountInfo().email,
237 ValueOrEmpty(device_account.FindStringKey("email")));
238 EXPECT_EQ(GetDeviceAccountInfo().id,
239 ValueOrEmpty(device_account.FindStringKey("id")));
240 EXPECT_EQ(GetDeviceAccountInfo().organization,
241 ValueOrEmpty(device_account.FindStringKey("organization")));
242 }
243
IN_PROC_BROWSER_TEST_P(AccountManagerUIHandlerTest,OnGetAccountsWithSecondaryAccounts)244 IN_PROC_BROWSER_TEST_P(AccountManagerUIHandlerTest,
245 OnGetAccountsWithSecondaryAccounts) {
246 UpsertAccount("secondary1@example.com");
247 UpsertAccount("secondary2@example.com");
248 const std::vector<AccountManager::Account> account_manager_accounts =
249 GetAccountsFromAccountManager();
250 ASSERT_EQ(3UL, account_manager_accounts.size());
251
252 // Call "getAccounts".
253 base::ListValue args;
254 args.AppendString(kHandleFunctionName);
255 web_ui()->HandleReceivedMessage(kGetAccountsMessage, &args);
256
257 const content::TestWebUI::CallData& call_data = *web_ui()->call_data().back();
258 EXPECT_EQ("cr.webUIResponse", call_data.function_name());
259 EXPECT_EQ(kHandleFunctionName, call_data.arg1()->GetString());
260 ASSERT_TRUE(call_data.arg2()->GetBool());
261
262 // Get results from JS callback.
263 const base::span<const base::Value> result = call_data.arg3()->GetList();
264 ASSERT_EQ(account_manager_accounts.size(), result.size());
265
266 // Check first (device) account.
267 const base::Value& device_account = result[0];
268 EXPECT_TRUE(device_account.FindBoolKey("isDeviceAccount").value());
269 EXPECT_TRUE(device_account.FindBoolKey("isSignedIn").value());
270 EXPECT_FALSE(device_account.FindBoolKey("unmigrated").value());
271 EXPECT_EQ(GetDeviceAccountInfo().account_type,
272 device_account.FindIntKey("accountType"));
273 EXPECT_EQ(GetDeviceAccountInfo().email,
274 ValueOrEmpty(device_account.FindStringKey("email")));
275 EXPECT_EQ(GetDeviceAccountInfo().id,
276 ValueOrEmpty(device_account.FindStringKey("id")));
277 EXPECT_EQ(GetDeviceAccountInfo().organization,
278 ValueOrEmpty(device_account.FindStringKey("organization")));
279
280 // Check secondary accounts.
281 for (const base::Value& account : result) {
282 if (ValueOrEmpty(account.FindStringKey("id")) == GetDeviceAccountInfo().id)
283 continue;
284 EXPECT_FALSE(account.FindBoolKey("isDeviceAccount").value());
285
286 AccountManager::Account expected_account =
287 GetAccountByKey(account_manager_accounts,
288 {ValueOrEmpty(account.FindStringKey("id")),
289 account_manager::AccountType::ACCOUNT_TYPE_GAIA});
290 EXPECT_EQ(account_manager()->HasDummyGaiaToken(expected_account.key),
291 account.FindBoolKey("unmigrated").value());
292 EXPECT_EQ(expected_account.key.account_type,
293 account.FindIntKey("accountType"));
294 EXPECT_EQ(expected_account.raw_email,
295 ValueOrEmpty(account.FindStringKey("email")));
296
297 base::Optional<AccountInfo> expected_account_info =
298 identity_manager()
299 ->FindExtendedAccountInfoForAccountWithRefreshTokenByGaiaId(
300 expected_account.key.id);
301 EXPECT_TRUE(expected_account_info.has_value());
302 EXPECT_EQ(expected_account_info->full_name,
303 ValueOrEmpty(account.FindStringKey("fullName")));
304 EXPECT_EQ(
305 !identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
306 expected_account_info->account_id),
307 account.FindBoolKey("isSignedIn").value());
308 }
309 }
310
311 INSTANTIATE_TEST_SUITE_P(
312 AccountManagerUIHandlerTestSuite,
313 AccountManagerUIHandlerTest,
314 ::testing::Values(GetActiveDirectoryDeviceAccountInfo(),
315 GetGaiaDeviceAccountInfo()));
316
317 } // namespace settings
318 } // namespace chromeos
319