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

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: Modify metrics 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" 19 #include "components/signin/core/browser/signin_oauth_helper.h"
Mike Lerman 2014/09/23 14:27:47 We no longer have any references to the signin_oau
Roger Tawa OOO till Jul 10th 2014/09/23 21:25:58 Done.
20 #include "components/signin/core/common/profile_management_switches.h" 20 #include "components/signin/core/common/profile_management_switches.h"
21 #include "google_apis/gaia/gaia_auth_fetcher.h" 21 #include "google_apis/gaia/gaia_auth_fetcher.h"
22 #include "google_apis/gaia/gaia_auth_util.h" 22 #include "google_apis/gaia/gaia_auth_util.h"
23 #include "google_apis/gaia/gaia_constants.h" 23 #include "google_apis/gaia/gaia_constants.h"
24 #include "google_apis/gaia/gaia_oauth_client.h" 24 #include "google_apis/gaia/gaia_oauth_client.h"
25 #include "google_apis/gaia/gaia_urls.h" 25 #include "google_apis/gaia/gaia_urls.h"
26 #include "net/cookies/canonical_cookie.h" 26 #include "net/cookies/canonical_cookie.h"
27 27
28 28
29 namespace { 29 namespace {
30 30
31 class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > { 31 class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > {
32 public: 32 public:
33 bool operator()(const std::pair<std::string, bool>& p1, 33 bool operator()(const std::pair<std::string, bool>& p1,
34 const std::pair<std::string, bool>& p2) const; 34 const std::pair<std::string, bool>& p2) const;
35 }; 35 };
36 36
37 bool EmailEqualToFunc::operator()( 37 bool EmailEqualToFunc::operator()(
38 const std::pair<std::string, bool>& p1, 38 const std::pair<std::string, bool>& p1,
39 const std::pair<std::string, bool>& p2) const { 39 const std::pair<std::string, bool>& p2) const {
40 return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first); 40 return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first);
41 } 41 }
42 42
43 class AreEmailsSameFunc : public std::equal_to<std::string> {
44 public:
45 bool operator()(const std::string& p1,
46 const std::string& p2) const;
47 };
48
49 bool AreEmailsSameFunc::operator()(
50 const std::string& p1,
51 const std::string& p2) const {
52 return gaia::AreEmailsSame(p1, p2);
53 }
54
43 } // namespace 55 } // namespace
44 56
45 57
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, 58 AccountReconcilor::AccountReconcilor(ProfileOAuth2TokenService* token_service,
195 SigninManagerBase* signin_manager, 59 SigninManagerBase* signin_manager,
196 SigninClient* client) 60 SigninClient* client)
197 : OAuth2TokenService::Consumer("account_reconcilor"), 61 : token_service_(token_service),
198 token_service_(token_service),
199 signin_manager_(signin_manager), 62 signin_manager_(signin_manager),
200 client_(client), 63 client_(client),
201 merge_session_helper_(token_service_, 64 merge_session_helper_(token_service_,
202 client->GetURLRequestContext(), 65 client->GetURLRequestContext(),
203 this), 66 this),
204 registered_with_token_service_(false), 67 registered_with_token_service_(false),
205 is_reconcile_started_(false), 68 is_reconcile_started_(false),
206 first_execution_(true), 69 first_execution_(true),
207 are_gaia_accounts_set_(false), 70 are_gaia_accounts_set_(false) {
208 requests_(NULL) {
209 VLOG(1) << "AccountReconcilor::AccountReconcilor"; 71 VLOG(1) << "AccountReconcilor::AccountReconcilor";
210 } 72 }
211 73
212 AccountReconcilor::~AccountReconcilor() { 74 AccountReconcilor::~AccountReconcilor() {
213 VLOG(1) << "AccountReconcilor::~AccountReconcilor"; 75 VLOG(1) << "AccountReconcilor::~AccountReconcilor";
214 // Make sure shutdown was called first. 76 // Make sure shutdown was called first.
215 DCHECK(!registered_with_token_service_); 77 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 } 78 }
220 79
221 void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) { 80 void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
222 VLOG(1) << "AccountReconcilor::Initialize"; 81 VLOG(1) << "AccountReconcilor::Initialize";
223 RegisterWithSigninManager(); 82 RegisterWithSigninManager();
224 83
225 // If this user is not signed in, the reconcilor should do nothing but 84 // If this user is not signed in, the reconcilor should do nothing but
226 // wait for signin. 85 // wait for signin.
227 if (IsProfileConnected()) { 86 if (IsProfileConnected()) {
228 RegisterForCookieChanges(); 87 RegisterForCookieChanges();
229 RegisterWithTokenService(); 88 RegisterWithTokenService();
230 89
231 // Start a reconcile if the tokens are already loaded. 90 // Start a reconcile if the tokens are already loaded.
232 if (start_reconcile_if_tokens_available && 91 if (start_reconcile_if_tokens_available &&
233 token_service_->GetAccounts().size() > 0) { 92 token_service_->GetAccounts().size() > 0) {
234 StartReconcile(); 93 StartReconcile();
235 } 94 }
236 } 95 }
237 } 96 }
238 97
239 void AccountReconcilor::Shutdown() { 98 void AccountReconcilor::Shutdown() {
240 VLOG(1) << "AccountReconcilor::Shutdown"; 99 VLOG(1) << "AccountReconcilor::Shutdown";
241 merge_session_helper_.CancelAll(); 100 merge_session_helper_.CancelAll();
242 merge_session_helper_.RemoveObserver(this); 101 merge_session_helper_.RemoveObserver(this);
243 gaia_fetcher_.reset(); 102 gaia_fetcher_.reset();
244 get_gaia_accounts_callbacks_.clear(); 103 get_gaia_accounts_callbacks_.clear();
245 DeleteFetchers();
246 UnregisterWithSigninManager(); 104 UnregisterWithSigninManager();
247 UnregisterWithTokenService(); 105 UnregisterWithTokenService();
248 UnregisterForCookieChanges(); 106 UnregisterForCookieChanges();
249 } 107 }
250 108
251 void AccountReconcilor::AddMergeSessionObserver( 109 void AccountReconcilor::AddMergeSessionObserver(
252 MergeSessionHelper::Observer* observer) { 110 MergeSessionHelper::Observer* observer) {
253 merge_session_helper_.AddObserver(observer); 111 merge_session_helper_.AddObserver(observer);
254 } 112 }
255 113
256 void AccountReconcilor::RemoveMergeSessionObserver( 114 void AccountReconcilor::RemoveMergeSessionObserver(
257 MergeSessionHelper::Observer* observer) { 115 MergeSessionHelper::Observer* observer) {
258 merge_session_helper_.RemoveObserver(observer); 116 merge_session_helper_.RemoveObserver(observer);
259 } 117 }
260 118
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() { 119 void AccountReconcilor::RegisterForCookieChanges() {
275 // First clear any existing registration to avoid DCHECKs that can otherwise 120 // First clear any existing registration to avoid DCHECKs that can otherwise
276 // go off in some embedders on reauth (e.g., ChromeSigninClient). 121 // go off in some embedders on reauth (e.g., ChromeSigninClient).
277 UnregisterForCookieChanges(); 122 UnregisterForCookieChanges();
278 cookie_changed_subscription_ = client_->AddCookieChangedCallback( 123 cookie_changed_subscription_ = client_->AddCookieChangedCallback(
279 base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this))); 124 base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
280 } 125 }
281 126
282 void AccountReconcilor::UnregisterForCookieChanges() { 127 void AccountReconcilor::UnregisterForCookieChanges() {
283 cookie_changed_subscription_.reset(); 128 cookie_changed_subscription_.reset();
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 if (!token_service_->GetAccounts().size()) { 170 if (!token_service_->GetAccounts().size()) {
326 VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored" 171 VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored"
327 "because O2RT is not available yet."; 172 "because O2RT is not available yet.";
328 return; 173 return;
329 } 174 }
330 175
331 StartReconcile(); 176 StartReconcile();
332 } 177 }
333 } 178 }
334 179
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() { 180 void AccountReconcilor::OnEndBatchChanges() {
341 VLOG(1) << "AccountReconcilor::OnEndBatchChanges"; 181 VLOG(1) << "AccountReconcilor::OnEndBatchChanges";
342 StartReconcile(); 182 StartReconcile();
343 } 183 }
344 184
345 void AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id, 185 void AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id,
346 const std::string& username, 186 const std::string& username,
347 const std::string& password) { 187 const std::string& password) {
348 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in"; 188 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
349 RegisterForCookieChanges(); 189 RegisterForCookieChanges();
(...skipping 13 matching lines...) Expand all
363 203
364 void AccountReconcilor::PerformMergeAction(const std::string& account_id) { 204 void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
365 if (!switches::IsEnableAccountConsistency()) { 205 if (!switches::IsEnableAccountConsistency()) {
366 MarkAccountAsAddedToCookie(account_id); 206 MarkAccountAsAddedToCookie(account_id);
367 return; 207 return;
368 } 208 }
369 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id; 209 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
370 merge_session_helper_.LogIn(account_id); 210 merge_session_helper_.LogIn(account_id);
371 } 211 }
372 212
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() { 213 void AccountReconcilor::PerformLogoutAllAccountsAction() {
422 if (!switches::IsEnableAccountConsistency()) 214 if (!switches::IsEnableAccountConsistency())
423 return; 215 return;
424 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction"; 216 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
425 merge_session_helper_.LogOutAllAccounts(); 217 merge_session_helper_.LogOutAllAccounts();
426 } 218 }
427 219
428 void AccountReconcilor::StartReconcile() { 220 void AccountReconcilor::StartReconcile() {
429 if (!IsProfileConnected() || is_reconcile_started_ || 221 if (!IsProfileConnected() || is_reconcile_started_ ||
430 get_gaia_accounts_callbacks_.size() > 0 || 222 get_gaia_accounts_callbacks_.size() > 0 ||
431 merge_session_helper_.is_running()) 223 merge_session_helper_.is_running())
432 return; 224 return;
433 225
434 is_reconcile_started_ = true; 226 is_reconcile_started_ = true;
435 227
436 StartFetchingExternalCcResult(); 228 StartFetchingExternalCcResult();
437 229
438 // Reset state for validating gaia cookie. 230 // Reset state for validating gaia cookie.
439 are_gaia_accounts_set_ = false; 231 are_gaia_accounts_set_ = false;
440 gaia_accounts_.clear(); 232 gaia_accounts_.clear();
441 GetAccountsFromCookie(base::Bind( 233 GetAccountsFromCookie(base::Bind(
442 &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts, 234 &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts,
443 base::Unretained(this))); 235 base::Unretained(this)));
444 236
445 // Reset state for validating oauth2 tokens. 237 // Reset state for validating oauth2 tokens.
446 primary_account_.clear(); 238 primary_account_.clear();
447 chrome_accounts_.clear(); 239 chrome_accounts_.clear();
448 DeleteFetchers();
449 valid_chrome_accounts_.clear();
450 invalid_chrome_accounts_.clear();
451 add_to_cookie_.clear(); 240 add_to_cookie_.clear();
452 add_to_chrome_.clear();
453 ValidateAccountsFromTokenService(); 241 ValidateAccountsFromTokenService();
454 } 242 }
455 243
456 void AccountReconcilor::GetAccountsFromCookie( 244 void AccountReconcilor::GetAccountsFromCookie(
457 GetAccountsFromCookieCallback callback) { 245 GetAccountsFromCookieCallback callback) {
458 get_gaia_accounts_callbacks_.push_back(callback); 246 get_gaia_accounts_callbacks_.push_back(callback);
459 if (!gaia_fetcher_) { 247 if (!gaia_fetcher_) {
460 // There is no list account request in flight. 248 // There is no list account request in flight.
461 gaia_fetcher_.reset(new GaiaAuthFetcher( 249 gaia_fetcher_.reset(new GaiaAuthFetcher(
462 this, GaiaConstants::kChromeSource, client_->GetURLRequestContext())); 250 this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 322
535 void AccountReconcilor::ValidateAccountsFromTokenService() { 323 void AccountReconcilor::ValidateAccountsFromTokenService() {
536 primary_account_ = signin_manager_->GetAuthenticatedAccountId(); 324 primary_account_ = signin_manager_->GetAuthenticatedAccountId();
537 DCHECK(!primary_account_.empty()); 325 DCHECK(!primary_account_.empty());
538 326
539 chrome_accounts_ = token_service_->GetAccounts(); 327 chrome_accounts_ = token_service_->GetAccounts();
540 328
541 VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: " 329 VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
542 << "Chrome " << chrome_accounts_.size() << " accounts, " 330 << "Chrome " << chrome_accounts_.size() << " accounts, "
543 << "Primary is '" << primary_account_ << "'"; 331 << "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 } 332 }
593 333
594 void AccountReconcilor::OnNewProfileManagementFlagChanged( 334 void AccountReconcilor::OnNewProfileManagementFlagChanged(
595 bool new_flag_status) { 335 bool new_flag_status) {
596 if (new_flag_status) { 336 if (new_flag_status) {
597 // The reconciler may have been newly created just before this call, or may 337 // 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 338 // have already existed and in mid-reconcile. To err on the safe side, force
599 // a restart. 339 // a restart.
600 Shutdown(); 340 Shutdown();
601 Initialize(true); 341 Initialize(true);
602 } else { 342 } else {
603 Shutdown(); 343 Shutdown();
604 } 344 }
605 } 345 }
606 346
607 void AccountReconcilor::FinishReconcile() { 347 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"; 348 VLOG(1) << "AccountReconcilor::FinishReconcile";
614 349 DCHECK(are_gaia_accounts_set_);
615 DeleteFetchers();
616
617 DCHECK(add_to_cookie_.empty()); 350 DCHECK(add_to_cookie_.empty());
618 DCHECK(add_to_chrome_.empty());
619 int number_gaia_accounts = gaia_accounts_.size(); 351 int number_gaia_accounts = gaia_accounts_.size();
620 bool are_primaries_equal = 352 bool are_primaries_equal = number_gaia_accounts > 0 &&
621 number_gaia_accounts > 0 &&
622 gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first); 353 gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
623 354
355 // If there are any accounts in the gaia cookie but not in chrome, then
356 // those accounts need to be removed from the cookie. This means we need
357 // to blow the cookie away.
358 int removed_from_cookie = 0;
359 for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
360 const std::string& gaia_account = gaia_accounts_[i].first;
361 if (gaia_accounts_[i].second &&
362 chrome_accounts_.end() ==
363 std::find_if(chrome_accounts_.begin(),
364 chrome_accounts_.end(),
Mike Lerman 2014/09/23 14:27:47 nit: 1 space less here and the line below
Roger Tawa OOO till Jul 10th 2014/09/23 21:25:58 Done.
365 std::bind1st(AreEmailsSameFunc(), gaia_account))) {
366 ++removed_from_cookie;
367 }
368 }
624 369
625 if (are_primaries_equal) { 370 if (!are_primaries_equal || removed_from_cookie > 0) {
626 // Determine if we need to merge accounts from gaia cookie to chrome.
627 for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
628 const std::string& gaia_account = gaia_accounts_[i].first;
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"; 371 VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
637 // Really messed up state. Blow away the gaia cookie completely and 372 // Really messed up state. Blow away the gaia cookie completely and
638 // rebuild it, making sure the primary account as specified by the 373 // rebuild it, making sure the primary account as specified by the
639 // SigninManager is the first session in the gaia cookie. 374 // SigninManager is the first session in the gaia cookie.
640 PerformLogoutAllAccountsAction(); 375 PerformLogoutAllAccountsAction();
641 gaia_accounts_.clear(); 376 gaia_accounts_.clear();
642 } 377 }
643 378
644 // Create a list of accounts that need to be added to the gaia cookie. 379 // 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 380 // 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. 381 // account in the case where chrome is completely rebuilding the cookie.
647 add_to_cookie_.push_back(primary_account_); 382 add_to_cookie_.push_back(primary_account_);
648 for (EmailSet::const_iterator i = valid_chrome_accounts_.begin(); 383 for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
649 i != valid_chrome_accounts_.end(); 384 if (chrome_accounts_[i] != primary_account_)
650 ++i) { 385 add_to_cookie_.push_back(chrome_accounts_[i]);
651 if (*i != primary_account_)
652 add_to_cookie_.push_back(*i);
653 } 386 }
654 387
655 // For each account known to chrome, PerformMergeAction() if the account is 388 // 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 389 // 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 390 // completed otherwise. Make a copy of |add_to_cookie_| since calls to
658 // SignalComplete() will change the array. 391 // SignalComplete() will change the array.
659 std::vector<std::string> add_to_cookie_copy = add_to_cookie_; 392 std::vector<std::string> add_to_cookie_copy = add_to_cookie_;
660 int added_to_cookie = 0; 393 int added_to_cookie = 0;
661 bool external_cc_result_completed = 394 bool external_cc_result_completed =
662 !merge_session_helper_.StillFetchingExternalCcResult(); 395 !merge_session_helper_.StillFetchingExternalCcResult();
(...skipping 11 matching lines...) Expand all
674 PerformMergeAction(add_to_cookie_copy[i]); 407 PerformMergeAction(add_to_cookie_copy[i]);
675 added_to_cookie++; 408 added_to_cookie++;
676 } 409 }
677 } 410 }
678 411
679 // Log whether the external connection checks were completed when we tried 412 // Log whether the external connection checks were completed when we tried
680 // to add the accounts to the cookie. 413 // to add the accounts to the cookie.
681 if (added_to_cookie > 0) 414 if (added_to_cookie > 0)
682 signin_metrics::LogExternalCcResultFetches(external_cc_result_completed); 415 signin_metrics::LogExternalCcResultFetches(external_cc_result_completed);
683 416
684 std::string signin_scoped_device_id = client_->GetSigninScopedDeviceId(); 417 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, 418 added_to_cookie,
698 add_to_chrome_.size(), 419 removed_from_cookie,
699 are_primaries_equal, 420 are_primaries_equal,
700 first_execution_, 421 first_execution_,
701 number_gaia_accounts); 422 number_gaia_accounts);
702 first_execution_ = false; 423 first_execution_ = false;
703 CalculateIfReconcileIsDone(); 424 CalculateIfReconcileIsDone();
704 ScheduleStartReconcileIfChromeAccountsChanged(); 425 ScheduleStartReconcileIfChromeAccountsChanged();
705 } 426 }
706 427
707 void AccountReconcilor::AbortReconcile() { 428 void AccountReconcilor::AbortReconcile() {
708 VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later"; 429 VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
709 DeleteFetchers();
710 add_to_cookie_.clear(); 430 add_to_cookie_.clear();
711 add_to_chrome_.clear();
712 CalculateIfReconcileIsDone(); 431 CalculateIfReconcileIsDone();
713 } 432 }
714 433
715 void AccountReconcilor::CalculateIfReconcileIsDone() { 434 void AccountReconcilor::CalculateIfReconcileIsDone() {
716 is_reconcile_started_ = !add_to_cookie_.empty() || !add_to_chrome_.empty(); 435 is_reconcile_started_ = !add_to_cookie_.empty();
717 if (!is_reconcile_started_) 436 if (!is_reconcile_started_)
718 VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done"; 437 VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
719 } 438 }
720 439
721 void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() { 440 void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() {
722 if (is_reconcile_started_) 441 if (is_reconcile_started_)
723 return; 442 return;
724 443
725 // Start a reconcile as the token accounts have changed. 444 // Start a reconcile as the token accounts have changed.
726 VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged"; 445 VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged";
(...skipping 18 matching lines...) Expand all
745 add_to_cookie_.erase(i); 464 add_to_cookie_.erase(i);
746 return true; 465 return true;
747 } 466 }
748 } 467 }
749 return false; 468 return false;
750 } 469 }
751 470
752 void AccountReconcilor::MergeSessionCompleted( 471 void AccountReconcilor::MergeSessionCompleted(
753 const std::string& account_id, 472 const std::string& account_id,
754 const GoogleServiceAuthError& error) { 473 const GoogleServiceAuthError& error) {
755 VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id=" 474 VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id="
Mike Lerman 2014/09/23 14:27:47 We should add a human readable representation of t
Roger Tawa OOO till Jul 10th 2014/09/23 21:25:58 Done.
756 << account_id; 475 << account_id;
757 476
758 if (MarkAccountAsAddedToCookie(account_id)) { 477 if (MarkAccountAsAddedToCookie(account_id)) {
759 CalculateIfReconcileIsDone(); 478 CalculateIfReconcileIsDone();
760 ScheduleStartReconcileIfChromeAccountsChanged(); 479 ScheduleStartReconcileIfChromeAccountsChanged();
761 } 480 }
762 } 481 }
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

Powered by Google App Engine
This is Rietveld 408576698