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