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

Side by Side Diff: chrome/browser/sync/engine/auth_watcher.cc

Issue 246098: Sync: Remove pthreads from auth_watcher. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months 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 (c) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2009 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 "chrome/browser/sync/engine/auth_watcher.h" 5 #include "chrome/browser/sync/engine/auth_watcher.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/string_util.h" 8 #include "base/string_util.h"
9 #include "chrome/browser/sync/engine/all_status.h" 9 #include "chrome/browser/sync/engine/all_status.h"
10 #include "chrome/browser/sync/engine/authenticator.h" 10 #include "chrome/browser/sync/engine/authenticator.h"
11 #include "chrome/browser/sync/engine/net/gaia_authenticator.h" 11 #include "chrome/browser/sync/engine/net/gaia_authenticator.h"
12 #include "chrome/browser/sync/engine/net/server_connection_manager.h" 12 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
13 #include "chrome/browser/sync/notifier/listener/talk_mediator.h" 13 #include "chrome/browser/sync/notifier/listener/talk_mediator.h"
14 #include "chrome/browser/sync/protocol/service_constants.h"
15 #include "chrome/browser/sync/syncable/directory_manager.h" 14 #include "chrome/browser/sync/syncable/directory_manager.h"
16 #include "chrome/browser/sync/syncable/syncable.h" 15 #include "chrome/browser/sync/syncable/syncable.h"
17 #include "chrome/browser/sync/util/character_set_converters.h" 16 #include "chrome/browser/sync/util/character_set_converters.h"
18 #include "chrome/browser/sync/util/event_sys-inl.h" 17 #include "chrome/browser/sync/util/event_sys-inl.h"
19 #include "chrome/browser/sync/util/pthread_helpers.h"
20 #include "chrome/browser/sync/util/user_settings.h" 18 #include "chrome/browser/sync/util/user_settings.h"
21 19
22 // How authentication happens: 20 // How authentication happens:
23 // 21 //
24 // Kick Off: 22 // Kick Off:
25 // The sync API looks to see if the user's name and 23 // The sync API looks to see if the user's name and
26 // password are stored. If so, it calls authwatcher.Authenticate() with 24 // password are stored. If so, it calls authwatcher.Authenticate() with
27 // them. Otherwise it fires an error event. 25 // them. Otherwise it fires an error event.
28 // 26 //
29 // On failed Gaia Auth: 27 // On failed Gaia Auth:
(...skipping 20 matching lines...) Expand all
50 UserSettings* user_settings, 48 UserSettings* user_settings,
51 GaiaAuthenticator* gaia_auth, 49 GaiaAuthenticator* gaia_auth,
52 TalkMediator* talk_mediator) 50 TalkMediator* talk_mediator)
53 : gaia_(gaia_auth), 51 : gaia_(gaia_auth),
54 dirman_(dirman), 52 dirman_(dirman),
55 scm_(scm), 53 scm_(scm),
56 allstatus_(allstatus), 54 allstatus_(allstatus),
57 status_(NOT_AUTHENTICATED), 55 status_(NOT_AUTHENTICATED),
58 user_settings_(user_settings), 56 user_settings_(user_settings),
59 talk_mediator_(talk_mediator), 57 talk_mediator_(talk_mediator),
60 thread_handle_valid_(false), 58 auth_backend_thread_("SyncEngine_AuthWatcherThread"),
61 authenticating_now_(false),
62 current_attempt_trigger_(AuthWatcherEvent::USER_INITIATED) { 59 current_attempt_trigger_(AuthWatcherEvent::USER_INITIATED) {
60
61 if (!auth_backend_thread_.Start())
62 NOTREACHED() << "Couldn't start SyncEngine_AuthWatcherThread";
63
64 gaia_->set_message_loop(message_loop());
65
63 connmgr_hookup_.reset( 66 connmgr_hookup_.reset(
64 NewEventListenerHookup(scm->channel(), this, 67 NewEventListenerHookup(scm->channel(), this,
65 &AuthWatcher::HandleServerConnectionEvent)); 68 &AuthWatcher::HandleServerConnectionEvent));
66 AuthWatcherEvent done = { AuthWatcherEvent::AUTHWATCHER_DESTROYED }; 69 AuthWatcherEvent done = { AuthWatcherEvent::AUTHWATCHER_DESTROYED };
67 channel_.reset(new Channel(done)); 70 channel_.reset(new Channel(done));
68 } 71 }
69 72
70 void* AuthWatcher::AuthenticationThreadStartRoutine(void* arg) { 73 void AuthWatcher::PersistCredentials() {
71 ThreadParams* args = reinterpret_cast<ThreadParams*>(arg); 74 DCHECK_EQ(MessageLoop::current(), message_loop());
72 return args->self->AuthenticationThreadMain(args);
73 }
74
75 bool AuthWatcher::ProcessGaiaAuthSuccess() {
76 GaiaAuthenticator::AuthResults results = gaia_->results(); 75 GaiaAuthenticator::AuthResults results = gaia_->results();
77 76
78 // We just successfully signed in again, let's clear out any residual cached 77 // We just successfully signed in again, let's clear out any residual cached
79 // login data from earlier sessions. 78 // login data from earlier sessions.
80 ClearAuthenticationData(); 79 ClearAuthenticationData();
81 80
82 user_settings_->StoreEmailForSignin(results.email, results.primary_email); 81 user_settings_->StoreEmailForSignin(results.email, results.primary_email);
83 user_settings_->RememberSigninType(results.email, results.signin); 82 user_settings_->RememberSigninType(results.email, results.signin);
84 user_settings_->RememberSigninType(results.primary_email, results.signin); 83 user_settings_->RememberSigninType(results.primary_email, results.signin);
85 results.email = results.primary_email; 84 results.email = results.primary_email;
86 gaia_->SetUsernamePassword(results.primary_email, results.password); 85 gaia_->SetUsernamePassword(results.primary_email, results.password);
87 if (!user_settings_->VerifyAgainstStoredHash(results.email, results.password)) 86 if (!user_settings_->VerifyAgainstStoredHash(results.email, results.password))
88 user_settings_->StoreHashedPassword(results.email, results.password); 87 user_settings_->StoreHashedPassword(results.email, results.password);
89 88
90 if (PERSIST_TO_DISK == results.credentials_saved) { 89 if (PERSIST_TO_DISK == results.credentials_saved) {
91 user_settings_->SetAuthTokenForService(results.email, 90 user_settings_->SetAuthTokenForService(results.email,
92 SYNC_SERVICE_NAME, 91 SYNC_SERVICE_NAME,
93 gaia_->auth_token()); 92 gaia_->auth_token());
94 } 93 }
95
96 return AuthenticateWithToken(results.email, gaia_->auth_token());
97 }
98
99 bool AuthWatcher::GetAuthTokenForService(const string& service_name,
100 string* service_token) {
101 string user_name;
102
103 // We special case this one by trying to return it from memory first. We
104 // do this because the user may not have checked "Remember me" and so we
105 // may not have persisted the sync service token beyond the initial
106 // login.
107 if (SYNC_SERVICE_NAME == service_name && !sync_service_token_.empty()) {
108 *service_token = sync_service_token_;
109 return true;
110 }
111
112 if (user_settings_->GetLastUserAndServiceToken(service_name, &user_name,
113 service_token)) {
114 // The casing gets preserved in some places and not in others it seems,
115 // at least I have observed different casings persisted to different DB
116 // tables.
117 if (!base::strcasecmp(user_name.c_str(),
118 user_settings_->email().c_str())) {
119 return true;
120 } else {
121 LOG(ERROR) << "ERROR: We seem to have saved credentials for someone "
122 << " other than the current user.";
123 return false;
124 }
125 }
126
127 return false;
128 } 94 }
129 95
130 const char kAuthWatcher[] = "AuthWatcher"; 96 const char kAuthWatcher[] = "AuthWatcher";
131 97
132 bool AuthWatcher::AuthenticateWithToken(const string& gaia_email, 98 void AuthWatcher::AuthenticateWithToken(const std::string& gaia_email,
133 const string& auth_token) { 99 const std::string& auth_token) {
134 // Store a copy of the sync service token in memory. 100 message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
135 sync_service_token_ = auth_token; 101 &AuthWatcher::DoAuthenticateWithToken, gaia_email, auth_token));
136 scm_->set_auth_token(sync_service_token_); 102 }
103
104 void AuthWatcher::DoAuthenticateWithToken(const std::string& gaia_email,
105 const std::string& auth_token) {
106 DCHECK_EQ(MessageLoop::current(), message_loop());
137 107
138 Authenticator auth(scm_, user_settings_); 108 Authenticator auth(scm_, user_settings_);
139 Authenticator::AuthenticationResult result = 109 Authenticator::AuthenticationResult result =
140 auth.AuthenticateToken(auth_token); 110 auth.AuthenticateToken(auth_token);
141 string email = gaia_email; 111 string email = gaia_email;
142 if (auth.display_email() && *auth.display_email()) { 112 if (auth.display_email() && *auth.display_email()) {
143 email = auth.display_email(); 113 email = auth.display_email();
144 LOG(INFO) << "Auth returned email " << email << " for gaia email " << 114 LOG(INFO) << "Auth returned email " << email << " for gaia email " <<
145 gaia_email; 115 gaia_email;
146 } 116 }
147 AuthWatcherEvent event = {AuthWatcherEvent::ILLEGAL_VALUE , 0}; 117 AuthWatcherEvent event = {AuthWatcherEvent::ILLEGAL_VALUE , 0};
148 gaia_->SetUsername(email); 118 gaia_->SetUsername(email);
149 gaia_->SetAuthToken(auth_token, SAVE_IN_MEMORY_ONLY); 119 gaia_->SetAuthToken(auth_token, SAVE_IN_MEMORY_ONLY);
150 const bool was_authenticated = NOT_AUTHENTICATED != status_; 120 const bool was_authenticated = NOT_AUTHENTICATED != status_;
151 switch (result) { 121 switch (result) {
152 case Authenticator::SUCCESS: 122 case Authenticator::SUCCESS:
153 { 123 {
154 status_ = GAIA_AUTHENTICATED; 124 status_ = GAIA_AUTHENTICATED;
155 PathString share_name; 125 PathString share_name;
156 CHECK(AppendUTF8ToPathString(email.data(), email.size(), &share_name)); 126 CHECK(AppendUTF8ToPathString(email.data(), email.size(), &share_name));
157 user_settings_->SwitchUser(email); 127 user_settings_->SwitchUser(email);
158 128
159 // Set the authentication token for notifications 129 // Set the authentication token for notifications
160 talk_mediator_->SetAuthToken(email, auth_token); 130 talk_mediator_->SetAuthToken(email, auth_token);
131 scm_->set_auth_token(auth_token);
161 132
162 if (!was_authenticated) 133 if (!was_authenticated)
163 LoadDirectoryListAndOpen(share_name); 134 LoadDirectoryListAndOpen(share_name);
164 NotifyAuthSucceeded(email); 135 NotifyAuthSucceeded(email);
165 return true; 136 return;
166 } 137 }
167 case Authenticator::BAD_AUTH_TOKEN: 138 case Authenticator::BAD_AUTH_TOKEN:
168 event.what_happened = AuthWatcherEvent::SERVICE_AUTH_FAILED; 139 event.what_happened = AuthWatcherEvent::SERVICE_AUTH_FAILED;
169 break; 140 break;
170 case Authenticator::CORRUPT_SERVER_RESPONSE: 141 case Authenticator::CORRUPT_SERVER_RESPONSE:
171 case Authenticator::SERVICE_DOWN: 142 case Authenticator::SERVICE_DOWN:
172 event.what_happened = AuthWatcherEvent::SERVICE_CONNECTION_FAILED; 143 event.what_happened = AuthWatcherEvent::SERVICE_CONNECTION_FAILED;
173 break; 144 break;
174 case Authenticator::USER_NOT_ACTIVATED: 145 case Authenticator::USER_NOT_ACTIVATED:
175 event.what_happened = AuthWatcherEvent::SERVICE_USER_NOT_SIGNED_UP; 146 event.what_happened = AuthWatcherEvent::SERVICE_USER_NOT_SIGNED_UP;
176 break; 147 break;
177 default: 148 default:
178 LOG(FATAL) << "Illegal return from AuthenticateToken"; 149 LOG(FATAL) << "Illegal return from AuthenticateToken";
179 return true; // keep the compiler happy 150 return;
180 } 151 }
181 // Always fall back to local authentication. 152 // Always fall back to local authentication.
182 if (was_authenticated || AuthenticateLocally(email)) { 153 if (was_authenticated || AuthenticateLocally(email)) {
183 if (AuthWatcherEvent::SERVICE_CONNECTION_FAILED == event.what_happened) 154 if (AuthWatcherEvent::SERVICE_CONNECTION_FAILED == event.what_happened)
184 return true; 155 return;
185 } 156 }
186 CHECK(event.what_happened != AuthWatcherEvent::ILLEGAL_VALUE); 157 DCHECK_NE(event.what_happened, AuthWatcherEvent::ILLEGAL_VALUE);
187 NotifyListeners(&event); 158 NotifyListeners(&event);
188 return true;
189 } 159 }
190 160
191 bool AuthWatcher::AuthenticateLocally(string email) { 161 bool AuthWatcher::AuthenticateLocally(string email) {
162 DCHECK_EQ(MessageLoop::current(), message_loop());
192 user_settings_->GetEmailForSignin(&email); 163 user_settings_->GetEmailForSignin(&email);
193 if (file_util::PathExists(FilePath(dirman_->GetSyncDataDatabasePath()))) { 164 if (file_util::PathExists(FilePath(dirman_->GetSyncDataDatabasePath()))) {
194 gaia_->SetUsername(email); 165 gaia_->SetUsername(email);
195 status_ = LOCALLY_AUTHENTICATED; 166 status_ = LOCALLY_AUTHENTICATED;
196 user_settings_->SwitchUser(email); 167 user_settings_->SwitchUser(email);
197 PathString share_name; 168 PathString share_name;
198 CHECK(AppendUTF8ToPathString(email.data(), email.size(), &share_name)); 169 CHECK(AppendUTF8ToPathString(email.data(), email.size(), &share_name));
199 LoadDirectoryListAndOpen(share_name); 170 LoadDirectoryListAndOpen(share_name);
200 NotifyAuthSucceeded(email); 171 NotifyAuthSucceeded(email);
201 return true; 172 return true;
202 } else { 173 } else {
203 return false; 174 return false;
204 } 175 }
205 } 176 }
206 177
207 bool AuthWatcher::AuthenticateLocally(string email, const string& password) { 178 bool AuthWatcher::AuthenticateLocally(string email, const string& password) {
179 DCHECK_EQ(MessageLoop::current(), message_loop());
208 user_settings_->GetEmailForSignin(&email); 180 user_settings_->GetEmailForSignin(&email);
209 return user_settings_->VerifyAgainstStoredHash(email, password) 181 return user_settings_->VerifyAgainstStoredHash(email, password)
210 && AuthenticateLocally(email); 182 && AuthenticateLocally(email);
211 } 183 }
212 184
213 void AuthWatcher::ProcessGaiaAuthFailure() { 185 void AuthWatcher::ProcessGaiaAuthFailure() {
186 DCHECK_EQ(MessageLoop::current(), message_loop());
214 GaiaAuthenticator::AuthResults results = gaia_->results(); 187 GaiaAuthenticator::AuthResults results = gaia_->results();
215 if (LOCALLY_AUTHENTICATED == status_) { 188 if (LOCALLY_AUTHENTICATED == status_) {
216 return; // nothing todo 189 return; // nothing todo
217 } else if (AuthenticateLocally(results.email, results.password)) { 190 } else if (AuthenticateLocally(results.email, results.password)) {
218 // We save the "Remember me" checkbox by putting a non-null auth 191 // We save the "Remember me" checkbox by putting a non-null auth
219 // token into the last_user table. So if we're offline and the 192 // token into the last_user table. So if we're offline and the
220 // user checks the box, insert a bogus auth token. 193 // user checks the box, insert a bogus auth token.
221 if (PERSIST_TO_DISK == results.credentials_saved) { 194 if (PERSIST_TO_DISK == results.credentials_saved) {
222 const string auth_token("bogus"); 195 const string auth_token("bogus");
223 user_settings_->SetAuthTokenForService(results.email, 196 user_settings_->SetAuthTokenForService(results.email,
224 SYNC_SERVICE_NAME, 197 SYNC_SERVICE_NAME,
225 auth_token); 198 auth_token);
226 } 199 }
227 const bool unavailable = ConnectionUnavailable == results.auth_error || 200 const bool unavailable = ConnectionUnavailable == results.auth_error ||
228 Unknown == results.auth_error || 201 Unknown == results.auth_error ||
229 ServiceUnavailable == results.auth_error; 202 ServiceUnavailable == results.auth_error;
230 if (unavailable) 203 if (unavailable)
231 return; 204 return;
232 } 205 }
233 AuthWatcherEvent myevent = { AuthWatcherEvent::GAIA_AUTH_FAILED, &results }; 206 AuthWatcherEvent myevent = { AuthWatcherEvent::GAIA_AUTH_FAILED, &results };
234 NotifyListeners(&myevent); 207 NotifyListeners(&myevent);
235 } 208 }
236 209
237 void* AuthWatcher::AuthenticationThreadMain(ThreadParams* args) { 210 void AuthWatcher::DoAuthenticate(const AuthRequest& request) {
238 NameCurrentThreadForDebugging("SyncEngine_AuthWatcherThread"); 211 DCHECK_EQ(MessageLoop::current(), message_loop());
239 // TODO(timsteele): Remove this; this is temporary to satisfy code that 212
240 // compares MessageLoop pointers until AuthWatcher uses a base::Thread. 213 AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START };
241 // We allocate a message_loop from the AuthWatcherThread so that 214 NotifyListeners(&event);
242 // GaiaAuth and EventChannel get a valid opaque pointer to the current 215
243 // message loop used for comparison. It gets stored in TLS as the 'current' 216 current_attempt_trigger_ = request.trigger;
244 // loop for this thread. 217
245 MessageLoop message_loop; 218 SaveCredentials save = request.persist_creds_to_disk ?
246 { 219 PERSIST_TO_DISK : SAVE_IN_MEMORY_ONLY;
247 // This short lock ensures our launching function (StartNewAuthAttempt) is 220 SignIn const signin = user_settings_->
248 // done. 221 RecallSigninType(request.email, GMAIL_SIGNIN);
249 MutexLock lock(&mutex_); 222
250 current_attempt_trigger_ = args->trigger; 223 if (!request.password.empty()) {
224 bool authenticated = false;
225 if (!request.captcha_token.empty() && !request.captcha_value.empty()) {
226 authenticated = gaia_->Authenticate(request.email, request.password,
227 save, request.captcha_token,
228 request.captcha_value, signin);
229 } else {
230 authenticated = gaia_->Authenticate(request.email, request.password,
231 save, signin);
232 }
233 if (authenticated) {
234 PersistCredentials();
235 DoAuthenticateWithToken(gaia_->email(), gaia_->auth_token());
236 } else {
237 ProcessGaiaAuthFailure();
238 }
239 } else if (!request.auth_token.empty()) {
240 DoAuthenticateWithToken(request.email, request.auth_token);
241 } else {
242 LOG(ERROR) << "Attempt to authenticate with no credentials.";
251 } 243 }
252 SaveCredentials save = args->persist_creds_to_disk ?
253 PERSIST_TO_DISK : SAVE_IN_MEMORY_ONLY;
254 int attempt = 0;
255 SignIn const signin = user_settings_->
256 RecallSigninType(args->email, GMAIL_SIGNIN);
257
258 gaia_->set_message_loop(&message_loop);
259
260 if (!args->password.empty()) {
261 // TODO(timsteele): Split this mess up into functions.
262 while (true) {
263 bool authenticated;
264 if (!args->captcha_token.empty() && !args->captcha_value.empty()) {
265 authenticated = gaia_->Authenticate(args->email, args->password,
266 save, args->captcha_token,
267 args->captcha_value, signin);
268 } else {
269 authenticated = gaia_->Authenticate(args->email, args->password,
270 save, signin);
271 }
272 if (authenticated) {
273 if (!ProcessGaiaAuthSuccess()) {
274 if (3 != ++attempt) {
275 continue;
276 }
277 AuthWatcherEvent event =
278 { AuthWatcherEvent::SERVICE_CONNECTION_FAILED, 0 };
279 NotifyListeners(&event);
280 }
281 } else {
282 ProcessGaiaAuthFailure();
283 }
284 break; // We are done trying to authenticate.
285 }
286 } else if (!args->auth_token.empty()) {
287 AuthenticateWithToken(args->email, args->auth_token);
288 } else {
289 LOG(ERROR) << "Attempt to authenticate with no credentials.";
290 }
291
292 // We're done trying to authenticate. Set state and terminate the thread.
293 {
294 MutexLock lock(&mutex_);
295 authenticating_now_ = false;
296 }
297 // TODO(timsteele): Remove this; nothing ever gets posted to this loop.
298 gaia_->set_message_loop(NULL);
299 delete args;
300 return 0;
301 }
302
303 void AuthWatcher::Reset() {
304 status_ = NOT_AUTHENTICATED;
305 } 244 }
306 245
307 void AuthWatcher::NotifyAuthSucceeded(const string& email) { 246 void AuthWatcher::NotifyAuthSucceeded(const string& email) {
247 DCHECK_EQ(MessageLoop::current(), message_loop());
308 LOG(INFO) << "NotifyAuthSucceeded"; 248 LOG(INFO) << "NotifyAuthSucceeded";
309 AuthWatcherEvent event = { AuthWatcherEvent::AUTH_SUCCEEDED }; 249 AuthWatcherEvent event = { AuthWatcherEvent::AUTH_SUCCEEDED };
310 event.user_email = email; 250 event.user_email = email;
311 251
312 NotifyListeners(&event); 252 NotifyListeners(&event);
313 } 253 }
314 254
315 bool AuthWatcher::StartNewAuthAttempt(const string& email,
316 const string& password, const string& auth_token,
317 const string& captcha_token, const string& captcha_value,
318 bool persist_creds_to_disk,
319 AuthWatcherEvent::AuthenticationTrigger trigger) {
320 AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START };
321 NotifyListeners(&event);
322 MutexLock lock(&mutex_);
323 if (authenticating_now_)
324 return false;
325 if (thread_handle_valid_) {
326 int join_return = pthread_join(thread_, 0);
327 if (0 != join_return)
328 LOG(ERROR) << "pthread_join failed returning " << join_return;
329 }
330 string mail = email;
331 if (email.find('@') == string::npos) {
332 mail.push_back('@');
333 // TODO(chron): Should this be done only at the UI level?
334 mail.append(DEFAULT_SIGNIN_DOMAIN);
335 }
336 ThreadParams* args = new ThreadParams;
337 args->self = this;
338 args->email = mail;
339 args->password = password;
340 args->auth_token = auth_token;
341 args->captcha_token = captcha_token;
342 args->captcha_value = captcha_value;
343 args->persist_creds_to_disk = persist_creds_to_disk;
344 args->trigger = trigger;
345 if (0 != pthread_create(&thread_, NULL, AuthenticationThreadStartRoutine,
346 args)) {
347 LOG(ERROR) << "Failed to create auth thread.";
348 return false;
349 }
350 authenticating_now_ = true;
351 thread_handle_valid_ = true;
352 return true;
353 }
354
355 void AuthWatcher::WaitForAuthThreadFinish() {
356 {
357 MutexLock lock(&mutex_);
358 if (!thread_handle_valid_)
359 return;
360 }
361 pthread_join(thread_, 0);
362 }
363
364 void AuthWatcher::HandleServerConnectionEvent( 255 void AuthWatcher::HandleServerConnectionEvent(
365 const ServerConnectionEvent& event) { 256 const ServerConnectionEvent& event) {
257 message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
258 &AuthWatcher::DoHandleServerConnectionEvent, event,
259 scm_->auth_token()));
260 }
261
262 void AuthWatcher::DoHandleServerConnectionEvent(
263 const ServerConnectionEvent& event,
264 const std::string& auth_token_snapshot) {
265 DCHECK_EQ(MessageLoop::current(), message_loop());
366 if (event.server_reachable && 266 if (event.server_reachable &&
367 !authenticating_now_ && 267 // If the auth_token at the time of the event differs from the current
268 // one, we have authenticated since then and don't need to re-try.
269 (auth_token_snapshot == gaia_->auth_token()) &&
368 (event.connection_code == HttpResponse::SYNC_AUTH_ERROR || 270 (event.connection_code == HttpResponse::SYNC_AUTH_ERROR ||
369 status_ == LOCALLY_AUTHENTICATED)) { 271 status_ == LOCALLY_AUTHENTICATED)) {
370 // We're either online or just got reconnected and want to try to 272 // We're either online or just got reconnected and want to try to
371 // authenticate. If we've got a saved token this should just work. If not 273 // authenticate. If we've got a saved token this should just work. If not
372 // the auth failure should trigger UI indications that we're not logged in. 274 // the auth failure should trigger UI indications that we're not logged in.
373 275
374 // METRIC: If we get a SYNC_AUTH_ERROR, our token expired. 276 // METRIC: If we get a SYNC_AUTH_ERROR, our token expired.
375 GaiaAuthenticator::AuthResults authresults = gaia_->results(); 277 GaiaAuthenticator::AuthResults authresults = gaia_->results();
376 if (!StartNewAuthAttempt(authresults.email, authresults.password, 278 AuthRequest request = { authresults.email, authresults.password,
377 authresults.auth_token, "", "", 279 authresults.auth_token, std::string(),
378 PERSIST_TO_DISK == authresults.credentials_saved, 280 std::string(),
379 AuthWatcherEvent::EXPIRED_CREDENTIALS)) 281 PERSIST_TO_DISK == authresults.credentials_saved,
380 LOG(INFO) << "Couldn't start a new auth attempt."; 282 AuthWatcherEvent::EXPIRED_CREDENTIALS };
283 DoAuthenticate(request);
381 } 284 }
382 } 285 }
383 286
384 bool AuthWatcher::LoadDirectoryListAndOpen(const PathString& login) { 287 bool AuthWatcher::LoadDirectoryListAndOpen(const PathString& login) {
288 DCHECK_EQ(MessageLoop::current(), message_loop());
385 LOG(INFO) << "LoadDirectoryListAndOpen(" << login << ")"; 289 LOG(INFO) << "LoadDirectoryListAndOpen(" << login << ")";
386 bool initial_sync_ended = false; 290 bool initial_sync_ended = false;
387 291
388 dirman_->Open(login); 292 dirman_->Open(login);
389 syncable::ScopedDirLookup dir(dirman_, login); 293 syncable::ScopedDirLookup dir(dirman_, login);
390 if (dir.good() && dir->initial_sync_ended()) 294 if (dir.good() && dir->initial_sync_ended())
391 initial_sync_ended = true; 295 initial_sync_ended = true;
392 296
393 LOG(INFO) << "LoadDirectoryListAndOpen returning " << initial_sync_ended; 297 LOG(INFO) << "LoadDirectoryListAndOpen returning " << initial_sync_ended;
394 return initial_sync_ended; 298 return initial_sync_ended;
395 } 299 }
396 300
397 AuthWatcher::~AuthWatcher() { 301 AuthWatcher::~AuthWatcher() {
398 WaitForAuthThreadFinish(); 302 auth_backend_thread_.Stop();
303 // The gaia authenticator takes a const MessageLoop* because it only uses it
304 // to ensure all methods are invoked on the given loop. Once our thread has
305 // stopped, the current message loop will be NULL, and no methods should be
306 // invoked on |gaia_| after this point. We could set it to NULL, but
307 // abstaining allows for even more sanity checking that nothing is invoked on
308 // it from now on.
399 } 309 }
400 310
401 void AuthWatcher::Authenticate(const string& email, const string& password, 311 void AuthWatcher::Authenticate(const string& email, const string& password,
402 const string& captcha_token, const string& captcha_value, 312 const string& captcha_token, const string& captcha_value,
403 bool persist_creds_to_disk) { 313 bool persist_creds_to_disk) {
404 LOG(INFO) << "AuthWatcher::Authenticate called"; 314 LOG(INFO) << "AuthWatcher::Authenticate called";
405 WaitForAuthThreadFinish();
406 315
407 // We CHECK here because WaitForAuthThreadFinish should ensure there's no
408 // ongoing auth attempt.
409 string empty; 316 string empty;
410 CHECK(StartNewAuthAttempt(email, password, empty, captcha_token, 317 AuthRequest request = { FormatAsEmailAddress(email), password, empty,
411 captcha_value, persist_creds_to_disk, 318 captcha_token, captcha_value, persist_creds_to_disk,
412 AuthWatcherEvent::USER_INITIATED)); 319 AuthWatcherEvent::USER_INITIATED };
413 } 320 message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
414 321 &AuthWatcher::DoAuthenticate, request));
415 void AuthWatcher::Logout() {
416 scm_->ResetAuthStatus();
417 Reset();
418 WaitForAuthThreadFinish();
419 ClearAuthenticationData();
420 } 322 }
421 323
422 void AuthWatcher::ClearAuthenticationData() { 324 void AuthWatcher::ClearAuthenticationData() {
423 sync_service_token_.clear(); 325 scm_->set_auth_token(std::string());
424 scm_->set_auth_token(sync_service_token());
425 user_settings_->ClearAllServiceTokens(); 326 user_settings_->ClearAllServiceTokens();
426 } 327 }
427 328
428 string AuthWatcher::email() const { 329 string AuthWatcher::email() const {
429 return gaia_->email(); 330 return gaia_->email();
430 } 331 }
431 332
432 void AuthWatcher::NotifyListeners(AuthWatcherEvent* event) { 333 void AuthWatcher::NotifyListeners(AuthWatcherEvent* event) {
433 event->trigger = current_attempt_trigger_; 334 event->trigger = current_attempt_trigger_;
434 channel_->NotifyListeners(*event); 335 channel_->NotifyListeners(*event);
435 } 336 }
436 337
437 } // namespace browser_sync 338 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/auth_watcher.h ('k') | chrome/browser/sync/engine/auth_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698