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

Side by Side Diff: chrome/browser/signin/account_reconcilor.cc

Issue 57363003: Enable account reconcilor when --new-profile-management is used. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "base/json/json_reader.h"
5 #include "base/logging.h" 6 #include "base/logging.h"
6 #include "base/time/time.h" 7 #include "base/time/time.h"
7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/net/chrome_cookie_notification_details.h" 9 #include "chrome/browser/net/chrome_cookie_notification_details.h"
9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/signin/account_reconcilor.h" 11 #include "chrome/browser/signin/account_reconcilor.h"
11 #include "chrome/browser/signin/google_auto_login_helper.h" 12 #include "chrome/browser/signin/google_auto_login_helper.h"
12 #include "chrome/browser/signin/profile_oauth2_token_service.h" 13 #include "chrome/browser/signin/profile_oauth2_token_service.h"
13 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 14 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
14 #include "chrome/browser/signin/signin_manager.h" 15 #include "chrome/browser/signin/signin_manager.h"
15 #include "chrome/browser/signin/signin_manager_factory.h" 16 #include "chrome/browser/signin/signin_manager_factory.h"
16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/notification_details.h" 18 #include "content/public/browser/notification_details.h"
18 #include "content/public/browser/notification_source.h" 19 #include "content/public/browser/notification_source.h"
20 #include "google_apis/gaia/gaia_auth_fetcher.h"
21 #include "google_apis/gaia/gaia_constants.h"
19 22
20 AccountReconcilor::AccountReconcilor(Profile* profile) : profile_(profile) { 23 AccountReconcilor::AccountReconcilor(Profile* profile)
24 : profile_(profile),
25 are_gaia_accounts_set_(false),
26 requests_(NULL) {
21 RegisterWithSigninManager(); 27 RegisterWithSigninManager();
22 RegisterWithCookieMonster(); 28 RegisterWithCookieMonster();
23 29
24 // If this profile is not connected, the reconcilor should do nothing but 30 // If this profile is not connected, the reconcilor should do nothing but
25 // wait for the connection. 31 // wait for the connection.
26 SigninManagerBase* signin_manager = 32 if (IsProfileConnected()) {
27 SigninManagerFactory::GetForProfile(profile_);
28 if (!signin_manager->GetAuthenticatedUsername().empty()) {
29 RegisterWithTokenService(); 33 RegisterWithTokenService();
30 StartPeriodicReconciliation(); 34 StartPeriodicReconciliation();
31 } 35 }
32 } 36 }
33 37
38 AccountReconcilor::~AccountReconcilor() {
39 // Make sure shutdown was called first.
40 DCHECK(registrar_.IsEmpty());
41 DCHECK(!reconciliation_timer_.IsRunning());
42 DCHECK(!requests_);
43 }
44
45 void AccountReconcilor::Shutdown() {
46 DVLOG(1) << "AccountReconcilor::Shutdown";
47 DeleteAccessTokenRequests();
48 UnregisterWithSigninManager();
49 UnregisterWithTokenService();
50 UnregisterWithCookieMonster();
51 StopPeriodicReconciliation();
52 }
53
54 void AccountReconcilor::DeleteAccessTokenRequests() {
55 delete[] requests_;
56 requests_ = NULL;
57 }
58
34 void AccountReconcilor::RegisterWithCookieMonster() { 59 void AccountReconcilor::RegisterWithCookieMonster() {
35 content::Source<Profile> source(profile_); 60 content::Source<Profile> source(profile_);
36 registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source); 61 registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
37 } 62 }
38 63
39 void AccountReconcilor::UnregisterWithCookieMonster() { 64 void AccountReconcilor::UnregisterWithCookieMonster() {
40 content::Source<Profile> source(profile_); 65 content::Source<Profile> source(profile_);
41 registrar_.Remove(this, chrome::NOTIFICATION_COOKIE_CHANGED, source); 66 registrar_.Remove(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
42 } 67 }
43 68
(...skipping 15 matching lines...) Expand all
59 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); 84 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
60 token_service->AddObserver(this); 85 token_service->AddObserver(this);
61 } 86 }
62 87
63 void AccountReconcilor::UnregisterWithTokenService() { 88 void AccountReconcilor::UnregisterWithTokenService() {
64 ProfileOAuth2TokenService* token_service = 89 ProfileOAuth2TokenService* token_service =
65 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); 90 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
66 token_service->RemoveObserver(this); 91 token_service->RemoveObserver(this);
67 } 92 }
68 93
94 bool AccountReconcilor::IsProfileConnected() {
95 return !SigninManagerFactory::GetForProfile(profile_)->
96 GetAuthenticatedUsername().empty();
97 }
98
69 void AccountReconcilor::StartPeriodicReconciliation() { 99 void AccountReconcilor::StartPeriodicReconciliation() {
100 DVLOG(1) << "AccountReconcilor::StartPeriodicReconciliation";
70 // TODO(rogerta): pick appropriate thread and timeout value. 101 // TODO(rogerta): pick appropriate thread and timeout value.
71 reconciliation_timer_.Start( 102 reconciliation_timer_.Start(
72 FROM_HERE, 103 FROM_HERE,
73 base::TimeDelta::FromMinutes(5), 104 base::TimeDelta::FromSeconds(300),
74 this, 105 this,
75 &AccountReconcilor::PeriodicReconciliation); 106 &AccountReconcilor::PeriodicReconciliation);
76 } 107 }
77 108
78 void AccountReconcilor::StopPeriodicReconciliation() { 109 void AccountReconcilor::StopPeriodicReconciliation() {
110 DVLOG(1) << "AccountReconcilor::StopPeriodicReconciliation";
79 reconciliation_timer_.Stop(); 111 reconciliation_timer_.Stop();
80 } 112 }
81 113
82 void AccountReconcilor::PeriodicReconciliation() { 114 void AccountReconcilor::PeriodicReconciliation() {
83 PerformReconcileAction(); 115 DVLOG(1) << "AccountReconcilor::PeriodicReconciliation";
116 StartReconcileAction();
84 } 117 }
85 118
86 void AccountReconcilor::Observe(int type, 119 void AccountReconcilor::Observe(int type,
87 const content::NotificationSource& source, 120 const content::NotificationSource& source,
88 const content::NotificationDetails& details) { 121 const content::NotificationDetails& details) {
89 switch (type) { 122 switch (type) {
90 case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: 123 case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL:
124 DVLOG(1) << "AccountReconcilor::Observe: signed in";
91 RegisterWithTokenService(); 125 RegisterWithTokenService();
92 StartPeriodicReconciliation(); 126 StartPeriodicReconciliation();
93 break; 127 break;
94 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: 128 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
129 DVLOG(1) << "AccountReconcilor::Observe: signed out";
95 UnregisterWithTokenService(); 130 UnregisterWithTokenService();
96 StopPeriodicReconciliation(); 131 StopPeriodicReconciliation();
97 break; 132 break;
98 case chrome::NOTIFICATION_COOKIE_CHANGED: 133 case chrome::NOTIFICATION_COOKIE_CHANGED:
134 DVLOG(1) << "AccountReconcilor::Observe: cookies changed";
acleung1 2013/11/04 21:19:00 This might be too verbose. We should probably LOG
Roger Tawa OOO till Jul 10th 2013/11/04 23:38:42 Agreed. Removed for now.
99 OnCookieChanged(content::Details<ChromeCookieDetails>(details).ptr()); 135 OnCookieChanged(content::Details<ChromeCookieDetails>(details).ptr());
100 break; 136 break;
101 default: 137 default:
102 NOTREACHED(); 138 NOTREACHED();
103 break; 139 break;
104 } 140 }
105 } 141 }
106 142
107 void AccountReconcilor::OnCookieChanged(ChromeCookieDetails* details) { 143 void AccountReconcilor::OnCookieChanged(ChromeCookieDetails* details) {
108 // TODO(acleung): Filter out cookies by looking at the domain. 144 // TODO(acleung): Filter out cookies by looking at the domain.
109 // PerformReconcileAction(); 145 // StartReconcileAction();
110 } 146 }
111 147
112 void AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) { 148 void AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) {
149 DVLOG(1) << "AccountReconcilor::OnRefreshTokenAvailable: " << account_id;
113 PerformMergeAction(account_id); 150 PerformMergeAction(account_id);
114 } 151 }
115 152
116 void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) { 153 void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) {
154 DVLOG(1) << "AccountReconcilor::OnRefreshTokenRevoked: " << account_id;
117 PerformRemoveAction(account_id); 155 PerformRemoveAction(account_id);
118 } 156 }
119 157
120 void AccountReconcilor::OnRefreshTokensLoaded() {} 158 void AccountReconcilor::OnRefreshTokensLoaded() {}
121 159
122 void AccountReconcilor::PerformMergeAction(const std::string& account_id) { 160 void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
123 // GoogleAutoLoginHelper deletes itself upon success / failure. 161 // GoogleAutoLoginHelper deletes itself upon success / failure.
124 GoogleAutoLoginHelper* helper = new GoogleAutoLoginHelper(profile_); 162 GoogleAutoLoginHelper* helper = new GoogleAutoLoginHelper(profile_);
guohui 2013/11/04 22:44:16 another helper? we have a bunch of helpers to clea
Roger Tawa OOO till Jul 10th 2013/11/04 23:38:42 :-) Yes lets do a pass on all our helpers and see
acleung1 2013/11/05 00:04:28 This is slightly misnamed. We used to use that for
125 helper->LogIn(account_id); 163 helper->LogIn(account_id);
126 } 164 }
127 165
128 void AccountReconcilor::PerformRemoveAction(const std::string& account_id) { 166 void AccountReconcilor::PerformRemoveAction(const std::string& account_id) {
129 // TODO(acleung): Implement this: 167 // TODO(acleung): Implement this:
130 } 168 }
131 169
132 void AccountReconcilor::PerformReconcileAction() { 170 void AccountReconcilor::StartReconcileAction() {
133 // TODO(acleung): Implement this: 171 if (!IsProfileConnected())
172 return;
173
174 // Reset state for validating gaia cookie.
175 are_gaia_accounts_set_ = false;
176 gaia_accounts_.clear();
177 GetAccountsFromCookie();
178
179 // Reset state for validating oauth2 tokens.
180 primary_account_.clear();
181 chrome_accounts_.clear();
182 DeleteAccessTokenRequests();
183 valid_chrome_accounts_.clear();
184 invalid_chrome_accounts_.clear();
185 ValidateAccountsFromTokenService();
134 } 186 }
135 187
136 AccountReconcilor::~AccountReconcilor() { 188 void AccountReconcilor::GetAccountsFromCookie() {
137 // Make sure shutdown was called first. 189 gaia_fetcher_.reset(new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
138 DCHECK(registrar_.IsEmpty()); 190 profile_->GetRequestContext()));
191 gaia_fetcher_->StartListAccounts();
139 } 192 }
140 193
141 void AccountReconcilor::Shutdown() { 194 void AccountReconcilor::OnListAccountsSuccess(const std::string& data) {
142 UnregisterWithSigninManager(); 195 gaia_fetcher_.reset();
143 UnregisterWithTokenService(); 196
144 UnregisterWithCookieMonster(); 197 // Get account information from response data.
145 StopPeriodicReconciliation(); 198 gaia_accounts_ = ParseListAccountsData(data);
199 if (gaia_accounts_.size() > 0) {
200 DVLOG(1) << "AccountReconcilor::OnListAccountsSuccess: "
201 << "Gaia " << gaia_accounts_.size() << " accounts, "
202 << "Primary is '" << gaia_accounts_[0] << "'";
203 } else {
204 DVLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts";
205 }
206
207 are_gaia_accounts_set_ = true;
208 FinishReconcileAction();
146 } 209 }
210
211 std::vector<std::string> AccountReconcilor::ParseListAccountsData(
guohui 2013/11/04 22:44:16 is it better to move the parsing code to GaiaAuthF
Roger Tawa OOO till Jul 10th 2013/11/04 23:38:42 I'm not sure. Maybe leave it here for now until s
212 const std::string& data) {
213 std::vector<std::string> account_ids;
214
215 // Parse returned data and make sure we have data.
216 scoped_ptr<base::Value> value(base::JSONReader::Read(data));
acleung1 2013/11/04 21:19:00 What are the cases where we get no data? Should th
Roger Tawa OOO till Jul 10th 2013/11/04 23:38:42 This would be an error. The gaia auth fetcher alr
217 if (!value)
218 return account_ids;
219
220 base::ListValue* list;
221 if (!value->GetAsList(&list) || list->GetSize() < 2)
222 return account_ids;
223
224 // Get list of account info.
225 base::ListValue* accounts;
226 list->GetList(1, &accounts);
227 if (accounts == NULL)
228 return account_ids;
229
230 // Build a vector of accounts from the cookie. Order is important: the first
231 // account in the list is the primary account.
232 for (size_t i = 0; i < accounts->GetSize(); ++i) {
233 base::ListValue* account;
234 accounts->GetList(i, &account);
235 if (accounts != NULL) {
236 std::string email;
237 account->GetString(3, &email);
238 if (!email.empty())
239 account_ids.push_back(email);
240 }
241 }
242
243 return account_ids;
244 }
245
246 void AccountReconcilor::OnListAccountsFailure(
247 const GoogleServiceAuthError& error) {
248 gaia_fetcher_.reset();
249 DVLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString();
250
251 are_gaia_accounts_set_ = true;
252 FinishReconcileAction();
253 }
254
255 void AccountReconcilor::ValidateAccountsFromTokenService() {
256 primary_account_ =
257 SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername();
258 DCHECK(!primary_account_.empty());
259
260 ProfileOAuth2TokenService* token_service =
261 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
262 chrome_accounts_ = token_service->GetAccounts();
263 DCHECK(chrome_accounts_.size() > 0);
guohui 2013/11/04 22:44:16 why is this a DCHECK? shouldn't we handle this jus
Roger Tawa OOO till Jul 10th 2013/11/04 23:38:42 The AC is only enabled for connected profiles. Th
264
265 DVLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
266 << "Chrome " << chrome_accounts_.size() << " accounts, "
267 << "Primary is '" << primary_account_ << "'";
268
269 DCHECK(!requests_);
270 requests_ =
271 new scoped_ptr<OAuth2TokenService::Request>[chrome_accounts_.size()];
272 for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
acleung1 2013/11/04 21:19:00 I am not entirely following this step. Wouldn't w
Roger Tawa OOO till Jul 10th 2013/11/04 23:38:42 The O2TS may have an list of tokens, but they coul
273 requests_[i] = token_service->StartRequest(chrome_accounts_[i],
274 OAuth2TokenService::ScopeSet(),
275 this);
276 }
277 }
278
279 void AccountReconcilor::OnGetTokenSuccess(
280 const OAuth2TokenService::Request* request,
281 const std::string& access_token,
282 const base::Time& expiration_time) {
283 DVLOG(1) << "AccountReconcilor::OnGetTokenSuccess: valid "
284 << request->GetAccountId();
285 valid_chrome_accounts_.insert(request->GetAccountId());
286 FinishReconcileAction();
287 }
288
289 void AccountReconcilor::OnGetTokenFailure(
290 const OAuth2TokenService::Request* request,
291 const GoogleServiceAuthError& error) {
292 DVLOG(1) << "AccountReconcilor::OnGetTokenSuccess: invalid "
293 << request->GetAccountId();
294 invalid_chrome_accounts_.insert(request->GetAccountId());
295 FinishReconcileAction();
296 }
297
298 void AccountReconcilor::FinishReconcileAction() {
299 // Make sure that the process of validating the gaia cookie and the oauth2
300 // tokens individually is done before proceeding with reconciliation.
301 if (!are_gaia_accounts_set_ ||
302 (chrome_accounts_.size() != (valid_chrome_accounts_.size() +
303 invalid_chrome_accounts_.size()))) {
304 return;
305 }
306
307 DVLOG(1) << "AccountReconcilor::FinishReconcileAction";
308
309 bool are_primaries_equal =
310 gaia_accounts_.size() > 0 && primary_account_ == gaia_accounts_[0];
311 bool have_same_accounts = chrome_accounts_.size() == gaia_accounts_.size();
312 if (have_same_accounts) {
313 for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
314 if (std::find(chrome_accounts_.begin(), chrome_accounts_.end(),
315 gaia_accounts_[i]) == chrome_accounts_.end()) {
316 have_same_accounts = false;
317 break;
318 }
319 }
320 }
321
322 if (!are_primaries_equal || !have_same_accounts) {
323 // TODO(rogerta): fix things up.
324 }
325 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698