1 // Copyright 2013 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.
5 #include "chrome/browser/signin/account_reconcilor.h"
7 #include "base/json/json_reader.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/net/chrome_cookie_notification_details.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/signin/profile_oauth2_token_service.h"
16 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "google_apis/gaia/gaia_auth_fetcher.h"
21 #include "google_apis/gaia/gaia_auth_util.h"
22 #include "google_apis/gaia/gaia_constants.h"
23 #include "google_apis/gaia/gaia_oauth_client.h"
24 #include "google_apis/gaia/gaia_urls.h"
26 // Fetches a refresh token from the given session in the GAIA cookie. This is
27 // a best effort only. If it should fail, another reconcile action will occur
29 class AccountReconcilor::RefreshTokenFetcher : public GaiaAuthConsumer {
31 RefreshTokenFetcher(AccountReconcilor* reconcilor,
32 const std::string& account_id,
34 virtual ~RefreshTokenFetcher() {}
37 // Overridden from GaiaAuthConsumer:
38 virtual void OnClientOAuthSuccess(const ClientOAuthResult& result) OVERRIDE;
39 virtual void OnClientOAuthFailure(
40 const GoogleServiceAuthError& error) OVERRIDE;
42 AccountReconcilor* reconcilor_;
43 GaiaAuthFetcher fetcher_;
44 const std::string account_id_;
47 DISALLOW_COPY_AND_ASSIGN(RefreshTokenFetcher);
50 AccountReconcilor::RefreshTokenFetcher::RefreshTokenFetcher(
51 AccountReconcilor* reconcilor,
52 const std::string& account_id,
54 : reconcilor_(reconcilor),
55 fetcher_(this, GaiaConstants::kChromeSource,
56 reconcilor_->profile()->GetRequestContext()),
57 account_id_(account_id),
58 session_index_(session_index) {
60 DCHECK(!account_id.empty());
61 fetcher_.StartCookieForOAuthLoginTokenExchange(
62 base::IntToString(session_index_));
65 void AccountReconcilor::RefreshTokenFetcher::OnClientOAuthSuccess(
66 const ClientOAuthResult& result) {
67 VLOG(1) << "RefreshTokenFetcher::OnClientOAuthSuccess:"
68 << " account=" << account_id_
69 << " session_index=" << session_index_;
71 reconcilor_->HandleRefreshTokenFetched(account_id_,
72 result.refresh_token);
75 void AccountReconcilor::RefreshTokenFetcher::OnClientOAuthFailure(
76 const GoogleServiceAuthError& error) {
77 VLOG(1) << "RefreshTokenFetcher::OnClientOAuthFailure:"
78 << " account=" << account_id_
79 << " session_index=" << session_index_;
80 reconcilor_->HandleRefreshTokenFetched(account_id_, std::string());
84 class AccountReconcilor::UserIdFetcher
85 : public gaia::GaiaOAuthClient::Delegate {
87 UserIdFetcher(AccountReconcilor* reconcilor,
88 const std::string& access_token,
89 const std::string& account_id);
91 // Returns the scopes needed by the UserIdFetcher.
92 static OAuth2TokenService::ScopeSet GetScopes();
95 // Overriden from gaia::GaiaOAuthClient::Delegate.
96 virtual void OnGetUserIdResponse(const std::string& user_id) OVERRIDE;
97 virtual void OnOAuthError() OVERRIDE;
98 virtual void OnNetworkError(int response_code) OVERRIDE;
100 AccountReconcilor* const reconcilor_;
101 const std::string account_id_;
102 const std::string access_token_;
103 gaia::GaiaOAuthClient gaia_auth_client_;
105 DISALLOW_COPY_AND_ASSIGN(UserIdFetcher);
108 AccountReconcilor::UserIdFetcher::UserIdFetcher(AccountReconcilor* reconcilor,
109 const std::string& access_token,
110 const std::string& account_id)
111 : reconcilor_(reconcilor),
112 account_id_(account_id),
113 access_token_(access_token),
114 gaia_auth_client_(reconcilor_->profile()->GetRequestContext()) {
116 DCHECK(!account_id_.empty());
118 const int kMaxRetries = 5;
119 gaia_auth_client_.GetUserId(access_token_, kMaxRetries, this);
123 OAuth2TokenService::ScopeSet AccountReconcilor::UserIdFetcher::GetScopes() {
124 OAuth2TokenService::ScopeSet scopes;
125 scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
129 void AccountReconcilor::UserIdFetcher::OnGetUserIdResponse(
130 const std::string& user_id) {
131 VLOG(1) << "AccountReconcilor::OnGetUserIdResponse: " << account_id_;
132 reconcilor_->HandleSuccessfulAccountIdCheck(account_id_);
135 void AccountReconcilor::UserIdFetcher::OnOAuthError() {
136 VLOG(1) << "AccountReconcilor::OnOAuthError: " << account_id_;
137 reconcilor_->HandleFailedAccountIdCheck(account_id_);
139 // Invalidate the access token to force a refetch next time.
140 ProfileOAuth2TokenService* token_service =
141 ProfileOAuth2TokenServiceFactory::GetForProfile(reconcilor_->profile());
142 token_service->InvalidateToken(account_id_, GetScopes(), access_token_);
145 void AccountReconcilor::UserIdFetcher::OnNetworkError(int response_code) {
146 VLOG(1) << "AccountReconcilor::OnNetworkError: " << account_id_
147 << " response_code=" << response_code;
149 // TODO(rogerta): some response error should not be treated like
150 // permanent errors. Figure out appropriate ones.
151 reconcilor_->HandleFailedAccountIdCheck(account_id_);
154 AccountReconcilor::AccountReconcilor(Profile* profile)
155 : OAuth2TokenService::Consumer("account_reconcilor"),
157 merge_session_helper_(
158 ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
159 profile->GetRequestContext(),
161 registered_with_token_service_(false),
162 is_reconcile_started_(false),
163 are_gaia_accounts_set_(false),
165 VLOG(1) << "AccountReconcilor::AccountReconcilor";
166 RegisterWithSigninManager();
168 // If this profile is not connected, the reconcilor should do nothing but
169 // wait for the connection.
170 if (IsProfileConnected()) {
171 RegisterWithCookieMonster();
172 RegisterWithTokenService();
173 StartPeriodicReconciliation();
177 AccountReconcilor::~AccountReconcilor() {
178 // Make sure shutdown was called first.
179 DCHECK(!registered_with_token_service_);
180 DCHECK(registrar_.IsEmpty());
181 DCHECK(!reconciliation_timer_.IsRunning());
183 DCHECK_EQ(0u, user_id_fetchers_.size());
184 DCHECK_EQ(0u, refresh_token_fetchers_.size());
187 void AccountReconcilor::Shutdown() {
188 VLOG(1) << "AccountReconcilor::Shutdown";
189 merge_session_helper_.CancelAll();
190 merge_session_helper_.RemoveObserver(this);
191 gaia_fetcher_.reset();
193 UnregisterWithSigninManager();
194 UnregisterWithTokenService();
195 UnregisterWithCookieMonster();
196 StopPeriodicReconciliation();
199 void AccountReconcilor::AddMergeSessionObserver(
200 MergeSessionHelper::Observer* observer) {
201 merge_session_helper_.AddObserver(observer);
204 void AccountReconcilor::RemoveMergeSessionObserver(
205 MergeSessionHelper::Observer* observer) {
206 merge_session_helper_.RemoveObserver(observer);
209 void AccountReconcilor::DeleteFetchers() {
213 user_id_fetchers_.clear();
214 refresh_token_fetchers_.clear();
217 bool AccountReconcilor::AreAllRefreshTokensChecked() const {
218 return chrome_accounts_.size() ==
219 (valid_chrome_accounts_.size() + invalid_chrome_accounts_.size());
222 void AccountReconcilor::RegisterWithCookieMonster() {
223 content::Source<Profile> source(profile_);
224 if (!registrar_.IsRegistered(this, chrome::NOTIFICATION_COOKIE_CHANGED,
226 registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
230 void AccountReconcilor::UnregisterWithCookieMonster() {
231 content::Source<Profile> source(profile_);
232 if (registrar_.IsRegistered(this, chrome::NOTIFICATION_COOKIE_CHANGED,
234 registrar_.Remove(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
238 void AccountReconcilor::RegisterWithSigninManager() {
239 SigninManagerBase* signin_manager =
240 SigninManagerFactory::GetForProfile(profile_);
241 signin_manager->AddObserver(this);
244 void AccountReconcilor::UnregisterWithSigninManager() {
245 SigninManagerBase* signin_manager =
246 SigninManagerFactory::GetForProfile(profile_);
247 signin_manager->RemoveObserver(this);
250 void AccountReconcilor::RegisterWithTokenService() {
251 VLOG(1) << "AccountReconcilor::RegisterWithTokenService";
252 // During re-auth, the reconcilor will get a GOOGLE_SIGNIN_SUCCESSFUL
253 // even when the profile is already connected. Avoid re-registering
254 // with the token service since this will DCHECK.
255 if (registered_with_token_service_)
258 ProfileOAuth2TokenService* token_service =
259 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
260 token_service->AddObserver(this);
261 registered_with_token_service_ = true;
264 void AccountReconcilor::UnregisterWithTokenService() {
265 if (!registered_with_token_service_)
268 ProfileOAuth2TokenService* token_service =
269 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
270 token_service->RemoveObserver(this);
271 registered_with_token_service_ = false;
274 bool AccountReconcilor::IsProfileConnected() {
275 return !SigninManagerFactory::GetForProfile(profile_)->
276 GetAuthenticatedUsername().empty();
279 void AccountReconcilor::StartPeriodicReconciliation() {
280 VLOG(1) << "AccountReconcilor::StartPeriodicReconciliation";
281 // TODO(rogerta): pick appropriate thread and timeout value.
282 reconciliation_timer_.Start(
284 base::TimeDelta::FromSeconds(300),
286 &AccountReconcilor::PeriodicReconciliation);
289 void AccountReconcilor::StopPeriodicReconciliation() {
290 VLOG(1) << "AccountReconcilor::StopPeriodicReconciliation";
291 reconciliation_timer_.Stop();
294 void AccountReconcilor::PeriodicReconciliation() {
295 VLOG(1) << "AccountReconcilor::PeriodicReconciliation";
299 void AccountReconcilor::Observe(int type,
300 const content::NotificationSource& source,
301 const content::NotificationDetails& details) {
303 case chrome::NOTIFICATION_COOKIE_CHANGED:
304 OnCookieChanged(content::Details<ChromeCookieDetails>(details).ptr());
312 void AccountReconcilor::OnCookieChanged(ChromeCookieDetails* details) {
313 if (details->cookie->Name() == "LSID" &&
314 details->cookie->Domain() == GaiaUrls::GetInstance()->gaia_url().host() &&
315 details->cookie->IsSecure() &&
316 details->cookie->IsHttpOnly()) {
317 VLOG(1) << "AccountReconcilor::OnCookieChanged: LSID changed";
322 void AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) {
323 VLOG(1) << "AccountReconcilor::OnRefreshTokenAvailable: " << account_id;
327 void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) {
328 VLOG(1) << "AccountReconcilor::OnRefreshTokenRevoked: " << account_id;
329 StartRemoveAction(account_id);
332 void AccountReconcilor::OnRefreshTokensLoaded() {}
334 void AccountReconcilor::GoogleSigninSucceeded(
335 const std::string& username, const std::string& password) {
336 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
337 RegisterWithCookieMonster();
338 RegisterWithTokenService();
339 StartPeriodicReconciliation();
342 void AccountReconcilor::GoogleSignedOut(const std::string& username) {
343 VLOG(1) << "AccountReconcilor::GoogleSignedOut: signed out";
344 UnregisterWithTokenService();
345 UnregisterWithCookieMonster();
346 StopPeriodicReconciliation();
349 void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
350 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
351 merge_session_helper_.LogIn(account_id);
354 void AccountReconcilor::StartRemoveAction(const std::string& account_id) {
355 VLOG(1) << "AccountReconcilor::StartRemoveAction: " << account_id;
356 GetAccountsFromCookie(
357 base::Bind(&AccountReconcilor::FinishRemoveAction,
358 base::Unretained(this),
362 void AccountReconcilor::FinishRemoveAction(
363 const std::string& account_id,
364 const GoogleServiceAuthError& error,
365 const std::vector<std::pair<std::string, bool> >& accounts) {
366 VLOG(1) << "AccountReconcilor::FinishRemoveAction:"
367 << " account=" << account_id
368 << " error=" << error.ToString();
369 if (error.state() == GoogleServiceAuthError::NONE) {
371 std::vector<std::string> accounts_only;
372 for (std::vector<std::pair<std::string, bool> >::const_iterator i =
373 accounts.begin(); i != accounts.end(); ++i) {
374 accounts_only.push_back(i->first);
376 merge_session_helper_.LogOut(account_id, accounts_only);
378 // Wait for the next ReconcileAction if there is an error.
381 void AccountReconcilor::PerformAddToChromeAction(
382 const std::string& account_id,
384 VLOG(1) << "AccountReconcilor::PerformAddToChromeAction:"
385 << " account=" << account_id
386 << " session_index=" << session_index;
388 #if !defined(OS_ANDROID) && !defined(OS_IOS)
389 refresh_token_fetchers_.push_back(
390 new RefreshTokenFetcher(this, account_id, session_index));
394 void AccountReconcilor::PerformLogoutAllAccountsAction() {
395 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
396 merge_session_helper_.LogOutAllAccounts();
399 void AccountReconcilor::StartReconcile() {
400 if (!IsProfileConnected() || is_reconcile_started_)
403 is_reconcile_started_ = true;
405 // Reset state for validating gaia cookie.
406 are_gaia_accounts_set_ = false;
407 gaia_accounts_.clear();
408 GetAccountsFromCookie(base::Bind(
409 &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts,
410 base::Unretained(this)));
412 // Reset state for validating oauth2 tokens.
413 primary_account_.clear();
414 chrome_accounts_.clear();
416 valid_chrome_accounts_.clear();
417 invalid_chrome_accounts_.clear();
418 add_to_cookie_.clear();
419 add_to_chrome_.clear();
420 ValidateAccountsFromTokenService();
423 void AccountReconcilor::GetAccountsFromCookie(
424 GetAccountsFromCookieCallback callback) {
425 get_gaia_accounts_callbacks_.push_back(callback);
426 if (!gaia_fetcher_) {
427 // There is no list account request in flight.
428 gaia_fetcher_.reset(new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
429 profile_->GetRequestContext()));
430 gaia_fetcher_->StartListAccounts();
434 void AccountReconcilor::OnListAccountsSuccess(const std::string& data) {
435 gaia_fetcher_.reset();
437 // Get account information from response data.
438 std::vector<std::pair<std::string, bool> > gaia_accounts;
439 bool valid_json = gaia::ParseListAccountsData(data, &gaia_accounts);
441 VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: parsing error";
442 } else if (gaia_accounts.size() > 0) {
443 VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: "
444 << "Gaia " << gaia_accounts.size() << " accounts, "
445 << "Primary is '" << gaia_accounts[0].first << "'";
447 VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts";
450 // There must be at least one callback waiting for result.
451 DCHECK(!get_gaia_accounts_callbacks_.empty());
453 GoogleServiceAuthError error = !valid_json
454 ? GoogleServiceAuthError(
455 GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE)
456 : GoogleServiceAuthError::AuthErrorNone();
457 get_gaia_accounts_callbacks_.front().Run(error, gaia_accounts);
458 get_gaia_accounts_callbacks_.pop_front();
460 MayBeDoNextListAccounts();
463 void AccountReconcilor::OnListAccountsFailure(
464 const GoogleServiceAuthError& error) {
465 gaia_fetcher_.reset();
466 VLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString();
467 std::vector<std::pair<std::string, bool> > empty_accounts;
469 // There must be at least one callback waiting for result.
470 DCHECK(!get_gaia_accounts_callbacks_.empty());
472 get_gaia_accounts_callbacks_.front().Run(error, empty_accounts);
473 get_gaia_accounts_callbacks_.pop_front();
475 MayBeDoNextListAccounts();
478 void AccountReconcilor::MayBeDoNextListAccounts() {
479 if (!get_gaia_accounts_callbacks_.empty()) {
480 gaia_fetcher_.reset(new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
481 profile_->GetRequestContext()));
482 gaia_fetcher_->StartListAccounts();
486 void AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts(
487 const GoogleServiceAuthError& error,
488 const std::vector<std::pair<std::string, bool> >& accounts) {
489 if (error.state() == GoogleServiceAuthError::NONE) {
490 gaia_accounts_ = accounts;
491 are_gaia_accounts_set_ = true;
498 void AccountReconcilor::ValidateAccountsFromTokenService() {
500 SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername();
501 DCHECK(!primary_account_.empty());
503 ProfileOAuth2TokenService* token_service =
504 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
505 chrome_accounts_ = token_service->GetAccounts();
506 DCHECK(chrome_accounts_.size() > 0);
508 VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
509 << "Chrome " << chrome_accounts_.size() << " accounts, "
510 << "Primary is '" << primary_account_ << "'";
514 new scoped_ptr<OAuth2TokenService::Request>[chrome_accounts_.size()];
515 const OAuth2TokenService::ScopeSet scopes =
516 AccountReconcilor::UserIdFetcher::GetScopes();
517 for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
518 requests_[i] = token_service->StartRequest(chrome_accounts_[i],
523 DCHECK_EQ(0u, user_id_fetchers_.size());
524 user_id_fetchers_.resize(chrome_accounts_.size());
527 void AccountReconcilor::OnGetTokenSuccess(
528 const OAuth2TokenService::Request* request,
529 const std::string& access_token,
530 const base::Time& expiration_time) {
532 for (index = 0; index < chrome_accounts_.size(); ++index) {
533 if (request == requests_[index].get())
536 DCHECK(index < chrome_accounts_.size());
538 const std::string& account_id = chrome_accounts_[index];
540 VLOG(1) << "AccountReconcilor::OnGetTokenSuccess: valid " << account_id;
542 DCHECK(!user_id_fetchers_[index]);
543 user_id_fetchers_[index] =
544 new UserIdFetcher(this, access_token, account_id);
547 void AccountReconcilor::OnGetTokenFailure(
548 const OAuth2TokenService::Request* request,
549 const GoogleServiceAuthError& error) {
551 for (index = 0; index < chrome_accounts_.size(); ++index) {
552 if (request == requests_[index].get())
555 DCHECK(index < chrome_accounts_.size());
557 const std::string& account_id = chrome_accounts_[index];
559 VLOG(1) << "AccountReconcilor::OnGetTokenFailure: invalid "
561 HandleFailedAccountIdCheck(account_id);
564 void AccountReconcilor::FinishReconcile() {
565 // Make sure that the process of validating the gaia cookie and the oauth2
566 // tokens individually is done before proceeding with reconciliation.
567 if (!are_gaia_accounts_set_ || !AreAllRefreshTokensChecked())
570 VLOG(1) << "AccountReconcilor::FinishReconcile";
574 DCHECK(add_to_cookie_.empty());
575 DCHECK(add_to_chrome_.empty());
576 bool are_primaries_equal =
577 gaia_accounts_.size() > 0 && primary_account_ == gaia_accounts_[0].first;
579 if (are_primaries_equal) {
580 // Determine if we need to merge accounts from gaia cookie to chrome.
581 for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
582 const std::string& gaia_account = gaia_accounts_[i].first;
583 if (gaia_accounts_[i].second &&
584 valid_chrome_accounts_.find(gaia_account) ==
585 valid_chrome_accounts_.end()) {
586 add_to_chrome_.push_back(std::make_pair(gaia_account, i));
590 // Determine if we need to merge accounts from chrome into gaia cookie.
591 for (std::set<std::string>::const_iterator i =
592 valid_chrome_accounts_.begin();
593 i != valid_chrome_accounts_.end(); ++i) {
594 bool add_to_cookie = true;
595 for (size_t j = 0; j < gaia_accounts_.size(); ++j) {
596 if (gaia_accounts_[j].first == *i) {
597 add_to_cookie = !gaia_accounts_[j].second;
602 add_to_cookie_.push_back(*i);
605 VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
606 // Really messed up state. Blow away the gaia cookie completely and
607 // rebuild it, making sure the primary account as specified by the
608 // SigninManager is the first session in the gaia cookie.
609 PerformLogoutAllAccountsAction();
610 add_to_cookie_.push_back(primary_account_);
611 for (std::set<std::string>::const_iterator i =
612 valid_chrome_accounts_.begin();
613 i != valid_chrome_accounts_.end(); ++i) {
614 if (*i != primary_account_)
615 add_to_cookie_.push_back(*i);
619 // For each account known to chrome but not in the gaia cookie,
620 // PerformMergeAction().
621 for (size_t i = 0; i < add_to_cookie_.size(); ++i)
622 PerformMergeAction(add_to_cookie_[i]);
624 // For each account in the gaia cookie not known to chrome,
625 // PerformAddToChromeAction.
626 for (std::vector<std::pair<std::string, int> >::const_iterator i =
627 add_to_chrome_.begin();
628 i != add_to_chrome_.end(); ++i) {
629 PerformAddToChromeAction(i->first, i->second);
632 CalculateIfReconcileIsDone();
635 void AccountReconcilor::AbortReconcile() {
636 VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
638 add_to_cookie_.clear();
639 add_to_chrome_.clear();
640 CalculateIfReconcileIsDone();
643 void AccountReconcilor::CalculateIfReconcileIsDone() {
644 is_reconcile_started_ = !add_to_cookie_.empty() || !add_to_chrome_.empty();
645 if (!is_reconcile_started_)
646 VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
649 void AccountReconcilor::MergeSessionCompleted(
650 const std::string& account_id,
651 const GoogleServiceAuthError& error) {
652 VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id="
655 // Remove the account from the list that is being merged.
656 for (std::vector<std::string>::iterator i = add_to_cookie_.begin();
657 i != add_to_cookie_.end(); ++i) {
658 if (account_id == *i) {
659 add_to_cookie_.erase(i);
664 CalculateIfReconcileIsDone();
667 void AccountReconcilor::HandleSuccessfulAccountIdCheck(
668 const std::string& account_id) {
669 valid_chrome_accounts_.insert(account_id);
673 void AccountReconcilor::HandleFailedAccountIdCheck(
674 const std::string& account_id) {
675 invalid_chrome_accounts_.insert(account_id);
679 void AccountReconcilor::HandleRefreshTokenFetched(
680 const std::string& account_id,
681 const std::string& refresh_token) {
682 if (!refresh_token.empty()) {
683 ProfileOAuth2TokenService* token_service =
684 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
685 token_service->UpdateCredentials(account_id, refresh_token);
688 // Remove the account from the list that is being updated.
689 for (std::vector<std::pair<std::string, int> >::iterator i =
690 add_to_chrome_.begin();
691 i != add_to_chrome_.end(); ++i) {
692 if (account_id == i->first) {
693 add_to_chrome_.erase(i);
698 CalculateIfReconcileIsDone();