diff options
author | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-08 00:06:34 +0000 |
---|---|---|
committer | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-08 00:06:34 +0000 |
commit | 478dbee251a327e6e678f15512f204a67b2f7f1f (patch) | |
tree | 151dd1e2887711e299c08ce8872c382a56452778 /chrome/browser/sync/engine | |
parent | 3f4e4665beaa1396d970e4317cf04194197d8a08 (diff) | |
download | chromium_src-478dbee251a327e6e678f15512f204a67b2f7f1f.zip chromium_src-478dbee251a327e6e678f15512f204a67b2f7f1f.tar.gz chromium_src-478dbee251a327e6e678f15512f204a67b2f7f1f.tar.bz2 |
New authorization framework for sync.
To quote chron's original patch (http://codereview.chromium.org/3148036/show)
<blockquote>
This patch removes: authenticator.cc, auth_watcher.cc
removes calls to user_settings.cc, removes an authenticate PB request to the server, and moves token storage into the Chrome TokenService. This patch introduces the SigninManager, which is an interim solution for user management prior to moving the system into chrome.
Other changes include removing the dependency on the sync backend to be running while the sync wizard is intially displayed. This means that the backend can be brought up in response to credentials becoming available. The backend now is always provided credentials on startup. If an auth error occurs, it propogates it up via a notification. Some event handlers were removed and streamlined for more straightforward sync system startup.
</blockquote>
BUG=51001, 50293, 35158
TEST=Unit tests && Start up sync, log in, log out, run with expired credentials, run with new gaia credentials, run with gaia credentials updated while system is syncing. Try logging in with incorrect username. Trigger CAPTCHA. Try logging out and in repeatedly. Check about:sync works. Try going offline and back online again. Expire gaia credentials and try renewing it with the UI dialog.
Review URL: http://codereview.chromium.org/3305003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58778 0039d316-1c4b-4281-b951-d872f2087c98
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()); |