Index: chrome/browser/sync/engine/auth_watcher.cc |
=================================================================== |
--- chrome/browser/sync/engine/auth_watcher.cc (revision 58702) |
+++ chrome/browser/sync/engine/auth_watcher.cc (working copy) |
@@ -1,352 +0,0 @@ |
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/sync/engine/auth_watcher.h" |
- |
-#include "base/file_util.h" |
-#include "base/string_util.h" |
-#include "chrome/browser/sync/engine/all_status.h" |
-#include "chrome/browser/sync/engine/authenticator.h" |
-#include "chrome/browser/sync/engine/net/server_connection_manager.h" |
-#include "chrome/browser/sync/syncable/directory_manager.h" |
-#include "chrome/browser/sync/syncable/syncable.h" |
-#include "chrome/browser/sync/util/user_settings.h" |
-#include "chrome/common/deprecated/event_sys-inl.h" |
-#include "chrome/common/net/gaia/gaia_authenticator.h" |
- |
-// How authentication happens: |
-// |
-// Kick Off: |
-// The sync API looks to see if the user's name and |
-// password are stored. If so, it calls authwatcher.Authenticate() with |
-// them. Otherwise it fires an error event. |
-// |
-// On failed Gaia Auth: |
-// The AuthWatcher attempts to use saved hashes to authenticate |
-// locally, and on success opens the share. |
-// On failure, fires an error event. |
-// |
-// On successful Gaia Auth: |
-// AuthWatcher launches a thread to open the share and to get the |
-// authentication token from the sync server. |
- |
-using std::pair; |
-using std::string; |
-using std::vector; |
- |
-namespace browser_sync { |
- |
-AuthWatcher::AuthWatcher(DirectoryManager* dirman, |
- ServerConnectionManager* scm, |
- const string& user_agent, |
- const string& service_id, |
- const string& gaia_url, |
- UserSettings* user_settings, |
- gaia::GaiaAuthenticator* gaia_auth) |
- : gaia_(gaia_auth), |
- dirman_(dirman), |
- scm_(scm), |
- status_(NOT_AUTHENTICATED), |
- user_settings_(user_settings), |
- auth_backend_thread_("SyncEngine_AuthWatcherThread"), |
- current_attempt_trigger_(AuthWatcherEvent::USER_INITIATED) { |
- |
- if (!auth_backend_thread_.Start()) |
- NOTREACHED() << "Couldn't start SyncEngine_AuthWatcherThread"; |
- |
- gaia_->set_message_loop(message_loop()); |
- loop_proxy_ = auth_backend_thread_.message_loop_proxy(); |
- |
- connmgr_hookup_.reset( |
- NewEventListenerHookup(scm->channel(), this, |
- &AuthWatcher::HandleServerConnectionEvent)); |
- AuthWatcherEvent done = { AuthWatcherEvent::AUTHWATCHER_DESTROYED }; |
- channel_.reset(new Channel(done)); |
-} |
- |
-void AuthWatcher::PersistCredentials() { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- gaia::GaiaAuthenticator::AuthResults results = gaia_->results(); |
- |
- // We just successfully signed in again, let's clear out any residual cached |
- // login data from earlier sessions. |
- ClearAuthenticationData(); |
- |
- user_settings_->StoreEmailForSignin(results.email, results.primary_email); |
- results.email = results.primary_email; |
- gaia_->SetUsernamePassword(results.primary_email, results.password); |
- if (!user_settings_->VerifyAgainstStoredHash(results.email, results.password)) |
- user_settings_->StoreHashedPassword(results.email, results.password); |
- |
- user_settings_->SetAuthTokenForService(results.email, |
- SYNC_SERVICE_NAME, |
- gaia_->auth_token()); |
-} |
- |
-// TODO(chron): Full integration test suite needed. http://crbug.com/35429 |
-void AuthWatcher::RenewAuthToken(const std::string& updated_token) { |
- message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod(this, |
- &AuthWatcher::DoRenewAuthToken, updated_token)); |
-} |
- |
-void AuthWatcher::DoRenewAuthToken(const std::string& updated_token) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- // TODO(chron): We should probably only store auth token in one place. |
- if (scm_->auth_token() == updated_token) { |
- return; // This thread is the only one writing to the SCM's auth token. |
- } |
- LOG(INFO) << "Updating auth token:" << updated_token; |
- scm_->set_auth_token(updated_token); |
- gaia_->RenewAuthToken(updated_token); // Must be on AuthWatcher thread |
- user_settings_->SetAuthTokenForService(user_settings_->email(), |
- SYNC_SERVICE_NAME, |
- updated_token); |
- |
- NotifyAuthChanged(user_settings_->email(), updated_token, true); |
-} |
- |
-void AuthWatcher::AuthenticateWithLsid(const std::string& lsid) { |
- message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod(this, |
- &AuthWatcher::DoAuthenticateWithLsid, lsid)); |
-} |
- |
-void AuthWatcher::DoAuthenticateWithLsid(const std::string& lsid) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- |
- AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START }; |
- NotifyListeners(&event); |
- |
- if (gaia_->AuthenticateWithLsid(lsid)) { |
- PersistCredentials(); |
- DoAuthenticateWithToken(gaia_->email(), gaia_->auth_token()); |
- } else { |
- ProcessGaiaAuthFailure(); |
- } |
-} |
- |
-const char kAuthWatcher[] = "AuthWatcher"; |
- |
-void AuthWatcher::AuthenticateWithToken(const std::string& gaia_email, |
- const std::string& auth_token) { |
- message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod(this, |
- &AuthWatcher::DoAuthenticateWithToken, gaia_email, auth_token)); |
-} |
- |
-void AuthWatcher::DoAuthenticateWithToken(const std::string& gaia_email, |
- const std::string& auth_token) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- |
- Authenticator auth(scm_, user_settings_); |
- Authenticator::AuthenticationResult result = |
- auth.AuthenticateToken(auth_token); |
- string email = gaia_email; |
- if (auth.display_email() && *auth.display_email()) { |
- email = auth.display_email(); |
- LOG(INFO) << "Auth returned email " << email << " for gaia email " << |
- gaia_email; |
- } |
- |
- AuthWatcherEvent event = {AuthWatcherEvent::ILLEGAL_VALUE , 0}; |
- gaia_->SetUsername(email); |
- gaia_->SetAuthToken(auth_token); |
- const bool was_authenticated = NOT_AUTHENTICATED != status_; |
- switch (result) { |
- case Authenticator::SUCCESS: |
- { |
- status_ = GAIA_AUTHENTICATED; |
- const std::string& share_name = email; |
- user_settings_->SwitchUser(email); |
- scm_->set_auth_token(auth_token); |
- |
- if (!was_authenticated) { |
- LOG(INFO) << "Opening DB for AuthenticateWithToken (" |
- << share_name << ")"; |
- dirman_->Open(share_name); |
- } |
- NotifyAuthChanged(email, auth_token, false); |
- return; |
- } |
- case Authenticator::BAD_AUTH_TOKEN: |
- event.what_happened = AuthWatcherEvent::SERVICE_AUTH_FAILED; |
- break; |
- case Authenticator::CORRUPT_SERVER_RESPONSE: |
- case Authenticator::SERVICE_DOWN: |
- event.what_happened = AuthWatcherEvent::SERVICE_CONNECTION_FAILED; |
- break; |
- case Authenticator::USER_NOT_ACTIVATED: |
- event.what_happened = AuthWatcherEvent::SERVICE_USER_NOT_SIGNED_UP; |
- break; |
- default: |
- LOG(FATAL) << "Illegal return from AuthenticateToken"; |
- return; |
- } |
- // Always fall back to local authentication. |
- if (was_authenticated || AuthenticateLocally(email)) { |
- if (AuthWatcherEvent::SERVICE_CONNECTION_FAILED == event.what_happened) |
- return; |
- } |
- DCHECK_NE(event.what_happened, AuthWatcherEvent::ILLEGAL_VALUE); |
- NotifyListeners(&event); |
-} |
- |
-bool AuthWatcher::AuthenticateLocally(string email) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- user_settings_->GetEmailForSignin(&email); |
- if (file_util::PathExists(FilePath(dirman_->GetSyncDataDatabasePath()))) { |
- gaia_->SetUsername(email); |
- status_ = LOCALLY_AUTHENTICATED; |
- user_settings_->SwitchUser(email); |
- LOG(INFO) << "Opening DB for AuthenticateLocally (" << email << ")"; |
- dirman_->Open(email); |
- NotifyAuthChanged(email, "", false); |
- return true; |
- } else { |
- return false; |
- } |
-} |
- |
-bool AuthWatcher::AuthenticateLocally(string email, const string& password) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- user_settings_->GetEmailForSignin(&email); |
- return user_settings_->VerifyAgainstStoredHash(email, password) |
- && AuthenticateLocally(email); |
-} |
- |
-void AuthWatcher::ProcessGaiaAuthFailure() { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- gaia::GaiaAuthenticator::AuthResults results = gaia_->results(); |
- if (LOCALLY_AUTHENTICATED != status_ && |
- AuthenticateLocally(results.email, results.password)) { |
- // TODO(chron): Do we really want a bogus token? |
- const string auth_token("bogus"); |
- user_settings_->SetAuthTokenForService(results.email, |
- SYNC_SERVICE_NAME, |
- auth_token); |
- } |
- AuthWatcherEvent myevent = { AuthWatcherEvent::GAIA_AUTH_FAILED, &results }; |
- NotifyListeners(&myevent); |
-} |
- |
-void AuthWatcher::DoAuthenticate(const AuthRequest& request) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- |
- AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START }; |
- NotifyListeners(&event); |
- |
- current_attempt_trigger_ = request.trigger; |
- |
- // We let the caller be lazy and try using the last captcha token seen by |
- // the gaia authenticator if they haven't provided a token but have sent |
- // a challenge response. Of course, if the captcha token is specified, |
- // we use that one instead. |
- std::string captcha_token(request.captcha_token); |
- if (!request.captcha_value.empty() && captcha_token.empty()) |
- captcha_token = gaia_->captcha_token(); |
- |
- if (!request.password.empty()) { |
- bool authenticated = false; |
- if (!captcha_token.empty()) { |
- authenticated = gaia_->Authenticate(request.email, request.password, |
- captcha_token, |
- request.captcha_value); |
- } else { |
- authenticated = gaia_->Authenticate(request.email, request.password); |
- } |
- if (authenticated) { |
- PersistCredentials(); |
- DoAuthenticateWithToken(gaia_->email(), gaia_->auth_token()); |
- } else { |
- ProcessGaiaAuthFailure(); |
- } |
- } else if (!request.auth_token.empty()) { |
- DoAuthenticateWithToken(request.email, request.auth_token); |
- } else { |
- LOG(ERROR) << "Attempt to authenticate with no credentials."; |
- } |
-} |
- |
-void AuthWatcher::NotifyAuthChanged(const string& email, |
- const string& auth_token, |
- bool renewed) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- LOG(INFO) << "NotifyAuthSucceeded"; |
- AuthWatcherEvent event = { |
- renewed ? |
- AuthWatcherEvent::AUTH_RENEWED : |
- AuthWatcherEvent::AUTH_SUCCEEDED |
- }; |
- event.user_email = email; |
- event.auth_token = auth_token; |
- |
- NotifyListeners(&event); |
-} |
- |
-void AuthWatcher::HandleServerConnectionEvent( |
- const ServerConnectionEvent& event) { |
- message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod(this, |
- &AuthWatcher::DoHandleServerConnectionEvent, event, |
- scm_->auth_token())); |
-} |
- |
-void AuthWatcher::DoHandleServerConnectionEvent( |
- const ServerConnectionEvent& event, |
- const std::string& auth_token_snapshot) { |
- DCHECK_EQ(MessageLoop::current(), message_loop()); |
- if (event.server_reachable && |
- // If the auth_token at the time of the event differs from the current |
- // one, we have authenticated since then and don't need to re-try. |
- (auth_token_snapshot == gaia_->auth_token()) && |
- (event.connection_code == HttpResponse::SYNC_AUTH_ERROR || |
- status_ == LOCALLY_AUTHENTICATED)) { |
- // We're either online or just got reconnected and want to try to |
- // authenticate. If we've got a saved token this should just work. If not |
- // the auth failure should trigger UI indications that we're not logged in. |
- |
- // METRIC: If we get a SYNC_AUTH_ERROR, our token expired. |
- gaia::GaiaAuthenticator::AuthResults authresults = gaia_->results(); |
- AuthRequest request = { authresults.email, authresults.password, |
- authresults.auth_token, std::string(), |
- std::string(), |
- AuthWatcherEvent::EXPIRED_CREDENTIALS }; |
- DoAuthenticate(request); |
- } |
-} |
- |
-AuthWatcher::~AuthWatcher() { |
- auth_backend_thread_.Stop(); |
- // The gaia authenticator takes a const MessageLoop* because it only uses it |
- // to ensure all methods are invoked on the given loop. Once our thread has |
- // stopped, the current message loop will be NULL, and no methods should be |
- // invoked on |gaia_| after this point. We could set it to NULL, but |
- // abstaining allows for even more sanity checking that nothing is invoked on |
- // it from now on. |
-} |
- |
-void AuthWatcher::Authenticate(const string& email, const string& password, |
- const string& captcha_token, const string& captcha_value) { |
- LOG(INFO) << "AuthWatcher::Authenticate called"; |
- |
- string empty; |
- AuthRequest request = { FormatAsEmailAddress(email), password, empty, |
- captcha_token, captcha_value, |
- AuthWatcherEvent::USER_INITIATED }; |
- message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod(this, |
- &AuthWatcher::DoAuthenticate, request)); |
-} |
- |
-void AuthWatcher::ClearAuthenticationData() { |
- scm_->set_auth_token(std::string()); |
- user_settings_->ClearAllServiceTokens(); |
-} |
- |
-string AuthWatcher::email() const { |
- return gaia_->email(); |
-} |
- |
-void AuthWatcher::NotifyListeners(AuthWatcherEvent* event) { |
- event->trigger = current_attempt_trigger_; |
- channel_->NotifyListeners(*event); |
-} |
- |
-} // namespace browser_sync |