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 3 // found in the LICENSE file. 4 #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_H_ 5 #define COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_H_ 6 7 #include <memory> 8 #include <string> 9 #include <vector> 10 11 #include "base/callback_forward.h" 12 #include "base/compiler_specific.h" 13 #include "base/gtest_prod_util.h" 14 #include "base/macros.h" 15 #include "base/memory/weak_ptr.h" 16 #include "base/observer_list.h" 17 #include "base/threading/thread_checker.h" 18 #include "base/time/time.h" 19 #include "base/timer/timer.h" 20 #include "build/build_config.h" 21 #include "components/content_settings/core/browser/content_settings_observer.h" 22 #include "components/content_settings/core/common/content_settings_pattern.h" 23 #include "components/keyed_service/core/keyed_service.h" 24 #include "components/signin/core/browser/account_reconcilor_delegate.h" 25 #include "components/signin/core/browser/signin_header_helper.h" 26 #include "components/signin/public/base/signin_client.h" 27 #include "components/signin/public/base/signin_metrics.h" 28 #include "components/signin/public/identity_manager/identity_manager.h" 29 #include "google_apis/gaia/google_service_auth_error.h" 30 31 namespace signin { 32 class AccountReconcilorDelegate; 33 enum class SetAccountsInCookieResult; 34 } 35 36 class SigninClient; 37 38 class AccountReconcilor : public KeyedService, 39 public content_settings::Observer, 40 public signin::IdentityManager::Observer { 41 public: 42 // When an instance of this class exists, the account reconcilor is suspended. 43 // It will automatically restart when all instances of Lock have been 44 // destroyed. 45 class Lock final { 46 public: 47 explicit Lock(AccountReconcilor* reconcilor); 48 ~Lock(); 49 50 private: 51 base::WeakPtr<AccountReconcilor> reconcilor_; 52 THREAD_CHECKER(thread_checker_); 53 DISALLOW_COPY_AND_ASSIGN(Lock); 54 }; 55 56 // Helper class to indicate that synced data is being deleted. The object 57 // must be destroyed when the data deletion is complete. 58 class ScopedSyncedDataDeletion { 59 public: 60 ~ScopedSyncedDataDeletion(); 61 62 private: 63 friend class AccountReconcilor; 64 explicit ScopedSyncedDataDeletion(AccountReconcilor* reconcilor); 65 base::WeakPtr<AccountReconcilor> reconcilor_; 66 DISALLOW_COPY_AND_ASSIGN(ScopedSyncedDataDeletion); 67 }; 68 69 class Observer { 70 public: ~Observer()71 virtual ~Observer() {} 72 73 // The typical order of events is: 74 // - When reconcile is blocked: 75 // 1. current reconcile is aborted with AbortReconcile(), 76 // 2. OnStateChanged() is called with SCHEDULED. 77 // 3. OnBlockReconcile() is called. 78 // - When reconcile is unblocked: 79 // 1. OnUnblockReconcile() is called, 80 // 2. reconcile is restarted if needed with StartReconcile(), which 81 // triggers a call to OnStateChanged() with RUNNING. 82 83 // Called whe reconcile starts. OnStateChanged(signin_metrics::AccountReconcilorState state)84 virtual void OnStateChanged(signin_metrics::AccountReconcilorState state) {} 85 // Called when the AccountReconcilor is blocked. OnBlockReconcile()86 virtual void OnBlockReconcile() {} 87 // Called when the AccountReconcilor is unblocked. OnUnblockReconcile()88 virtual void OnUnblockReconcile() {} 89 }; 90 91 AccountReconcilor( 92 signin::IdentityManager* identity_manager, 93 SigninClient* client, 94 std::unique_ptr<signin::AccountReconcilorDelegate> delegate); 95 ~AccountReconcilor() override; 96 97 // Initializes the account reconcilor. Should be called once after 98 // construction. 99 void Initialize(bool start_reconcile_if_tokens_available); 100 101 // Enables and disables the reconciliation. 102 void EnableReconcile(); 103 void DisableReconcile(bool logout_all_gaia_accounts); 104 105 // Signal that an X-Chrome-Manage-Accounts was received from GAIA. Pass the 106 // ServiceType specified by GAIA in the 204 response. 107 // Virtual for testing. 108 virtual void OnReceivedManageAccountsResponse( 109 signin::GAIAServiceType service_type); 110 111 // KeyedService implementation. 112 void Shutdown() override; 113 114 // Determine what the reconcilor is currently doing. 115 signin_metrics::AccountReconcilorState GetState(); 116 117 // Adds ands removes observers. 118 void AddObserver(Observer* observer); 119 void RemoveObserver(Observer* observer); 120 121 // ScopedSyncedDataDeletion can be created when synced data is being removed 122 // and destroyed when the deletion is complete. It prevents the Sync account 123 // from being invalidated during the deletion. 124 std::unique_ptr<ScopedSyncedDataDeletion> GetScopedSyncDataDeletion(); 125 126 // Returns true if reconcilor is blocked. 127 bool IsReconcileBlocked() const; 128 129 private: 130 friend class AccountReconcilorTest; 131 friend class DiceBrowserTest; 132 friend class BaseAccountReconcilorTestTable; 133 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestForceDiceMigration, 134 TableRowTestCheckNoOp); 135 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 136 IdentityManagerRegistration); 137 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, Reauth); 138 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 139 ProfileAlreadyConnected); 140 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestTable, TableRowTest); 141 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestTable, 142 InconsistencyReasonLogging); 143 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestDiceMultilogin, TableRowTest); 144 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestMirrorMultilogin, TableRowTest); 145 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestMiceMultilogin, TableRowTest); 146 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMiceTest, 147 AccountReconcilorStateScheduled); 148 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 149 DiceTokenServiceRegistration); 150 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 151 DiceReconcileWithoutSignin); 152 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 153 DiceReconcileNoop); 154 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 155 DiceLastKnownFirstAccount); 156 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 157 UnverifiedAccountNoop); 158 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 159 UnverifiedAccountMerge); 160 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 161 HandleSigninDuringReconcile); 162 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceEndpointParamTest, 163 DiceReconcileReuseGaiaFirstAccount); 164 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceDeleteCookie); 165 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, TokensNotLoaded); 166 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 167 StartReconcileCookiesDisabled); 168 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 169 StartReconcileContentSettings); 170 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 171 StartReconcileContentSettingsGaiaUrl); 172 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 173 StartReconcileContentSettingsNonGaiaUrl); 174 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 175 StartReconcileContentSettingsInvalidPattern); 176 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 177 GetAccountsFromCookieSuccess); 178 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 179 EnableReconcileWhileAlreadyRunning); 180 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 181 GetAccountsFromCookieFailure); 182 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 183 ExtraCookieChangeNotification); 184 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, StartReconcileNoop); 185 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 186 StartReconcileNoopWithDots); 187 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 188 StartReconcileNoopMultiple); 189 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 190 StartReconcileAddToCookie); 191 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, AuthErrorTriggersListAccount); 192 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 193 SignoutAfterErrorDoesNotRecordUma); 194 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, TokenErrorOnPrimary); 195 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 196 StartReconcileRemoveFromCookie); 197 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 198 StartReconcileAddToCookieTwice); 199 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 200 StartReconcileBadPrimary); 201 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, StartReconcileOnlyOnce); 202 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, Lock); 203 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMethodParamTest, 204 StartReconcileWithSessionInfoExpiredDefault); 205 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMethodParamTest, 206 AccountReconcilorStateScheduled); 207 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 208 AddAccountToCookieCompletedWithBogusAccount); 209 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, NoLoopWithBadPrimary); 210 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 211 WontMergeAccountsWithError); 212 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsCalled); 213 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest, 214 DelegateTimeoutIsNotCalled); 215 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, 216 DelegateTimeoutIsNotCalledIfTimeoutIsNotReached); 217 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, MultiloginLogout); 218 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestForceDiceMigration, 219 TableRowTest); 220 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestActiveDirectory, 221 TableRowTestMergeSession); 222 FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestActiveDirectory, 223 TableRowTestMultilogin); 224 225 void set_timer_for_testing(std::unique_ptr<base::OneShotTimer> timer); 226 IsRegisteredWithIdentityManager()227 bool IsRegisteredWithIdentityManager() const { 228 return registered_with_identity_manager_; 229 } 230 231 // Register and unregister with dependent services. 232 void RegisterWithAllDependencies(); 233 void UnregisterWithAllDependencies(); 234 void RegisterWithIdentityManager(); 235 void UnregisterWithIdentityManager(); 236 void RegisterWithContentSettings(); 237 void UnregisterWithContentSettings(); 238 239 // All actions with side effects, only doing meaningful work if account 240 // consistency is enabled. Virtual so that they can be overridden in tests. 241 virtual void PerformMergeAction(const CoreAccountId& account_id); 242 virtual void PerformLogoutAllAccountsAction(); 243 virtual void PerformSetCookiesAction( 244 const signin::MultiloginParameters& parameters); 245 246 // Used during periodic reconciliation. 247 void StartReconcile(); 248 // |gaia_accounts| are the accounts in the Gaia cookie. 249 void FinishReconcile(const CoreAccountId& primary_account, 250 const std::vector<CoreAccountId>& chrome_accounts, 251 std::vector<gaia::ListedAccount>&& gaia_accounts); 252 void AbortReconcile(); 253 void CalculateIfReconcileIsDone(); 254 void ScheduleStartReconcileIfChromeAccountsChanged(); 255 256 // Returns the list of valid accounts from the TokenService. 257 std::vector<CoreAccountId> LoadValidAccountsFromTokenService() const; 258 259 // Note internally that this |account_id| is added to the cookie jar. 260 bool MarkAccountAsAddedToCookie(const CoreAccountId& account_id); 261 262 // The reconcilor only starts when the token service is ready. 263 bool IsIdentityManagerReady(); 264 265 // Overridden from content_settings::Observer. 266 void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern, 267 const ContentSettingsPattern& secondary_pattern, 268 ContentSettingsType content_type) override; 269 270 // Overridden from signin::IdentityManager::Observer. 271 void OnEndBatchOfRefreshTokenStateChanges() override; 272 void OnRefreshTokensLoaded() override; 273 void OnErrorStateOfRefreshTokenUpdatedForAccount( 274 const CoreAccountInfo& account_info, 275 const GoogleServiceAuthError& error) override; 276 void OnAccountsInCookieUpdated( 277 const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info, 278 const GoogleServiceAuthError& error) override; 279 void OnAccountsCookieDeletedByUserAction() override; 280 281 void FinishReconcileWithMultiloginEndpoint( 282 const CoreAccountId& primary_account, 283 const std::vector<CoreAccountId>& chrome_accounts, 284 std::vector<gaia::ListedAccount>&& gaia_accounts); 285 286 void OnAddAccountToCookieCompleted(const CoreAccountId& account_id, 287 const GoogleServiceAuthError& error); 288 void OnSetAccountsInCookieCompleted(signin::SetAccountsInCookieResult result); 289 void OnLogOutFromCookieCompleted(const GoogleServiceAuthError& error); 290 291 // Lock related methods. 292 void IncrementLockCount(); 293 void DecrementLockCount(); 294 void BlockReconcile(); 295 void UnblockReconcile(); 296 297 void HandleReconcileTimeout(); 298 299 // Returns true is multilogin endpoint can be enabled. 300 bool IsMultiloginEndpointEnabled() const; 301 302 // Returns true if current array of existing accounts in cookie is different 303 // from the desired one. If this returns false, the multilogin call would be a 304 // no-op. 305 bool CookieNeedsUpdate( 306 const signin::MultiloginParameters& parameters, 307 const std::vector<gaia::ListedAccount>& existing_accounts); 308 309 // Sets the reconcilor state and calls Observer::OnStateChanged() if needed. 310 void SetState(signin_metrics::AccountReconcilorState state); 311 312 std::unique_ptr<signin::AccountReconcilorDelegate> delegate_; 313 314 // The IdentityManager associated with this reconcilor. 315 signin::IdentityManager* identity_manager_; 316 317 // The SigninClient associated with this reconcilor. 318 SigninClient* client_; 319 320 bool registered_with_identity_manager_; 321 bool registered_with_content_settings_; 322 323 // True while the reconcilor is busy checking or managing the accounts in 324 // this profile. 325 bool is_reconcile_started_; 326 base::Time reconcile_start_time_; 327 328 // True iff this is the first time the reconcilor is executing. 329 bool first_execution_; 330 331 // 'Most severe' error encountered during the last attempt to reconcile. If 332 // the last reconciliation attempt was successful, this will be 333 // |GoogleServiceAuthError::State::NONE|. 334 // Severity of an error is defined on the basis of 335 // |GoogleServiceAuthError::IsPersistentError()| only, i.e. any persistent 336 // error is considered more severe than all non-persistent errors, but 337 // persistent (or non-persistent) errors do not have an internal severity 338 // ordering among themselves. 339 GoogleServiceAuthError error_during_last_reconcile_; 340 341 // Used for Dice migration: migration can happen if the accounts are 342 // consistent, which is indicated by reconcile being a no-op. 343 bool reconcile_is_noop_; 344 345 // Used during reconcile action. 346 std::vector<CoreAccountId> add_to_cookie_; // Progress of AddAccount calls. 347 bool set_accounts_in_progress_; // Progress of SetAccounts calls. 348 bool log_out_in_progress_; // Progress of LogOut calls. 349 bool chrome_accounts_changed_; 350 351 // Used for the Lock. 352 // StartReconcile() is blocked while this is > 0. 353 int account_reconcilor_lock_count_; 354 // StartReconcile() should be started when the reconcilor is unblocked. 355 bool reconcile_on_unblock_; 356 357 base::ObserverList<Observer, true>::Unchecked observer_list_; 358 359 // A timer to set off reconciliation timeout handlers, if account 360 // reconciliation does not happen in a given |timeout_| duration. 361 // Any delegate that wants to use this feature must override 362 // |AccountReconcilorDelegate::GetReconcileTimeout|. 363 // Note: This is intended as a safeguard for delegates that want a 'guarantee' 364 // of reconciliation completing within a finite time. It is technically 365 // possible for account reconciliation to be running/waiting forever in cases 366 // such as a network connection not being present. 367 std::unique_ptr<base::OneShotTimer> timer_; 368 base::TimeDelta timeout_; 369 370 // Greater than 0 when synced data is being deleted, and it is important to 371 // not invalidate the primary token while this is happening. 372 int synced_data_deletion_in_progress_count_ = 0; 373 374 signin_metrics::AccountReconcilorState state_; 375 376 base::WeakPtrFactory<AccountReconcilor> weak_factory_{this}; 377 378 DISALLOW_COPY_AND_ASSIGN(AccountReconcilor); 379 }; 380 381 #endif // COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_H_ 382