account_reconcilor.h revision 116680a4aac90f2aa7413d9095a592090648e557
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 <deque>
8#include <functional>
9#include <set>
10#include <string>
11#include <utility>
12#include <vector>
13
14#include "base/basictypes.h"
15#include "base/callback_forward.h"
16#include "base/compiler_specific.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/memory/scoped_vector.h"
19#include "components/keyed_service/core/keyed_service.h"
20#include "components/signin/core/browser/signin_manager.h"
21#include "google_apis/gaia/gaia_auth_consumer.h"
22#include "google_apis/gaia/google_service_auth_error.h"
23#include "google_apis/gaia/merge_session_helper.h"
24#include "google_apis/gaia/oauth2_token_service.h"
25
26class GaiaAuthFetcher;
27class ProfileOAuth2TokenService;
28class SigninClient;
29class SigninOAuthHelper;
30
31namespace net {
32class CanonicalCookie;
33}
34
35class AccountReconcilor : public KeyedService,
36                          public GaiaAuthConsumer,
37                          public MergeSessionHelper::Observer,
38                          public OAuth2TokenService::Consumer,
39                          public OAuth2TokenService::Observer,
40                          public SigninManagerBase::Observer {
41 public:
42  AccountReconcilor(ProfileOAuth2TokenService* token_service,
43                    SigninManagerBase* signin_manager,
44                    SigninClient* client);
45  virtual ~AccountReconcilor();
46
47  void Initialize(bool start_reconcile_if_tokens_available);
48
49  // Signal that the status of the new_profile_management flag has changed.
50  // Pass the new status as an explicit parameter since disabling the flag
51  // doesn't remove it from the CommandLine::ForCurrentProcess().
52  void OnNewProfileManagementFlagChanged(bool new_flag_status);
53
54  // KeyedService implementation.
55  virtual void Shutdown() OVERRIDE;
56
57  // Add or remove observers for the merge session notification.
58  void AddMergeSessionObserver(MergeSessionHelper::Observer* observer);
59  void RemoveMergeSessionObserver(MergeSessionHelper::Observer* observer);
60
61  ProfileOAuth2TokenService* token_service() { return token_service_; }
62  SigninClient* client() { return client_; }
63
64 protected:
65  // Used during GetAccountsFromCookie.
66  // Stores a callback for the next action to perform.
67  typedef base::Callback<
68      void(const GoogleServiceAuthError& error,
69           const std::vector<std::pair<std::string, bool> >&)>
70      GetAccountsFromCookieCallback;
71
72  virtual void GetAccountsFromCookie(GetAccountsFromCookieCallback callback);
73
74 private:
75  // An std::set<> for use with email addresses that uses
76  // gaia::CanonicalizeEmail() during comparisons.
77  // TODO(rogerta): this is a workaround for the fact that SigninManager and
78  // SigninOAuthHelper use the gaia "email" property when adding accounts to
79  // the token service, whereas gaia::ParseListAccountsData() returns email
80  // addresses that have been passed through gaia::CanonicalizeEmail().  These
81  // two types of email addresses are not directly comparable.
82  class EmailLessFunc : public std::less<std::string> {
83   public:
84    bool operator()(const std::string& s1, const std::string& s2) const;
85  };
86  typedef std::set<std::string, EmailLessFunc> EmailSet;
87
88  class RefreshTokenFetcher;
89  class UserIdFetcher;
90
91  bool IsRegisteredWithTokenService() const {
92    return registered_with_token_service_;
93  }
94
95  bool AreGaiaAccountsSet() const { return are_gaia_accounts_set_; }
96
97  bool AreAllRefreshTokensChecked() const;
98
99  const std::vector<std::pair<std::string, bool> >& GetGaiaAccountsForTesting()
100      const {
101    return gaia_accounts_;
102  }
103
104  const EmailSet& GetValidChromeAccountsForTesting() const {
105    return valid_chrome_accounts_;
106  }
107
108  const EmailSet& GetInvalidChromeAccountsForTesting() const {
109    return invalid_chrome_accounts_;
110  }
111
112
113  friend class AccountReconcilorTest;
114  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, SigninManagerRegistration);
115  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Reauth);
116  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, ProfileAlreadyConnected);
117  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, GetAccountsFromCookieSuccess);
118  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, GetAccountsFromCookieFailure);
119  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, ValidateAccountsFromTokens);
120  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
121                           ValidateAccountsFromTokensFailedUserInfo);
122  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
123                           ValidateAccountsFromTokensFailedTokenRequest);
124  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoop);
125  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopWithDots);
126  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopMultiple);
127  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileAddToCookie);
128  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
129                           StartReconcileAddToCookieTwice);
130  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileAddToChrome);
131  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileBadPrimary);
132  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileOnlyOnce);
133  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
134                           StartReconcileWithSessionInfoExpiredDefault);
135  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
136                           MergeSessionCompletedWithBogusAccount);
137
138  // Register and unregister with dependent services.
139  void RegisterForCookieChanges();
140  void UnregisterForCookieChanges();
141  void RegisterWithSigninManager();
142  void UnregisterWithSigninManager();
143  void RegisterWithTokenService();
144  void UnregisterWithTokenService();
145
146  bool IsProfileConnected();
147
148  void DeleteFetchers();
149
150  // All actions with side effects.  Virtual so that they can be overridden
151  // in tests.
152  virtual void PerformMergeAction(const std::string& account_id);
153  virtual void PerformAddToChromeAction(
154      const std::string& account_id,
155      int session_index,
156      const std::string& signin_scoped_device_id);
157  virtual void PerformLogoutAllAccountsAction();
158  virtual void PerformAddAccountToTokenService(
159      const std::string& account_id,
160      const std::string& refresh_token);
161
162  // Used to remove an account from chrome and the cookie jar.
163  virtual void PerformStartRemoveAction(const std::string& account_id);
164  virtual void PerformFinishRemoveAction(
165      const std::string& account_id,
166      const GoogleServiceAuthError& error,
167      const std::vector<std::pair<std::string, bool> >& accounts);
168
169  // Used during periodic reconciliation.
170  void StartReconcile();
171  void FinishReconcile();
172  void AbortReconcile();
173  void CalculateIfReconcileIsDone();
174  void ScheduleStartReconcileIfChromeAccountsChanged();
175  void HandleSuccessfulAccountIdCheck(const std::string& account_id);
176  void HandleFailedAccountIdCheck(const std::string& account_id);
177  void HandleRefreshTokenFetched(const std::string& account_id,
178                                 const std::string& refresh_token);
179
180  void ContinueReconcileActionAfterGetGaiaAccounts(
181      const GoogleServiceAuthError& error,
182      const std::vector<std::pair<std::string, bool> >& accounts);
183  void ValidateAccountsFromTokenService();
184  // Note internally that this |account_id| is added to the cookie jar.
185  bool MarkAccountAsAddedToCookie(const std::string& account_id);
186  // Note internally that this |account_id| is added to the token service.
187  void MarkAccountAsAddedToChrome(const std::string& account_id);
188
189  void OnCookieChanged(const net::CanonicalCookie* cookie);
190
191  // Overriden from GaiaAuthConsumer.
192  virtual void OnListAccountsSuccess(const std::string& data) OVERRIDE;
193  virtual void OnListAccountsFailure(const GoogleServiceAuthError& error)
194      OVERRIDE;
195
196  // Overriden from MergeSessionHelper::Observer.
197  virtual void MergeSessionCompleted(const std::string& account_id,
198                                     const GoogleServiceAuthError& error)
199      OVERRIDE;
200
201  // Overriden from OAuth2TokenService::Consumer.
202  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
203                                 const std::string& access_token,
204                                 const base::Time& expiration_time) OVERRIDE;
205  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
206                                 const GoogleServiceAuthError& error) OVERRIDE;
207
208  // Overriden from OAuth2TokenService::Observer.
209  virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE;
210  virtual void OnEndBatchChanges() OVERRIDE;
211
212  // Overriden from SigninManagerBase::Observer.
213  virtual void GoogleSigninSucceeded(const std::string& username,
214                                     const std::string& password) OVERRIDE;
215  virtual void GoogleSignedOut(const std::string& username) OVERRIDE;
216
217  void MayBeDoNextListAccounts();
218
219  // The ProfileOAuth2TokenService associated with this reconcilor.
220  ProfileOAuth2TokenService* token_service_;
221
222  // The SigninManager associated with this reconcilor.
223  SigninManagerBase* signin_manager_;
224
225  // The SigninClient associated with this reconcilor.
226  SigninClient* client_;
227
228  MergeSessionHelper merge_session_helper_;
229  scoped_ptr<GaiaAuthFetcher> gaia_fetcher_;
230  bool registered_with_token_service_;
231
232  // True while the reconcilor is busy checking or managing the accounts in
233  // this profile.
234  bool is_reconcile_started_;
235
236  // True iff this is the first time the reconcilor is executing.
237  bool first_execution_;
238
239  // Used during reconcile action.
240  // These members are used used to validate the gaia cookie.  |gaia_accounts_|
241  // holds the state of google accounts in the gaia cookie.  Each element is
242  // a pair that holds the email address of the account and a boolean that
243  // indicates whether the account is valid or not.  The accounts in the vector
244  // are ordered the in same way as the gaia cookie.
245  bool are_gaia_accounts_set_;
246  std::vector<std::pair<std::string, bool> > gaia_accounts_;
247
248  // Used during reconcile action.
249  // These members are used to validate the tokens in OAuth2TokenService.
250  std::string primary_account_;
251  std::vector<std::string> chrome_accounts_;
252  scoped_ptr<OAuth2TokenService::Request>* requests_;
253  ScopedVector<UserIdFetcher> user_id_fetchers_;
254  ScopedVector<SigninOAuthHelper> refresh_token_fetchers_;
255  EmailSet valid_chrome_accounts_;
256  EmailSet invalid_chrome_accounts_;
257  std::vector<std::string> add_to_cookie_;
258  std::vector<std::pair<std::string, int> > add_to_chrome_;
259
260  std::deque<GetAccountsFromCookieCallback> get_gaia_accounts_callbacks_;
261
262  DISALLOW_COPY_AND_ASSIGN(AccountReconcilor);
263};
264
265#endif  // COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_H_
266