OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } | |
OLD | NEW |