Chromium Code Reviews| 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 |