diff options
Diffstat (limited to 'chrome/browser/sync/engine')
21 files changed, 188 insertions, 1532 deletions
diff --git a/chrome/browser/sync/engine/all_status.cc b/chrome/browser/sync/engine/all_status.cc index 178fe7f..72e1f6d 100644 --- a/chrome/browser/sync/engine/all_status.cc +++ b/chrome/browser/sync/engine/all_status.cc @@ -8,7 +8,6 @@ #include "base/logging.h" #include "base/port.h" -#include "chrome/browser/sync/engine/auth_watcher.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/engine/syncer.h" #include "chrome/browser/sync/engine/syncer_thread.h" @@ -48,11 +47,6 @@ AllStatus::~AllStatus() { delete channel_; } -void AllStatus::WatchConnectionManager(ServerConnectionManager* conn_mgr) { - conn_mgr_hookup_.reset(NewEventListenerHookup(conn_mgr->channel(), this, - &AllStatus::HandleServerConnectionEvent)); -} - void AllStatus::WatchSyncerThread(SyncerThread* syncer_thread) { syncer_thread_hookup_.reset(syncer_thread == NULL ? NULL : syncer_thread->relay_channel()->AddObserver(this)); @@ -99,10 +93,6 @@ AllStatus::Status AllStatus::CalcSyncing(const SyncerEvent &event) const { return status; } -AllStatus::Status AllStatus::CalcSyncing() const { - return CreateBlankStatus(); -} - int AllStatus::CalcStatusChanges(Status* old_status) { int what_changed = 0; @@ -153,34 +143,6 @@ int AllStatus::CalcStatusChanges(Status* old_status) { return what_changed; } -void AllStatus::HandleAuthWatcherEvent(const AuthWatcherEvent& auth_event) { - ScopedStatusLockWithNotify lock(this); - switch (auth_event.what_happened) { - case AuthWatcherEvent::GAIA_AUTH_FAILED: - case AuthWatcherEvent::SERVICE_AUTH_FAILED: - case AuthWatcherEvent::SERVICE_CONNECTION_FAILED: - case AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START: - status_.authenticated = false; - break; - case AuthWatcherEvent::AUTH_SUCCEEDED: - // If we've already calculated that the server is reachable, since we've - // successfully authenticated, we can be confident that the server is up. - if (status_.server_reachable) - status_.server_up = true; - - if (!status_.authenticated) { - status_.authenticated = true; - status_ = CalcSyncing(); - } else { - lock.set_notify_plan(DONT_NOTIFY); - } - break; - default: - lock.set_notify_plan(DONT_NOTIFY); - break; - } -} - void AllStatus::HandleChannelEvent(const SyncerEvent& event) { ScopedStatusLockWithNotify lock(this); switch (event.what_happened) { @@ -222,6 +184,15 @@ void AllStatus::HandleServerConnectionEvent( ScopedStatusLockWithNotify lock(this); status_.server_up = IsGoodReplyFromServer(event.connection_code); status_.server_reachable = event.server_reachable; + + if (event.connection_code == HttpResponse::SERVER_CONNECTION_OK) { + if (!status_.authenticated) { + status_ = CreateBlankStatus(); + } + status_.authenticated = true; + } else { + status_.authenticated = false; + } } } diff --git a/chrome/browser/sync/engine/all_status.h b/chrome/browser/sync/engine/all_status.h index 772f40d..b843a1a 100644 --- a/chrome/browser/sync/engine/all_status.h +++ b/chrome/browser/sync/engine/all_status.h @@ -89,7 +89,6 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> { AllStatus(); ~AllStatus(); - void WatchConnectionManager(ServerConnectionManager* conn_mgr); void HandleServerConnectionEvent(const ServerConnectionEvent& event); void HandleAuthWatcherEvent(const AuthWatcherEvent& event); @@ -116,7 +115,6 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> { // Examines syncer to calculate syncing and the unsynced count, // and returns a Status with new values. - Status CalcSyncing() const; Status CalcSyncing(const SyncerEvent& event) const; Status CreateBlankStatus() const; @@ -125,7 +123,6 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> { Status status_; Channel* const channel_; - scoped_ptr<EventListenerHookup> conn_mgr_hookup_; scoped_ptr<ChannelHookup<SyncerEvent> > syncer_thread_hookup_; scoped_ptr<EventListenerHookup> diskfull_hookup_; scoped_ptr<EventListenerHookup> talk_mediator_hookup_; diff --git a/chrome/browser/sync/engine/auth_watcher.cc b/chrome/browser/sync/engine/auth_watcher.cc deleted file mode 100644 index b414e18..0000000 --- a/chrome/browser/sync/engine/auth_watcher.cc +++ /dev/null @@ -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 diff --git a/chrome/browser/sync/engine/auth_watcher.h b/chrome/browser/sync/engine/auth_watcher.h deleted file mode 100644 index da90f95..0000000 --- a/chrome/browser/sync/engine/auth_watcher.h +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (c) 2010 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. -// -// AuthWatcher watches authentication events and user open and close -// events and accordingly opens and closes shares. - -#ifndef CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_ -#define CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_ -#pragma once - -#include <string> - -#include "base/gtest_prod_util.h" -#include "base/message_loop_proxy.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" -#include "base/thread.h" -#include "chrome/browser/sync/protocol/service_constants.h" -#include "chrome/common/deprecated/event_sys.h" -#include "chrome/common/net/gaia/gaia_authenticator.h" - -namespace syncable { -struct DirectoryManagerEvent; -class DirectoryManager; -} - -namespace browser_sync { - -class AuthWatcher; -class ServerConnectionManager; -class URLFactory; -class UserSettings; -struct ServerConnectionEvent; - -struct AuthWatcherEvent { - enum WhatHappened { - AUTHENTICATION_ATTEMPT_START, - AUTHWATCHER_DESTROYED, - AUTH_RENEWED, // Currently only used in testing. - AUTH_SUCCEEDED, - GAIA_AUTH_FAILED, - SERVICE_USER_NOT_SIGNED_UP, - SERVICE_AUTH_FAILED, - SERVICE_CONNECTION_FAILED, - // Used in a safety check in AuthWatcher::AuthenticateWithToken() - ILLEGAL_VALUE, - }; - WhatHappened what_happened; - const gaia::GaiaAuthenticator::AuthResults* auth_results; - // use AuthWatcherEvent as its own traits type in hookups. - typedef AuthWatcherEvent EventType; - static inline bool IsChannelShutdownEvent(const AuthWatcherEvent& event) { - return event.what_happened == AUTHWATCHER_DESTROYED; - } - - // Used for AUTH_SUCCEEDED/AUTH_RENEWED notification. - std::string user_email; - // May be empty if we're only locally authenticated. - std::string auth_token; - - // How was this auth attempt initiated? - enum AuthenticationTrigger { - USER_INITIATED = 0, // default value. - EXPIRED_CREDENTIALS, - }; - - AuthenticationTrigger trigger; -}; - -// The mother-class of Authentication for the sync backend. Handles both gaia -// and sync service authentication via asynchronous Authenticate* methods, -// raising AuthWatcherEvents on success/failure. The implementation currently -// runs its own backend thread for the actual auth processing, which means -// the AuthWatcherEvents can be raised on a different thread than the one that -// invoked authentication. -class AuthWatcher : public base::RefCountedThreadSafe<AuthWatcher> { - friend class AuthWatcherTest; - FRIEND_TEST_ALL_PREFIXES(AuthWatcherTest, Construction); - public: - // Normal progression is local -> gaia -> token. - enum Status { LOCALLY_AUTHENTICATED, GAIA_AUTHENTICATED, NOT_AUTHENTICATED }; - typedef syncable::DirectoryManagerEvent DirectoryManagerEvent; - typedef syncable::DirectoryManager DirectoryManager; - - AuthWatcher(DirectoryManager* dirman, - ServerConnectionManager* scm, - const std::string& user_agent, - const std::string& service_id, - const std::string& gaia_url, - UserSettings* user_settings, - gaia::GaiaAuthenticator* gaia_auth); - ~AuthWatcher(); - - typedef EventChannel<AuthWatcherEvent, Lock> Channel; - - inline Channel* channel() const { - return channel_.get(); - } - - // The following 3 flavors of authentication routines are asynchronous and can - // be called from any thread. - // If |captcha_value| is specified but |captcha_token| is not, this will - // attempt authentication using the last observed captcha token out of - // convenience in the common case so the token doesn't have to be plumbed - // everywhere. - void Authenticate(const std::string& email, const std::string& password, - const std::string& captcha_token, const std::string& captcha_value); - - void Authenticate(const std::string& email, const std::string& password, - bool persist_creds_to_disk) { - Authenticate(email, password, "", ""); - } - - // Use this to update only the token of the current email address. - void RenewAuthToken(const std::string& updated_token); - - // Use this version when you don't need the gaia authentication step because - // you already have a valid LSID cookie for |gaia_email|. - void AuthenticateWithLsid(const std::string& lsid); - - // Use this version when you don't need the gaia authentication step because - // you already have a valid token for |gaia_email|. - void AuthenticateWithToken(const std::string& gaia_email, - const std::string& auth_token); - - // Joins on the backend thread. The AuthWatcher is useless after this and - // should be destroyed. - void Shutdown() { auth_backend_thread_.Stop(); } - - std::string email() const; - syncable::DirectoryManager* dirman() const { return dirman_; } - ServerConnectionManager* scm() const { return scm_; } - UserSettings* settings() const { return user_settings_; } - Status status() const { return (Status)status_; } - - private: - void ClearAuthenticationData(); - - void NotifyAuthChanged(const std::string& email, - const std::string& auth_token, - bool renewed); - void HandleServerConnectionEvent(const ServerConnectionEvent& event); - - void SaveUserSettings(const std::string& username, - const std::string& auth_token); - - MessageLoop* message_loop() { return auth_backend_thread_.message_loop(); } - - base::MessageLoopProxy* message_loop_proxy() { - return loop_proxy_; - } - - void DoRenewAuthToken(const std::string& updated_token); - - // These two helpers should only be called from the auth function. - // Called when authentication with gaia succeeds, to save credential info. - void PersistCredentials(); - // Called when authentication with gaia fails. - void ProcessGaiaAuthFailure(); - - // Just checks that the user has at least one local share cache. - bool AuthenticateLocally(std::string email); - // Also checks the user's password against stored password hash. - bool AuthenticateLocally(std::string email, const std::string& password); - - // Sets the trigger member of the event and sends the event on channel_. - void NotifyListeners(AuthWatcherEvent* event); - - inline std::string FormatAsEmailAddress(const std::string& email) const { - std::string mail(email); - if (email.find('@') == std::string::npos) { - mail.push_back('@'); - // TODO(chron): Should this be done only at the UI level? - mail.append(DEFAULT_SIGNIN_DOMAIN); - } - return mail; - } - - // A struct to marshal various data across to the auth_backend_thread_ on - // Authenticate() and AuthenticateWithToken calls. - struct AuthRequest { - std::string email; - std::string password; - std::string auth_token; - std::string captcha_token; - std::string captcha_value; - bool persist_creds_to_disk; - AuthWatcherEvent::AuthenticationTrigger trigger; - }; - - // The public interface Authenticate methods are proxies to these, which - // can only be called from |auth_backend_thread_|. - void DoAuthenticate(const AuthRequest& request); - void DoAuthenticateWithLsid(const std::string& lsid); - void DoAuthenticateWithToken(const std::string& email, - const std::string& auth_token); - - // The public HandleServerConnectionEvent method proxies to this method, which - // can only be called on |auth_backend_thread_|. - void DoHandleServerConnectionEvent( - const ServerConnectionEvent& event, - const std::string& auth_token_snapshot); - - scoped_ptr<gaia::GaiaAuthenticator> const gaia_; - syncable::DirectoryManager* const dirman_; - ServerConnectionManager* const scm_; - scoped_ptr<EventListenerHookup> connmgr_hookup_; - Status status_; - UserSettings* const user_settings_; - scoped_ptr<Channel> channel_; - - base::Thread auth_backend_thread_; - scoped_refptr<base::MessageLoopProxy> loop_proxy_; - - AuthWatcherEvent::AuthenticationTrigger current_attempt_trigger_; - DISALLOW_COPY_AND_ASSIGN(AuthWatcher); -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_ diff --git a/chrome/browser/sync/engine/auth_watcher_unittest.cc b/chrome/browser/sync/engine/auth_watcher_unittest.cc deleted file mode 100644 index cc840c7..0000000 --- a/chrome/browser/sync/engine/auth_watcher_unittest.cc +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2010 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 "base/scoped_ptr.h" -#include "base/scoped_temp_dir.h" -#include "base/test/test_file_util.h" -#include "base/waitable_event.h" -#include "chrome/browser/password_manager/encryptor.h" -#include "chrome/browser/sync/engine/auth_watcher.h" -#include "chrome/browser/sync/engine/syncer_thread.h" -#include "chrome/browser/sync/util/user_settings.h" -#include "chrome/common/deprecated/event_sys-inl.h" -#include "chrome/common/net/http_return.h" -#include "chrome/common/net/gaia/gaia_authenticator.h" -#include "chrome/test/sync/engine/mock_connection_manager.h" -#include "chrome/test/sync/engine/test_directory_setter_upper.h" -#include "testing/gtest/include/gtest/gtest.h" - -static FilePath::CharType kUserSettingsDB[] = - FILE_PATH_LITERAL("Settings.sqlite3"); -static const char* kTestUserAgent = "useragent"; -static const char* kTestServiceId = "serviceid"; -static const char* kTestGaiaURL = "http://gaia_url"; -static const char* kUserDisplayName = "Mr. Auth Watcher"; -static const char* kUserDisplayEmail = "authwatcherdisplay@gmail.com"; -static const char* kTestEmail = "authwatchertest@gmail.com"; -static const char* kWrongPassword = "wrongpassword"; -static const char* kCorrectPassword = "correctpassword"; -static const char* kValidSID = "validSID"; -static const char* kValidLSID = "validLSID"; -static const char* kInvalidAuthToken = "invalidAuthToken"; -static const char* kValidAuthToken = "validAuthToken"; - -namespace browser_sync { - -class GaiaAuthMockForAuthWatcher : public gaia::GaiaAuthenticator { - public: - GaiaAuthMockForAuthWatcher() : GaiaAuthenticator( - kTestUserAgent, kTestServiceId, kTestGaiaURL), - use_bad_auth_token_(false) {} - virtual ~GaiaAuthMockForAuthWatcher() {} - - virtual int GetBackoffDelaySeconds( - int current_backoff_delay) { - return SyncerThread::GetRecommendedDelaySeconds(current_backoff_delay); - } - - void SendBadAuthTokenForNextRequest() { use_bad_auth_token_ = true; } - - std::string renewed_token() { - return renewed_token_; - } - - protected: - bool PerformGaiaRequest(const AuthParams& params, AuthResults* results) { - if (params.password == kWrongPassword) { - results->auth_error = gaia::BadAuthentication; - return false; - } - if (params.password == kCorrectPassword) { - results->sid = kValidSID; - results->lsid = kValidLSID; - results->auth_token = kValidAuthToken; - } - if (use_bad_auth_token_) { - results->auth_token = kInvalidAuthToken; - use_bad_auth_token_ = false; - } - return true; - } - - void RenewAuthToken(const std::string& auth_token) { - renewed_token_ = auth_token; - } - - private: - // Whether we should send an invalid auth token on the next request. - bool use_bad_auth_token_; - std::string renewed_token_; -}; - -class AuthWatcherTest : public testing::Test { - public: - AuthWatcherTest() : metadb_(kUserDisplayEmail), - consumer_ready(false, false), - event_produced(false, false), - last_event_reason_(AuthWatcherEvent::ILLEGAL_VALUE) {} - virtual void SetUp() { -#if defined(OS_MACOSX) - // Need to mock the Keychain for unit tests on Mac to avoid possible - // blocking UI. |SetAuthTokenForService| uses Encryptor. - Encryptor::UseMockKeychain(true); -#endif - metadb_.SetUp(); - connection_.reset(new MockConnectionManager(metadb_.manager(), - metadb_.name())); - // Mock out data that would normally be sent back from a server. - connection()->SetAuthenticationResponseInfo(kValidAuthToken, - kUserDisplayName, kUserDisplayEmail, "ID"); - user_settings_.reset(new UserSettings()); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath user_settings_path = temp_dir_.path().Append(kUserSettingsDB); - user_settings_->Init(user_settings_path); - gaia_auth_ = new GaiaAuthMockForAuthWatcher(); - auth_watcher_ = new AuthWatcher(metadb_.manager(), connection_.get(), - kTestUserAgent, kTestServiceId, kTestGaiaURL, - user_settings_.get(), gaia_auth_); - authwatcher_hookup_.reset(NewEventListenerHookup(auth_watcher_->channel(), - this, &AuthWatcherTest::HandleAuthWatcherEvent)); - } - - virtual void TearDown() { - metadb_.TearDown(); - auth_watcher_->Shutdown(); - EXPECT_FALSE(auth_watcher()->message_loop()); - } - - void HandleAuthWatcherEvent(const AuthWatcherEvent& event) { - if (event.what_happened == AuthWatcherEvent::AUTHWATCHER_DESTROYED) - return; - consumer_ready.Wait(); // Block progress until the test is ready. - - last_event_reason_ = event.what_happened; - if (event.what_happened == AuthWatcherEvent::AUTH_SUCCEEDED) - user_email_ = event.user_email; - - event_produced.Signal(); - } - - AuthWatcherEvent::WhatHappened ConsumeNextEvent() { - consumer_ready.Signal(); - event_produced.Wait(); - return last_event_reason_; - } - - AuthWatcher* auth_watcher() { return auth_watcher_.get(); } - MockConnectionManager* connection() { return connection_.get(); } - GaiaAuthMockForAuthWatcher* gaia_auth() { return gaia_auth_; } - const std::string& user_email() { return user_email_; } - - private: - // Responsible for creating / deleting a temp dir containing user settings DB. - ScopedTempDir temp_dir_; - - // The event listener hookup registered for HandleAuthWatcherEvent. - scoped_ptr<EventListenerHookup> authwatcher_hookup_; - - // The sync engine pieces necessary to run an AuthWatcher. - TriggeredOpenTestDirectorySetterUpper metadb_; - scoped_ptr<MockConnectionManager> connection_; - scoped_ptr<UserSettings> user_settings_; - GaiaAuthMockForAuthWatcher* gaia_auth_; // Owned by auth_watcher_. - scoped_refptr<AuthWatcher> auth_watcher_; - - // This is used to block the AuthWatcherThread when it raises events until we - // are ready to read the event. It is not a manual-reset event, so it goes - // straight back to non-signaled after one thread (the main thread) is - // signaled (or "consumes" the signaled state). - base::WaitableEvent consumer_ready; - - // This is signaled by the AuthWatcherThread after it sets last_event_reason_ - // and possibly user_email_ for us to read. - base::WaitableEvent event_produced; - - // The 'WhatHappened' value from the last AuthWatcherEvent we handled. - AuthWatcherEvent::WhatHappened last_event_reason_; - - // Set when we receive an AUTH_SUCCEEDED event. - std::string user_email_; - - DISALLOW_COPY_AND_ASSIGN(AuthWatcherTest); -}; - -TEST_F(AuthWatcherTest, Construction) { - EXPECT_TRUE(auth_watcher()->message_loop()); - EXPECT_EQ("SyncEngine_AuthWatcherThread", - auth_watcher()->message_loop()->thread_name()); - EXPECT_TRUE(auth_watcher()->auth_backend_thread_.IsRunning()); - EXPECT_EQ(AuthWatcher::NOT_AUTHENTICATED, auth_watcher()->status()); -} - -TEST_F(AuthWatcherTest, AuthenticateGaiaAuthFailure) { - auth_watcher()->Authenticate(kTestEmail, kWrongPassword, - std::string(), // captcha_token - std::string()); // captcha_value - - EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent()); - EXPECT_EQ(AuthWatcherEvent::GAIA_AUTH_FAILED, ConsumeNextEvent()); -} - -TEST_F(AuthWatcherTest, AuthenticateBadAuthToken) { - gaia_auth()->SendBadAuthTokenForNextRequest(); - auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(), - std::string()); - EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent()); - EXPECT_EQ(AuthWatcherEvent::SERVICE_AUTH_FAILED, ConsumeNextEvent()); -} - -TEST_F(AuthWatcherTest, AuthenticateSuccess) { - auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(), - std::string()); - EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent()); - EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent()); - - // The server responds with a different email than what we used in the call - // to Authenticate, and the AuthWatcher should have told us about. - EXPECT_EQ(kUserDisplayEmail, user_email()); -} - -TEST_F(AuthWatcherTest, AuthenticateWithTokenBadAuthToken) { - auth_watcher()->AuthenticateWithToken(kTestEmail, kInvalidAuthToken); - EXPECT_EQ(AuthWatcherEvent::SERVICE_AUTH_FAILED, ConsumeNextEvent()); -} - -TEST_F(AuthWatcherTest, AuthenticateWithTokenSuccess) { - auth_watcher()->AuthenticateWithToken(kTestEmail, kValidAuthToken); - EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent()); - EXPECT_EQ(kUserDisplayEmail, user_email()); -} - -// Just check that the thread task was properly issued. -TEST_F(AuthWatcherTest, RenewAuthToken) { - auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(), - std::string()); - EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent()); - EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent()); - - auth_watcher()->RenewAuthToken("updated_token"); - EXPECT_EQ(AuthWatcherEvent::AUTH_RENEWED, ConsumeNextEvent()); - EXPECT_EQ(gaia_auth()->renewed_token(), "updated_token"); - EXPECT_EQ(connection()->auth_token(), "updated_token"); -} - -} // namespace browser_sync diff --git a/chrome/browser/sync/engine/authenticator.cc b/chrome/browser/sync/engine/authenticator.cc deleted file mode 100644 index eec7af3..0000000 --- a/chrome/browser/sync/engine/authenticator.cc +++ /dev/null @@ -1,110 +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/authenticator.h" - -#include "chrome/browser/sync/engine/net/server_connection_manager.h" -#include "chrome/browser/sync/engine/syncproto.h" -#include "chrome/browser/sync/protocol/sync.pb.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" - -namespace browser_sync { - -using std::string; - -Authenticator::Authenticator(ServerConnectionManager* manager, - UserSettings* settings) - : server_connection_manager_(manager), settings_(settings) { -} - -Authenticator::Authenticator(ServerConnectionManager* manager) - : server_connection_manager_(manager), settings_(NULL) { -} - -Authenticator::AuthenticationResult Authenticator::Authenticate() { - // TODO(sync): Pull and work with saved credentials. - return NO_SAVED_CREDENTIALS; -} - -Authenticator::AuthenticationResult Authenticator::Authenticate( - string username, string password) { - // TODO(sync): need to figure out if this routine is used anywhere other - // than the test code. - gaia::GaiaAuthenticator auth_service("ChromiumBrowser", "chromiumsync", - "https://www.google.com:443/accounts/ClientLogin"); - auth_service.set_message_loop(MessageLoop::current()); - if (!auth_service.Authenticate(username, password)) { - return UNSPECIFIC_ERROR_RETURN; - } - CHECK(!auth_service.auth_token().empty()); - return AuthenticateToken(auth_service.auth_token()); -} - -COMPILE_ASSERT(sync_pb::ClientToServerResponse::ErrorType_MAX == 7, - client_to_server_response_errors_changed); - -Authenticator::AuthenticationResult Authenticator::HandleSuccessfulTokenRequest( - const sync_pb::UserIdentification* user) { - display_email_ = user->has_email() ? user->email() : ""; - display_name_ = user->has_display_name() ? user->display_name() : ""; - obfuscated_id_ = user->has_obfuscated_id() ? user->obfuscated_id() : ""; - return SUCCESS; -} - -Authenticator::AuthenticationResult Authenticator::AuthenticateToken( - string auth_token) { - ClientToServerMessage client_to_server_message; - // Used to be required for all requests. - client_to_server_message.set_share(""); - client_to_server_message.set_message_contents( - ClientToServerMessage::AUTHENTICATE); - - string tx, rx; - client_to_server_message.SerializeToString(&tx); - HttpResponse http_response; - - ServerConnectionManager::PostBufferParams params = - { tx, &rx, &http_response }; - ScopedServerStatusWatcher watch(server_connection_manager_, &http_response); - if (!server_connection_manager_->PostBufferWithAuth(¶ms, auth_token, - &watch)) { - LOG(WARNING) << "Error posting from authenticator:" << http_response; - return SERVICE_DOWN; - } - sync_pb::ClientToServerResponse response; - if (!response.ParseFromString(rx)) - return CORRUPT_SERVER_RESPONSE; - - switch (response.error_code()) { - case sync_pb::ClientToServerResponse::SUCCESS: - if (response.has_authenticate() && response.authenticate().has_user()) - return HandleSuccessfulTokenRequest(&response.authenticate().user()); - // TODO:(sync) make this CORRUPT_SERVER_RESPONSE when all servers are - // returning user identification at login time. - return SUCCESS; - case sync_pb::ClientToServerResponse::USER_NOT_ACTIVATED: - return USER_NOT_ACTIVATED; - case sync_pb::ClientToServerResponse::AUTH_INVALID: - case sync_pb::ClientToServerResponse::AUTH_EXPIRED: - // TODO(tim): This is an egregious layering violation (bug 35060). - http_response.server_status = HttpResponse::SYNC_AUTH_ERROR; - return BAD_AUTH_TOKEN; - // should never happen (no birthday in this request). - case sync_pb::ClientToServerResponse::NOT_MY_BIRTHDAY: - // should never happen (auth isn't throttled). - case sync_pb::ClientToServerResponse::THROTTLED: - // should never happen (only for stores). - case sync_pb::ClientToServerResponse::ACCESS_DENIED: - // should never happen (only sent on get updates / commit) - case sync_pb::ClientToServerResponse::CLEAR_PENDING: - default: - LOG(ERROR) << "Corrupt Server packet received by auth, error code " << - response.error_code(); - return CORRUPT_SERVER_RESPONSE; - } -} - -} // namespace browser_sync diff --git a/chrome/browser/sync/engine/authenticator.h b/chrome/browser/sync/engine/authenticator.h deleted file mode 100644 index 1abca3c..0000000 --- a/chrome/browser/sync/engine/authenticator.h +++ /dev/null @@ -1,105 +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. -// -// The authenticator is a cross-platform class that handles authentication for -// the sync client. -// -// Current State: -// The authenticator is currently only used to authenticate tokens using the -// newer protocol buffer request. - -#ifndef CHROME_BROWSER_SYNC_ENGINE_AUTHENTICATOR_H_ -#define CHROME_BROWSER_SYNC_ENGINE_AUTHENTICATOR_H_ -#pragma once - -#include <string> - -#include "base/basictypes.h" -#include "base/port.h" - -namespace sync_pb { -class UserIdentification; -} - -namespace browser_sync { - -class ServerConnectionManager; -class UserSettings; - -class Authenticator { - public: - // Single return enum. - enum AuthenticationResult { - SUCCESS = 0, - // We couldn't log on because we don't have saved credentials. - NO_SAVED_CREDENTIALS, - // We can't reach auth server (i.e. we're offline or server's down). - NOT_CONNECTED, - // Server's up, but we're down. - SERVICE_DOWN, - // We contacted the server, but the response didn't make sense. - CORRUPT_SERVER_RESPONSE, - // Bad username/password. - BAD_CREDENTIALS, - // Credentials are fine, but the user hasn't signed up. - USER_NOT_ACTIVATED, - - // Return values for internal use. - - // We will never return this to the user unless they call AuthenticateToken - // directly. Other auth functions retry and then return - // CORRUPT_SERVER_RESPONSE. - // TODO(sync): Implement retries. - BAD_AUTH_TOKEN, - // We should never return this, it's a placeholder during development. - // TODO(sync): Remove this - UNSPECIFIC_ERROR_RETURN, - }; - - // Constructor. This class will keep the connection authenticated. - // TODO(sync): Make it work as described. - // TODO(sync): Require a UI callback mechanism. - Authenticator(ServerConnectionManager* manager, UserSettings* settings); - - // Constructor for a simple authenticator used for programmatic login from - // test programs. - explicit Authenticator(ServerConnectionManager* manager); - - // This version of Authenticate tries to use saved credentials, if we have - // any. - AuthenticationResult Authenticate(); - - // We save the username and password in memory (if given) so we - // can refresh the long-lived auth token if it expires. - // Also we save a 10-bit hash of the password to allow offline login. - AuthenticationResult Authenticate(std::string username, std::string password); - - // A version of the auth token to authenticate cookie portion of - // authentication. It uses the new proto buffer based call instead of the HTTP - // GET based one we currently use. - // Can return one of SUCCESS, SERVICE_DOWN, CORRUPT_SERVER_RESPONSE, - // USER_NOT_ACTIVATED or BAD_AUTH_TOKEN. See above for the meaning of these - // values. - // TODO(sync): Make this function private when we're done. - AuthenticationResult AuthenticateToken(std::string auth_token); - - const char* display_email() const { return display_email_.c_str(); } - const char* display_name() const { return display_name_.c_str(); } - private: - // Stores the information in the UserIdentification returned from the server. - AuthenticationResult HandleSuccessfulTokenRequest( - const sync_pb::UserIdentification* user); - // The server connection manager that we're looking after. - ServerConnectionManager* server_connection_manager_; - // Returns SUCCESS or the value that should be returned to the user. - std::string display_email_; - std::string display_name_; - std::string obfuscated_id_; - UserSettings* const settings_; - DISALLOW_COPY_AND_ASSIGN(Authenticator); -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_ENGINE_AUTHENTICATOR_H_ diff --git a/chrome/browser/sync/engine/net/server_connection_manager.cc b/chrome/browser/sync/engine/net/server_connection_manager.cc index 4953836..6d35811 100644 --- a/chrome/browser/sync/engine/net/server_connection_manager.cc +++ b/chrome/browser/sync/engine/net/server_connection_manager.cc @@ -135,11 +135,9 @@ ServerConnectionManager::ServerConnectionManager( const string& server, int port, bool use_ssl, - const string& user_agent, - const string& client_id) + const string& user_agent) : sync_server_(server), sync_server_port_(port), - client_id_(client_id), user_agent_(user_agent), use_ssl_(use_ssl), proto_sync_path_(kSyncServerSyncPath), @@ -163,7 +161,6 @@ void ServerConnectionManager::NotifyStatusChanged() { channel_->NotifyListeners(event); } -// Uses currently set auth token. Set by AuthWatcher. bool ServerConnectionManager::PostBufferWithCachedAuth( const PostBufferParams* params, ScopedServerStatusWatcher* watcher) { string path = @@ -171,14 +168,6 @@ bool ServerConnectionManager::PostBufferWithCachedAuth( return PostBufferToPath(params, path, auth_token(), watcher); } -bool ServerConnectionManager::PostBufferWithAuth(const PostBufferParams* params, - const string& auth_token, ScopedServerStatusWatcher* watcher) { - string path = MakeSyncServerPath(proto_sync_path(), - MakeSyncQueryString(client_id_)); - - return PostBufferToPath(params, path, auth_token, watcher); -} - bool ServerConnectionManager::PostBufferToPath(const PostBufferParams* params, const string& path, const string& auth_token, ScopedServerStatusWatcher* watcher) { diff --git a/chrome/browser/sync/engine/net/server_connection_manager.h b/chrome/browser/sync/engine/net/server_connection_manager.h index 602116a..526dc8e 100644 --- a/chrome/browser/sync/engine/net/server_connection_manager.h +++ b/chrome/browser/sync/engine/net/server_connection_manager.h @@ -213,8 +213,7 @@ class ServerConnectionManager { ServerConnectionManager(const std::string& server, int port, bool use_ssl, - const std::string& user_agent, - const std::string& client_id); + const std::string& user_agent); virtual ~ServerConnectionManager(); @@ -225,14 +224,6 @@ class ServerConnectionManager { virtual bool PostBufferWithCachedAuth(const PostBufferParams* params, ScopedServerStatusWatcher* watcher); - // POSTS buffer_in and reads a response into buffer_out. Add a specific auth - // token to http headers. - // - // Returns true if executed successfully. - virtual bool PostBufferWithAuth(const PostBufferParams* params, - const std::string& auth_token, - ScopedServerStatusWatcher* watcher); - // Checks the time on the server. Returns false if the request failed. |time| // is an out parameter that stores the value returned from the server. virtual bool CheckTime(int32* out_time); @@ -289,6 +280,11 @@ class ServerConnectionManager { return NULL; // For testing. }; + void set_client_id(const std::string& client_id) { + DCHECK(client_id_.empty()); + client_id_.assign(client_id); + } + void set_auth_token(const std::string& auth_token) { // TODO(chron): Consider adding a message loop check here. AutoLock lock(auth_token_mutex_); @@ -333,7 +329,7 @@ class ServerConnectionManager { int sync_server_port_; // The unique id of the user's client. - const std::string client_id_; + std::string client_id_; // The user-agent string for HTTP. std::string user_agent_; diff --git a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h index 67424b9..4108f9a 100644 --- a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h +++ b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h @@ -51,10 +51,8 @@ class SyncAPIServerConnectionManager int port, bool use_ssl, const std::string& client_version, - const std::string& client_id, HttpPostProviderFactory* factory) - : ServerConnectionManager(server, port, use_ssl, client_version, - client_id), + : ServerConnectionManager(server, port, use_ssl, client_version), post_provider_factory_(factory) { DCHECK(post_provider_factory_.get()); } diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc index 00d1c4f..15e0e8d 100644 --- a/chrome/browser/sync/engine/syncapi.cc +++ b/chrome/browser/sync/engine/syncapi.cc @@ -25,7 +25,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/sync/sync_constants.h" #include "chrome/browser/sync/engine/all_status.h" -#include "chrome/browser/sync/engine/auth_watcher.h" #include "chrome/browser/sync/engine/change_reorder_buffer.h" #include "chrome/browser/sync/engine/model_safe_worker.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" @@ -49,7 +48,6 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/util/crypto_helpers.h" -#include "chrome/browser/sync/util/user_settings.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/deprecated/event_sys.h" #include "chrome/common/net/gaia/gaia_authenticator.h" @@ -61,17 +59,15 @@ using browser_sync::AllStatus; using browser_sync::AllStatusEvent; -using browser_sync::AuthWatcher; -using browser_sync::AuthWatcherEvent; using browser_sync::Cryptographer; using browser_sync::KeyParams; using browser_sync::ModelSafeRoutingInfo; using browser_sync::ModelSafeWorker; using browser_sync::ModelSafeWorkerRegistrar; +using browser_sync::ServerConnectionEvent; using browser_sync::Syncer; using browser_sync::SyncerEvent; using browser_sync::SyncerThread; -using browser_sync::UserSettings; using browser_sync::kNigoriTag; using browser_sync::sessions::SyncSessionContext; using notifier::TalkMediator; @@ -910,7 +906,6 @@ class SyncManager::SyncInternal explicit SyncInternal(SyncManager* sync_manager) : core_message_loop_(NULL), observer_(NULL), - auth_problem_(AuthError::NONE), sync_manager_(sync_manager), registrar_(NULL), notification_pending_(false), @@ -929,40 +924,25 @@ class SyncManager::SyncInternal bool Init(const FilePath& database_location, const std::string& sync_server_and_path, int port, - const char* gaia_service_id, - const char* gaia_source, bool use_ssl, HttpPostProviderFactory* post_factory, - HttpPostProviderFactory* auth_post_factory, ModelSafeWorkerRegistrar* model_safe_worker_registrar, - bool attempt_last_user_authentication, - bool invalidate_last_user_auth_token, - bool invalidate_xmpp_auth_token, const char* user_agent, - const std::string& lsid, + const SyncCredentials& credentials, const bool use_chrome_async_socket, const bool try_ssltcp_first, browser_sync::NotificationMethod notification_method, const std::string& restored_key_for_bootstrapping); - // Tell sync engine to submit credentials to GAIA for verification. - // Successful GAIA authentication will kick off the following chain of events: - // 1. Cause sync engine to open the syncer database. - // 2. Trigger the AuthWatcher to create a Syncer for the directory and call - // SyncerThread::SyncDirectory; the SyncerThread will block until (4). - // 3. Tell the ServerConnectionManager to pass the newly received GAIA auth - // token to a sync server to obtain a sync token. - // 4. On receipt of this token, the ServerConnectionManager broadcasts - // a server-reachable event, which will unblock the SyncerThread. - // 5. When StartSyncing is called, the Syncer will begin the sync process, by - // downloading from or uploading to the server. - // - // If authentication fails, an event will be broadcast all the way up to - // the SyncManager::Observer. It may, in turn, decide to try again with new - // credentials. Calling this method again is the appropriate course of action - // to "retry". - void Authenticate(const std::string& username, const std::string& password, - const std::string& captcha); + + // Sign into sync with given credentials. + // We do not verify the tokens given. After this call, the tokens are set + // and the sync DB is open. True if successful, false if something + // went wrong. + bool SignIn(const SyncCredentials& credentials); + + // Update tokens that we're using in Sync. Email must stay the same. + void UpdateCredentials(const SyncCredentials& credentials); // Tell the sync engine to start the syncing process. void StartSyncing(); @@ -987,20 +967,17 @@ class SyncManager::SyncInternal // This listener is called by the syncer channel for all syncer events. virtual void HandleChannelEvent(const SyncerEvent& event); - // We have a direct hookup to the authwatcher to be notified for auth failures - // on startup, to serve our UI needs. - void HandleAuthWatcherEvent(const AuthWatcherEvent& event); + // Listens for notifications from the ServerConnectionManager + void HandleServerConnectionEvent(const ServerConnectionEvent& event); - // Listen here for directory opened events. - void HandleDirectoryManagerEvent( - const syncable::DirectoryManagerEvent& event); + // Open the directory named with username_for_share + bool OpenDirectory(); // Login to the talk mediator with the given credentials. void TalkMediatorLogin( const std::string& email, const std::string& token); // TalkMediator::Delegate implementation. - virtual void OnNotificationStateChange( bool notifications_enabled); @@ -1016,14 +993,13 @@ class SyncManager::SyncInternal } SyncerThread* syncer_thread() { return syncer_thread_.get(); } TalkMediator* talk_mediator() { return talk_mediator_.get(); } - AuthWatcher* auth_watcher() { return auth_watcher_.get(); } void set_observer(SyncManager::Observer* observer) { observer_ = observer; } UserShare* GetUserShare() { return &share_; } // Return the currently active (validated) username for use with syncable // types. const std::string& username_for_share() const { - return share_.authenticated_name; + return share_.name; } // Note about SyncManager::Status implementation: Status is a trimmed @@ -1078,21 +1054,6 @@ class SyncManager::SyncInternal } private: - // Try to authenticate using a LSID cookie. - void AuthenticateWithLsid(const std::string& lsid); - - // Try to authenticate using persisted credentials from a previous successful - // authentication. If no such credentials exist, calls OnAuthError on the - // client to collect credentials. Otherwise, there exist local credentials - // that were once used for a successful auth, so we'll try to re-use these. - // Failure of that attempt will be communicated as normal using OnAuthError. - // Since this entry point will bypass normal GAIA authentication and try to - // authenticate directly with the sync service using a cached token, - // authentication failure will generally occur due to expired credentials, or - // possibly because of a password change. - bool AuthenticateForUser(const std::string& username, - const std::string& auth_token); - // Helper to call OnAuthError when no authentication credentials are // available. void RaiseAuthNeededEvent(); @@ -1171,10 +1132,6 @@ class SyncManager::SyncInternal // constructing any transaction type. UserShare share_; - // A wrapper around a sqlite store used for caching authentication data, - // last user information, current sync-related URLs, and more. - scoped_ptr<UserSettings> user_settings_; - MessageLoop* core_message_loop_; // Observer registered via SetObserver/RemoveObserver. @@ -1195,13 +1152,6 @@ class SyncManager::SyncInternal // sync components. AllStatus allstatus_; - // AuthWatcher kicks off the authentication process and follows it through - // phase 1 (GAIA) to phase 2 (sync engine). As part of this work it determines - // the initial connectivity and causes the server connection event to be - // broadcast, which signals the syncer thread to start syncing. - // It has a heavy duty constructor requiring boilerplate so we heap allocate. - scoped_refptr<AuthWatcher> auth_watcher_; - // Each element of this array is a store of change records produced by // HandleChangeEvent during the CALCULATE_CHANGES step. The changes are // segregated by model type, and are stored here to be processed and @@ -1213,20 +1163,12 @@ class SyncManager::SyncInternal scoped_ptr<browser_sync::ChannelHookup<syncable::DirectoryChangeEvent> > dir_change_hookup_; + // Event listener hookup for the ServerConnectionManager. + scoped_ptr<EventListenerHookup> connection_manager_hookup_; + // The event listener hookup registered for HandleSyncerEvent. scoped_ptr<browser_sync::ChannelHookup<SyncerEvent> > syncer_event_; - // The event listener hookup registered for HandleAuthWatcherEvent. - scoped_ptr<EventListenerHookup> authwatcher_hookup_; - - // The event listener hookup registered for the DirectoryManager (OPENED). - scoped_ptr<EventListenerHookup> directory_manager_hookup_; - - // Our cache of a recent authentication problem. If no authentication problem - // occurred, or if the last problem encountered has been cleared (by a - // subsequent AuthWatcherEvent), this is set to NONE. - AuthError::State auth_problem_; - // The sync dir_manager to which we belong. SyncManager* const sync_manager_; @@ -1261,17 +1203,11 @@ SyncManager::SyncManager() { bool SyncManager::Init(const FilePath& database_location, const char* sync_server_and_path, int sync_server_port, - const char* gaia_service_id, - const char* gaia_source, bool use_ssl, HttpPostProviderFactory* post_factory, - HttpPostProviderFactory* auth_post_factory, ModelSafeWorkerRegistrar* registrar, - bool attempt_last_user_authentication, - bool invalidate_last_user_auth_token, - bool invalidate_xmpp_auth_token, const char* user_agent, - const char* lsid, + const SyncCredentials& credentials, bool use_chrome_async_socket, bool try_ssltcp_first, browser_sync::NotificationMethod notification_method, @@ -1282,29 +1218,22 @@ bool SyncManager::Init(const FilePath& database_location, return data_->Init(database_location, server_string, sync_server_port, - gaia_service_id, - gaia_source, use_ssl, post_factory, - auth_post_factory, registrar, - attempt_last_user_authentication, - invalidate_last_user_auth_token, - invalidate_xmpp_auth_token, user_agent, - lsid, + credentials, use_chrome_async_socket, try_ssltcp_first, notification_method, restored_key_for_bootstrapping); } -void SyncManager::Authenticate(const char* username, const char* password, - const char* captcha) { - data_->Authenticate(std::string(username), std::string(password), - std::string(captcha)); +void SyncManager::UpdateCredentials(const SyncCredentials& credentials) { + data_->UpdateCredentials(credentials); } + bool SyncManager::InitialSyncEndedForAllEnabledTypes() { return data_->InitialSyncEndedForAllEnabledTypes(); } @@ -1329,6 +1258,7 @@ void SyncManager::RequestNudge() { data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal); } +// TODO(chron): Don't need to plumb this so deep. const std::string& SyncManager::GetAuthenticatedUsername() { DCHECK(data_); return data_->username_for_share(); @@ -1338,17 +1268,11 @@ bool SyncManager::SyncInternal::Init( const FilePath& database_location, const std::string& sync_server_and_path, int port, - const char* gaia_service_id, - const char* gaia_source, bool use_ssl, HttpPostProviderFactory* post_factory, - HttpPostProviderFactory* auth_post_factory, ModelSafeWorkerRegistrar* model_safe_worker_registrar, - bool attempt_last_user_authentication, - bool invalidate_last_user_auth_token, - bool invalidate_xmpp_auth_token, const char* user_agent, - const std::string& lsid, + const SyncCredentials& credentials, bool use_chrome_async_socket, bool try_ssltcp_first, browser_sync::NotificationMethod notification_method, @@ -1359,32 +1283,16 @@ bool SyncManager::SyncInternal::Init( core_message_loop_ = MessageLoop::current(); DCHECK(core_message_loop_); notification_method_ = notification_method; - // Set up UserSettings, creating the db if necessary. We need this to - // instantiate a URLFactory to give to the Syncer. - FilePath settings_db_file = - database_location.Append(FilePath(kBookmarkSyncUserSettingsDatabase)); - user_settings_.reset(new UserSettings()); - if (!user_settings_->Init(settings_db_file)) - return false; - registrar_ = model_safe_worker_registrar; - LOG(INFO) << "Initialized sync user settings. Starting DirectoryManager."; - share_.dir_manager.reset(new DirectoryManager(database_location)); - directory_manager_hookup_.reset(NewEventListenerHookup( - share_.dir_manager->channel(), this, - &SyncInternal::HandleDirectoryManagerEvent)); - share_.dir_manager->cryptographer()->Bootstrap( - restored_key_for_bootstrapping); - string client_id = user_settings_->GetClientId(); connection_manager_.reset(new SyncAPIServerConnectionManager( - sync_server_and_path, port, use_ssl, user_agent, client_id, - post_factory)); + sync_server_and_path, port, use_ssl, user_agent, post_factory)); - // Watch various objects for aggregated status. - allstatus_.WatchConnectionManager(connection_manager()); + connection_manager_hookup_.reset( + NewEventListenerHookup(connection_manager()->channel(), this, + &SyncManager::SyncInternal::HandleServerConnectionEvent)); net::NetworkChangeNotifier::AddObserver(this); // TODO(akalin): CheckServerReachable() can block, which may cause jank if we @@ -1404,7 +1312,7 @@ bool SyncManager::SyncInternal::Init( const bool kInitializeSsl = true; const bool kConnectImmediately = false; talk_mediator_.reset(new TalkMediatorImpl(mediator_thread, kInitializeSsl, - kConnectImmediately, invalidate_xmpp_auth_token)); + kConnectImmediately, false)); if (notification_method != browser_sync::NOTIFICATION_LEGACY && notification_method != browser_sync::NOTIFICATION_SERVER) { if (notification_method == browser_sync::NOTIFICATION_TRANSITIONAL) { @@ -1417,30 +1325,11 @@ bool SyncManager::SyncInternal::Init( // Listen to TalkMediator events ourselves talk_mediator_->SetDelegate(this); - std::string gaia_url = gaia::kGaiaUrl; - const char* service_id = gaia_service_id ? - gaia_service_id : SYNC_SERVICE_NAME; - - BridgedGaiaAuthenticator* gaia_auth = new BridgedGaiaAuthenticator( - gaia_source, service_id, gaia_url, auth_post_factory); - - LOG(INFO) << "Sync is bringing up authwatcher and SyncSessionContext."; - - auth_watcher_ = new AuthWatcher(dir_manager(), - connection_manager(), - gaia_source, - service_id, - gaia_url, - user_settings_.get(), - gaia_auth); - - authwatcher_hookup_.reset(NewEventListenerHookup(auth_watcher_->channel(), - this, &SyncInternal::HandleAuthWatcherEvent)); + LOG(INFO) << "Sync is bringing up SyncSessionContext."; // Build a SyncSessionContext and store the worker in it. SyncSessionContext* context = new SyncSessionContext( - connection_manager_.get(), auth_watcher(), - dir_manager(), model_safe_worker_registrar); + connection_manager_.get(), dir_manager(), model_safe_worker_registrar); // The SyncerThread takes ownership of |context|. syncer_thread_ = new SyncerThread(context); @@ -1449,22 +1338,7 @@ bool SyncManager::SyncInternal::Init( // Subscribe to the syncer thread's channel. syncer_event_.reset(syncer_thread()->relay_channel()->AddObserver(this)); - bool attempting_auth = false; - std::string username, auth_token; - if (attempt_last_user_authentication && - auth_watcher()->settings()->GetLastUserAndServiceToken( - SYNC_SERVICE_NAME, &username, &auth_token)) { - if (invalidate_last_user_auth_token) { - auth_token += "bogus"; - } - attempting_auth = AuthenticateForUser(username, auth_token); - } else if (!lsid.empty()) { - attempting_auth = true; - AuthenticateWithLsid(lsid); - } - if (attempt_last_user_authentication && !attempting_auth) - RaiseAuthNeededEvent(); - return true; + return SignIn(credentials); } void SyncManager::SyncInternal::StartSyncing() { @@ -1536,53 +1410,62 @@ void SyncManager::SyncInternal::SendPendingXMPPNotification( } } -void SyncManager::SyncInternal::Authenticate(const std::string& username, - const std::string& password, - const std::string& captcha) { - DCHECK(username_for_share().empty() || username == username_for_share()) - << "Username change from valid username detected"; - if (allstatus_.status().authenticated) - return; - if (password.empty()) { - // TODO(timsteele): Seems like this shouldn't be needed, but auth_watcher - // currently drops blank password attempts on the floor and doesn't update - // state; it only LOGs an error in this case. We want to make sure we set - // our GoogleServiceAuthError state to denote an error. - RaiseAuthNeededEvent(); +bool SyncManager::SyncInternal::OpenDirectory() { + DCHECK(!initialized()) << "Should only happen once"; + + bool share_opened = dir_manager()->Open(username_for_share()); + DCHECK(share_opened); + if (!share_opened) { + if (observer_) { + observer_->OnStopSyncingPermanently(); + } + + LOG(ERROR) << "Could not open share for:" << username_for_share(); + return false; + } + + // Database has to be initialized for the guid to be available. + syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); + if (!lookup.good()) { + NOTREACHED(); + return false; } - auth_watcher()->Authenticate(username, password, std::string(), - captcha); -} -void SyncManager::SyncInternal::AuthenticateWithLsid(const string& lsid) { - DCHECK(!lsid.empty()); - auth_watcher()->AuthenticateWithLsid(lsid); + connection_manager()->set_client_id(lookup->cache_guid()); + syncer_thread()->CreateSyncer(username_for_share()); + MarkAndNotifyInitializationComplete(); + dir_change_hookup_.reset(lookup->AddChangeObserver(this)); + return true; } -bool SyncManager::SyncInternal::AuthenticateForUser( - const std::string& username, const std::string& auth_token) { - share_.authenticated_name = username; +bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) { + DCHECK_EQ(MessageLoop::current(), core_message_loop_); + DCHECK(share_.name.empty()); + share_.name = credentials.email; - // We optimize by opening the directory before the "fresh" authentication - // attempt completes so that we can immediately begin processing changes. - if (!dir_manager()->Open(username_for_share())) { - if (observer_) - observer_->OnStopSyncingPermanently(); + LOG(INFO) << "Signing in user: " << username_for_share(); + if (!OpenDirectory()) { return false; } - // Load the last-known good auth token into the connection manager and send - // it off to the AuthWatcher for validation. The result of the validation - // will update the connection manager if necessary. - connection_manager()->set_auth_token(auth_token); - auth_watcher()->AuthenticateWithToken(username, auth_token); + UpdateCredentials(credentials); return true; } +void SyncManager::SyncInternal::UpdateCredentials( + const SyncCredentials& credentials) { + DCHECK_EQ(MessageLoop::current(), core_message_loop_); + DCHECK(share_.name == credentials.email); + connection_manager()->set_auth_token(credentials.sync_token); + TalkMediatorLogin(credentials.email, credentials.sync_token); + CheckServerReachable(); + sync_manager_->RequestNudge(); +} + void SyncManager::SyncInternal::RaiseAuthNeededEvent() { - auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS; - if (observer_) - observer_->OnAuthError(AuthError(auth_problem_)); + if (observer_) { + observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)); + } } void SyncManager::SyncInternal::SetPassphrase( @@ -1642,15 +1525,6 @@ void SyncManager::SyncInternal::Shutdown() { // TODO(akalin): NULL the other member variables defensively, too. scoped_ptr<TalkMediator> talk_mediator(talk_mediator_.release()); - // First reset the AuthWatcher in case an auth attempt is in progress so that - // it terminates gracefully before we shutdown and close other components. - // Otherwise the attempt can complete after we've closed the directory, for - // example, and cause initialization to continue, which is bad. - if (auth_watcher_) { - auth_watcher_->Shutdown(); - authwatcher_hookup_.reset(); - } - if (syncer_thread()) { if (!syncer_thread()->Stop(kThreadExitTimeoutMsec)) { LOG(FATAL) << "Unable to stop the syncer, it won't be happy..."; @@ -1659,15 +1533,6 @@ void SyncManager::SyncInternal::Shutdown() { syncer_thread_ = NULL; } - // TODO(chron): Since the auth_watcher_ is held by the sync session state, - // we release the ref here after the syncer is deallocated. - // In reality the SyncerSessionState's pointer to the - // authwatcher should be ref counted, but for M6 we use this - // lower risk fix so it's deallocated on the original thread. - if (auth_watcher_) { - auth_watcher_ = NULL; - } - // Shutdown the xmpp buzz connection. if (talk_mediator.get()) { LOG(INFO) << "P2P: Mediator logout started."; @@ -1679,7 +1544,7 @@ void SyncManager::SyncInternal::Shutdown() { // Pump any messages the auth watcher, syncer thread, or talk // mediator posted before they shut down. (See HandleSyncerEvent(), - // HandleAuthWatcherEvent(), and HandleTalkMediatorEvent() for the + // and HandleTalkMediatorEvent() for the // events that may be posted.) { CHECK(core_message_loop_); @@ -1691,6 +1556,8 @@ void SyncManager::SyncInternal::Shutdown() { net::NetworkChangeNotifier::RemoveObserver(this); + connection_manager_hookup_.reset(); + if (dir_manager()) { dir_manager()->FinalSaveChangesForAll(); dir_manager()->Close(username_for_share()); @@ -1699,7 +1566,6 @@ void SyncManager::SyncInternal::Shutdown() { // Reset the DirectoryManager and UserSettings so they relinquish sqlite // handles to backing files. share_.dir_manager.reset(); - user_settings_.reset(); // We don't want to process any more events. dir_change_hookup_.reset(); @@ -1712,22 +1578,7 @@ void SyncManager::SyncInternal::OnIPAddressChanged() { // TODO(akalin): CheckServerReachable() can block, which may cause // jank if we try to shut down sync. Fix this. connection_manager()->CheckServerReachable(); -} - -void SyncManager::SyncInternal::HandleDirectoryManagerEvent( - const syncable::DirectoryManagerEvent& event) { - LOG(INFO) << "Sync internal handling a directory manager event"; - if (syncable::DirectoryManagerEvent::OPENED == event.what_happened) { - DCHECK(!initialized()) << "Should only happen once"; - if (username_for_share().empty()) { - share_.authenticated_name = event.dirname; - } - DCHECK(LowerCaseEqualsASCII(username_for_share(), - StringToLowerASCII(event.dirname).c_str())) - << "username_for_share= " << username_for_share() - << ", event.dirname= " << event.dirname; - MarkAndNotifyInitializationComplete(); - } + sync_manager_->RequestNudge(); } // Listen to model changes, filter out ones initiated by the sync API, and @@ -1750,6 +1601,25 @@ void SyncManager::SyncInternal::HandleChannelEvent( } } +void SyncManager::SyncInternal::HandleServerConnectionEvent( + const ServerConnectionEvent& event) { + allstatus_.HandleServerConnectionEvent(event); + if (event.what_happened == ServerConnectionEvent::STATUS_CHANGED) { + if (event.connection_code == + browser_sync::HttpResponse::SERVER_CONNECTION_OK) { + if (observer_) { + observer_->OnAuthError(AuthError(AuthError::None())); + } + } + + if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) { + if (observer_) { + observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)); + } + } + } +} + void SyncManager::SyncInternal::HandleTransactionEndingChangeEvent( const syncable::DirectoryChangeEvent& event) { // This notification happens immediately before a syncable WriteTransaction @@ -1981,105 +1851,11 @@ void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) { observer_->OnStopSyncingPermanently(); return; } -} -void SyncManager::SyncInternal::HandleAuthWatcherEvent( - const AuthWatcherEvent& event) { - allstatus_.HandleAuthWatcherEvent(event); - // We don't care about an authentication attempt starting event, and we - // don't want to reset our state to GoogleServiceAuthError::NONE because the - // fact that an _attempt_ is starting doesn't change the fact that we have an - // auth problem. - if (event.what_happened == AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START) + if (event.what_happened == SyncerEvent::UPDATED_TOKEN) { + observer_->OnUpdatedToken(event.updated_token); return; - // We clear our last auth problem cache on new auth watcher events, and only - // set it to indicate a problem state for certain AuthWatcherEvent types. - auth_problem_ = AuthError::NONE; - switch (event.what_happened) { - case AuthWatcherEvent::AUTH_SUCCEEDED: - DCHECK(!event.user_email.empty()); - // We now know the supplied username and password were valid. If this - // wasn't the first sync, authenticated_name should already be assigned. - if (username_for_share().empty()) { - share_.authenticated_name = event.user_email; - } - - DCHECK(LowerCaseEqualsASCII(username_for_share(), - StringToLowerASCII(event.user_email).c_str())) - << "username_for_share= " << username_for_share() - << ", event.user_email= " << event.user_email; - - if (observer_) - observer_->OnAuthError(AuthError::None()); - - // Hook up the DirectoryChangeEvent listener, HandleChangeEvent. - { - syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); - if (!lookup.good()) { - DCHECK(false) << "ScopedDirLookup creation failed; unable to hook " - << "up directory change event listener!"; - return; - } - - // Note that we can end up here multiple times, for example if the - // user had to re-login and we got a second AUTH_SUCCEEDED event. Take - // care not to add ourselves as an observer a second time. - if (!dir_change_hookup_.get()) - dir_change_hookup_.reset(lookup->AddChangeObserver(this)); - } - - if (!event.auth_token.empty()) { - core_message_loop_->PostTask( - FROM_HERE, - NewRunnableMethod( - this, &SyncManager::SyncInternal::TalkMediatorLogin, - event.user_email, event.auth_token)); - } - return; - case AuthWatcherEvent::AUTH_RENEWED: - DCHECK(!event.user_email.empty()); - DCHECK(!event.auth_token.empty()); - core_message_loop_->PostTask( - FROM_HERE, - NewRunnableMethod( - this, &SyncManager::SyncInternal::TalkMediatorLogin, - event.user_email, event.auth_token)); - return; - // Authentication failures translate to GoogleServiceAuthError events. - case AuthWatcherEvent::GAIA_AUTH_FAILED: // Invalid GAIA credentials. - if (event.auth_results->auth_error == gaia::CaptchaRequired) { - auth_problem_ = AuthError::CAPTCHA_REQUIRED; - std::string url_string("https://www.google.com/accounts/"); - url_string += event.auth_results->captcha_url; - GURL captcha(url_string); - observer_->OnAuthError(AuthError::FromCaptchaChallenge( - event.auth_results->captcha_token, captcha, - GURL(event.auth_results->auth_error_url))); - return; - } else if (event.auth_results->auth_error == - gaia::ConnectionUnavailable) { - auth_problem_ = AuthError::CONNECTION_FAILED; - } else { - auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS; - } - break; - case AuthWatcherEvent::SERVICE_AUTH_FAILED: // Expired GAIA credentials. - auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS; - break; - case AuthWatcherEvent::SERVICE_USER_NOT_SIGNED_UP: - auth_problem_ = AuthError::USER_NOT_SIGNED_UP; - break; - case AuthWatcherEvent::SERVICE_CONNECTION_FAILED: - auth_problem_ = AuthError::CONNECTION_FAILED; - break; - default: // We don't care about the many other AuthWatcherEvent types. - return; } - - - // Fire notification that the status changed due to an authentication error. - if (observer_) - observer_->OnAuthError(AuthError(auth_problem_)); } void SyncManager::SyncInternal::OnNotificationStateChange( @@ -2121,8 +1897,8 @@ void SyncManager::SyncInternal::TalkMediatorLogin( << "(talk_mediator_ is NULL)"; return; } - // TODO(akalin): Make talk_mediator automatically login on - // auth token change. + LOG(INFO) << "P2P: Trying talk mediator login."; + talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME); talk_mediator_->Login(); } @@ -2184,7 +1960,7 @@ void SyncManager::SetupForTestMode(const std::wstring& test_username) { void SyncManager::SyncInternal::SetupForTestMode( const std::wstring& test_username) { - share_.authenticated_name = WideToUTF8(test_username); + share_.name = WideToUTF8(test_username); // Some tests are targeting only local db operations & integrity, and don't // want syncer thread interference. @@ -2192,18 +1968,8 @@ void SyncManager::SyncInternal::SetupForTestMode( allstatus_.WatchSyncerThread(NULL); syncer_thread_ = NULL; - if (!dir_manager()->Open(username_for_share())) + if (!dir_manager()->Open(username_for_share())) { DCHECK(false) << "Could not open directory when running in test mode"; - - // Hook up the DirectoryChangeEvent listener, HandleChangeEvent. - { - syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); - if (!lookup.good()) { - DCHECK(false) << "ScopedDirLookup creation failed; unable to hook " - << "up directory change event listener!"; - return; - } - dir_change_hookup_.reset(lookup->AddChangeObserver(this)); } } @@ -2213,7 +1979,7 @@ BaseTransaction::BaseTransaction(UserShare* share) : lookup_(NULL) { DCHECK(share && share->dir_manager.get()); lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(), - share->authenticated_name); + share->name); cryptographer_ = share->dir_manager->cryptographer(); if (!(lookup_->good())) DCHECK(false) << "ScopedDirLookup failed on valid DirManager."; diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h index e4e8510..16f8bd9 100644 --- a/chrome/browser/sync/engine/syncapi.h +++ b/chrome/browser/sync/engine/syncapi.h @@ -107,12 +107,14 @@ struct UserShare { // be shared across multiple threads (unlike Directory). scoped_ptr<syncable::DirectoryManager> dir_manager; - // The username of the sync user. This is empty until we have performed at - // least one successful GAIA authentication with this username, which means - // on first-run it is empty until an AUTH_SUCCEEDED event and on future runs - // it is set as soon as the client instructs us to authenticate for the last - // known valid user (AuthenticateForLastKnownUser()). - std::string authenticated_name; + // The username of the sync user. + std::string name; +}; + +// Contains everything needed to talk to and identify a user account. +struct SyncCredentials { + std::string email; + std::string sync_token; }; // A valid BaseNode will never have an ID of zero. @@ -669,6 +671,9 @@ class SyncManager { // Called when user interaction may be required due to an auth problem. virtual void OnAuthError(const GoogleServiceAuthError& auth_error) = 0; + // Called when a new auth token is provided by the sync server. + virtual void OnUpdatedToken(const std::string& token) = 0; + // Called when user interaction is required to obtain a valid passphrase. virtual void OnPassphraseRequired() = 0; @@ -715,52 +720,22 @@ class SyncManager { // |sync_server_and_path| and |sync_server_port| represent the Chrome sync // server to use, and |use_ssl| specifies whether to communicate securely; // the default is false. - // |gaia_service_id| is the service id used for GAIA authentication. If it's - // null then default will be used. // |post_factory| will be owned internally and used to create // instances of an HttpPostProvider. - // |auth_post_factory| will be owned internally and used to create - // instances of an HttpPostProvider for communicating with GAIA. - // TODO(timsteele): It seems like one factory should suffice, but for now to - // avoid having to deal with threading issues since the auth code and syncer - // code live on separate threads that run simultaneously, we just dedicate - // one to each component. Long term we may want to reconsider the HttpBridge - // API to take all the params in one chunk in a threadsafe manner.. which is - // still suboptimal as there will be high contention between the two threads - // on startup; so maybe what we have now is the best solution- it does mirror - // the CURL implementation as each thread creates their own internet handle. - // Investigate. // |model_safe_worker| ownership is given to the SyncManager. // |user_agent| is a 7-bit ASCII string suitable for use as the User-Agent // HTTP header. Used internally when collecting stats to classify clients. - // As a fallback when no cached auth information is available, try to - // bootstrap authentication using |lsid|, if it isn't empty. - // - // |invalidate_last_user_auth_token| makes it so that any auth token - // read from user settings is invalidated. This is used for testing - // code paths related to authentication failures. - // - // |invalidate_xmpp_auth_token| makes it so that any auth token - // used to log into XMPP is invalidated. This is used for testing - // code paths related to authentication failures for XMPP only. - // // |try_ssltcp_first| indicates that the SSLTCP port (443) is tried before the // the XMPP port (5222) during login. It is used by the sync tests that are // run on the chromium builders because port 5222 is blocked. bool Init(const FilePath& database_location, const char* sync_server_and_path, int sync_server_port, - const char* gaia_service_id, - const char* gaia_source, bool use_ssl, HttpPostProviderFactory* post_factory, - HttpPostProviderFactory* auth_post_factory, browser_sync::ModelSafeWorkerRegistrar* registrar, - bool attempt_last_user_authentication, - bool invalidate_last_user_auth_token, - bool invalidate_xmpp_auth_token, const char* user_agent, - const char* lsid, + const SyncCredentials& credentials, bool use_chrome_async_socket, bool try_ssltcp_first, browser_sync::NotificationMethod notification_method, @@ -776,15 +751,11 @@ class SyncManager { // called. bool InitialSyncEndedForAllEnabledTypes(); - // Submit credentials to GAIA for verification. On success, both |username| - // and the obtained auth token are persisted on disk for future re-use. - // If authentication fails, OnAuthProblem is called on our Observer. - // The Observer may, in turn, decide to try again with new - // credentials. Calling this method again is the appropriate course of action - // to "retry". - // |username|, |password|, and |captcha| are owned by the caller. - void Authenticate(const char* username, const char* password, - const char* captcha); + // Migrate tokens from user settings DB to the token service. + void MigrateTokens(); + + // Update tokens that we're using in Sync. Email must stay the same. + void UpdateCredentials(const SyncCredentials& credentials); // Start the SyncerThread. void StartSyncing(); diff --git a/chrome/browser/sync/engine/syncapi_unittest.cc b/chrome/browser/sync/engine/syncapi_unittest.cc index a77134b..b83c501 100644 --- a/chrome/browser/sync/engine/syncapi_unittest.cc +++ b/chrome/browser/sync/engine/syncapi_unittest.cc @@ -25,7 +25,7 @@ class SyncApiTest : public testing::Test { virtual void SetUp() { setter_upper_.SetUp(); share_.dir_manager.reset(setter_upper_.manager()); - share_.authenticated_name = setter_upper_.name(); + share_.name = setter_upper_.name(); } virtual void TearDown() { diff --git a/chrome/browser/sync/engine/syncer_proto_util.cc b/chrome/browser/sync/engine/syncer_proto_util.cc index 17de218..2cc2300 100644 --- a/chrome/browser/sync/engine/syncer_proto_util.cc +++ b/chrome/browser/sync/engine/syncer_proto_util.cc @@ -6,9 +6,9 @@ #include "base/format_macros.h" #include "base/string_util.h" -#include "chrome/browser/sync/engine/auth_watcher.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/engine/syncer.h" +#include "chrome/browser/sync/engine/syncer_types.h" #include "chrome/browser/sync/engine/syncer_util.h" #include "chrome/browser/sync/protocol/service_constants.h" #include "chrome/browser/sync/sessions/sync_session.h" @@ -124,7 +124,7 @@ void SyncerProtoUtil::AddRequestBirthday(syncable::Directory* dir, // static bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm, - AuthWatcher* auth_watcher, + sessions::SyncSession* session, const ClientToServerMessage& msg, ClientToServerResponse* response) { @@ -144,12 +144,9 @@ bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm, std::string new_token = http_response.update_client_auth_header; if (!new_token.empty()) { - // We could also do this in the SCM's PostBufferWithAuth. - // But then we could be in the middle of authentication, which seems - // like a bad time to update the token. A consequence of this is that - // we can't reset the cookie in response to auth attempts, but this - // should be OK. - auth_watcher->RenewAuthToken(new_token); + SyncerEvent event(SyncerEvent::UPDATED_TOKEN); + event.updated_token = new_token; + session->context()->syncer_event_channel()->Notify(event); } if (response->ParseFromString(rx)) { @@ -189,7 +186,7 @@ bool SyncerProtoUtil::PostClientToServerMessage( } if (!PostAndProcessHeaders(session->context()->connection_manager(), - session->context()->auth_watcher(), + session, msg, response)) { return false; diff --git a/chrome/browser/sync/engine/syncer_proto_util.h b/chrome/browser/sync/engine/syncer_proto_util.h index 39fcc5c..ca68ec3 100644 --- a/chrome/browser/sync/engine/syncer_proto_util.h +++ b/chrome/browser/sync/engine/syncer_proto_util.h @@ -105,7 +105,7 @@ class SyncerProtoUtil { // Post the message using the scm, and do some processing on the returned // headers. Decode the server response. static bool PostAndProcessHeaders(browser_sync::ServerConnectionManager* scm, - browser_sync::AuthWatcher* authwatcher, + sessions::SyncSession* session, const ClientToServerMessage& msg, sync_pb::ClientToServerResponse* response); diff --git a/chrome/browser/sync/engine/syncer_proto_util_unittest.cc b/chrome/browser/sync/engine/syncer_proto_util_unittest.cc index e6eb68b..57cae0a 100644 --- a/chrome/browser/sync/engine/syncer_proto_util_unittest.cc +++ b/chrome/browser/sync/engine/syncer_proto_util_unittest.cc @@ -182,7 +182,7 @@ TEST_F(SyncerProtoUtilTest, AddRequestBirthday) { class DummyConnectionManager : public browser_sync::ServerConnectionManager { public: DummyConnectionManager() - : ServerConnectionManager("unused", 0, false, "version", "id"), + : ServerConnectionManager("unused", 0, false, "version"), send_error_(false), access_denied_(false) {} diff --git a/chrome/browser/sync/engine/syncer_thread.cc b/chrome/browser/sync/engine/syncer_thread.cc index 800ddddb..9f369ed8 100644 --- a/chrome/browser/sync/engine/syncer_thread.cc +++ b/chrome/browser/sync/engine/syncer_thread.cc @@ -17,12 +17,10 @@ #include "base/rand_util.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "chrome/browser/sync/engine/auth_watcher.h" #include "chrome/browser/sync/engine/model_safe_worker.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/engine/syncer.h" #include "chrome/browser/sync/sessions/session_state.h" -#include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/common/chrome_switches.h" #include "jingle/notifier/listener/notification_constants.h" @@ -75,19 +73,12 @@ SyncerThread::SyncerThread(sessions::SyncSessionContext* context) syncer_long_poll_interval_seconds_(kDefaultLongPollIntervalSeconds), syncer_polling_interval_(kDefaultShortPollIntervalSeconds), syncer_max_interval_(kDefaultMaxPollIntervalMs), - directory_manager_hookup_(NULL), syncer_events_(NULL), session_context_(context), disable_idle_detection_(false) { DCHECK(context); syncer_event_relay_channel_.reset(new SyncerEventChannel()); - if (context->directory_manager()) { - directory_manager_hookup_.reset(NewEventListenerHookup( - context->directory_manager()->channel(), this, - &SyncerThread::HandleDirectoryManagerEvent)); - } - if (context->connection_manager()) WatchConnectionManager(context->connection_manager()); @@ -98,7 +89,6 @@ SyncerThread::~SyncerThread() { syncer_event_relay_channel_->Notify(SyncerEvent( SyncerEvent::SHUTDOWN_USE_WITH_CARE)); syncer_event_relay_channel_.reset(); - directory_manager_hookup_.reset(); syncer_events_.reset(); delete vault_.syncer_; CHECK(!thread_.IsRunning()); @@ -587,22 +577,18 @@ void SyncerThread::HandleChannelEvent(const SyncerEvent& event) { NudgeSyncImpl(event.nudge_delay_milliseconds, kUnknown); } -void SyncerThread::HandleDirectoryManagerEvent( - const syncable::DirectoryManagerEvent& event) { - LOG(INFO) << "Handling a directory manager event"; - if (syncable::DirectoryManagerEvent::OPENED == event.what_happened) { - AutoLock lock(lock_); - LOG(INFO) << "Syncer starting up for: " << event.dirname; - // The underlying database structure is ready, and we should create - // the syncer. - CHECK(vault_.syncer_ == NULL); - session_context_->set_account_name(event.dirname); - vault_.syncer_ = new Syncer(session_context_.get()); - - syncer_events_.reset( - session_context_->syncer_event_channel()->AddObserver(this)); - vault_field_changed_.Broadcast(); - } +void SyncerThread::CreateSyncer(const std::string& dirname) { + AutoLock lock(lock_); + LOG(INFO) << "Creating syncer up for: " << dirname; + // The underlying database structure is ready, and we should create + // the syncer. + CHECK(vault_.syncer_ == NULL); + session_context_->set_account_name(dirname); + vault_.syncer_ = new Syncer(session_context_.get()); + + syncer_events_.reset( + session_context_->syncer_event_channel()->AddObserver(this)); + vault_field_changed_.Broadcast(); } // Sets |*connected| to false if it is currently true but |code| suggests that diff --git a/chrome/browser/sync/engine/syncer_thread.h b/chrome/browser/sync/engine/syncer_thread.h index 8c71db4..158d759 100644 --- a/chrome/browser/sync/engine/syncer_thread.h +++ b/chrome/browser/sync/engine/syncer_thread.h @@ -29,11 +29,6 @@ class EventListenerHookup; -namespace syncable { -class DirectoryManager; -struct DirectoryManagerEvent; -} - namespace browser_sync { class ModelSafeWorker; @@ -138,6 +133,9 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>, virtual SyncerEventChannel* relay_channel(); + // Call this when a directory is opened + void CreateSyncer(const std::string& dirname); + // DDOS avoidance function. The argument and return value is in seconds static int GetRecommendedDelaySeconds(int base_delay_seconds); @@ -230,8 +228,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>, friend void* RunSyncerThread(void* syncer_thread); void* Run(); - void HandleDirectoryManagerEvent( - const syncable::DirectoryManagerEvent& event); void HandleChannelEvent(const SyncerEvent& event); // SyncSession::Delegate implementation. @@ -323,7 +319,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>, // this is called. void NudgeSyncImpl(int milliseconds_from_now, NudgeSource source); - scoped_ptr<EventListenerHookup> directory_manager_hookup_; scoped_ptr<ChannelHookup<SyncerEvent> > syncer_events_; #if defined(OS_LINUX) diff --git a/chrome/browser/sync/engine/syncer_thread_unittest.cc b/chrome/browser/sync/engine/syncer_thread_unittest.cc index 16328bd..ded07f0 100644 --- a/chrome/browser/sync/engine/syncer_thread_unittest.cc +++ b/chrome/browser/sync/engine/syncer_thread_unittest.cc @@ -66,7 +66,7 @@ class SyncerThreadWithSyncerTest : public testing::Test, metadb_.name())); worker_ = new ModelSafeWorker(); SyncSessionContext* context = new SyncSessionContext(connection_.get(), - NULL, metadb_.manager(), this); + metadb_.manager(), this); syncer_thread_ = new SyncerThread(context); syncer_event_hookup_.reset( syncer_thread_->relay_channel()->AddObserver(this)); @@ -217,12 +217,12 @@ class SyncShareIntercept }; TEST_F(SyncerThreadTest, Construction) { - SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL); + SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL); scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context)); } TEST_F(SyncerThreadTest, StartStop) { - SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL); + SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL); scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context)); EXPECT_TRUE(syncer_thread->Start()); EXPECT_TRUE(syncer_thread->Stop(2000)); @@ -247,7 +247,7 @@ TEST(SyncerThread, GetRecommendedDelay) { } TEST_F(SyncerThreadTest, CalculateSyncWaitTime) { - SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL); + SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL); scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context)); syncer_thread->DisableIdleDetection(); @@ -307,7 +307,7 @@ TEST_F(SyncerThreadTest, CalculateSyncWaitTime) { TEST_F(SyncerThreadTest, CalculatePollingWaitTime) { // Set up the environment. int user_idle_milliseconds_param = 0; - SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL); + SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL); scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context)); syncer_thread->DisableIdleDetection(); // Hold the lock to appease asserts in code. @@ -639,8 +639,8 @@ TEST_F(SyncerThreadWithSyncerTest, Polling) { syncer_thread()->SetSyncerShortPollInterval(poll_interval); EXPECT_TRUE(syncer_thread()->Start()); - // Calling Open() should cause the SyncerThread to create a Syncer. metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); TimeDelta two_polls = poll_interval + poll_interval; // We could theoretically return immediately from the wait if the interceptor @@ -673,6 +673,7 @@ TEST_F(SyncerThreadWithSyncerTest, Nudge) { PreventThreadFromPolling(); EXPECT_TRUE(syncer_thread()->Start()); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); const TimeDelta poll_interval = TimeDelta::FromMinutes(5); interceptor.WaitForSyncShare(1, poll_interval + poll_interval); @@ -697,6 +698,7 @@ TEST_F(SyncerThreadWithSyncerTest, Throttling) { EXPECT_TRUE(syncer_thread()->Start()); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); // Wait for some healthy syncing. interceptor.WaitForSyncShare(4, poll_interval + poll_interval); @@ -750,6 +752,7 @@ TEST_F(SyncerThreadWithSyncerTest, StopSyncPermanently) { EXPECT_TRUE(syncer_thread()->Start()); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); ASSERT_TRUE(sync_cycle_ended_event.TimedWait(max_wait_time_)); connection()->set_store_birthday("NotYourLuckyDay"); @@ -765,6 +768,7 @@ TEST_F(SyncerThreadWithSyncerTest, AuthInvalid) { syncer_thread()->SetSyncerShortPollInterval(poll_interval); EXPECT_TRUE(syncer_thread()->Start()); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); // Wait for some healthy syncing. interceptor.WaitForSyncShare(2, TimeDelta::FromSeconds(10)); @@ -826,6 +830,7 @@ TEST_F(SyncerThreadWithSyncerTest, FLAKY_Pause) { Field(&SyncerEvent::what_happened, SyncerEvent::SYNCER_THREAD_EXITING))); ASSERT_TRUE(syncer_thread()->Start()); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); ASSERT_TRUE(sync_cycle_ended_event.TimedWait(max_wait_time_)); // Request a pause. @@ -869,6 +874,7 @@ TEST_F(SyncerThreadWithSyncerTest, StartWhenNotConnected) { connection()->SetServerNotReachable(); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); // Syncer thread will always go through once cycle at the start, // then it will wait for a connection. @@ -923,6 +929,8 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_PauseWhenNotConnected) { Field(&SyncerEvent::what_happened, SyncerEvent::WAITING_FOR_CONNECTION))). WillOnce(SignalEvent(&event)); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); + ASSERT_TRUE(syncer_thread()->Start()); ASSERT_TRUE(sync_cycle_ended_event.TimedWait(max_wait_time_)); ASSERT_TRUE(event.TimedWait(max_wait_time_)); @@ -994,6 +1002,7 @@ TEST_F(SyncerThreadWithSyncerTest, PauseResumeWhenNotRunning) { // Pause the thread then start the syncer. ASSERT_TRUE(Pause(&listener)); metadb()->Open(); + syncer_thread()->CreateSyncer(metadb()->name()); ASSERT_TRUE(syncer_thread()->Start()); // Resume and let the syncer cycle. diff --git a/chrome/browser/sync/engine/syncer_types.h b/chrome/browser/sync/engine/syncer_types.h index 19be54e..0805c89 100644 --- a/chrome/browser/sync/engine/syncer_types.h +++ b/chrome/browser/sync/engine/syncer_types.h @@ -78,6 +78,8 @@ struct SyncerEvent { STATUS_CHANGED, + UPDATED_TOKEN, // new token in updated_token + // Take care not to wait in shutdown handlers for the syncer to stop as it // causes a race in the event system. Use SyncerShutdownEvent instead. SHUTDOWN_USE_WITH_CARE, @@ -143,6 +145,9 @@ struct SyncerEvent { // How many milliseconds later should the syncer kick in? For // REQUEST_SYNC_NUDGE only. int nudge_delay_milliseconds; + + // Update-Client-Auth returns a new token for sync use. + std::string updated_token; }; struct SyncerShutdownEvent { diff --git a/chrome/browser/sync/engine/syncer_unittest.cc b/chrome/browser/sync/engine/syncer_unittest.cc index 0d9ab8e..74e5122 100644 --- a/chrome/browser/sync/engine/syncer_unittest.cc +++ b/chrome/browser/sync/engine/syncer_unittest.cc @@ -168,7 +168,7 @@ class SyncerTest : public testing::Test, new MockConnectionManager(syncdb_.manager(), syncdb_.name())); EnableDatatype(syncable::BOOKMARKS); worker_ = new ModelSafeWorker(); - context_.reset(new SyncSessionContext(mock_server_.get(), NULL, + context_.reset(new SyncSessionContext(mock_server_.get(), syncdb_.manager(), this)); context_->set_account_name(syncdb_.name()); ASSERT_FALSE(context_->syncer_event_channel()); |