1 // Copyright 2018 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 "chromeos/components/account_manager/account_manager.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_forward.h"
12 #include "base/callback_helpers.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/files/important_file_writer.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/metrics/histogram_functions.h"
19 #include "base/notreached.h"
20 #include "base/optional.h"
21 #include "base/sequenced_task_runner.h"
22 #include "base/task/post_task.h"
23 #include "base/task/thread_pool.h"
24 #include "base/task_runner_util.h"
25 #include "base/threading/sequenced_task_runner_handle.h"
26 #include "chromeos/components/account_manager/tokens.pb.h"
27 #include "chromeos/constants/chromeos_pref_names.h"
28 #include "components/prefs/pref_registry_simple.h"
29 #include "components/prefs/pref_service.h"
30 #include "google_apis/gaia/gaia_auth_consumer.h"
31 #include "google_apis/gaia/gaia_auth_fetcher.h"
32 #include "google_apis/gaia/gaia_auth_util.h"
33 #include "google_apis/gaia/gaia_constants.h"
34 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
35 #include "services/network/public/cpp/shared_url_loader_factory.h"
36 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
37
38 namespace chromeos {
39
40 namespace {
41
42 constexpr base::FilePath::CharType kTokensFileName[] =
43 FILE_PATH_LITERAL("AccountManagerTokens.bin");
44 constexpr int kTokensFileMaxSizeInBytes = 100000; // ~100 KB.
45
46 constexpr char kNumAccountsMetricName[] = "AccountManager.NumAccounts";
47 constexpr int kMaxNumAccountsMetric = 10;
48
49 // These values are persisted to logs. Entries should not be renumbered and
50 // numeric values should never be reused.
51 // Note: Enums labels are at |AccountManagerTokenLoadStatus|.
52 enum class TokenLoadStatus {
53 kSuccess = 0,
54 kFileReadError = 1,
55 kFileParseError = 2,
56 kAccountCorruptionDetected = 3,
57 kMaxValue = kAccountCorruptionDetected,
58 };
59
RecordNumAccountsMetric(const int num_accounts)60 void RecordNumAccountsMetric(const int num_accounts) {
61 base::UmaHistogramExactLinear(kNumAccountsMetricName, num_accounts,
62 kMaxNumAccountsMetric + 1);
63 }
64
RecordTokenLoadStatus(const TokenLoadStatus & token_load_status)65 void RecordTokenLoadStatus(const TokenLoadStatus& token_load_status) {
66 base::UmaHistogramEnumeration("AccountManager.TokenLoadStatus",
67 token_load_status);
68 }
69
RecordInitializationTime(const base::TimeTicks & initialization_start_time)70 void RecordInitializationTime(
71 const base::TimeTicks& initialization_start_time) {
72 base::UmaHistogramMicrosecondsTimes(
73 "AccountManager.InitializationTime",
74 base::TimeTicks::Now() - initialization_start_time);
75 }
76
77 // Returns `nullopt` if `account_type` is `ACCOUNT_TYPE_UNSPECIFIED`.
FromProtoAccountType(const chromeos::account_manager::AccountType & account_type)78 base::Optional<::account_manager::AccountType> FromProtoAccountType(
79 const chromeos::account_manager::AccountType& account_type) {
80 switch (account_type) {
81 case chromeos::account_manager::AccountType::ACCOUNT_TYPE_UNSPECIFIED:
82 return base::nullopt;
83 case chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA:
84 static_assert(
85 static_cast<int>(
86 chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA) ==
87 static_cast<int>(::account_manager::AccountType::kGaia),
88 "Underlying enum values must match");
89 return ::account_manager::AccountType::kGaia;
90 case chromeos::account_manager::AccountType::ACCOUNT_TYPE_ACTIVE_DIRECTORY:
91 static_assert(static_cast<int>(chromeos::account_manager::AccountType::
92 ACCOUNT_TYPE_ACTIVE_DIRECTORY) ==
93 static_cast<int>(
94 ::account_manager::AccountType::kActiveDirectory),
95 "Underlying enum values must match");
96 return ::account_manager::AccountType::kActiveDirectory;
97 }
98 }
99
ToProtoAccountType(const::account_manager::AccountType & account_type)100 chromeos::account_manager::AccountType ToProtoAccountType(
101 const ::account_manager::AccountType& account_type) {
102 switch (account_type) {
103 case ::account_manager::AccountType::kGaia:
104 return chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA;
105 case ::account_manager::AccountType::kActiveDirectory:
106 return chromeos::account_manager::AccountType::
107 ACCOUNT_TYPE_ACTIVE_DIRECTORY;
108 }
109 }
110
111 } // namespace
112
113 // static
114 const char AccountManager::kActiveDirectoryDummyToken[] = "dummy_ad_token";
115
116 // static
117 const char* const AccountManager::kInvalidToken =
118 GaiaConstants::kInvalidRefreshToken;
119
120 class AccountManager::GaiaTokenRevocationRequest : public GaiaAuthConsumer {
121 public:
GaiaTokenRevocationRequest(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,AccountManager::DelayNetworkCallRunner delay_network_call_runner,const std::string & refresh_token,base::WeakPtr<AccountManager> account_manager)122 GaiaTokenRevocationRequest(
123 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
124 AccountManager::DelayNetworkCallRunner delay_network_call_runner,
125 const std::string& refresh_token,
126 base::WeakPtr<AccountManager> account_manager)
127 : account_manager_(account_manager), refresh_token_(refresh_token) {
128 DCHECK(!refresh_token_.empty());
129 gaia_auth_fetcher_ = std::make_unique<GaiaAuthFetcher>(
130 this, gaia::GaiaSource::kChromeOS, url_loader_factory);
131 base::OnceClosure start_revoke_token = base::BindOnce(
132 &GaiaTokenRevocationRequest::Start, weak_factory_.GetWeakPtr());
133 delay_network_call_runner.Run(std::move(start_revoke_token));
134 }
135 GaiaTokenRevocationRequest(const GaiaTokenRevocationRequest&) = delete;
136 GaiaTokenRevocationRequest& operator=(const GaiaTokenRevocationRequest&) =
137 delete;
138 ~GaiaTokenRevocationRequest() override = default;
139
140 // GaiaAuthConsumer overrides.
OnOAuth2RevokeTokenCompleted(TokenRevocationStatus status)141 void OnOAuth2RevokeTokenCompleted(TokenRevocationStatus status) override {
142 VLOG(1) << "GaiaTokenRevocationRequest::OnOAuth2RevokeTokenCompleted";
143 // We cannot call |AccountManager::DeletePendingTokenRevocationRequest|
144 // directly because it will immediately start deleting |this|, before the
145 // method has had a chance to return.
146 base::SequencedTaskRunnerHandle::Get()->PostTask(
147 FROM_HERE,
148 base::BindOnce(&AccountManager::DeletePendingTokenRevocationRequest,
149 account_manager_, this));
150 }
151
152 private:
153 // Starts the actual work of sending a network request to revoke a token.
Start()154 void Start() { gaia_auth_fetcher_->StartRevokeOAuth2Token(refresh_token_); }
155
156 // A weak pointer to |AccountManager|. The only purpose is to signal
157 // the completion of work through
158 // |AccountManager::DeletePendingTokenRevocationRequest|.
159 base::WeakPtr<AccountManager> account_manager_;
160
161 // Does the actual work of revoking a token.
162 std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
163
164 // Refresh token to be revoked from GAIA.
165 std::string refresh_token_;
166
167 base::WeakPtrFactory<GaiaTokenRevocationRequest> weak_factory_{this};
168 };
169
170 AccountManager::Observer::Observer() = default;
171
172 AccountManager::Observer::~Observer() = default;
173
174 AccountManager::AccountManager() = default;
175
176 // static
RegisterPrefs(PrefRegistrySimple * registry)177 void AccountManager::RegisterPrefs(PrefRegistrySimple* registry) {
178 registry->RegisterBooleanPref(
179 chromeos::prefs::kSecondaryGoogleAccountSigninAllowed,
180 true /* default_value */);
181 }
182
SetPrefService(PrefService * pref_service)183 void AccountManager::SetPrefService(PrefService* pref_service) {
184 DCHECK(pref_service);
185 pref_service_ = pref_service;
186 }
187
InitializeInEphemeralMode(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)188 void AccountManager::InitializeInEphemeralMode(
189 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
190 InitializeInEphemeralMode(url_loader_factory,
191 /* initialization_callback= */
192 base::DoNothing());
193 }
194
InitializeInEphemeralMode(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,base::OnceClosure initialization_callback)195 void AccountManager::InitializeInEphemeralMode(
196 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
197 base::OnceClosure initialization_callback) {
198 Initialize(/* home_dir= */ base::FilePath(), url_loader_factory,
199 /* delay_network_call_runner= */
200 base::BindRepeating(
201 [](base::OnceClosure closure) { std::move(closure).Run(); }),
202 /* task_runner= */ nullptr, std::move(initialization_callback));
203 }
204
Initialize(const base::FilePath & home_dir,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,DelayNetworkCallRunner delay_network_call_runner)205 void AccountManager::Initialize(
206 const base::FilePath& home_dir,
207 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
208 DelayNetworkCallRunner delay_network_call_runner) {
209 Initialize(home_dir, url_loader_factory, delay_network_call_runner,
210 base::DoNothing());
211 }
212
Initialize(const base::FilePath & home_dir,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,DelayNetworkCallRunner delay_network_call_runner,base::OnceClosure initialization_callback)213 void AccountManager::Initialize(
214 const base::FilePath& home_dir,
215 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
216 DelayNetworkCallRunner delay_network_call_runner,
217 base::OnceClosure initialization_callback) {
218 Initialize(
219 home_dir, url_loader_factory, std::move(delay_network_call_runner),
220 base::ThreadPool::CreateSequencedTaskRunner(
221 {base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()}),
222 std::move(initialization_callback));
223 }
224
Initialize(const base::FilePath & home_dir,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,DelayNetworkCallRunner delay_network_call_runner,scoped_refptr<base::SequencedTaskRunner> task_runner,base::OnceClosure initialization_callback)225 void AccountManager::Initialize(
226 const base::FilePath& home_dir,
227 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
228 DelayNetworkCallRunner delay_network_call_runner,
229 scoped_refptr<base::SequencedTaskRunner> task_runner,
230 base::OnceClosure initialization_callback) {
231 VLOG(1) << "AccountManager::Initialize";
232 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
233 const base::TimeTicks initialization_start_time = base::TimeTicks::Now();
234
235 if (init_state_ != InitializationState::kNotStarted) {
236 // |Initialize| has already been called once. To help diagnose possible race
237 // conditions, check whether the |home_dir| parameter provided by the first
238 // invocation of |Initialize| matches the one it is currently being called
239 // with.
240 DCHECK_EQ(home_dir, home_dir_);
241 RunOnInitialization(std::move(initialization_callback));
242 return;
243 }
244
245 home_dir_ = home_dir;
246 init_state_ = InitializationState::kInProgress;
247 url_loader_factory_ = url_loader_factory;
248 delay_network_call_runner_ = std::move(delay_network_call_runner);
249 task_runner_ = task_runner;
250
251 base::FilePath tokens_file_path;
252 if (!IsEphemeralMode()) {
253 DCHECK(task_runner_);
254 tokens_file_path = home_dir_.Append(kTokensFileName);
255 writer_ = std::make_unique<base::ImportantFileWriter>(tokens_file_path,
256 task_runner_);
257 }
258 initialization_callbacks_.emplace_back(std::move(initialization_callback));
259
260 if (!IsEphemeralMode()) {
261 DCHECK(task_runner_);
262 PostTaskAndReplyWithResult(
263 task_runner_.get(), FROM_HERE,
264 base::BindOnce(&AccountManager::LoadAccountsFromDisk, tokens_file_path),
265 base::BindOnce(
266 &AccountManager::InsertAccountsAndRunInitializationCallbacks,
267 weak_factory_.GetWeakPtr(), initialization_start_time));
268 } else {
269 // We are running in ephemeral mode. There is nothing to load from disk.
270 RecordTokenLoadStatus(TokenLoadStatus::kSuccess);
271 InsertAccountsAndRunInitializationCallbacks(initialization_start_time,
272 /* accounts= */ AccountMap{});
273 }
274 }
275
276 // static
LoadAccountsFromDisk(const base::FilePath & tokens_file_path)277 AccountManager::AccountMap AccountManager::LoadAccountsFromDisk(
278 const base::FilePath& tokens_file_path) {
279 AccountMap accounts;
280
281 VLOG(1) << "AccountManager::LoadTokensFromDisk";
282
283 if (tokens_file_path.empty()) {
284 RecordTokenLoadStatus(TokenLoadStatus::kSuccess);
285 return accounts;
286 }
287
288 std::string token_file_data;
289 bool success = base::ReadFileToStringWithMaxSize(
290 tokens_file_path, &token_file_data, kTokensFileMaxSizeInBytes);
291 if (!success) {
292 if (base::PathExists(tokens_file_path)) {
293 // The file exists but cannot be read from.
294 LOG(ERROR) << "Unable to read accounts from disk";
295 RecordTokenLoadStatus(TokenLoadStatus::kFileReadError);
296 }
297 return accounts;
298 }
299
300 chromeos::account_manager::Accounts accounts_proto;
301 success = accounts_proto.ParseFromString(token_file_data);
302 if (!success) {
303 LOG(ERROR) << "Failed to parse tokens from file";
304 RecordTokenLoadStatus(TokenLoadStatus::kFileParseError);
305 return accounts;
306 }
307
308 bool is_any_account_corrupt = false;
309 for (const auto& account : accounts_proto.accounts()) {
310 const base::Optional<::account_manager::AccountType> account_type =
311 FromProtoAccountType(account.account_type());
312 if (!account_type.has_value()) {
313 LOG(WARNING) << "Ignoring invalid account_type load from disk";
314 is_any_account_corrupt = true;
315 continue;
316 }
317 ::account_manager::AccountKey account_key{account.id(),
318 account_type.value()};
319 if (!account_key.IsValid()) {
320 LOG(WARNING) << "Ignoring invalid account_key load from disk: "
321 << account_key;
322 is_any_account_corrupt = true;
323 continue;
324 }
325 accounts[account_key] = AccountInfo{account.raw_email(), account.token()};
326 }
327 if (is_any_account_corrupt) {
328 RecordTokenLoadStatus(TokenLoadStatus::kAccountCorruptionDetected);
329 return accounts;
330 }
331
332 RecordTokenLoadStatus(TokenLoadStatus::kSuccess);
333 return accounts;
334 }
335
InsertAccountsAndRunInitializationCallbacks(const base::TimeTicks & initialization_start_time,const AccountMap & accounts)336 void AccountManager::InsertAccountsAndRunInitializationCallbacks(
337 const base::TimeTicks& initialization_start_time,
338 const AccountMap& accounts) {
339 VLOG(1) << "AccountManager::RunInitializationCallbacks";
340 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
341
342 accounts_.insert(accounts.begin(), accounts.end());
343 init_state_ = InitializationState::kInitialized;
344 RecordInitializationTime(initialization_start_time);
345
346 for (auto& cb : initialization_callbacks_) {
347 std::move(cb).Run();
348 }
349 initialization_callbacks_.clear();
350
351 for (const auto& account : accounts_) {
352 NotifyTokenObservers(::account_manager::Account{account.first /* key */,
353 account.second.raw_email});
354 }
355
356 RecordNumAccountsMetric(accounts_.size());
357 }
358
359 // AccountManager is supposed to be used as a leaky global.
360 AccountManager::~AccountManager() = default;
361
IsInitialized() const362 bool AccountManager::IsInitialized() const {
363 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
364 return init_state_ == InitializationState::kInitialized;
365 }
366
RunOnInitialization(base::OnceClosure closure)367 void AccountManager::RunOnInitialization(base::OnceClosure closure) {
368 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
369
370 if (init_state_ != InitializationState::kInitialized) {
371 initialization_callbacks_.emplace_back(std::move(closure));
372 } else {
373 std::move(closure).Run();
374 }
375 }
376
GetAccounts(AccountListCallback callback)377 void AccountManager::GetAccounts(AccountListCallback callback) {
378 DCHECK_NE(init_state_, InitializationState::kNotStarted);
379
380 base::OnceClosure closure =
381 base::BindOnce(&AccountManager::GetAccountsInternal,
382 weak_factory_.GetWeakPtr(), std::move(callback));
383 RunOnInitialization(std::move(closure));
384 }
385
GetAccountsInternal(AccountListCallback callback)386 void AccountManager::GetAccountsInternal(AccountListCallback callback) {
387 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
388 DCHECK_EQ(init_state_, InitializationState::kInitialized);
389
390 std::move(callback).Run(GetAccounts());
391 }
392
GetAccountEmail(const::account_manager::AccountKey & account_key,base::OnceCallback<void (const std::string &)> callback)393 void AccountManager::GetAccountEmail(
394 const ::account_manager::AccountKey& account_key,
395 base::OnceCallback<void(const std::string&)> callback) {
396 DCHECK_NE(init_state_, InitializationState::kNotStarted);
397
398 base::OnceClosure closure = base::BindOnce(
399 &AccountManager::GetAccountEmailInternal, weak_factory_.GetWeakPtr(),
400 account_key, std::move(callback));
401 RunOnInitialization(std::move(closure));
402 }
403
GetAccountEmailInternal(const::account_manager::AccountKey & account_key,base::OnceCallback<void (const std::string &)> callback)404 void AccountManager::GetAccountEmailInternal(
405 const ::account_manager::AccountKey& account_key,
406 base::OnceCallback<void(const std::string&)> callback) {
407 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
408 DCHECK_EQ(init_state_, InitializationState::kInitialized);
409
410 auto it = accounts_.find(account_key);
411 if (it == accounts_.end()) {
412 std::move(callback).Run(std::string());
413 return;
414 }
415
416 std::move(callback).Run(it->second.raw_email);
417 }
418
RemoveAccount(const::account_manager::AccountKey & account_key)419 void AccountManager::RemoveAccount(
420 const ::account_manager::AccountKey& account_key) {
421 DCHECK_NE(init_state_, InitializationState::kNotStarted);
422
423 base::OnceClosure closure =
424 base::BindOnce(&AccountManager::RemoveAccountInternal,
425 weak_factory_.GetWeakPtr(), account_key);
426 RunOnInitialization(std::move(closure));
427 }
428
RemoveAccountInternal(const::account_manager::AccountKey & account_key)429 void AccountManager::RemoveAccountInternal(
430 const ::account_manager::AccountKey& account_key) {
431 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
432 DCHECK_EQ(init_state_, InitializationState::kInitialized);
433
434 auto it = accounts_.find(account_key);
435 if (it == accounts_.end()) {
436 return;
437 }
438
439 const std::string raw_email = it->second.raw_email;
440 const std::string old_token = it->second.token;
441 accounts_.erase(it);
442 PersistAccountsAsync();
443 NotifyAccountRemovalObservers(
444 ::account_manager::Account{account_key, raw_email});
445 MaybeRevokeTokenOnServer(account_key, old_token);
446 }
447
RemoveAccount(const std::string & email)448 void AccountManager::RemoveAccount(const std::string& email) {
449 DCHECK_NE(init_state_, InitializationState::kNotStarted);
450
451 base::OnceClosure closure =
452 base::BindOnce(&AccountManager::RemoveAccountByEmailInternal,
453 weak_factory_.GetWeakPtr(), email);
454 RunOnInitialization(std::move(closure));
455 }
456
RemoveAccountByEmailInternal(const std::string & email)457 void AccountManager::RemoveAccountByEmailInternal(const std::string& email) {
458 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
459 DCHECK_EQ(init_state_, InitializationState::kInitialized);
460
461 for (const std::pair<::account_manager::AccountKey, AccountInfo> account :
462 accounts_) {
463 if (gaia::AreEmailsSame(account.second.raw_email, email)) {
464 RemoveAccountInternal(account.first /* account_key */);
465 return;
466 }
467 }
468 }
469
UpsertAccount(const::account_manager::AccountKey & account_key,const std::string & raw_email,const std::string & token)470 void AccountManager::UpsertAccount(
471 const ::account_manager::AccountKey& account_key,
472 const std::string& raw_email,
473 const std::string& token) {
474 DCHECK_NE(init_state_, InitializationState::kNotStarted);
475 DCHECK(!raw_email.empty());
476
477 base::OnceClosure closure = base::BindOnce(
478 &AccountManager::UpsertAccountInternal, weak_factory_.GetWeakPtr(),
479 account_key, AccountInfo{raw_email, token});
480 RunOnInitialization(std::move(closure));
481 }
482
UpdateToken(const::account_manager::AccountKey & account_key,const std::string & token)483 void AccountManager::UpdateToken(
484 const ::account_manager::AccountKey& account_key,
485 const std::string& token) {
486 DCHECK_NE(init_state_, InitializationState::kNotStarted);
487
488 if (account_key.account_type ==
489 ::account_manager::AccountType::kActiveDirectory) {
490 DCHECK_EQ(token, kActiveDirectoryDummyToken);
491 }
492
493 base::OnceClosure closure =
494 base::BindOnce(&AccountManager::UpdateTokenInternal,
495 weak_factory_.GetWeakPtr(), account_key, token);
496 RunOnInitialization(std::move(closure));
497 }
498
UpdateTokenInternal(const::account_manager::AccountKey & account_key,const std::string & token)499 void AccountManager::UpdateTokenInternal(
500 const ::account_manager::AccountKey& account_key,
501 const std::string& token) {
502 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
503 DCHECK_EQ(init_state_, InitializationState::kInitialized);
504
505 auto it = accounts_.find(account_key);
506 DCHECK(it != accounts_.end())
507 << "UpdateToken cannot be used for adding accounts";
508 UpsertAccountInternal(account_key, AccountInfo{it->second.raw_email, token});
509 }
510
UpdateEmail(const::account_manager::AccountKey & account_key,const std::string & raw_email)511 void AccountManager::UpdateEmail(
512 const ::account_manager::AccountKey& account_key,
513 const std::string& raw_email) {
514 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
515 DCHECK_NE(init_state_, InitializationState::kNotStarted);
516
517 base::OnceClosure closure =
518 base::BindOnce(&AccountManager::UpdateEmailInternal,
519 weak_factory_.GetWeakPtr(), account_key, raw_email);
520 RunOnInitialization(std::move(closure));
521 }
522
UpdateEmailInternal(const::account_manager::AccountKey & account_key,const std::string & raw_email)523 void AccountManager::UpdateEmailInternal(
524 const ::account_manager::AccountKey& account_key,
525 const std::string& raw_email) {
526 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
527 DCHECK_EQ(init_state_, InitializationState::kInitialized);
528
529 auto it = accounts_.find(account_key);
530 DCHECK(it != accounts_.end())
531 << "UpdateEmail cannot be used for adding accounts";
532 UpsertAccountInternal(account_key, AccountInfo{raw_email, it->second.token});
533 }
534
UpsertAccountInternal(const::account_manager::AccountKey & account_key,const AccountInfo & account)535 void AccountManager::UpsertAccountInternal(
536 const ::account_manager::AccountKey& account_key,
537 const AccountInfo& account) {
538 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
539 DCHECK_EQ(init_state_, InitializationState::kInitialized);
540 DCHECK(account_key.IsValid()) << "Invalid account_key: " << account_key;
541
542 if (account_key.account_type == ::account_manager::AccountType::kGaia) {
543 DCHECK(!account.raw_email.empty())
544 << "Email must be present for Gaia accounts";
545 }
546
547 auto it = accounts_.find(account_key);
548 if (it == accounts_.end()) {
549 // This is a new account. Insert it.
550
551 // New account insertions can only happen through a user action, which
552 // implies that |Profile| must have been fully initialized at this point.
553 // |ProfileImpl|'s constructor guarantees that
554 // |AccountManager::SetPrefService| has been called on this object, which in
555 // turn guarantees that |pref_service_| is not null.
556 DCHECK(pref_service_);
557 if (!pref_service_->GetBoolean(
558 chromeos::prefs::kSecondaryGoogleAccountSigninAllowed)) {
559 // Secondary Account additions are disabled by policy and all flows for
560 // adding a Secondary Account are already blocked.
561 CHECK(accounts_.empty());
562 }
563 accounts_.emplace(account_key, account);
564 PersistAccountsAsync();
565 NotifyTokenObservers(
566 ::account_manager::Account{account_key, account.raw_email});
567 return;
568 }
569
570 // Precondition: Iterator |it| is valid and points to a previously known
571 // account.
572 const std::string old_token = it->second.token;
573 const bool did_token_change = (old_token != account.token);
574 it->second = account;
575 PersistAccountsAsync();
576
577 if (did_token_change) {
578 NotifyTokenObservers(
579 ::account_manager::Account{account_key, account.raw_email});
580 }
581 }
582
PersistAccountsAsync()583 void AccountManager::PersistAccountsAsync() {
584 if (IsEphemeralMode()) {
585 return;
586 }
587
588 // Schedule (immediately) a non-blocking write.
589 DCHECK(writer_);
590 writer_->WriteNow(std::make_unique<std::string>(GetSerializedAccounts()));
591 }
592
GetSerializedAccounts()593 std::string AccountManager::GetSerializedAccounts() {
594 chromeos::account_manager::Accounts accounts_proto;
595
596 for (const auto& account : accounts_) {
597 account_manager::Account* account_proto = accounts_proto.add_accounts();
598 account_proto->set_id(account.first.id);
599 account_proto->set_account_type(
600 ToProtoAccountType(account.first.account_type));
601 account_proto->set_raw_email(account.second.raw_email);
602 account_proto->set_token(account.second.token);
603 }
604
605 return accounts_proto.SerializeAsString();
606 }
607
GetAccounts()608 std::vector<::account_manager::Account> AccountManager::GetAccounts() {
609 std::vector<::account_manager::Account> accounts;
610 accounts.reserve(accounts_.size());
611
612 for (const auto& key_val : accounts_) {
613 accounts.emplace_back(
614 ::account_manager::Account{key_val.first, key_val.second.raw_email});
615 }
616
617 return accounts;
618 }
619
NotifyTokenObservers(const::account_manager::Account & account)620 void AccountManager::NotifyTokenObservers(
621 const ::account_manager::Account& account) {
622 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
623
624 for (auto& observer : observers_) {
625 observer.OnTokenUpserted(account);
626 }
627 }
628
NotifyAccountRemovalObservers(const::account_manager::Account & account)629 void AccountManager::NotifyAccountRemovalObservers(
630 const ::account_manager::Account& account) {
631 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
632
633 for (auto& observer : observers_) {
634 observer.OnAccountRemoved(account);
635 }
636 }
637
AddObserver(AccountManager::Observer * observer)638 void AccountManager::AddObserver(AccountManager::Observer* observer) {
639 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
640 observers_.AddObserver(observer);
641 }
642
RemoveObserver(AccountManager::Observer * observer)643 void AccountManager::RemoveObserver(AccountManager::Observer* observer) {
644 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
645 observers_.RemoveObserver(observer);
646 }
647
SetUrlLoaderFactoryForTests(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)648 void AccountManager::SetUrlLoaderFactoryForTests(
649 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
650 url_loader_factory_ = url_loader_factory;
651 }
652
653 std::unique_ptr<OAuth2AccessTokenFetcher>
CreateAccessTokenFetcher(const::account_manager::AccountKey & account_key,OAuth2AccessTokenConsumer * consumer) const654 AccountManager::CreateAccessTokenFetcher(
655 const ::account_manager::AccountKey& account_key,
656 OAuth2AccessTokenConsumer* consumer) const {
657 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
658
659 auto it = accounts_.find(account_key);
660 if (it == accounts_.end() || it->second.token.empty()) {
661 return nullptr;
662 }
663
664 return std::make_unique<OAuth2AccessTokenFetcherImpl>(
665 consumer, url_loader_factory_, it->second.token);
666 }
667
IsTokenAvailable(const::account_manager::AccountKey & account_key) const668 bool AccountManager::IsTokenAvailable(
669 const ::account_manager::AccountKey& account_key) const {
670 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
671
672 auto it = accounts_.find(account_key);
673 return it != accounts_.end() && !it->second.token.empty() &&
674 it->second.token != kActiveDirectoryDummyToken;
675 }
676
HasDummyGaiaToken(const::account_manager::AccountKey & account_key,base::OnceCallback<void (bool)> callback)677 void AccountManager::HasDummyGaiaToken(
678 const ::account_manager::AccountKey& account_key,
679 base::OnceCallback<void(bool)> callback) {
680 DCHECK_NE(init_state_, InitializationState::kNotStarted);
681
682 base::OnceClosure closure = base::BindOnce(
683 &AccountManager::HasDummyGaiaTokenInternal, weak_factory_.GetWeakPtr(),
684 account_key, std::move(callback));
685 RunOnInitialization(std::move(closure));
686 }
687
HasDummyGaiaTokenInternal(const::account_manager::AccountKey & account_key,base::OnceCallback<void (bool)> callback) const688 void AccountManager::HasDummyGaiaTokenInternal(
689 const ::account_manager::AccountKey& account_key,
690 base::OnceCallback<void(bool)> callback) const {
691 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
692 DCHECK_EQ(init_state_, InitializationState::kInitialized);
693
694 auto it = accounts_.find(account_key);
695 std::move(callback).Run(it != accounts_.end() &&
696 it->second.token == kInvalidToken);
697 }
698
CheckDummyGaiaTokenForAllAccounts(base::OnceCallback<void (const std::vector<std::pair<::account_manager::Account,bool>> &)> callback)699 void AccountManager::CheckDummyGaiaTokenForAllAccounts(
700 base::OnceCallback<
701 void(const std::vector<std::pair<::account_manager::Account, bool>>&)>
702 callback) {
703 DCHECK_NE(init_state_, InitializationState::kNotStarted);
704
705 base::OnceClosure closure =
706 base::BindOnce(&AccountManager::CheckDummyGaiaTokenForAllAccountsInternal,
707 weak_factory_.GetWeakPtr(), std::move(callback));
708 RunOnInitialization(std::move(closure));
709 }
710
CheckDummyGaiaTokenForAllAccountsInternal(base::OnceCallback<void (const std::vector<std::pair<::account_manager::Account,bool>> &)> callback) const711 void AccountManager::CheckDummyGaiaTokenForAllAccountsInternal(
712 base::OnceCallback<
713 void(const std::vector<std::pair<::account_manager::Account, bool>>&)>
714 callback) const {
715 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
716 DCHECK_EQ(init_state_, InitializationState::kInitialized);
717
718 std::vector<std::pair<::account_manager::Account, bool>> accounts_list;
719 accounts_list.reserve(accounts_.size());
720
721 for (const auto& key_val : accounts_) {
722 accounts_list.emplace_back(
723 ::account_manager::Account{key_val.first, key_val.second.raw_email},
724 key_val.second.token == kInvalidToken);
725 }
726
727 std::move(callback).Run(accounts_list);
728 }
729
MaybeRevokeTokenOnServer(const::account_manager::AccountKey & account_key,const std::string & old_token)730 void AccountManager::MaybeRevokeTokenOnServer(
731 const ::account_manager::AccountKey& account_key,
732 const std::string& old_token) {
733 if ((account_key.account_type == ::account_manager::AccountType::kGaia) &&
734 !old_token.empty() && (old_token != kInvalidToken)) {
735 RevokeGaiaTokenOnServer(old_token);
736 }
737 }
738
RevokeGaiaTokenOnServer(const std::string & refresh_token)739 void AccountManager::RevokeGaiaTokenOnServer(const std::string& refresh_token) {
740 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
741
742 pending_token_revocation_requests_.emplace_back(
743 std::make_unique<GaiaTokenRevocationRequest>(
744 url_loader_factory_, delay_network_call_runner_, refresh_token,
745 weak_factory_.GetWeakPtr()));
746 }
747
DeletePendingTokenRevocationRequest(GaiaTokenRevocationRequest * request)748 void AccountManager::DeletePendingTokenRevocationRequest(
749 GaiaTokenRevocationRequest* request) {
750 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
751
752 auto it = std::find_if(
753 pending_token_revocation_requests_.begin(),
754 pending_token_revocation_requests_.end(),
755 [&request](
756 const std::unique_ptr<GaiaTokenRevocationRequest>& pending_request)
757 -> bool { return pending_request.get() == request; });
758
759 if (it != pending_token_revocation_requests_.end()) {
760 pending_token_revocation_requests_.erase(it);
761 }
762 }
763
IsEphemeralMode() const764 bool AccountManager::IsEphemeralMode() const {
765 return home_dir_.empty();
766 }
767
768 } // namespace chromeos
769