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

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

Issue 1075273002: Handle ListAccount fetches from within the GaiaCookieManagerService. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix a test post rebase Created 5 years, 8 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 "components/signin/core/browser/profile_oauth2_token_service.h" 15 #include "components/signin/core/browser/profile_oauth2_token_service.h"
16 #include "components/signin/core/browser/signin_client.h" 16 #include "components/signin/core/browser/signin_client.h"
17 #include "components/signin/core/browser/signin_metrics.h" 17 #include "components/signin/core/browser/signin_metrics.h"
18 #include "components/signin/core/common/profile_management_switches.h" 18 #include "components/signin/core/common/profile_management_switches.h"
19 #include "google_apis/gaia/gaia_auth_fetcher.h"
20 #include "google_apis/gaia/gaia_auth_util.h" 19 #include "google_apis/gaia/gaia_auth_util.h"
21 #include "google_apis/gaia/gaia_constants.h"
22 #include "google_apis/gaia/gaia_oauth_client.h" 20 #include "google_apis/gaia/gaia_oauth_client.h"
23 #include "google_apis/gaia/gaia_urls.h" 21 #include "google_apis/gaia/gaia_urls.h"
24 #include "net/cookies/canonical_cookie.h"
25 22
26 23
27 namespace { 24 namespace {
28 25
29 class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > { 26 class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > {
30 public: 27 public:
31 bool operator()(const std::pair<std::string, bool>& p1, 28 bool operator()(const std::pair<std::string, bool>& p1,
32 const std::pair<std::string, bool>& p2) const; 29 const std::pair<std::string, bool>& p2) const;
33 }; 30 };
34 31
(...skipping 25 matching lines...) Expand all
60 GaiaCookieManagerService* cookie_manager_service) 57 GaiaCookieManagerService* cookie_manager_service)
61 : token_service_(token_service), 58 : token_service_(token_service),
62 signin_manager_(signin_manager), 59 signin_manager_(signin_manager),
63 client_(client), 60 client_(client),
64 cookie_manager_service_(cookie_manager_service), 61 cookie_manager_service_(cookie_manager_service),
65 registered_with_token_service_(false), 62 registered_with_token_service_(false),
66 registered_with_cookie_manager_service_(false), 63 registered_with_cookie_manager_service_(false),
67 registered_with_content_settings_(false), 64 registered_with_content_settings_(false),
68 is_reconcile_started_(false), 65 is_reconcile_started_(false),
69 first_execution_(true), 66 first_execution_(true),
70 are_gaia_accounts_set_(false),
71 chrome_accounts_changed_(false) { 67 chrome_accounts_changed_(false) {
72 VLOG(1) << "AccountReconcilor::AccountReconcilor"; 68 VLOG(1) << "AccountReconcilor::AccountReconcilor";
73 } 69 }
74 70
75 AccountReconcilor::~AccountReconcilor() { 71 AccountReconcilor::~AccountReconcilor() {
76 VLOG(1) << "AccountReconcilor::~AccountReconcilor"; 72 VLOG(1) << "AccountReconcilor::~AccountReconcilor";
77 // Make sure shutdown was called first. 73 // Make sure shutdown was called first.
78 DCHECK(!registered_with_token_service_); 74 DCHECK(!registered_with_token_service_);
79 DCHECK(!registered_with_cookie_manager_service_); 75 DCHECK(!registered_with_cookie_manager_service_);
80 } 76 }
81 77
82 void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) { 78 void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
83 VLOG(1) << "AccountReconcilor::Initialize"; 79 VLOG(1) << "AccountReconcilor::Initialize";
84 RegisterWithSigninManager(); 80 RegisterWithSigninManager();
85 81
86 // If this user is not signed in, the reconcilor should do nothing but 82 // If this user is not signed in, the reconcilor should do nothing but
87 // wait for signin. 83 // wait for signin.
88 if (IsProfileConnected()) { 84 if (IsProfileConnected()) {
89 RegisterWithCookieManagerService(); 85 RegisterWithCookieManagerService();
90 RegisterForCookieChanges();
91 RegisterWithContentSettings(); 86 RegisterWithContentSettings();
92 RegisterWithTokenService(); 87 RegisterWithTokenService();
93 88
94 // Start a reconcile if the tokens are already loaded. 89 // Start a reconcile if the tokens are already loaded.
95 if (start_reconcile_if_tokens_available && 90 if (start_reconcile_if_tokens_available &&
96 token_service_->GetAccounts().size() > 0) { 91 token_service_->GetAccounts().size() > 0) {
97 StartReconcile(); 92 StartReconcile();
98 } 93 }
99 } 94 }
100 } 95 }
101 96
102 void AccountReconcilor::Shutdown() { 97 void AccountReconcilor::Shutdown() {
103 VLOG(1) << "AccountReconcilor::Shutdown"; 98 VLOG(1) << "AccountReconcilor::Shutdown";
104 gaia_fetcher_.reset();
105 get_gaia_accounts_callbacks_.clear();
106 UnregisterWithCookieManagerService(); 99 UnregisterWithCookieManagerService();
107 UnregisterWithSigninManager(); 100 UnregisterWithSigninManager();
108 UnregisterWithTokenService(); 101 UnregisterWithTokenService();
109 UnregisterForCookieChanges();
110 UnregisterWithContentSettings(); 102 UnregisterWithContentSettings();
111 } 103 }
112 104
113 void AccountReconcilor::RegisterForCookieChanges() {
114 // First clear any existing registration to avoid DCHECKs that can otherwise
115 // go off in some embedders on reauth (e.g., ChromeSigninClient).
116 UnregisterForCookieChanges();
117 cookie_changed_subscription_ = client_->AddCookieChangedCallback(
118 GaiaUrls::GetInstance()->gaia_url(),
119 "LSID",
120 base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
121 }
122
123 void AccountReconcilor::UnregisterForCookieChanges() {
124 cookie_changed_subscription_.reset();
125 }
126
127 void AccountReconcilor::RegisterWithSigninManager() { 105 void AccountReconcilor::RegisterWithSigninManager() {
128 signin_manager_->AddObserver(this); 106 signin_manager_->AddObserver(this);
129 } 107 }
130 108
131 void AccountReconcilor::UnregisterWithSigninManager() { 109 void AccountReconcilor::UnregisterWithSigninManager() {
132 signin_manager_->RemoveObserver(this); 110 signin_manager_->RemoveObserver(this);
133 } 111 }
134 112
135 void AccountReconcilor::RegisterWithContentSettings() { 113 void AccountReconcilor::RegisterWithContentSettings() {
136 VLOG(1) << "AccountReconcilor::RegisterWithContentSettings"; 114 VLOG(1) << "AccountReconcilor::RegisterWithContentSettings";
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 return; 169 return;
192 170
193 cookie_manager_service_->RemoveObserver(this); 171 cookie_manager_service_->RemoveObserver(this);
194 registered_with_cookie_manager_service_ = false; 172 registered_with_cookie_manager_service_ = false;
195 } 173 }
196 174
197 bool AccountReconcilor::IsProfileConnected() { 175 bool AccountReconcilor::IsProfileConnected() {
198 return signin_manager_->IsAuthenticated(); 176 return signin_manager_->IsAuthenticated();
199 } 177 }
200 178
201 void AccountReconcilor::OnCookieChanged(const net::CanonicalCookie& cookie,
202 bool removed) {
203 DCHECK_EQ("LSID", cookie.Name());
204 DCHECK_EQ(GaiaUrls::GetInstance()->gaia_url().host(), cookie.Domain());
205 if (cookie.IsSecure() && cookie.IsHttpOnly()) {
206 VLOG(1) << "AccountReconcilor::OnCookieChanged: LSID changed";
207
208 // It is possible that O2RT is not available at this moment.
209 if (!token_service_->GetAccounts().size()) {
210 VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored"
211 "because O2RT is not available yet.";
212 return;
213 }
214
215 StartReconcile();
216 }
217 }
218
219 void AccountReconcilor::OnContentSettingChanged( 179 void AccountReconcilor::OnContentSettingChanged(
220 const ContentSettingsPattern& primary_pattern, 180 const ContentSettingsPattern& primary_pattern,
221 const ContentSettingsPattern& secondary_pattern, 181 const ContentSettingsPattern& secondary_pattern,
222 ContentSettingsType content_type, 182 ContentSettingsType content_type,
223 std::string resource_identifier) { 183 std::string resource_identifier) {
224 // If this is not a change to cookie settings, just ignore. 184 // If this is not a change to cookie settings, just ignore.
225 if (content_type != CONTENT_SETTINGS_TYPE_COOKIES) 185 if (content_type != CONTENT_SETTINGS_TYPE_COOKIES)
226 return; 186 return;
227 187
228 // If this does not affect GAIA, just ignore. If the primary pattern is 188 // If this does not affect GAIA, just ignore. If the primary pattern is
(...skipping 13 matching lines...) Expand all
242 // Remember that accounts have changed if a reconcile is already started. 202 // Remember that accounts have changed if a reconcile is already started.
243 chrome_accounts_changed_ = is_reconcile_started_; 203 chrome_accounts_changed_ = is_reconcile_started_;
244 StartReconcile(); 204 StartReconcile();
245 } 205 }
246 206
247 void AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id, 207 void AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id,
248 const std::string& username, 208 const std::string& username,
249 const std::string& password) { 209 const std::string& password) {
250 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in"; 210 VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
251 RegisterWithCookieManagerService(); 211 RegisterWithCookieManagerService();
252 RegisterForCookieChanges();
253 RegisterWithContentSettings(); 212 RegisterWithContentSettings();
254 RegisterWithTokenService(); 213 RegisterWithTokenService();
255 } 214 }
256 215
257 void AccountReconcilor::GoogleSignedOut(const std::string& account_id, 216 void AccountReconcilor::GoogleSignedOut(const std::string& account_id,
258 const std::string& username) { 217 const std::string& username) {
259 VLOG(1) << "AccountReconcilor::GoogleSignedOut: signed out"; 218 VLOG(1) << "AccountReconcilor::GoogleSignedOut: signed out";
260 gaia_fetcher_.reset();
261 get_gaia_accounts_callbacks_.clear();
262 AbortReconcile(); 219 AbortReconcile();
263 UnregisterWithCookieManagerService(); 220 UnregisterWithCookieManagerService();
264 UnregisterWithTokenService(); 221 UnregisterWithTokenService();
265 UnregisterForCookieChanges();
266 UnregisterWithContentSettings(); 222 UnregisterWithContentSettings();
267 PerformLogoutAllAccountsAction(); 223 PerformLogoutAllAccountsAction();
268 } 224 }
269 225
270 void AccountReconcilor::PerformMergeAction(const std::string& account_id) { 226 void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
271 if (!switches::IsEnableAccountConsistency()) { 227 if (!switches::IsEnableAccountConsistency()) {
272 MarkAccountAsAddedToCookie(account_id); 228 MarkAccountAsAddedToCookie(account_id);
273 return; 229 return;
274 } 230 }
275 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id; 231 VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
276 cookie_manager_service_->AddAccountToCookie(account_id); 232 cookie_manager_service_->AddAccountToCookie(account_id);
277 } 233 }
278 234
279 void AccountReconcilor::PerformLogoutAllAccountsAction() { 235 void AccountReconcilor::PerformLogoutAllAccountsAction() {
280 if (!switches::IsEnableAccountConsistency()) 236 if (!switches::IsEnableAccountConsistency())
281 return; 237 return;
282 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction"; 238 VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
283 cookie_manager_service_->LogOutAllAccounts(); 239 cookie_manager_service_->LogOutAllAccounts();
284 } 240 }
285 241
286 void AccountReconcilor::StartReconcile() { 242 void AccountReconcilor::StartReconcile() {
287 if (!IsProfileConnected() || !client_->AreSigninCookiesAllowed()) { 243 if (!IsProfileConnected() || !client_->AreSigninCookiesAllowed()) {
288 VLOG(1) << "AccountReconcilor::StartReconcile: !connected or no cookies"; 244 VLOG(1) << "AccountReconcilor::StartReconcile: !connected or no cookies";
289 return; 245 return;
290 } 246 }
291 247
292 if (is_reconcile_started_ || get_gaia_accounts_callbacks_.size() > 0) 248 if (is_reconcile_started_)
293 return; 249 return;
294 250
295 is_reconcile_started_ = true; 251 is_reconcile_started_ = true;
296 252
297 // Reset state for validating gaia cookie. 253 // Reset state for validating gaia cookie.
298 are_gaia_accounts_set_ = false;
299 gaia_accounts_.clear(); 254 gaia_accounts_.clear();
300 255
301 // Reset state for validating oauth2 tokens. 256 // Reset state for validating oauth2 tokens.
302 primary_account_.clear(); 257 primary_account_.clear();
303 chrome_accounts_.clear(); 258 chrome_accounts_.clear();
304 add_to_cookie_.clear(); 259 add_to_cookie_.clear();
305 ValidateAccountsFromTokenService(); 260 ValidateAccountsFromTokenService();
306 261
307 GetAccountsFromCookie(base::Bind( 262 // Rely on the GCMS to manage calls to and responses from ListAccounts.
308 &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts, 263 if (cookie_manager_service_->ListAccounts(&gaia_accounts_)) {
309 base::Unretained(this))); 264 OnGaiaAccountsInCookieUpdated(
310 } 265 gaia_accounts_, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
311
312 void AccountReconcilor::GetAccountsFromCookie(
313 GetAccountsFromCookieCallback callback) {
314 get_gaia_accounts_callbacks_.push_back(callback);
315 if (!gaia_fetcher_)
316 MayBeDoNextListAccounts();
317 }
318
319 void AccountReconcilor::OnListAccountsSuccess(const std::string& data) {
320 gaia_fetcher_.reset();
321
322 // Get account information from response data.
323 std::vector<std::pair<std::string, bool> > gaia_accounts;
324 bool valid_json = gaia::ParseListAccountsData(data, &gaia_accounts);
325 if (!valid_json) {
326 VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: parsing error";
327 } else if (gaia_accounts.size() > 0) {
328 VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: "
329 << "Gaia " << gaia_accounts.size() << " accounts, "
330 << "Primary is '" << gaia_accounts[0].first << "'";
331 } else {
332 VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts";
333 }
334
335 // There must be at least one callback waiting for result.
336 DCHECK(!get_gaia_accounts_callbacks_.empty());
337
338 GoogleServiceAuthError error =
339 !valid_json ? GoogleServiceAuthError(
340 GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE)
341 : GoogleServiceAuthError::AuthErrorNone();
342 get_gaia_accounts_callbacks_.front().Run(error, gaia_accounts);
343 get_gaia_accounts_callbacks_.pop_front();
344
345 MayBeDoNextListAccounts();
346 }
347
348 void AccountReconcilor::OnListAccountsFailure(
349 const GoogleServiceAuthError& error) {
350 gaia_fetcher_.reset();
351 VLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString();
352 std::vector<std::pair<std::string, bool> > empty_accounts;
353
354 // There must be at least one callback waiting for result.
355 DCHECK(!get_gaia_accounts_callbacks_.empty());
356
357 get_gaia_accounts_callbacks_.front().Run(error, empty_accounts);
358 get_gaia_accounts_callbacks_.pop_front();
359
360 MayBeDoNextListAccounts();
361 }
362
363 void AccountReconcilor::MayBeDoNextListAccounts() {
364 if (!get_gaia_accounts_callbacks_.empty()) {
365 gaia_fetcher_.reset(new GaiaAuthFetcher(
366 this, GaiaConstants::kReconcilorSource,
367 client_->GetURLRequestContext()));
368 gaia_fetcher_->StartListAccounts();
369 } 266 }
370 } 267 }
371 268
372 void AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts( 269 void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
373 const GoogleServiceAuthError& error, 270 const std::vector<std::pair<std::string, bool> >& accounts,
374 const std::vector<std::pair<std::string, bool> >& accounts) { 271 const GoogleServiceAuthError& error) {
375 if (error.state() == GoogleServiceAuthError::NONE) { 272 if (error.state() == GoogleServiceAuthError::NONE) {
376 gaia_accounts_ = accounts; 273 gaia_accounts_ = accounts;
377 are_gaia_accounts_set_ = true; 274
378 FinishReconcile(); 275 // It is possible that O2RT is not available at this moment.
276 if (token_service_->GetAccounts().empty())
277 return;
278
279 is_reconcile_started_ ? FinishReconcile() : StartReconcile();
379 } else { 280 } else {
380 AbortReconcile(); 281 AbortReconcile();
381 } 282 }
382 } 283 }
383 284
384 void AccountReconcilor::ValidateAccountsFromTokenService() { 285 void AccountReconcilor::ValidateAccountsFromTokenService() {
385 primary_account_ = signin_manager_->GetAuthenticatedAccountId(); 286 primary_account_ = signin_manager_->GetAuthenticatedAccountId();
386 DCHECK(!primary_account_.empty()); 287 DCHECK(!primary_account_.empty());
387 288
388 chrome_accounts_ = token_service_->GetAccounts(); 289 chrome_accounts_ = token_service_->GetAccounts();
(...skipping 11 matching lines...) Expand all
400 // a restart. 301 // a restart.
401 Shutdown(); 302 Shutdown();
402 Initialize(true); 303 Initialize(true);
403 } else { 304 } else {
404 Shutdown(); 305 Shutdown();
405 } 306 }
406 } 307 }
407 308
408 void AccountReconcilor::FinishReconcile() { 309 void AccountReconcilor::FinishReconcile() {
409 VLOG(1) << "AccountReconcilor::FinishReconcile"; 310 VLOG(1) << "AccountReconcilor::FinishReconcile";
410 DCHECK(are_gaia_accounts_set_);
411 DCHECK(add_to_cookie_.empty()); 311 DCHECK(add_to_cookie_.empty());
412 int number_gaia_accounts = gaia_accounts_.size(); 312 int number_gaia_accounts = gaia_accounts_.size();
413 bool are_primaries_equal = number_gaia_accounts > 0 && 313 bool are_primaries_equal = number_gaia_accounts > 0 &&
414 gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first); 314 gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
415 315
416 // If there are any accounts in the gaia cookie but not in chrome, then 316 // If there are any accounts in the gaia cookie but not in chrome, then
417 // those accounts need to be removed from the cookie. This means we need 317 // those accounts need to be removed from the cookie. This means we need
418 // to blow the cookie away. 318 // to blow the cookie away.
419 int removed_from_cookie = 0; 319 int removed_from_cookie = 0;
420 for (size_t i = 0; i < gaia_accounts_.size(); ++i) { 320 for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 431
532 void AccountReconcilor::OnAddAccountToCookieCompleted( 432 void AccountReconcilor::OnAddAccountToCookieCompleted(
533 const std::string& account_id, 433 const std::string& account_id,
534 const GoogleServiceAuthError& error) { 434 const GoogleServiceAuthError& error) {
535 // Always listens to GaiaCookieManagerService. Only proceed if reconciling. 435 // Always listens to GaiaCookieManagerService. Only proceed if reconciling.
536 if (is_reconcile_started_ && MarkAccountAsAddedToCookie(account_id)) { 436 if (is_reconcile_started_ && MarkAccountAsAddedToCookie(account_id)) {
537 CalculateIfReconcileIsDone(); 437 CalculateIfReconcileIsDone();
538 ScheduleStartReconcileIfChromeAccountsChanged(); 438 ScheduleStartReconcileIfChromeAccountsChanged();
539 } 439 }
540 } 440 }
OLDNEW
« no previous file with comments | « components/signin/core/browser/account_reconcilor.h ('k') | components/signin/core/browser/gaia_cookie_manager_service.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698