Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(797)

Side by Side Diff: components/signin/core/browser/account_reconcilor.cc

Issue 590113004: Handle account removal correctly on all platforms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/signin/core/browser/account_reconcilor.h" 5 #include "components/signin/core/browser/account_reconcilor.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h" 12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/time/time.h" 15 #include "base/time/time.h"
16 #include "components/signin/core/browser/profile_oauth2_token_service.h" 16 #include "components/signin/core/browser/profile_oauth2_token_service.h"
17 #include "components/signin/core/browser/signin_client.h" 17 #include "components/signin/core/browser/signin_client.h"
18 #include "components/signin/core/browser/signin_metrics.h" 18 #include "components/signin/core/browser/signin_metrics.h"
19 #include "components/signin/core/browser/signin_oauth_helper.h"
20 #include "components/signin/core/common/profile_management_switches.h" 19 #include "components/signin/core/common/profile_management_switches.h"
21 #include "google_apis/gaia/gaia_auth_fetcher.h" 20 #include "google_apis/gaia/gaia_auth_fetcher.h"
22 #include "google_apis/gaia/gaia_auth_util.h" 21 #include "google_apis/gaia/gaia_auth_util.h"
23 #include "google_apis/gaia/gaia_constants.h" 22 #include "google_apis/gaia/gaia_constants.h"
24 #include "google_apis/gaia/gaia_oauth_client.h" 23 #include "google_apis/gaia/gaia_oauth_client.h"
25 #include "google_apis/gaia/gaia_urls.h" 24 #include "google_apis/gaia/gaia_urls.h"
26 #include "net/cookies/canonical_cookie.h" 25 #include "net/cookies/canonical_cookie.h"
27 26
28 27
29 namespace { 28 namespace {
30 29
31 class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > { 30 class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > {
32 public: 31 public:
33 bool operator()(const std::pair<std::string, bool>& p1, 32 bool operator()(const std::pair<std::string, bool>& p1,
34 const std::pair<std::string, bool>& p2) const; 33 const std::pair<std::string, bool>& p2) const;
35 }; 34 };
36 35
37 bool EmailEqualToFunc::operator()( 36 bool EmailEqualToFunc::operator()(
38 const std::pair<std::string, bool>& p1, 37 const std::pair<std::string, bool>& p1,
39 const std::pair<std::string, bool>& p2) const { 38 const std::pair<std::string, bool>& p2) const {
40 return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first); 39 return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first);
41 } 40 }
42 41
42 class AreEmailsSameFunc : public std::equal_to<std::string> {
43 public:
44 bool operator()(const std::string& p1,
45 const std::string& p2) const;
46 };
47
48 bool AreEmailsSameFunc::operator()(
49 const std::string& p1,
50 const std::string& p2) const {
51 return gaia::AreEmailsSame(p1, p2);
52 }
53
43 } // namespace 54 } // namespace
44 55
45 56
46 // Fetches a refresh token from the given session in the GAIA cookie. This is
47 // a best effort only. If it should fail, another reconcile action will occur
48 // shortly anyway.
49 class AccountReconcilor::RefreshTokenFetcher
50 : public SigninOAuthHelper,
51 public SigninOAuthHelper::Consumer {
52 public:
53 RefreshTokenFetcher(AccountReconcilor* reconcilor,
54 const std::string& account_id,
55 int session_index,
56 const std::string& signin_scoped_device_id);
57 virtual ~RefreshTokenFetcher() {}
58
59 private:
60 // Overridden from GaiaAuthConsumer:
61 virtual void OnSigninOAuthInformationAvailable(
62 const std::string& email,
63 const std::string& display_email,
64 const std::string& refresh_token) OVERRIDE;
65
66 // Called when an error occurs while getting the information.
67 virtual void OnSigninOAuthInformationFailure(
68 const GoogleServiceAuthError& error) OVERRIDE;
69
70 AccountReconcilor* reconcilor_;
71 const std::string account_id_;
72 int session_index_;
73
74 DISALLOW_COPY_AND_ASSIGN(RefreshTokenFetcher);
75 };
76
77 AccountReconcilor::RefreshTokenFetcher::RefreshTokenFetcher(
78 AccountReconcilor* reconcilor,
79 const std::string& account_id,
80 int session_index,
81 const std::string& signin_scoped_device_id)
82 : SigninOAuthHelper(reconcilor->client()->GetURLRequestContext(),
83 base::IntToString(session_index),
84 signin_scoped_device_id,
85 this),
86 reconcilor_(reconcilor),
87 account_id_(account_id),
88 session_index_(session_index) {
89 DCHECK(reconcilor_);
90 DCHECK(!account_id.empty());
91 }
92
93 void AccountReconcilor::RefreshTokenFetcher::OnSigninOAuthInformationAvailable(
94 const std::string& email,
95 const std::string& display_email,
96 const std::string& refresh_token) {
97 VLOG(1) << "RefreshTokenFetcher::OnSigninOAuthInformationAvailable:"
98 << " account=" << account_id_ << " email=" << email
99 << " displayEmail=" << display_email;
100
101 // TODO(rogerta): because of the problem with email vs displayEmail and
102 // emails that have been canonicalized, the argument |email| is used here
103 // to make sure the correct string is used when calling the token service.
104 // This will be cleaned up when chrome moves to using gaia obfuscated id.
105 reconcilor_->HandleRefreshTokenFetched(email, refresh_token);
106 }
107
108 void AccountReconcilor::RefreshTokenFetcher::OnSigninOAuthInformationFailure(
109 const GoogleServiceAuthError& error) {
110 VLOG(1) << "RefreshTokenFetcher::OnSigninOAuthInformationFailure:"
111 << " account=" << account_id_ << " session_index=" << session_index_;
112 reconcilor_->HandleRefreshTokenFetched(account_id_, std::string());
113 }
114
115 bool AccountReconcilor::EmailLessFunc::operator()(const std::string& s1,
116 const std::string& s2) const {
117 return gaia::CanonicalizeEmail(s1) < gaia::CanonicalizeEmail(s2);
118 }
119
120 class AccountReconcilor::UserIdFetcher
121 : public gaia::GaiaOAuthClient::Delegate {
122 public:
123 UserIdFetcher(AccountReconcilor* reconcilor,
124 const std::string& access_token,
125 const std::string& account_id);
126
127 // Returns the scopes needed by the UserIdFetcher.
128 static OAuth2TokenService::ScopeSet GetScopes();
129
130 private:
131 // Overriden from gaia::GaiaOAuthClient::Delegate.
132 virtual void OnGetUserIdResponse(const std::string& user_id) OVERRIDE;
133 virtual void OnOAuthError() OVERRIDE;
134 virtual void OnNetworkError(int response_code) OVERRIDE;
135
136 AccountReconcilor* const reconcilor_;
137 const std::string account_id_;
138 const std::string access_token_;
139 gaia::GaiaOAuthClient gaia_auth_client_;
140
141 DISALLOW_COPY_AND_ASSIGN(UserIdFetcher);
142 };
143
144 AccountReconcilor::UserIdFetcher::UserIdFetcher(AccountReconcilor* reconcilor,
145 const std::string& access_token,
146 const std::string& account_id)
147 : reconcilor_(reconcilor),
148 account_id_(account_id),
149 access_token_(access_token),
150 gaia_auth_client_(reconcilor_->client()->GetURLRequestContext()) {
151 DCHECK(reconcilor_);
152 DCHECK(!account_id_.empty());
153
154 const int kMaxRetries = 5;
155 gaia_auth_client_.GetUserId(access_token_, kMaxRetries, this);
156 }
157
158 // static
159 OAuth2TokenService::ScopeSet AccountReconcilor::UserIdFetcher::GetScopes() {
160 OAuth2TokenService::ScopeSet scopes;
161 scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
162 return scopes;
163 }
164
165 void AccountReconcilor::UserIdFetcher::OnGetUserIdResponse(
166 const std::string& user_id) {
167 VLOG(1) << "AccountReconcilor::OnGetUserIdResponse: " << account_id_;
168
169 // HandleSuccessfulAccountIdCheck() may delete |this|, so call it last.
170 reconcilor_->HandleSuccessfulAccountIdCheck(account_id_);
171 }
172
173 void AccountReconcilor::UserIdFetcher::OnOAuthError() {
174 VLOG(1) << "AccountReconcilor::OnOAuthError: " << account_id_;
175
176 // Invalidate the access token to force a refetch next time.
177 reconcilor_->token_service()->InvalidateToken(
178 account_id_, GetScopes(), access_token_);
179
180 // HandleFailedAccountIdCheck() may delete |this|, so call it last.
181 reconcilor_->HandleFailedAccountIdCheck(account_id_);
182 }
183
184 void AccountReconcilor::UserIdFetcher::OnNetworkError(int response_code) {
185 VLOG(1) << "AccountReconcilor::OnNetworkError: " << account_id_
186 << " response_code=" << response_code;
187
188 // TODO(rogerta): some response error should not be treated like
189 // permanent errors. Figure out appropriate ones.
190 // HandleFailedAccountIdCheck() may delete |this|, so call it last.
191 reconcilor_->HandleFailedAccountIdCheck(account_id_);
192 }
193
194 AccountReconcilor::AccountReconcilor(ProfileOAuth2TokenService* token_service, 57 AccountReconcilor::AccountReconcilor(ProfileOAuth2TokenService* token_service,
195 SigninManagerBase* signin_manager, 58 SigninManagerBase* signin_manager,
196 SigninClient* client) 59 SigninClient* client)
197 : OAuth2TokenService::Consumer("account_reconcilor"), 60 : token_service_(token_service),
198 token_service_(token_service),
199 signin_manager_(signin_manager), 61 signin_manager_(signin_manager),
200 client_(client), 62 client_(client),
201 merge_session_helper_(token_service_, 63 merge_session_helper_(token_service_,
202 client->GetURLRequestContext(), 64 client->GetURLRequestContext(),
203 this), 65 this),
204 registered_with_token_service_(false), 66 registered_with_token_service_(false),
205 is_reconcile_started_(false), 67 is_reconcile_started_(false),
206 first_execution_(true), 68 first_execution_(true),
207 are_gaia_accounts_set_(false), 69 are_gaia_accounts_set_(false) {
208 requests_(NULL) {
209 VLOG(1) << "AccountReconcilor::AccountReconcilor"; 70 VLOG(1) << "AccountReconcilor::AccountReconcilor";
210 } 71 }
211 72
212 AccountReconcilor::~AccountReconcilor() { 73 AccountReconcilor::~AccountReconcilor() {
213 VLOG(1) << "AccountReconcilor::~AccountReconcilor"; 74 VLOG(1) << "AccountReconcilor::~AccountReconcilor";
214 // Make sure shutdown was called first. 75 // Make sure shutdown was called first.
215 DCHECK(!registered_with_token_service_); 76 DCHECK(!registered_with_token_service_);
216 DCHECK(!requests_);
217 DCHECK_EQ(0u, user_id_fetchers_.size());
218 DCHECK_EQ(0u, refresh_token_fetchers_.size());
219 } 77 }
220 78
221 void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) { 79 void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
222 VLOG(1) << "AccountReconcilor::Initialize"; 80 VLOG(1) << "AccountReconcilor::Initialize";
223 RegisterWithSigninManager(); 81 RegisterWithSigninManager();
224 82
225 // If this user is not signed in, the reconcilor should do nothing but 83 // If this user is not signed in, the reconcilor should do nothing but
226 // wait for signin. 84 // wait for signin.
227 if (IsProfileConnected()) { 85 if (IsProfileConnected()) {
228 RegisterForCookieChanges(); 86 RegisterForCookieChanges();
229 RegisterWithTokenService(); 87 RegisterWithTokenService();
230 88
231 // Start a reconcile if the tokens are already loaded. 89 // Start a reconcile if the tokens are already loaded.
232 if (start_reconcile_if_tokens_available && 90 if (start_reconcile_if_tokens_available &&
233 token_service_->GetAccounts().size() > 0) { 91 token_service_->GetAccounts().size() > 0) {
234 StartReconcile(); 92 StartReconcile();
235 } 93 }
236 } 94 }
237 } 95 }
238 96
239 void AccountReconcilor::Shutdown() { 97 void AccountReconcilor::Shutdown() {
240 VLOG(1) << "AccountReconcilor::Shutdown"; 98 VLOG(1) << "AccountReconcilor::Shutdown";
241 merge_session_helper_.CancelAll(); 99 merge_session_helper_.CancelAll();
242 merge_session_helper_.RemoveObserver(this); 100 merge_session_helper_.RemoveObserver(this);
243 gaia_fetcher_.reset(); 101 gaia_fetcher_.reset();
244 get_gaia_accounts_callbacks_.clear(); 102 get_gaia_accounts_callbacks_.clear();
245 DeleteFetchers();
246 UnregisterWithSigninManager(); 103 UnregisterWithSigninManager();
247 UnregisterWithTokenService(); 104 UnregisterWithTokenService();
248 UnregisterForCookieChanges(); 105 UnregisterForCookieChanges();
249 } 106 }
250 107
251 void AccountReconcilor::AddMergeSessionObserver( 108 void AccountReconcilor::AddMergeSessionObserver(
252 MergeSessionHelper::Observer* observer) { 109 MergeSessionHelper::Observer* observer) {
253 merge_session_helper_.AddObserver(observer); 110 merge_session_helper_.AddObserver(observer);
254 } 111 }
255 112
256 void AccountReconcilor::RemoveMergeSessionObserver( 113 void AccountReconcilor::RemoveMergeSessionObserver(
257 MergeSessionHelper::Observer* observer) { 114 MergeSessionHelper::Observer* observer) {
258 merge_session_helper_.RemoveObserver(observer); 115 merge_session_helper_.RemoveObserver(observer);
259 } 116 }
260 117
261 void AccountReconcilor::DeleteFetchers() {
262 delete[] requests_;
263 requests_ = NULL;
264
265 user_id_fetchers_.clear();
266 refresh_token_fetchers_.clear();
267 }
268
269 bool AccountReconcilor::AreAllRefreshTokensChecked() const {
270 return chrome_accounts_.size() ==
271 (valid_chrome_accounts_.size() + invalid_chrome_accounts_.size());
272 }
273
274 void AccountReconcilor::RegisterForCookieChanges() { 118 void AccountReconcilor::RegisterForCookieChanges() {
275 // First clear any existing registration to avoid DCHECKs that can otherwise 119 // First clear any existing registration to avoid DCHECKs that can otherwise
276 // go off in some embedders on reauth (e.g., ChromeSigninClient). 120 // go off in some embedders on reauth (e.g., ChromeSigninClient).
277 UnregisterForCookieChanges(); 121 UnregisterForCookieChanges();
278 cookie_changed_subscription_ = client_->AddCookieChangedCallback( 122 cookie_changed_subscription_ = client_->AddCookieChangedCallback(
279 base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this))); 123 base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
280 } 124 }
281 125
282 void AccountReconcilor::UnregisterForCookieChanges() { 126 void AccountReconcilor::UnregisterForCookieChanges() {
283 cookie_changed_subscription_.reset(); 127 cookie_changed_subscription_.reset();
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 if (!token_service_->GetAccounts().size()) { 169 if (!token_service_->GetAccounts().size()) {
326 VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored" 170 VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored"
327 "because O2RT is not available yet."; 171 "because O2RT is not available yet.";
328 return; 172 return;
329 } 173 }
330 174
331 StartReconcile(); 175 StartReconcile();
332 } 176 }
333 } 177 }
334 178
335 void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) {
336 VLOG(1) << "AccountReconcilor::OnRefreshTokenRevoked: " << account_id;
337 PerformStartRemoveAction(account_id);
338 }
339
340 void AccountReconcilor::OnEndBatchChanges() { 179 void AccountReconcilor::OnEndBatchChanges() {
341 VLOG(1) << "AccountReconcilor::OnEndBatchChanges"; 180 VLOG(1) << "AccountReconcilor::OnEndBatchChanges";
342 StartReconcile(); 181 StartReconcile();
343 } 182 }
344 183
345 void AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id, 184 void AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id,
346 const std::string& username, 185 const std::string& username,
347 const std::string& password) { 186 const std::string& password) {
348 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in"; 187 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
349 RegisterForCookieChanges(); 188 RegisterForCookieChanges();
(...skipping 13 matching lines...) Expand all
363 202
364 void AccountReconcilor::PerformMergeAction(const std::string& account_id) { 203 void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
365 if (!switches::IsEnableAccountConsistency()) { 204 if (!switches::IsEnableAccountConsistency()) {
366 MarkAccountAsAddedToCookie(account_id); 205 MarkAccountAsAddedToCookie(account_id);
367 return; 206 return;
368 } 207 }
369 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id; 208 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
370 merge_session_helper_.LogIn(account_id); 209 merge_session_helper_.LogIn(account_id);
371 } 210 }
372 211
373 void AccountReconcilor::PerformStartRemoveAction(
374 const std::string& account_id) {
375 VLOG(1) << "AccountReconcilor::PerformStartRemoveAction: " << account_id;
376 GetAccountsFromCookie(base::Bind(
377 &AccountReconcilor::PerformFinishRemoveAction,
378 base::Unretained(this),
379 account_id));
380 }
381
382 void AccountReconcilor::PerformFinishRemoveAction(
383 const std::string& account_id,
384 const GoogleServiceAuthError& error,
385 const std::vector<std::pair<std::string, bool> >& accounts) {
386 if (!switches::IsEnableAccountConsistency())
387 return;
388 VLOG(1) << "AccountReconcilor::PerformFinishRemoveAction:"
389 << " account=" << account_id << " error=" << error.ToString();
390 if (error.state() == GoogleServiceAuthError::NONE) {
391 AbortReconcile();
392 std::vector<std::string> accounts_only;
393 for (std::vector<std::pair<std::string, bool> >::const_iterator i =
394 accounts.begin();
395 i != accounts.end();
396 ++i) {
397 accounts_only.push_back(i->first);
398 }
399 merge_session_helper_.LogOut(account_id, accounts_only);
400 }
401 // Wait for the next ReconcileAction if there is an error.
402 }
403
404 void AccountReconcilor::PerformAddToChromeAction(
405 const std::string& account_id,
406 int session_index,
407 const std::string& signin_scoped_device_id) {
408 if (!switches::IsEnableAccountConsistency()) {
409 MarkAccountAsAddedToChrome(account_id);
410 return;
411 }
412 VLOG(1) << "AccountReconcilor::PerformAddToChromeAction:"
413 << " account=" << account_id << " session_index=" << session_index;
414
415 #if !defined(OS_ANDROID) && !defined(OS_IOS)
416 refresh_token_fetchers_.push_back(new RefreshTokenFetcher(
417 this, account_id, session_index, signin_scoped_device_id));
418 #endif
419 }
420
421 void AccountReconcilor::PerformLogoutAllAccountsAction() { 212 void AccountReconcilor::PerformLogoutAllAccountsAction() {
422 if (!switches::IsEnableAccountConsistency()) 213 if (!switches::IsEnableAccountConsistency())
423 return; 214 return;
424 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction"; 215 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
425 merge_session_helper_.LogOutAllAccounts(); 216 merge_session_helper_.LogOutAllAccounts();
426 } 217 }
427 218
428 void AccountReconcilor::StartReconcile() { 219 void AccountReconcilor::StartReconcile() {
429 if (!IsProfileConnected() || is_reconcile_started_ || 220 if (!IsProfileConnected() || is_reconcile_started_ ||
430 get_gaia_accounts_callbacks_.size() > 0 || 221 get_gaia_accounts_callbacks_.size() > 0 ||
431 merge_session_helper_.is_running()) 222 merge_session_helper_.is_running())
432 return; 223 return;
433 224
434 is_reconcile_started_ = true; 225 is_reconcile_started_ = true;
435 226
436 StartFetchingExternalCcResult(); 227 StartFetchingExternalCcResult();
437 228
438 // Reset state for validating gaia cookie. 229 // Reset state for validating gaia cookie.
439 are_gaia_accounts_set_ = false; 230 are_gaia_accounts_set_ = false;
440 gaia_accounts_.clear(); 231 gaia_accounts_.clear();
441 GetAccountsFromCookie(base::Bind( 232 GetAccountsFromCookie(base::Bind(
442 &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts, 233 &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts,
443 base::Unretained(this))); 234 base::Unretained(this)));
444 235
445 // Reset state for validating oauth2 tokens. 236 // Reset state for validating oauth2 tokens.
446 primary_account_.clear(); 237 primary_account_.clear();
447 chrome_accounts_.clear(); 238 chrome_accounts_.clear();
448 DeleteFetchers();
449 valid_chrome_accounts_.clear();
450 invalid_chrome_accounts_.clear();
451 add_to_cookie_.clear(); 239 add_to_cookie_.clear();
452 add_to_chrome_.clear();
453 ValidateAccountsFromTokenService(); 240 ValidateAccountsFromTokenService();
454 } 241 }
455 242
456 void AccountReconcilor::GetAccountsFromCookie( 243 void AccountReconcilor::GetAccountsFromCookie(
457 GetAccountsFromCookieCallback callback) { 244 GetAccountsFromCookieCallback callback) {
458 get_gaia_accounts_callbacks_.push_back(callback); 245 get_gaia_accounts_callbacks_.push_back(callback);
459 if (!gaia_fetcher_) { 246 if (!gaia_fetcher_) {
460 // There is no list account request in flight. 247 // There is no list account request in flight.
461 gaia_fetcher_.reset(new GaiaAuthFetcher( 248 gaia_fetcher_.reset(new GaiaAuthFetcher(
462 this, GaiaConstants::kChromeSource, client_->GetURLRequestContext())); 249 this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 321
535 void AccountReconcilor::ValidateAccountsFromTokenService() { 322 void AccountReconcilor::ValidateAccountsFromTokenService() {
536 primary_account_ = signin_manager_->GetAuthenticatedAccountId(); 323 primary_account_ = signin_manager_->GetAuthenticatedAccountId();
537 DCHECK(!primary_account_.empty()); 324 DCHECK(!primary_account_.empty());
538 325
539 chrome_accounts_ = token_service_->GetAccounts(); 326 chrome_accounts_ = token_service_->GetAccounts();
540 327
541 VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: " 328 VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
542 << "Chrome " << chrome_accounts_.size() << " accounts, " 329 << "Chrome " << chrome_accounts_.size() << " accounts, "
543 << "Primary is '" << primary_account_ << "'"; 330 << "Primary is '" << primary_account_ << "'";
544
545 DCHECK(!requests_);
546 requests_ =
547 new scoped_ptr<OAuth2TokenService::Request>[chrome_accounts_.size()];
548 const OAuth2TokenService::ScopeSet scopes =
549 AccountReconcilor::UserIdFetcher::GetScopes();
550 for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
551 requests_[i] =
552 token_service_->StartRequest(chrome_accounts_[i], scopes, this);
553 }
554
555 DCHECK_EQ(0u, user_id_fetchers_.size());
556 user_id_fetchers_.resize(chrome_accounts_.size());
557 }
558
559 void AccountReconcilor::OnGetTokenSuccess(
560 const OAuth2TokenService::Request* request,
561 const std::string& access_token,
562 const base::Time& expiration_time) {
563 size_t index;
564 for (index = 0; index < chrome_accounts_.size(); ++index) {
565 if (request == requests_[index].get())
566 break;
567 }
568 DCHECK(index < chrome_accounts_.size());
569
570 const std::string& account_id = chrome_accounts_[index];
571
572 VLOG(1) << "AccountReconcilor::OnGetTokenSuccess: valid " << account_id;
573
574 DCHECK(!user_id_fetchers_[index]);
575 user_id_fetchers_[index] = new UserIdFetcher(this, access_token, account_id);
576 }
577
578 void AccountReconcilor::OnGetTokenFailure(
579 const OAuth2TokenService::Request* request,
580 const GoogleServiceAuthError& error) {
581 size_t index;
582 for (index = 0; index < chrome_accounts_.size(); ++index) {
583 if (request == requests_[index].get())
584 break;
585 }
586 DCHECK(index < chrome_accounts_.size());
587
588 const std::string& account_id = chrome_accounts_[index];
589
590 VLOG(1) << "AccountReconcilor::OnGetTokenFailure: invalid " << account_id;
591 HandleFailedAccountIdCheck(account_id);
592 } 331 }
593 332
594 void AccountReconcilor::OnNewProfileManagementFlagChanged( 333 void AccountReconcilor::OnNewProfileManagementFlagChanged(
595 bool new_flag_status) { 334 bool new_flag_status) {
596 if (new_flag_status) { 335 if (new_flag_status) {
597 // The reconciler may have been newly created just before this call, or may 336 // The reconciler may have been newly created just before this call, or may
598 // have already existed and in mid-reconcile. To err on the safe side, force 337 // have already existed and in mid-reconcile. To err on the safe side, force
599 // a restart. 338 // a restart.
600 Shutdown(); 339 Shutdown();
601 Initialize(true); 340 Initialize(true);
602 } else { 341 } else {
603 Shutdown(); 342 Shutdown();
604 } 343 }
605 } 344 }
606 345
607 void AccountReconcilor::FinishReconcile() { 346 void AccountReconcilor::FinishReconcile() {
608 // Make sure that the process of validating the gaia cookie and the oauth2
609 // tokens individually is done before proceeding with reconciliation.
610 if (!are_gaia_accounts_set_ || !AreAllRefreshTokensChecked())
611 return;
612
613 VLOG(1) << "AccountReconcilor::FinishReconcile"; 347 VLOG(1) << "AccountReconcilor::FinishReconcile";
614 348 DCHECK(are_gaia_accounts_set_);
615 DeleteFetchers();
616
617 DCHECK(add_to_cookie_.empty()); 349 DCHECK(add_to_cookie_.empty());
618 DCHECK(add_to_chrome_.empty());
619 int number_gaia_accounts = gaia_accounts_.size(); 350 int number_gaia_accounts = gaia_accounts_.size();
620 bool are_primaries_equal = 351 bool are_primaries_equal = number_gaia_accounts > 0 &&
621 number_gaia_accounts > 0 &&
622 gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first); 352 gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
623 353
354 // If there are any accounts in the gaia cookie but not in chrome, then
355 // those accounts need to be removed from the cookie. This means we need
356 // to blow the cookie away.
357 int removed_from_cookie = 0;
358 for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
359 const std::string& gaia_account = gaia_accounts_[i].first;
360 if (gaia_accounts_[i].second &&
361 chrome_accounts_.end() ==
362 std::find_if(chrome_accounts_.begin(),
363 chrome_accounts_.end(),
364 std::bind1st(AreEmailsSameFunc(), gaia_account))) {
365 ++removed_from_cookie;
366 }
367 }
624 368
625 if (are_primaries_equal) { 369 bool rebuild_cookie = !are_primaries_equal || removed_from_cookie > 0;
626 // Determine if we need to merge accounts from gaia cookie to chrome. 370 std::vector<std::pair<std::string, bool> > original_gaia_accounts =
627 for (size_t i = 0; i < gaia_accounts_.size(); ++i) { 371 gaia_accounts_;
628 const std::string& gaia_account = gaia_accounts_[i].first; 372 if (rebuild_cookie) {
629 if (gaia_accounts_[i].second &&
630 valid_chrome_accounts_.find(gaia_account) ==
631 valid_chrome_accounts_.end()) {
632 add_to_chrome_.push_back(std::make_pair(gaia_account, i));
633 }
634 }
635 } else {
636 VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie"; 373 VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
637 // Really messed up state. Blow away the gaia cookie completely and 374 // Really messed up state. Blow away the gaia cookie completely and
638 // rebuild it, making sure the primary account as specified by the 375 // rebuild it, making sure the primary account as specified by the
639 // SigninManager is the first session in the gaia cookie. 376 // SigninManager is the first session in the gaia cookie.
640 PerformLogoutAllAccountsAction(); 377 PerformLogoutAllAccountsAction();
641 gaia_accounts_.clear(); 378 gaia_accounts_.clear();
642 } 379 }
643 380
644 // Create a list of accounts that need to be added to the gaia cookie. 381 // Create a list of accounts that need to be added to the gaia cookie.
645 // The primary account must be first to make sure it becomes the default 382 // The primary account must be first to make sure it becomes the default
646 // account in the case where chrome is completely rebuilding the cookie. 383 // account in the case where chrome is completely rebuilding the cookie.
647 add_to_cookie_.push_back(primary_account_); 384 add_to_cookie_.push_back(primary_account_);
648 for (EmailSet::const_iterator i = valid_chrome_accounts_.begin(); 385 for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
649 i != valid_chrome_accounts_.end(); 386 if (chrome_accounts_[i] != primary_account_)
650 ++i) { 387 add_to_cookie_.push_back(chrome_accounts_[i]);
651 if (*i != primary_account_)
652 add_to_cookie_.push_back(*i);
653 } 388 }
654 389
655 // For each account known to chrome, PerformMergeAction() if the account is 390 // For each account known to chrome, PerformMergeAction() if the account is
656 // not already in the cookie jar or its state is invalid, or signal merge 391 // not already in the cookie jar or its state is invalid, or signal merge
657 // completed otherwise. Make a copy of |add_to_cookie_| since calls to 392 // completed otherwise. Make a copy of |add_to_cookie_| since calls to
658 // SignalComplete() will change the array. 393 // SignalComplete() will change the array.
659 std::vector<std::string> add_to_cookie_copy = add_to_cookie_; 394 std::vector<std::string> add_to_cookie_copy = add_to_cookie_;
660 int added_to_cookie = 0; 395 int added_to_cookie = 0;
661 bool external_cc_result_completed = 396 bool external_cc_result_completed =
662 !merge_session_helper_.StillFetchingExternalCcResult(); 397 !merge_session_helper_.StillFetchingExternalCcResult();
663 for (size_t i = 0; i < add_to_cookie_copy.size(); ++i) { 398 for (size_t i = 0; i < add_to_cookie_copy.size(); ++i) {
664 if (gaia_accounts_.end() != 399 if (gaia_accounts_.end() !=
665 std::find_if(gaia_accounts_.begin(), 400 std::find_if(gaia_accounts_.begin(),
666 gaia_accounts_.end(), 401 gaia_accounts_.end(),
667 std::bind1st(EmailEqualToFunc(), 402 std::bind1st(EmailEqualToFunc(),
668 std::make_pair(add_to_cookie_copy[i], 403 std::make_pair(add_to_cookie_copy[i],
669 true)))) { 404 true)))) {
670 merge_session_helper_.SignalComplete( 405 merge_session_helper_.SignalComplete(
671 add_to_cookie_copy[i], 406 add_to_cookie_copy[i],
672 GoogleServiceAuthError::AuthErrorNone()); 407 GoogleServiceAuthError::AuthErrorNone());
673 } else { 408 } else {
674 PerformMergeAction(add_to_cookie_copy[i]); 409 PerformMergeAction(add_to_cookie_copy[i]);
675 added_to_cookie++; 410 if (original_gaia_accounts.end() ==
411 std::find_if(original_gaia_accounts.begin(),
412 original_gaia_accounts.end(),
413 std::bind1st(EmailEqualToFunc(),
414 std::make_pair(add_to_cookie_copy[i],
415 true)))) {
416 added_to_cookie++;
417 }
676 } 418 }
677 } 419 }
678 420
679 // Log whether the external connection checks were completed when we tried 421 // Log whether the external connection checks were completed when we tried
680 // to add the accounts to the cookie. 422 // to add the accounts to the cookie.
681 if (added_to_cookie > 0) 423 if (rebuild_cookie || added_to_cookie > 0)
682 signin_metrics::LogExternalCcResultFetches(external_cc_result_completed); 424 signin_metrics::LogExternalCcResultFetches(external_cc_result_completed);
683 425
684 std::string signin_scoped_device_id = client_->GetSigninScopedDeviceId(); 426 signin_metrics::LogSigninAccountReconciliation(chrome_accounts_.size(),
685 // For each account in the gaia cookie not known to chrome,
686 // PerformAddToChromeAction. Make a copy of |add_to_chrome| since calls to
687 // PerformAddToChromeAction() may modify this array.
688 std::vector<std::pair<std::string, int> > add_to_chrome_copy = add_to_chrome_;
689 for (std::vector<std::pair<std::string, int> >::const_iterator i =
690 add_to_chrome_copy.begin();
691 i != add_to_chrome_copy.end();
692 ++i) {
693 PerformAddToChromeAction(i->first, i->second, signin_scoped_device_id);
694 }
695
696 signin_metrics::LogSigninAccountReconciliation(valid_chrome_accounts_.size(),
697 added_to_cookie, 427 added_to_cookie,
698 add_to_chrome_.size(), 428 removed_from_cookie,
699 are_primaries_equal, 429 are_primaries_equal,
700 first_execution_, 430 first_execution_,
701 number_gaia_accounts); 431 number_gaia_accounts);
702 first_execution_ = false; 432 first_execution_ = false;
703 CalculateIfReconcileIsDone(); 433 CalculateIfReconcileIsDone();
704 ScheduleStartReconcileIfChromeAccountsChanged(); 434 ScheduleStartReconcileIfChromeAccountsChanged();
705 } 435 }
706 436
707 void AccountReconcilor::AbortReconcile() { 437 void AccountReconcilor::AbortReconcile() {
708 VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later"; 438 VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
709 DeleteFetchers();
710 add_to_cookie_.clear(); 439 add_to_cookie_.clear();
711 add_to_chrome_.clear();
712 CalculateIfReconcileIsDone(); 440 CalculateIfReconcileIsDone();
713 } 441 }
714 442
715 void AccountReconcilor::CalculateIfReconcileIsDone() { 443 void AccountReconcilor::CalculateIfReconcileIsDone() {
716 is_reconcile_started_ = !add_to_cookie_.empty() || !add_to_chrome_.empty(); 444 is_reconcile_started_ = !add_to_cookie_.empty();
717 if (!is_reconcile_started_) 445 if (!is_reconcile_started_)
718 VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done"; 446 VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
719 } 447 }
720 448
721 void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() { 449 void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() {
722 if (is_reconcile_started_) 450 if (is_reconcile_started_)
723 return; 451 return;
724 452
725 // Start a reconcile as the token accounts have changed. 453 // Start a reconcile as the token accounts have changed.
726 VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged"; 454 VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged";
(...skipping 19 matching lines...) Expand all
746 return true; 474 return true;
747 } 475 }
748 } 476 }
749 return false; 477 return false;
750 } 478 }
751 479
752 void AccountReconcilor::MergeSessionCompleted( 480 void AccountReconcilor::MergeSessionCompleted(
753 const std::string& account_id, 481 const std::string& account_id,
754 const GoogleServiceAuthError& error) { 482 const GoogleServiceAuthError& error) {
755 VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id=" 483 VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id="
756 << account_id; 484 << account_id << " error=" << error.ToString();
757 485
758 if (MarkAccountAsAddedToCookie(account_id)) { 486 if (MarkAccountAsAddedToCookie(account_id)) {
759 CalculateIfReconcileIsDone(); 487 CalculateIfReconcileIsDone();
760 ScheduleStartReconcileIfChromeAccountsChanged(); 488 ScheduleStartReconcileIfChromeAccountsChanged();
761 } 489 }
762 } 490 }
763
764 void AccountReconcilor::HandleSuccessfulAccountIdCheck(
765 const std::string& account_id) {
766 valid_chrome_accounts_.insert(account_id);
767 FinishReconcile();
768 }
769
770 void AccountReconcilor::HandleFailedAccountIdCheck(
771 const std::string& account_id) {
772 invalid_chrome_accounts_.insert(account_id);
773 FinishReconcile();
774 }
775
776 void AccountReconcilor::PerformAddAccountToTokenService(
777 const std::string& account_id,
778 const std::string& refresh_token) {
779 // The flow should never get to this method if new_profile_management is
780 // false, but better safe than sorry.
781 if (!switches::IsEnableAccountConsistency())
782 return;
783 token_service_->UpdateCredentials(account_id, refresh_token);
784 }
785
786 // Remove the account from the list that is being updated.
787 void AccountReconcilor::MarkAccountAsAddedToChrome(
788 const std::string& account_id) {
789 for (std::vector<std::pair<std::string, int> >::iterator i =
790 add_to_chrome_.begin();
791 i != add_to_chrome_.end();
792 ++i) {
793 if (gaia::AreEmailsSame(account_id, i->first)) {
794 add_to_chrome_.erase(i);
795 break;
796 }
797 }
798 }
799
800 void AccountReconcilor::HandleRefreshTokenFetched(
801 const std::string& account_id,
802 const std::string& refresh_token) {
803 if (!refresh_token.empty())
804 PerformAddAccountToTokenService(account_id, refresh_token);
805
806 MarkAccountAsAddedToChrome(account_id);
807 CalculateIfReconcileIsDone();
808 }
OLDNEW
« no previous file with comments | « components/signin/core/browser/account_reconcilor.h ('k') | components/signin/core/browser/signin_metrics.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698