summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 01:38:35 +0000
committerjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 01:38:35 +0000
commit265d8c32bd4dbb4b1a142c8204b434a03e8a8c8f (patch)
tree105095d5eead4db62bbf60ed0b3f1d243b202e76 /chrome
parent8b20191a72da085319a68e4953e9f2b355218825 (diff)
downloadchromium_src-265d8c32bd4dbb4b1a142c8204b434a03e8a8c8f.zip
chromium_src-265d8c32bd4dbb4b1a142c8204b434a03e8a8c8f.tar.gz
chromium_src-265d8c32bd4dbb4b1a142c8204b434a03e8a8c8f.tar.bz2
Revert 58778 - 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 TBR=johnnyg@chromium.org Review URL: http://codereview.chromium.org/3310019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58782 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc4
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.mm2
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.cc2
-rw-r--r--chrome/browser/gtk/options/content_page_gtk.cc2
-rw-r--r--chrome/browser/net/gaia/token_service.cc30
-rw-r--r--chrome/browser/net/gaia/token_service.h19
-rw-r--r--chrome/browser/net/gaia/token_service_unittest.cc126
-rw-r--r--chrome/browser/net/gaia/token_service_unittest.h130
-rw-r--r--chrome/browser/prefs/browser_prefs.cc2
-rw-r--r--chrome/browser/profile.cc5
-rw-r--r--chrome/browser/profile.h5
-rw-r--r--chrome/browser/profile_impl.cc13
-rw-r--r--chrome/browser/profile_impl.h4
-rw-r--r--chrome/browser/sync/abstract_profile_sync_service_test.h4
-rw-r--r--chrome/browser/sync/engine/all_status.cc47
-rw-r--r--chrome/browser/sync/engine/all_status.h3
-rw-r--r--chrome/browser/sync/engine/auth_watcher.cc352
-rw-r--r--chrome/browser/sync/engine/auth_watcher.h222
-rw-r--r--chrome/browser/sync/engine/auth_watcher_unittest.cc235
-rw-r--r--chrome/browser/sync/engine/authenticator.cc110
-rw-r--r--chrome/browser/sync/engine/authenticator.h105
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.cc13
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.h18
-rw-r--r--chrome/browser/sync/engine/net/syncapi_server_connection_manager.h4
-rw-r--r--chrome/browser/sync/engine/syncapi.cc450
-rw-r--r--chrome/browser/sync/engine/syncapi.h63
-rw-r--r--chrome/browser/sync/engine/syncapi_unittest.cc2
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util.cc15
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util.h2
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util_unittest.cc2
-rw-r--r--chrome/browser/sync/engine/syncer_thread.cc38
-rw-r--r--chrome/browser/sync/engine/syncer_thread.h11
-rw-r--r--chrome/browser/sync/engine/syncer_thread_unittest.cc21
-rw-r--r--chrome/browser/sync/engine/syncer_types.h5
-rw-r--r--chrome/browser/sync/engine/syncer_unittest.cc2
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc61
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h54
-rw-r--r--chrome/browser/sync/profile_sync_factory.h5
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.cc6
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.h5
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl_unittest.cc14
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.h4
-rw-r--r--chrome/browser/sync/profile_sync_service.cc275
-rw-r--r--chrome/browser/sync/profile_sync_service.h53
-rw-r--r--chrome/browser/sync/profile_sync_service_autofill_unittest.cc10
-rw-r--r--chrome/browser/sync/profile_sync_service_mock.h1
-rw-r--r--chrome/browser/sync/profile_sync_service_password_unittest.cc10
-rw-r--r--chrome/browser/sync/profile_sync_service_preference_unittest.cc5
-rw-r--r--chrome/browser/sync/profile_sync_service_session_unittest.cc5
-rw-r--r--chrome/browser/sync/profile_sync_service_startup_unittest.cc64
-rw-r--r--chrome/browser/sync/profile_sync_service_typed_url_unittest.cc10
-rw-r--r--chrome/browser/sync/profile_sync_service_unittest.cc35
-rw-r--r--chrome/browser/sync/sessions/sync_session_context.h7
-rw-r--r--chrome/browser/sync/sessions/sync_session_unittest.cc8
-rw-r--r--chrome/browser/sync/signin_manager.cc95
-rw-r--r--chrome/browser/sync/signin_manager.h81
-rw-r--r--chrome/browser/sync/signin_manager_unittest.cc93
-rw-r--r--chrome/browser/sync/sync_setup_wizard_unittest.cc2
-rw-r--r--chrome/browser/sync/sync_ui_util.cc4
-rw-r--r--chrome/browser/sync/syncable/directory_manager.cc11
-rw-r--r--chrome/browser/sync/syncable/directory_manager.h3
-rw-r--r--chrome/browser/sync/test_profile_sync_service.h9
-rw-r--r--chrome/browser/sync/token_migrator.cc53
-rw-r--r--chrome/browser/sync/token_migrator.h53
-rw-r--r--chrome/browser/views/options/content_page_view.cc2
-rw-r--r--chrome/chrome.gyp4
-rw-r--r--chrome/chrome_browser.gypi26
-rw-r--r--chrome/chrome_tests.gypi4
-rw-r--r--chrome/common/notification_type.h31
-rw-r--r--chrome/common/pref_names.cc7
-rw-r--r--chrome/common/pref_names.h2
-rw-r--r--chrome/test/live_sync/live_sync_test.cc10
-rw-r--r--chrome/test/live_sync/offline_sync_test.cc29
-rw-r--r--chrome/test/live_sync/profile_sync_service_test_harness.cc71
-rw-r--r--chrome/test/live_sync/profile_sync_service_test_harness.h12
-rw-r--r--chrome/test/live_sync/single_client_live_bookmarks_sync_test.cc31
-rw-r--r--chrome/test/profile_mock.h1
-rw-r--r--chrome/test/sync/engine/mock_connection_manager.cc2
-rw-r--r--chrome/test/sync/engine/syncer_command_test.h5
-rw-r--r--chrome/test/testing_profile.cc5
-rw-r--r--chrome/test/testing_profile.h3
81 files changed, 2035 insertions, 1314 deletions
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index c371880..9ec92d02 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -181,10 +181,6 @@ void LoginUtilsImpl::CompleteLogin(const std::string& username,
token_service->StartFetchingTokens();
}
- // Set the CrOS user by getting this constructor run with the
- // user's email on first retrieval.
- profile->GetProfileSyncService(username);
-
// Attempt to take ownership; this will fail if device is already owned.
OwnershipService::GetSharedInstance()->StartTakeOwnershipAttempt(
UserManager::Get()->logged_in_user().email());
diff --git a/chrome/browser/cocoa/preferences_window_controller.mm b/chrome/browser/cocoa/preferences_window_controller.mm
index 58df847..a2ab751 100644
--- a/chrome/browser/cocoa/preferences_window_controller.mm
+++ b/chrome/browser/cocoa/preferences_window_controller.mm
@@ -1350,7 +1350,7 @@ const int kDisabledIndex = 1;
} else {
// Otherwise, the sync button was a "sync my bookmarks" button.
// Kick off the sync setup process.
- syncService_->ShowLoginDialog(NULL);
+ syncService_->EnableForUser(NULL);
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
}
}
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
index 3ecd267..6970816 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
@@ -168,7 +168,7 @@ void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) {
} else {
// User clicked the 'Start now' link to begin syncing.
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_NTP);
- sync_service_->ShowLoginDialog(NULL);
+ sync_service_->EnableForUser(NULL);
}
}
diff --git a/chrome/browser/gtk/options/content_page_gtk.cc b/chrome/browser/gtk/options/content_page_gtk.cc
index 9d6d72b..13b2cea 100644
--- a/chrome/browser/gtk/options/content_page_gtk.cc
+++ b/chrome/browser/gtk/options/content_page_gtk.cc
@@ -595,7 +595,7 @@ void ContentPageGtk::OnSyncStartStopButtonClicked(GtkWidget* widget) {
gtk_util::ShowDialog(dialog);
return;
} else {
- sync_service_->ShowLoginDialog(NULL);
+ sync_service_->EnableForUser(NULL);
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
}
}
diff --git a/chrome/browser/net/gaia/token_service.cc b/chrome/browser/net/gaia/token_service.cc
index b61ab62..b46868f 100644
--- a/chrome/browser/net/gaia/token_service.cc
+++ b/chrome/browser/net/gaia/token_service.cc
@@ -13,8 +13,6 @@
#include "chrome/common/notification_service.h"
// Unfortunately kNumServices must be defined in the .h.
-// TODO(chron): Sync doesn't use the TalkToken anymore so we can stop
-// requesting it.
const char* TokenService::kServices[] = {GaiaConstants::kSyncService,
GaiaConstants::kTalkService};
TokenService::TokenService()
@@ -31,18 +29,12 @@ void TokenService::Initialize(const char* const source,
Profile* profile) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (!source_.empty()) {
- // Already initialized.
- return;
- }
+
getter_ = profile->GetRequestContext();
// Since the user can create a bookmark in incognito, sync may be running.
// Thus we have to go for explicit access.
web_data_service_ = profile->GetWebDataService(Profile::EXPLICIT_ACCESS);
source_ = std::string(source);
- registrar_.Add(this,
- NotificationType::TOKEN_UPDATED,
- NotificationService::AllSources());
}
void TokenService::ResetCredentialsInMemory() {
@@ -155,12 +147,6 @@ void TokenService::FireTokenRequestFailedNotification(
Details<const TokenRequestFailedDetails>(&details));
}
-void TokenService::IssueAuthTokenForTest(const std::string& service,
- const std::string& auth_token) {
- token_map_[service] = auth_token;
- FireTokenAvailableNotification(service, auth_token);
-}
-
void TokenService::OnIssueAuthTokenSuccess(const std::string& service,
const std::string& auth_token) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
@@ -192,11 +178,6 @@ void TokenService::OnWebDataServiceRequestDone(WebDataService::Handle h,
result);
LoadTokensIntoMemory(token_result->GetValue(), &token_map_);
}
-
- NotificationService::current()->Notify(
- NotificationType::TOKEN_LOADING_FINISHED,
- Source<TokenService>(this),
- NotificationService::NoDetails());
}
// Load tokens from the db_token map into the in memory token map.
@@ -226,12 +207,3 @@ void TokenService::LoadTokensIntoMemory(
}
}
}
-
-void TokenService::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NotificationType::TOKEN_UPDATED);
- TokenAvailableDetails* tok_details =
- Details<TokenAvailableDetails>(details).ptr();
- OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token());
-}
diff --git a/chrome/browser/net/gaia/token_service.h b/chrome/browser/net/gaia/token_service.h
index 006423f..20ca12d 100644
--- a/chrome/browser/net/gaia/token_service.h
+++ b/chrome/browser/net/gaia/token_service.h
@@ -37,15 +37,12 @@
#include <map>
#include <string>
-
-#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/gaia_authenticator2.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
+#include "base/gtest_prod_util.h"
class URLRequestContextGetter;
class Profile;
@@ -53,8 +50,7 @@ class Profile;
// The TokenService is a Profile member, so all calls are expected
// from the UI thread.
class TokenService : public GaiaAuthConsumer,
- public WebDataServiceConsumer,
- public NotificationObserver {
+ public WebDataServiceConsumer {
public:
TokenService();
virtual ~TokenService();
@@ -127,10 +123,6 @@ class TokenService : public GaiaAuthConsumer,
const bool HasTokenForService(const char* const service) const;
const std::string& GetTokenForService(const char* const service) const;
- // For tests only. Doesn't save to the WebDB.
- void IssueAuthTokenForTest(const std::string& service,
- const std::string& auth_token);
-
// GaiaAuthConsumer implementation.
virtual void OnIssueAuthTokenSuccess(const std::string& service,
const std::string& auth_token);
@@ -141,11 +133,6 @@ class TokenService : public GaiaAuthConsumer,
virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
const WDTypedResult* result);
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
private:
void FireTokenAvailableNotification(const std::string& service,
@@ -182,8 +169,6 @@ class TokenService : public GaiaAuthConsumer,
// Map from service to token.
std::map<std::string, std::string> token_map_;
- NotificationRegistrar registrar_;
-
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryBasic);
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryAdvanced);
diff --git a/chrome/browser/net/gaia/token_service_unittest.cc b/chrome/browser/net/gaia/token_service_unittest.cc
index ce0096b..512efff 100644
--- a/chrome/browser/net/gaia/token_service_unittest.cc
+++ b/chrome/browser/net/gaia/token_service_unittest.cc
@@ -4,18 +4,127 @@
//
// This file defines a unit test for the profile's token service.
-#include "chrome/browser/net/gaia/token_service_unittest.h"
-
+#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/password_manager/encryptor.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/gaia_authenticator2_unittest.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
+#include "chrome/test/signaling_task.h"
+#include "chrome/test/test_notification_tracker.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TestNotificationTracker doesn't do a deep copy on the notification details.
+// We have to in order to read it out, or we have a bad ptr, since the details
+// are a reference on the stack.
+class TokenAvailableTracker : public TestNotificationTracker {
+ public:
+ const TokenService::TokenAvailableDetails& get_last_token_details() {
+ return details_;
+ }
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ TestNotificationTracker::Observe(type, source, details);
+ if (type == NotificationType::TOKEN_AVAILABLE) {
+ Details<const TokenService::TokenAvailableDetails> full = details;
+ details_ = *full.ptr();
+ }
+ }
+
+ TokenService::TokenAvailableDetails details_;
+};
+
+class TokenFailedTracker : public TestNotificationTracker {
+ public:
+ const TokenService::TokenRequestFailedDetails& get_last_token_details() {
+ return details_;
+ }
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ TestNotificationTracker::Observe(type, source, details);
+ if (type == NotificationType::TOKEN_REQUEST_FAILED) {
+ Details<const TokenService::TokenRequestFailedDetails> full = details;
+ details_ = *full.ptr();
+ }
+ }
-class TokenServiceTest : public TokenServiceTestHarness {
+ TokenService::TokenRequestFailedDetails details_;
+};
+
+class TokenServiceTest : public testing::Test {
public:
+ TokenServiceTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_),
+ db_thread_(ChromeThread::DB) {
+ }
+
virtual void SetUp() {
- TokenServiceTestHarness::SetUp();
+#if defined(OS_MACOSX)
+ Encryptor::UseMockKeychain(true);
+#endif
+ credentials_.sid = "sid";
+ credentials_.lsid = "lsid";
+ credentials_.token = "token";
+ credentials_.data = "data";
+
+ ASSERT_TRUE(db_thread_.Start());
+
+ profile_.reset(new TestingProfile());
+ profile_->CreateWebDataService(false);
+ WaitForDBLoadCompletion();
+
+ success_tracker_.ListenFor(NotificationType::TOKEN_AVAILABLE,
+ Source<TokenService>(&service_));
+ failure_tracker_.ListenFor(NotificationType::TOKEN_REQUEST_FAILED,
+ Source<TokenService>(&service_));
+
+ service_.Initialize("test", profile_.get());
service_.UpdateCredentials(credentials_);
+
+ URLFetcher::set_factory(NULL);
+ }
+
+ virtual void TearDown() {
+ // You have to destroy the profile before the db_thread_ stops.
+ if (profile_.get()) {
+ profile_.reset(NULL);
+ }
+
+ db_thread_.Stop();
+ MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
+ MessageLoop::current()->Run();
+ }
+
+ void WaitForDBLoadCompletion() {
+ // The WebDB does all work on the DB thread. This will add an event
+ // to the end of the DB thread, so when we reach this task, all DB
+ // operations should be complete.
+ WaitableEvent done(false, false);
+ ChromeThread::PostTask(
+ ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
+ done.Wait();
+
+ // Notifications should be returned from the DB thread onto the UI thread.
+ message_loop_.RunAllPending();
}
+
+ MessageLoopForUI message_loop_;
+ ChromeThread ui_thread_; // Mostly so DCHECKS pass.
+ ChromeThread db_thread_; // WDS on here
+
+ TokenService service_;
+ TokenAvailableTracker success_tracker_;
+ TokenFailedTracker failure_tracker_;
+ GaiaAuthConsumer::ClientLoginResult credentials_;
+ scoped_ptr<TestingProfile> profile_;
};
TEST_F(TokenServiceTest, SanityCheck) {
@@ -36,7 +145,8 @@ TEST_F(TokenServiceTest, NotificationSuccess) {
EXPECT_EQ(1U, success_tracker_.size());
EXPECT_EQ(0U, failure_tracker_.size());
- TokenService::TokenAvailableDetails details = success_tracker_.details();
+ TokenService::TokenAvailableDetails details =
+ success_tracker_.get_last_token_details();
// MSVC doesn't like this comparison as EQ.
EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
EXPECT_EQ(details.token(), "token");
@@ -50,7 +160,8 @@ TEST_F(TokenServiceTest, NotificationFailed) {
EXPECT_EQ(0U, success_tracker_.size());
EXPECT_EQ(1U, failure_tracker_.size());
- TokenService::TokenRequestFailedDetails details = failure_tracker_.details();
+ TokenService::TokenRequestFailedDetails details =
+ failure_tracker_.get_last_token_details();
// MSVC doesn't like this comparison as EQ.
EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
@@ -164,7 +275,8 @@ TEST_F(TokenServiceTest, LoadTokensIntoMemoryBasic) {
service_.LoadTokensIntoMemory(db_tokens, &memory_tokens);
EXPECT_EQ(1U, success_tracker_.size());
- TokenService::TokenAvailableDetails details = success_tracker_.details();
+ TokenService::TokenAvailableDetails details =
+ success_tracker_.get_last_token_details();
// MSVC doesn't like this comparison as EQ.
EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
EXPECT_EQ(details.token(), "token");
diff --git a/chrome/browser/net/gaia/token_service_unittest.h b/chrome/browser/net/gaia/token_service_unittest.h
deleted file mode 100644
index ad46138..0000000
--- a/chrome/browser/net/gaia/token_service_unittest.h
+++ /dev/null
@@ -1,130 +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.
-//
-// This file defines a unit test harness for the profile's token service.
-
-#ifndef CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_UNITTEST_H_
-#define CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_UNITTEST_H_
-#pragma once
-
-#include "chrome/browser/net/gaia/token_service.h"
-#include "chrome/browser/password_manager/encryptor.h"
-#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/common/net/gaia/gaia_auth_consumer.h"
-#include "chrome/test/signaling_task.h"
-#include "chrome/test/test_notification_tracker.h"
-#include "chrome/test/testing_profile.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// TestNotificationTracker doesn't do a deep copy on the notification details.
-// We have to in order to read it out, or we have a bad ptr, since the details
-// are a reference on the stack.
-class TokenAvailableTracker : public TestNotificationTracker {
- public:
- const TokenService::TokenAvailableDetails& details() {
- return details_;
- }
-
- private:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- TestNotificationTracker::Observe(type, source, details);
- if (type == NotificationType::TOKEN_AVAILABLE) {
- Details<const TokenService::TokenAvailableDetails> full = details;
- details_ = *full.ptr();
- }
- }
-
- TokenService::TokenAvailableDetails details_;
-};
-
-class TokenFailedTracker : public TestNotificationTracker {
- public:
- const TokenService::TokenRequestFailedDetails& details() {
- return details_;
- }
-
- private:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- TestNotificationTracker::Observe(type, source, details);
- if (type == NotificationType::TOKEN_REQUEST_FAILED) {
- Details<const TokenService::TokenRequestFailedDetails> full = details;
- details_ = *full.ptr();
- }
- }
-
- TokenService::TokenRequestFailedDetails details_;
-};
-
-class TokenServiceTestHarness : public testing::Test {
- public:
- TokenServiceTestHarness()
- : ui_thread_(ChromeThread::UI, &message_loop_),
- db_thread_(ChromeThread::DB) {
- }
-
- virtual void SetUp() {
-#if defined(OS_MACOSX)
- Encryptor::UseMockKeychain(true);
-#endif
- credentials_.sid = "sid";
- credentials_.lsid = "lsid";
- credentials_.token = "token";
- credentials_.data = "data";
-
- ASSERT_TRUE(db_thread_.Start());
-
- profile_.reset(new TestingProfile());
- profile_->CreateWebDataService(false);
- WaitForDBLoadCompletion();
-
- success_tracker_.ListenFor(NotificationType::TOKEN_AVAILABLE,
- Source<TokenService>(&service_));
- failure_tracker_.ListenFor(NotificationType::TOKEN_REQUEST_FAILED,
- Source<TokenService>(&service_));
-
- service_.Initialize("test", profile_.get());
-
- URLFetcher::set_factory(NULL);
- }
-
- virtual void TearDown() {
- // You have to destroy the profile before the db_thread_ stops.
- if (profile_.get()) {
- profile_.reset(NULL);
- }
-
- db_thread_.Stop();
- MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
- MessageLoop::current()->Run();
- }
-
- void WaitForDBLoadCompletion() {
- // The WebDB does all work on the DB thread. This will add an event
- // to the end of the DB thread, so when we reach this task, all DB
- // operations should be complete.
- WaitableEvent done(false, false);
- ChromeThread::PostTask(
- ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
- done.Wait();
-
- // Notifications should be returned from the DB thread onto the UI thread.
- message_loop_.RunAllPending();
- }
-
- MessageLoopForUI message_loop_;
- ChromeThread ui_thread_; // Mostly so DCHECKS pass.
- ChromeThread db_thread_; // WDS on here
-
- TokenService service_;
- TokenAvailableTracker success_tracker_;
- TokenFailedTracker failure_tracker_;
- GaiaAuthConsumer::ClientLoginResult credentials_;
- scoped_ptr<TestingProfile> profile_;
-};
-
-#endif // CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_UNITTEST_H_
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 075cbf1..2b37c26 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -42,7 +42,6 @@
#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/ssl/ssl_manager.h"
-#include "chrome/browser/sync/signin_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/pinned_tab_codec.h"
#include "chrome/browser/task_manager.h"
@@ -140,7 +139,6 @@ void RegisterUserPrefs(PrefService* user_prefs) {
#endif
BackgroundContentsService::RegisterUserPrefs(user_prefs);
CookiePromptModalDialog::RegisterUserPrefs(user_prefs);
- SigninManager::RegisterUserPrefs(user_prefs);
}
} // namespace browser
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index b2d7eba..5c3669c 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -444,11 +444,6 @@ class OffTheRecordProfileImpl : public Profile,
return NULL;
}
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_user) {
- return NULL;
- }
-
virtual CloudPrintProxyService* GetCloudPrintProxyService() {
return NULL;
}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 68eec93..d876d8c 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -377,11 +377,6 @@ class Profile {
// Returns the ProfileSyncService, creating if not yet created.
virtual ProfileSyncService* GetProfileSyncService() = 0;
- // Returns the ProfileSyncService, creating if not yet created, with
- // the specified CrOS username.
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_user) = 0;
-
// Returns the CloudPrintProxyService, creating if not yet created.
virtual CloudPrintProxyService* GetCloudPrintProxyService() = 0;
diff --git a/chrome/browser/profile_impl.cc b/chrome/browser/profile_impl.cc
index ff6a8da..6a7cb51 100644
--- a/chrome/browser/profile_impl.cc
+++ b/chrome/browser/profile_impl.cc
@@ -479,7 +479,6 @@ ProfileImpl::~ProfileImpl() {
// Delete the NTP resource cache so we can unregister pref observers.
ntp_resource_cache_.reset();
- // The sync service needs to be deleted before the services it calls.
sync_service_.reset();
// Both HistoryService and WebDataService maintain threads for background
@@ -1236,16 +1235,10 @@ TokenService* ProfileImpl::GetTokenService() {
}
ProfileSyncService* ProfileImpl::GetProfileSyncService() {
- return GetProfileSyncService("");
-}
-
-ProfileSyncService* ProfileImpl::GetProfileSyncService(
- const std::string& cros_user) {
-
if (!ProfileSyncService::IsSyncEnabled())
return NULL;
if (!sync_service_.get())
- InitSyncService(cros_user);
+ InitSyncService();
return sync_service_.get();
}
@@ -1255,11 +1248,11 @@ CloudPrintProxyService* ProfileImpl::GetCloudPrintProxyService() {
return cloud_print_proxy_service_.get();
}
-void ProfileImpl::InitSyncService(const std::string& cros_user) {
+void ProfileImpl::InitSyncService() {
profile_sync_factory_.reset(
new ProfileSyncFactoryImpl(this, CommandLine::ForCurrentProcess()));
sync_service_.reset(
- profile_sync_factory_->CreateProfileSyncService(cros_user));
+ profile_sync_factory_->CreateProfileSyncService());
sync_service_->Initialize();
}
diff --git a/chrome/browser/profile_impl.h b/chrome/browser/profile_impl.h
index 79e4438..d3831cb 100644
--- a/chrome/browser/profile_impl.h
+++ b/chrome/browser/profile_impl.h
@@ -100,10 +100,8 @@ class ProfileImpl : public Profile,
virtual FilePath last_selected_directory();
virtual void set_last_selected_directory(const FilePath& path);
virtual ProfileSyncService* GetProfileSyncService();
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_user);
virtual TokenService* GetTokenService();
- void InitSyncService(const std::string& cros_user);
+ void InitSyncService();
virtual CloudPrintProxyService* GetCloudPrintProxyService();
void InitCloudPrintProxyService();
virtual ChromeBlobStorageContext* GetBlobStorageContext();
diff --git a/chrome/browser/sync/abstract_profile_sync_service_test.h b/chrome/browser/sync/abstract_profile_sync_service_test.h
index 73d59ef..7f81ca2 100644
--- a/chrome/browser/sync/abstract_profile_sync_service_test.h
+++ b/chrome/browser/sync/abstract_profile_sync_service_test.h
@@ -12,7 +12,6 @@
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/password_model_associator.h"
@@ -56,7 +55,7 @@ class ProfileSyncServiceTestHelper {
UserShare* user_share = service->backend()->GetUserShareHandle();
DirectoryManager* dir_manager = user_share->dir_manager.get();
- ScopedDirLookup dir(dir_manager, user_share->name);
+ ScopedDirLookup dir(dir_manager, user_share->authenticated_name);
if (!dir.good())
return false;
@@ -121,7 +120,6 @@ class AbstractProfileSyncServiceTest : public testing::Test {
MessageLoopForUI message_loop_;
ChromeThread ui_thread_;
ProfileSyncFactoryMock factory_;
- TokenService token_service_;
scoped_ptr<TestProfileSyncService> service_;
TestIdFactory ids_;
};
diff --git a/chrome/browser/sync/engine/all_status.cc b/chrome/browser/sync/engine/all_status.cc
index 72e1f6d..178fe7f 100644
--- a/chrome/browser/sync/engine/all_status.cc
+++ b/chrome/browser/sync/engine/all_status.cc
@@ -8,6 +8,7 @@
#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"
@@ -47,6 +48,11 @@ 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));
@@ -93,6 +99,10 @@ 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;
@@ -143,6 +153,34 @@ 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) {
@@ -184,15 +222,6 @@ 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 b843a1a..772f40d 100644
--- a/chrome/browser/sync/engine/all_status.h
+++ b/chrome/browser/sync/engine/all_status.h
@@ -89,6 +89,7 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> {
AllStatus();
~AllStatus();
+ void WatchConnectionManager(ServerConnectionManager* conn_mgr);
void HandleServerConnectionEvent(const ServerConnectionEvent& event);
void HandleAuthWatcherEvent(const AuthWatcherEvent& event);
@@ -115,6 +116,7 @@ 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;
@@ -123,6 +125,7 @@ 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
new file mode 100644
index 0000000..b414e18
--- /dev/null
+++ b/chrome/browser/sync/engine/auth_watcher.cc
@@ -0,0 +1,352 @@
+// 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
new file mode 100644
index 0000000..da90f95
--- /dev/null
+++ b/chrome/browser/sync/engine/auth_watcher.h
@@ -0,0 +1,222 @@
+// 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
new file mode 100644
index 0000000..cc840c7
--- /dev/null
+++ b/chrome/browser/sync/engine/auth_watcher_unittest.cc
@@ -0,0 +1,235 @@
+// 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
new file mode 100644
index 0000000..eec7af3
--- /dev/null
+++ b/chrome/browser/sync/engine/authenticator.cc
@@ -0,0 +1,110 @@
+// 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(&params, 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
new file mode 100644
index 0000000..1abca3c
--- /dev/null
+++ b/chrome/browser/sync/engine/authenticator.h
@@ -0,0 +1,105 @@
+// 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 6d35811..4953836 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.cc
+++ b/chrome/browser/sync/engine/net/server_connection_manager.cc
@@ -135,9 +135,11 @@ ServerConnectionManager::ServerConnectionManager(
const string& server,
int port,
bool use_ssl,
- const string& user_agent)
+ const string& user_agent,
+ const string& client_id)
: sync_server_(server),
sync_server_port_(port),
+ client_id_(client_id),
user_agent_(user_agent),
use_ssl_(use_ssl),
proto_sync_path_(kSyncServerSyncPath),
@@ -161,6 +163,7 @@ void ServerConnectionManager::NotifyStatusChanged() {
channel_->NotifyListeners(event);
}
+// Uses currently set auth token. Set by AuthWatcher.
bool ServerConnectionManager::PostBufferWithCachedAuth(
const PostBufferParams* params, ScopedServerStatusWatcher* watcher) {
string path =
@@ -168,6 +171,14 @@ 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 526dc8e..602116a 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.h
+++ b/chrome/browser/sync/engine/net/server_connection_manager.h
@@ -213,7 +213,8 @@ class ServerConnectionManager {
ServerConnectionManager(const std::string& server,
int port,
bool use_ssl,
- const std::string& user_agent);
+ const std::string& user_agent,
+ const std::string& client_id);
virtual ~ServerConnectionManager();
@@ -224,6 +225,14 @@ 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);
@@ -280,11 +289,6 @@ 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_);
@@ -329,7 +333,7 @@ class ServerConnectionManager {
int sync_server_port_;
// The unique id of the user's client.
- std::string client_id_;
+ const 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 4108f9a..67424b9 100644
--- a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h
+++ b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h
@@ -51,8 +51,10 @@ 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),
+ : ServerConnectionManager(server, port, use_ssl, client_version,
+ client_id),
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 15e0e8d..00d1c4f 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -25,6 +25,7 @@
#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"
@@ -48,6 +49,7 @@
#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"
@@ -59,15 +61,17 @@
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;
@@ -906,6 +910,7 @@ 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),
@@ -924,25 +929,40 @@ 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 SyncCredentials& credentials,
+ const std::string& lsid,
const bool use_chrome_async_socket,
const bool try_ssltcp_first,
browser_sync::NotificationMethod notification_method,
const std::string& restored_key_for_bootstrapping);
-
- // 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 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);
// Tell the sync engine to start the syncing process.
void StartSyncing();
@@ -967,17 +987,20 @@ class SyncManager::SyncInternal
// This listener is called by the syncer channel for all syncer events.
virtual void HandleChannelEvent(const SyncerEvent& event);
- // Listens for notifications from the ServerConnectionManager
- void HandleServerConnectionEvent(const ServerConnectionEvent& 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);
- // Open the directory named with username_for_share
- bool OpenDirectory();
+ // Listen here for directory opened events.
+ void HandleDirectoryManagerEvent(
+ const syncable::DirectoryManagerEvent& event);
// 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);
@@ -993,13 +1016,14 @@ 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_.name;
+ return share_.authenticated_name;
}
// Note about SyncManager::Status implementation: Status is a trimmed
@@ -1054,6 +1078,21 @@ 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();
@@ -1132,6 +1171,10 @@ 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.
@@ -1152,6 +1195,13 @@ 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
@@ -1163,12 +1213,20 @@ 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_;
@@ -1203,11 +1261,17 @@ 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 SyncCredentials& credentials,
+ const char* lsid,
bool use_chrome_async_socket,
bool try_ssltcp_first,
browser_sync::NotificationMethod notification_method,
@@ -1218,22 +1282,29 @@ 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,
- credentials,
+ lsid,
use_chrome_async_socket,
try_ssltcp_first,
notification_method,
restored_key_for_bootstrapping);
}
-void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
- data_->UpdateCredentials(credentials);
+void SyncManager::Authenticate(const char* username, const char* password,
+ const char* captcha) {
+ data_->Authenticate(std::string(username), std::string(password),
+ std::string(captcha));
}
-
bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
return data_->InitialSyncEndedForAllEnabledTypes();
}
@@ -1258,7 +1329,6 @@ 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();
@@ -1268,11 +1338,17 @@ 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 SyncCredentials& credentials,
+ const std::string& lsid,
bool use_chrome_async_socket,
bool try_ssltcp_first,
browser_sync::NotificationMethod notification_method,
@@ -1283,16 +1359,32 @@ 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, post_factory));
+ sync_server_and_path, port, use_ssl, user_agent, client_id,
+ post_factory));
- connection_manager_hookup_.reset(
- NewEventListenerHookup(connection_manager()->channel(), this,
- &SyncManager::SyncInternal::HandleServerConnectionEvent));
+ // Watch various objects for aggregated status.
+ allstatus_.WatchConnectionManager(connection_manager());
net::NetworkChangeNotifier::AddObserver(this);
// TODO(akalin): CheckServerReachable() can block, which may cause jank if we
@@ -1312,7 +1404,7 @@ bool SyncManager::SyncInternal::Init(
const bool kInitializeSsl = true;
const bool kConnectImmediately = false;
talk_mediator_.reset(new TalkMediatorImpl(mediator_thread, kInitializeSsl,
- kConnectImmediately, false));
+ kConnectImmediately, invalidate_xmpp_auth_token));
if (notification_method != browser_sync::NOTIFICATION_LEGACY &&
notification_method != browser_sync::NOTIFICATION_SERVER) {
if (notification_method == browser_sync::NOTIFICATION_TRANSITIONAL) {
@@ -1325,11 +1417,30 @@ bool SyncManager::SyncInternal::Init(
// Listen to TalkMediator events ourselves
talk_mediator_->SetDelegate(this);
- LOG(INFO) << "Sync is bringing up SyncSessionContext.";
+ 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));
// Build a SyncSessionContext and store the worker in it.
SyncSessionContext* context = new SyncSessionContext(
- connection_manager_.get(), dir_manager(), model_safe_worker_registrar);
+ connection_manager_.get(), auth_watcher(),
+ dir_manager(), model_safe_worker_registrar);
// The SyncerThread takes ownership of |context|.
syncer_thread_ = new SyncerThread(context);
@@ -1338,7 +1449,22 @@ bool SyncManager::SyncInternal::Init(
// Subscribe to the syncer thread's channel.
syncer_event_.reset(syncer_thread()->relay_channel()->AddObserver(this));
- return SignIn(credentials);
+ 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;
}
void SyncManager::SyncInternal::StartSyncing() {
@@ -1410,62 +1536,53 @@ void SyncManager::SyncInternal::SendPendingXMPPNotification(
}
}
-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;
+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();
}
+ auth_watcher()->Authenticate(username, password, std::string(),
+ captcha);
+}
- connection_manager()->set_client_id(lookup->cache_guid());
- syncer_thread()->CreateSyncer(username_for_share());
- MarkAndNotifyInitializationComplete();
- dir_change_hookup_.reset(lookup->AddChangeObserver(this));
- return true;
+void SyncManager::SyncInternal::AuthenticateWithLsid(const string& lsid) {
+ DCHECK(!lsid.empty());
+ auth_watcher()->AuthenticateWithLsid(lsid);
}
-bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
- DCHECK_EQ(MessageLoop::current(), core_message_loop_);
- DCHECK(share_.name.empty());
- share_.name = credentials.email;
+bool SyncManager::SyncInternal::AuthenticateForUser(
+ const std::string& username, const std::string& auth_token) {
+ share_.authenticated_name = username;
- LOG(INFO) << "Signing in user: " << username_for_share();
- if (!OpenDirectory()) {
+ // 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();
return false;
}
- UpdateCredentials(credentials);
+ // 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);
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() {
- if (observer_) {
- observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
- }
+ auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS;
+ if (observer_)
+ observer_->OnAuthError(AuthError(auth_problem_));
}
void SyncManager::SyncInternal::SetPassphrase(
@@ -1525,6 +1642,15 @@ 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...";
@@ -1533,6 +1659,15 @@ 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.";
@@ -1544,7 +1679,7 @@ void SyncManager::SyncInternal::Shutdown() {
// Pump any messages the auth watcher, syncer thread, or talk
// mediator posted before they shut down. (See HandleSyncerEvent(),
- // and HandleTalkMediatorEvent() for the
+ // HandleAuthWatcherEvent(), and HandleTalkMediatorEvent() for the
// events that may be posted.)
{
CHECK(core_message_loop_);
@@ -1556,8 +1691,6 @@ void SyncManager::SyncInternal::Shutdown() {
net::NetworkChangeNotifier::RemoveObserver(this);
- connection_manager_hookup_.reset();
-
if (dir_manager()) {
dir_manager()->FinalSaveChangesForAll();
dir_manager()->Close(username_for_share());
@@ -1566,6 +1699,7 @@ 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();
@@ -1578,7 +1712,22 @@ 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();
- sync_manager_->RequestNudge();
+}
+
+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();
+ }
}
// Listen to model changes, filter out ones initiated by the sync API, and
@@ -1601,25 +1750,6 @@ 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
@@ -1851,11 +1981,105 @@ void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) {
observer_->OnStopSyncingPermanently();
return;
}
+}
- if (event.what_happened == SyncerEvent::UPDATED_TOKEN) {
- observer_->OnUpdatedToken(event.updated_token);
+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)
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(
@@ -1897,8 +2121,8 @@ void SyncManager::SyncInternal::TalkMediatorLogin(
<< "(talk_mediator_ is NULL)";
return;
}
- LOG(INFO) << "P2P: Trying talk mediator login.";
-
+ // TODO(akalin): Make talk_mediator automatically login on
+ // auth token change.
talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
talk_mediator_->Login();
}
@@ -1960,7 +2184,7 @@ void SyncManager::SetupForTestMode(const std::wstring& test_username) {
void SyncManager::SyncInternal::SetupForTestMode(
const std::wstring& test_username) {
- share_.name = WideToUTF8(test_username);
+ share_.authenticated_name = WideToUTF8(test_username);
// Some tests are targeting only local db operations & integrity, and don't
// want syncer thread interference.
@@ -1968,8 +2192,18 @@ 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));
}
}
@@ -1979,7 +2213,7 @@ BaseTransaction::BaseTransaction(UserShare* share)
: lookup_(NULL) {
DCHECK(share && share->dir_manager.get());
lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(),
- share->name);
+ share->authenticated_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 16f8bd9..e4e8510 100644
--- a/chrome/browser/sync/engine/syncapi.h
+++ b/chrome/browser/sync/engine/syncapi.h
@@ -107,14 +107,12 @@ struct UserShare {
// be shared across multiple threads (unlike Directory).
scoped_ptr<syncable::DirectoryManager> dir_manager;
- // 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;
+ // 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;
};
// A valid BaseNode will never have an ID of zero.
@@ -671,9 +669,6 @@ 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;
@@ -720,22 +715,52 @@ 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 SyncCredentials& credentials,
+ const char* lsid,
bool use_chrome_async_socket,
bool try_ssltcp_first,
browser_sync::NotificationMethod notification_method,
@@ -751,11 +776,15 @@ class SyncManager {
// called.
bool InitialSyncEndedForAllEnabledTypes();
- // 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);
+ // 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);
// Start the SyncerThread.
void StartSyncing();
diff --git a/chrome/browser/sync/engine/syncapi_unittest.cc b/chrome/browser/sync/engine/syncapi_unittest.cc
index b83c501..a77134b 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_.name = setter_upper_.name();
+ share_.authenticated_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 2cc2300..17de218 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,
- sessions::SyncSession* session,
+ AuthWatcher* auth_watcher,
const ClientToServerMessage& msg,
ClientToServerResponse* response) {
@@ -144,9 +144,12 @@ bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm,
std::string new_token =
http_response.update_client_auth_header;
if (!new_token.empty()) {
- SyncerEvent event(SyncerEvent::UPDATED_TOKEN);
- event.updated_token = new_token;
- session->context()->syncer_event_channel()->Notify(event);
+ // 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);
}
if (response->ParseFromString(rx)) {
@@ -186,7 +189,7 @@ bool SyncerProtoUtil::PostClientToServerMessage(
}
if (!PostAndProcessHeaders(session->context()->connection_manager(),
- session,
+ session->context()->auth_watcher(),
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 ca68ec3..39fcc5c 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,
- sessions::SyncSession* session,
+ browser_sync::AuthWatcher* authwatcher,
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 57cae0a..e6eb68b 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"),
+ : ServerConnectionManager("unused", 0, false, "version", "id"),
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 9f369ed8..800ddddb 100644
--- a/chrome/browser/sync/engine/syncer_thread.cc
+++ b/chrome/browser/sync/engine/syncer_thread.cc
@@ -17,10 +17,12 @@
#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"
@@ -73,12 +75,19 @@ 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());
@@ -89,6 +98,7 @@ 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());
@@ -577,18 +587,22 @@ void SyncerThread::HandleChannelEvent(const SyncerEvent& event) {
NudgeSyncImpl(event.nudge_delay_milliseconds, kUnknown);
}
-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();
+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();
+ }
}
// 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 158d759..8c71db4 100644
--- a/chrome/browser/sync/engine/syncer_thread.h
+++ b/chrome/browser/sync/engine/syncer_thread.h
@@ -29,6 +29,11 @@
class EventListenerHookup;
+namespace syncable {
+class DirectoryManager;
+struct DirectoryManagerEvent;
+}
+
namespace browser_sync {
class ModelSafeWorker;
@@ -133,9 +138,6 @@ 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);
@@ -228,6 +230,8 @@ 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.
@@ -319,6 +323,7 @@ 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 ded07f0..16328bd 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(),
- metadb_.manager(), this);
+ NULL, 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);
+ SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL);
scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context));
}
TEST_F(SyncerThreadTest, StartStop) {
- SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL);
+ SyncSessionContext* context = new SyncSessionContext(NULL, 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);
+ SyncSessionContext* context = new SyncSessionContext(NULL, 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);
+ SyncSessionContext* context = new SyncSessionContext(NULL, 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,7 +673,6 @@ 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);
@@ -698,7 +697,6 @@ 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);
@@ -752,7 +750,6 @@ 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");
@@ -768,7 +765,6 @@ 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));
@@ -830,7 +826,6 @@ 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.
@@ -874,7 +869,6 @@ 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.
@@ -929,8 +923,6 @@ 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_));
@@ -1002,7 +994,6 @@ 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 0805c89..19be54e 100644
--- a/chrome/browser/sync/engine/syncer_types.h
+++ b/chrome/browser/sync/engine/syncer_types.h
@@ -78,8 +78,6 @@ 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,
@@ -145,9 +143,6 @@ 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 74e5122..0d9ab8e 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(),
+ context_.reset(new SyncSessionContext(mock_server_.get(), NULL,
syncdb_.manager(), this));
context_->set_account_name(syncdb_.name());
ASSERT_FALSE(context_->syncer_event_channel());
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index c4e0963..b570c4f 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -10,7 +10,6 @@
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
@@ -22,25 +21,24 @@
#include "chrome/browser/sync/glue/password_model_worker.h"
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/common/chrome_version_info.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "webkit/glue/webkit_glue.h"
static const int kSaveChangesIntervalSeconds = 10;
+static const char kGaiaServiceId[] = "chromiumsync";
+static const char kGaiaSourceForChrome[] = "ChromiumBrowser";
static const FilePath::CharType kSyncDataFolderName[] =
FILE_PATH_LITERAL("Sync Data");
using browser_sync::DataTypeController;
-typedef TokenService::TokenAvailableDetails TokenAvailableDetails;
typedef GoogleServiceAuthError AuthError;
namespace browser_sync {
using sessions::SyncSessionSnapshot;
-using sync_api::SyncCredentials;
SyncBackendHost::SyncBackendHost(
SyncFrontend* frontend,
@@ -77,8 +75,10 @@ void SyncBackendHost::Initialize(
const GURL& sync_service_url,
const syncable::ModelTypeSet& types,
URLRequestContextGetter* baseline_context_getter,
- const SyncCredentials& credentials,
+ const std::string& lsid,
bool delete_sync_data_folder,
+ bool invalidate_sync_login,
+ bool invalidate_sync_xmpp_login,
bool use_chrome_async_socket,
bool try_ssltcp_first,
NotificationMethod notification_method) {
@@ -110,10 +110,13 @@ void SyncBackendHost::Initialize(
}
InitCore(Core::DoInitializeOptions(
- sync_service_url,
+ sync_service_url, lsid.empty(),
MakeHttpBridgeFactory(baseline_context_getter),
- credentials,
+ MakeHttpBridgeFactory(baseline_context_getter),
+ lsid,
delete_sync_data_folder,
+ invalidate_sync_login,
+ invalidate_sync_xmpp_login,
use_chrome_async_socket,
try_ssltcp_first,
notification_method,
@@ -145,11 +148,12 @@ void SyncBackendHost::InitCore(const Core::DoInitializeOptions& options) {
options));
}
-void SyncBackendHost::UpdateCredentials(const SyncCredentials& credentials) {
+void SyncBackendHost::Authenticate(const std::string& username,
+ const std::string& password,
+ const std::string& captcha) {
core_thread_.message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(core_.get(),
- &SyncBackendHost::Core::DoUpdateCredentials,
- credentials));
+ NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate,
+ username, password, captcha));
}
void SyncBackendHost::StartSyncingWithServer() {
@@ -340,15 +344,6 @@ void SyncBackendHost::Core::NotifyPassphraseAccepted(
NotificationService::NoDetails());
}
-void SyncBackendHost::Core::NotifyUpdatedToken(const std::string& token) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- TokenAvailableDetails details(GaiaConstants::kSyncService, token);
- NotificationService::current()->Notify(
- NotificationType::TOKEN_UPDATED,
- NotificationService::AllSources(),
- Details<const TokenAvailableDetails>(&details));
-}
-
SyncBackendHost::UserShareHandle SyncBackendHost::GetUserShareHandle() const {
DCHECK(syncapi_initialized_);
return core_->syncapi()->GetUserShare();
@@ -437,9 +432,8 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
// Blow away the partial or corrupt sync data folder before doing any more
// initialization, if necessary.
- if (options.delete_sync_data_folder) {
+ if (options.delete_sync_data_folder)
DeleteSyncDataFolder();
- }
// Make sure that the directory exists before initializing the backend.
// If it already exists, this will do no harm.
@@ -451,11 +445,17 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
success = syncapi_->Init(path_str,
(options.service_url.host() + options.service_url.path()).c_str(),
options.service_url.EffectiveIntPort(),
+ kGaiaServiceId,
+ kGaiaSourceForChrome,
options.service_url.SchemeIsSecure(),
options.http_bridge_factory,
+ options.auth_http_bridge_factory,
host_, // ModelSafeWorkerRegistrar.
+ options.attempt_last_user_authentication,
+ options.invalidate_sync_login,
+ options.invalidate_sync_xmpp_login,
MakeUserAgentForSyncapi().c_str(),
- options.credentials,
+ options.lsid.c_str(),
options.use_chrome_async_socket,
options.try_ssltcp_first,
options.notification_method,
@@ -463,10 +463,11 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
DCHECK(success) << "Syncapi initialization failed!";
}
-void SyncBackendHost::Core::DoUpdateCredentials(
- const SyncCredentials& credentials) {
+void SyncBackendHost::Core::DoAuthenticate(const std::string& username,
+ const std::string& password,
+ const std::string& captcha) {
DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
- syncapi_->UpdateCredentials(credentials);
+ syncapi_->Authenticate(username.c_str(), password.c_str(), captcha.c_str());
}
void SyncBackendHost::Core::DoStartSyncing() {
@@ -623,7 +624,8 @@ bool SyncBackendHost::Core::IsCurrentThreadSafeForModel(
void SyncBackendHost::Core::OnAuthError(const AuthError& auth_error) {
- // Post to our core loop so we can modify state. Could be on another thread.
+ // We could be on SyncEngine_AuthWatcherThread. Post to our core loop so
+ // we can modify state.
host_->frontend_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &Core::HandleAuthErrorEventOnFrontendLoop,
auth_error));
@@ -658,11 +660,6 @@ void SyncBackendHost::Core::OnStopSyncingPermanently() {
&Core::HandleStopSyncingPermanentlyOnFrontendLoop));
}
-void SyncBackendHost::Core::OnUpdatedToken(const std::string& token) {
- host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
- &Core::NotifyUpdatedToken, token));
-}
-
void SyncBackendHost::Core::HandleStopSyncingPermanentlyOnFrontendLoop() {
if (!host_ || !host_->frontend_)
return;
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 9e0a9f1..2b8680d 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -16,7 +16,6 @@
#include "base/ref_counted.h"
#include "base/thread.h"
#include "base/timer.h"
-#include "base/utf_string_conversions.h"
#include "chrome/browser/sync/notification_method.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
@@ -102,14 +101,17 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
void Initialize(const GURL& service_url,
const syncable::ModelTypeSet& types,
URLRequestContextGetter* baseline_context_getter,
- const sync_api::SyncCredentials& credentials,
+ const std::string& lsid,
bool delete_sync_data_folder,
+ bool invalidate_sync_login,
+ bool invalidate_sync_xmpp_login,
bool use_chrome_async_socket,
bool try_ssltcp_first,
NotificationMethod notification_method);
- // Called from |frontend_loop| to update SyncCredentials.
- void UpdateCredentials(const sync_api::SyncCredentials& credentials);
+ // Called on |frontend_loop_| to kick off asynchronous authentication.
+ void Authenticate(const std::string& username, const std::string& password,
+ const std::string& captcha);
// This starts the SyncerThread running a Syncer object to communicate with
// sync servers. Until this is called, no changes will leave or enter this
@@ -206,22 +208,29 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
virtual void OnPaused();
virtual void OnResumed();
virtual void OnStopSyncingPermanently();
- virtual void OnUpdatedToken(const std::string& token);
struct DoInitializeOptions {
DoInitializeOptions(
const GURL& service_url,
+ bool attempt_last_user_authentication,
sync_api::HttpPostProviderFactory* http_bridge_factory,
- const sync_api::SyncCredentials& credentials,
+ sync_api::HttpPostProviderFactory* auth_http_bridge_factory,
+ const std::string& lsid,
bool delete_sync_data_folder,
+ bool invalidate_sync_login,
+ bool invalidate_sync_xmpp_login,
bool use_chrome_async_socket,
bool try_ssltcp_first,
NotificationMethod notification_method,
std::string restored_key_for_bootstrapping)
: service_url(service_url),
+ attempt_last_user_authentication(attempt_last_user_authentication),
http_bridge_factory(http_bridge_factory),
- credentials(credentials),
+ auth_http_bridge_factory(auth_http_bridge_factory),
+ lsid(lsid),
delete_sync_data_folder(delete_sync_data_folder),
+ invalidate_sync_login(invalidate_sync_login),
+ invalidate_sync_xmpp_login(invalidate_sync_xmpp_login),
use_chrome_async_socket(use_chrome_async_socket),
try_ssltcp_first(try_ssltcp_first),
notification_method(notification_method),
@@ -230,7 +239,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
GURL service_url;
bool attempt_last_user_authentication;
sync_api::HttpPostProviderFactory* http_bridge_factory;
- sync_api::SyncCredentials credentials;
+ sync_api::HttpPostProviderFactory* auth_http_bridge_factory;
std::string lsid;
bool delete_sync_data_folder;
bool invalidate_sync_login;
@@ -251,9 +260,11 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// of the syncapi on behalf of SyncBackendHost::Initialize.
void DoInitialize(const DoInitializeOptions& options);
- // Called on our SyncBackendHost's core_thread_ to perform credential
- // update on behalf of SyncBackendHost::UpdateCredentials
- void DoUpdateCredentials(const sync_api::SyncCredentials& credentials);
+ // Called on our SyncBackendHost's core_thread_ to perform authentication
+ // on behalf of SyncBackendHost::Authenticate.
+ void DoAuthenticate(const std::string& username,
+ const std::string& password,
+ const std::string& captcha);
// Called on the SyncBackendHost core_thread_ to tell the syncapi to start
// syncing (generally after initialization and authentication).
@@ -297,17 +308,14 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// setup to nudge the syncapi into a useable state.
void DoInitializeForTest(const std::wstring& test_user,
sync_api::HttpPostProviderFactory* factory,
+ sync_api::HttpPostProviderFactory* auth_factory,
bool delete_sync_data_folder,
NotificationMethod notification_method) {
- // Construct dummy credentials for test.
- sync_api::SyncCredentials credentials;
- credentials.email = WideToUTF8(test_user);
- credentials.sync_token = "token";
- DoInitialize(DoInitializeOptions(GURL(), factory,
- credentials,
- delete_sync_data_folder, false, false,
- notification_method, std::string()));
- syncapi_->SetupForTestMode(test_user);
+ DoInitialize(DoInitializeOptions(GURL(), false, factory, auth_factory,
+ std::string(), delete_sync_data_folder,
+ false, false, false, false,
+ notification_method, ""));
+ syncapi_->SetupForTestMode(test_user);
}
#endif
@@ -350,9 +358,6 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Invoked when the passphrase provided by the user has been accepted.
void NotifyPassphraseAccepted(const std::string& bootstrap_token);
- // Invoked when an updated token is available from the sync server.
- void NotifyUpdatedToken(const std::string& token);
-
// Called from Core::OnSyncCycleCompleted to handle updating frontend
// thread components.
void HandleSyncCycleCompletedOnFrontendLoop(
@@ -367,9 +372,6 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Return true if a model lives on the current thread.
bool IsCurrentThreadSafeForModel(syncable::ModelType model_type);
- // True if credentials are ready for sync use.
- bool CredentialsAvailable();
-
// Our parent SyncBackendHost
SyncBackendHost* host_;
diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h
index a4a2550..1ca0473 100644
--- a/chrome/browser/sync/profile_sync_factory.h
+++ b/chrome/browser/sync/profile_sync_factory.h
@@ -6,9 +6,7 @@
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
#pragma once
-#include <string>
#include <utility>
-
#include "base/task.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
@@ -50,8 +48,7 @@ class ProfileSyncFactory {
// Instantiates and initializes a new ProfileSyncService. Enabled
// data types are registered with the service. The return pointer
// is owned by the caller.
- virtual ProfileSyncService* CreateProfileSyncService(
- const std::string& cros_user) = 0;
+ virtual ProfileSyncService* CreateProfileSyncService() = 0;
// Instantiates a new DataTypeManager with a SyncBackendHost and a
// list of data type controllers. The return pointer is owned by
diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc
index d6708cd..a5df306 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl.cc
@@ -76,11 +76,9 @@ ProfileSyncFactoryImpl::ProfileSyncFactoryImpl(Profile* profile,
command_line_(command_line) {
}
-ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
- const std::string& cros_user) {
-
+ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService() {
ProfileSyncService* pss = new ProfileSyncService(
- this, profile_, cros_user);
+ this, profile_, browser_defaults::kBootstrapSyncAuthentication);
// App sync is enabled by default. Register unless explicitly
// disabled.
diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h
index 233f3f1..ce535e5 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.h
+++ b/chrome/browser/sync/profile_sync_factory_impl.h
@@ -6,8 +6,6 @@
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_IMPL_H__
#pragma once
-#include <string>
-
#include "base/basictypes.h"
#include "chrome/browser/sync/profile_sync_factory.h"
@@ -20,8 +18,7 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory {
virtual ~ProfileSyncFactoryImpl() {}
// ProfileSyncFactory interface.
- virtual ProfileSyncService* CreateProfileSyncService(
- const std::string& cros_user);
+ virtual ProfileSyncService* CreateProfileSyncService();
virtual browser_sync::DataTypeManager* CreateDataTypeManager(
browser_sync::SyncBackendHost* backend,
diff --git a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
index 26f47d1..908ccae 100644
--- a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
@@ -39,7 +39,7 @@ class ProfileSyncFactoryImplTest : public testing::Test {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDefault) {
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
@@ -55,7 +55,7 @@ TEST_F(ProfileSyncFactoryImplTest, CreatePSSDefault) {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableAutofill) {
command_line_->AppendSwitch(switches::kDisableSyncAutofill);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
@@ -71,7 +71,7 @@ TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableAutofill) {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableBookmarks) {
command_line_->AppendSwitch(switches::kDisableSyncBookmarks);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
@@ -87,7 +87,7 @@ TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableBookmarks) {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisablePreferences) {
command_line_->AppendSwitch(switches::kDisableSyncPreferences);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
@@ -103,7 +103,7 @@ TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisablePreferences) {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableThemes) {
command_line_->AppendSwitch(switches::kDisableSyncThemes);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
@@ -119,7 +119,7 @@ TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableThemes) {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableExtensions) {
command_line_->AppendSwitch(switches::kDisableSyncExtensions);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
@@ -135,7 +135,7 @@ TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableExtensions) {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableApps) {
command_line_->AppendSwitch(switches::kDisableSyncApps);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h
index 18cc30c..6c14d1e 100644
--- a/chrome/browser/sync/profile_sync_factory_mock.h
+++ b/chrome/browser/sync/profile_sync_factory_mock.h
@@ -23,8 +23,8 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory {
browser_sync::AssociatorInterface* bookmark_model_associator,
browser_sync::ChangeProcessor* bookmark_change_processor);
- MOCK_METHOD1(CreateProfileSyncService,
- ProfileSyncService*(const std::string&));
+ MOCK_METHOD0(CreateProfileSyncService,
+ ProfileSyncService*(void));
MOCK_METHOD2(CreateDataTypeManager,
browser_sync::DataTypeManager*(
browser_sync::SyncBackendHost*,
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 567631d..5732ebf 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -30,10 +30,7 @@
#include "chrome/browser/sync/glue/session_data_type_controller.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
-#include "chrome/browser/sync/token_migrator.h"
-#include "chrome/browser/sync/util/user_settings.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
@@ -47,7 +44,6 @@ using browser_sync::ChangeProcessor;
using browser_sync::DataTypeController;
using browser_sync::DataTypeManager;
using browser_sync::SyncBackendHost;
-using sync_api::SyncCredentials;
typedef GoogleServiceAuthError AuthError;
@@ -59,20 +55,20 @@ const char* ProfileSyncService::kDevServerUrl =
ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
Profile* profile,
- const std::string& cros_user)
+ bool bootstrap_sync_authentication)
: last_auth_error_(AuthError::None()),
factory_(factory),
profile_(profile),
- cros_user_(cros_user),
+ bootstrap_sync_authentication_(bootstrap_sync_authentication),
sync_service_url_(kDevServerUrl),
backend_initialized_(false),
+ expecting_first_run_auth_needed_event_(false),
is_auth_in_progress_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(wizard_(this)),
unrecoverable_error_detected_(false),
use_chrome_async_socket_(false),
notification_method_(browser_sync::kDefaultNotificationMethod),
- ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)),
- token_migrator_(NULL) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)) {
DCHECK(factory);
DCHECK(profile);
registrar_.Add(this,
@@ -113,8 +109,10 @@ ProfileSyncService::ProfileSyncService()
: last_auth_error_(AuthError::None()),
factory_(NULL),
profile_(NULL),
+ bootstrap_sync_authentication_(false),
sync_service_url_(kSyncServerUrl),
backend_initialized_(false),
+ expecting_first_run_auth_needed_event_(false),
is_auth_in_progress_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(wizard_(this)),
unrecoverable_error_detected_(false),
@@ -128,37 +126,6 @@ ProfileSyncService::~ProfileSyncService() {
Shutdown(false);
}
-bool ProfileSyncService::AreCredentialsAvailable() {
- if (IsManaged()) {
- return false;
- }
-
- if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
- return false;
- }
-
- // CrOS user is always logged in. Chrome uses signin_ to check logged in.
- if (!cros_user_.empty() || !signin_.GetUsername().empty()) {
- // TODO(chron): Verify CrOS unit test behavior.
- if (profile()->GetTokenService() &&
- profile()->GetTokenService()->HasTokenForService(
- GaiaConstants::kSyncService)) {
- return true;
- }
- }
- return false;
-}
-
-void ProfileSyncService::LoadMigratedCredentials(const std::string& username,
- const std::string& token) {
- signin_.SetUsername(username);
- profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username);
- profile()->GetTokenService()->OnIssueAuthTokenSuccess(
- GaiaConstants::kSyncService, token);
- profile()->GetPrefs()->SetBoolean(prefs::kSyncCredentialsMigrated, true);
- token_migrator_.reset();
-}
-
void ProfileSyncService::Initialize() {
LOG(INFO) << "Starting ProfileSyncService.";
InitSettings();
@@ -174,49 +141,24 @@ void ProfileSyncService::Initialize() {
return;
}
- RegisterAuthNotifications();
-
- // In Chrome, we integrate a SigninManager which works with the sync
- // setup wizard to kick off the TokenService. CrOS does its own plumbing
- // for the TokenService.
- if (cros_user_.empty()) {
- // Will load tokens from DB and broadcast Token events after.
- signin_.Initialize(profile_);
- }
-
- if (!HasSyncSetupCompleted()) {
+ if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) {
DisableForUser(); // Clean up in case of previous crash / setup abort.
- if (!cros_user_.empty() && AreCredentialsAvailable()) {
- StartUp(); // Under ChromeOS, just autostart it anyway if creds are here.
+
+ // Automatically start sync in Chromium OS.
+ if (bootstrap_sync_authentication_ &&
+ !profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
+ // If the LSID is empty, we're in a CrOS UI test that is not testing sync
+ // behavior, so we don't want the sync service to start.
+ if (profile()->GetTokenService() &&
+ !profile()->GetTokenService()->HasLsid()) {
+ LOG(WARNING) << "Skipping CrOS sync startup, no LSID present.";
+ return;
+ }
+ StartUp();
}
- } else if (AreCredentialsAvailable()) {
- // If we have credentials and sync setup finished, autostart the backend.
- // Note that if we haven't finished setting up sync, backend bring up will
- // be done by the wizard.
- StartUp();
} else {
- // Try to migrate the tokens (if that hasn't already succeeded).
- if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncCredentialsMigrated)) {
- token_migrator_.reset(new TokenMigrator(this, profile_->GetPath()));
- token_migrator_->TryMigration();
- }
+ StartUp();
}
-
-}
-
-void ProfileSyncService::RegisterAuthNotifications() {
- registrar_.Add(this,
- NotificationType::TOKEN_AVAILABLE,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::TOKEN_LOADING_FINISHED,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::GOOGLE_SIGNIN_FAILED,
- NotificationService::AllSources());
}
void ProfileSyncService::RegisterDataTypeController(
@@ -290,7 +232,6 @@ void ProfileSyncService::RegisterPreferences() {
pref_service->RegisterInt64Pref(prefs::kSyncLastSyncedTime, 0);
pref_service->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, false);
pref_service->RegisterBooleanPref(prefs::kSyncSuppressStart, false);
- pref_service->RegisterBooleanPref(prefs::kSyncCredentialsMigrated, false);
// If you've never synced before, or if you're using Chrome OS, all datatypes
// are on by default.
@@ -328,29 +269,23 @@ void ProfileSyncService::ClearPreferences() {
pref_service->ScheduleSavePersistentPrefs();
}
-SyncCredentials ProfileSyncService::GetCredentials() {
- SyncCredentials credentials;
- credentials.email = !cros_user_.empty() ? cros_user_ : signin_.GetUsername();
- DCHECK(!credentials.email.empty());
- TokenService* service = profile_->GetTokenService();
- credentials.sync_token = service->GetTokenForService(
- GaiaConstants::kSyncService);
- return credentials;
-}
-
void ProfileSyncService::InitializeBackend(bool delete_sync_data_folder) {
if (!backend_.get()) {
NOTREACHED();
return;
}
- // TODO(chron): Reimplement invalidate XMPP login / Sync login
- // command line switches. Perhaps make it a command
- // line in the TokenService itself to pass an arbitrary
- // token.
+ // TODO(akalin): Gather all the command-line-controlled switches
+ // into an Options struct to make passing them down less annoying.
+ bool invalidate_sync_login = false;
+ bool invalidate_sync_xmpp_login = false;
bool try_ssltcp_first = false;
#if !defined(NDEBUG)
+ invalidate_sync_login = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kInvalidateSyncLogin);
+ invalidate_sync_xmpp_login = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kInvalidateSyncXmppLogin);
try_ssltcp_first = CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSyncUseSslTcp);
#endif
@@ -359,17 +294,15 @@ void ProfileSyncService::InitializeBackend(bool delete_sync_data_folder) {
// If sync setup hasn't finished, we don't want to initialize routing info
// for any data types so that we don't download updates for types that the
// user chooses not to sync on the first DownloadUpdatesCommand.
- if (HasSyncSetupCompleted()) {
+ if (HasSyncSetupCompleted())
GetPreferredDataTypes(&types);
- }
-
- SyncCredentials credentials = GetCredentials();
-
backend_->Initialize(sync_service_url_,
types,
profile_->GetRequestContext(),
- credentials,
+ profile_->GetTokenService()->GetLsid(),
delete_sync_data_folder,
+ invalidate_sync_login,
+ invalidate_sync_xmpp_login,
use_chrome_async_socket_,
try_ssltcp_first,
notification_method_);
@@ -388,9 +321,7 @@ void ProfileSyncService::StartUp() {
return;
}
- DCHECK(AreCredentialsAvailable());
-
- LOG(INFO) << "ProfileSyncService bringing up backend host.";
+ LOG(INFO) << "ProfileSyncSerivce bringing up backend host.";
last_synced_time_ = base::Time::FromInternalValue(
profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
@@ -424,21 +355,31 @@ void ProfileSyncService::Shutdown(bool sync_disabled) {
// Clear various flags.
is_auth_in_progress_ = false;
backend_initialized_ = false;
+ expecting_first_run_auth_needed_event_ = false;
last_attempted_user_email_.clear();
}
+void ProfileSyncService::EnableForUser(gfx::NativeWindow parent_window) {
+ if (WizardIsVisible()) {
+ wizard_.Focus();
+ return;
+ }
+ expecting_first_run_auth_needed_event_ = true;
+ DCHECK(!data_type_manager_.get());
+
+ wizard_.SetParent(parent_window);
+ StartUp();
+ FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+}
+
void ProfileSyncService::DisableForUser() {
- LOG(INFO) << "Disabling sync for user.";
+ LOG(INFO) << "Clearing Sync DB.";
- // Clear prefs (including SyncSetupHasCompleted) before shutting down so
+ // Clear prefs (including SyncSetupHasCompleted) before shutting down so
// PSS clients don't think we're set up while we're shutting down.
ClearPreferences();
Shutdown(true);
- if (cros_user_.empty()) {
- signin_.SignOut();
- }
-
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
@@ -500,20 +441,29 @@ void ProfileSyncService::OnUnrecoverableError(
from_here.file_name(),
from_here.line_number()));
+ // Shut all data types down.
+ if (data_type_manager_.get())
+ data_type_manager_->Stop();
+
// Tell the wizard so it can inform the user only if it is already open.
wizard_.Step(SyncSetupWizard::FATAL_ERROR);
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
- LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable."
- << message;
+ LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable.";
std::string location;
from_here.Write(true, true, &location);
LOG(ERROR) << location;
- // Shut all data types down.
- MessageLoop::current()->PostTask(FROM_HERE,
+ if (SetupInProgress()) {
+ // We've hit an error in the middle of a startup process- shutdown all the
+ // backend stuff, and then restart it, so we're in the same state as before.
+ MessageLoop::current()->PostTask(FROM_HERE,
scoped_runnable_method_factory_.NewRunnableMethod(
&ProfileSyncService::Shutdown, true));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ scoped_runnable_method_factory_.NewRunnableMethod(
+ &ProfileSyncService::StartUp));
+ }
}
void ProfileSyncService::OnBackendInitialized() {
@@ -522,12 +472,11 @@ void ProfileSyncService::OnBackendInitialized() {
// The very first time the backend initializes is effectively the first time
// we can say we successfully "synced". last_synced_time_ will only be null
// in this case, because the pref wasn't restored on StartUp.
- if (last_synced_time_.is_null()) {
+ if (last_synced_time_.is_null())
UpdateLastSyncedTime();
- }
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
- if (!cros_user_.empty()) {
+ if (bootstrap_sync_authentication_) {
if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
ShowChooseDataTypes(NULL);
} else {
@@ -535,9 +484,8 @@ void ProfileSyncService::OnBackendInitialized() {
}
}
- if (HasSyncSetupCompleted()) {
+ if (HasSyncSetupCompleted())
ConfigureDataTypeManager();
- }
}
void ProfileSyncService::OnSyncCycleCompleted() {
@@ -545,16 +493,22 @@ void ProfileSyncService::OnSyncCycleCompleted() {
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
-void ProfileSyncService::UpdateAuthErrorState(
- const GoogleServiceAuthError& error) {
- last_auth_error_ = error;
+void ProfileSyncService::OnAuthError() {
+ last_auth_error_ = backend_->GetAuthError();
// Protect against the in-your-face dialogs that pop out of nowhere.
// Require the user to click somewhere to run the setup wizard in the case
// of a steady-state auth failure.
- if (WizardIsVisible()) {
+ if (WizardIsVisible() || expecting_first_run_auth_needed_event_) {
wizard_.Step(AuthError::NONE == last_auth_error_.state() ?
SyncSetupWizard::GAIA_SUCCESS : SyncSetupWizard::GAIA_LOGIN);
- } else {
+ }
+
+ if (expecting_first_run_auth_needed_event_) {
+ last_auth_error_ = AuthError::None();
+ expecting_first_run_auth_needed_event_ = false;
+ }
+
+ if (!WizardIsVisible()) {
auth_error_time_ == base::TimeTicks::Now();
}
@@ -569,10 +523,6 @@ void ProfileSyncService::UpdateAuthErrorState(
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
-void ProfileSyncService::OnAuthError() {
- UpdateAuthErrorState(backend_->GetAuthError());
- }
-
void ProfileSyncService::OnStopSyncingPermanently() {
if (SetupInProgress()) {
wizard_.Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR);
@@ -583,12 +533,6 @@ void ProfileSyncService::OnStopSyncingPermanently() {
}
void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
- // TODO(johnnyg): File a bug to make sure this doesn't happen.
- if (!cros_user_.empty()) {
- LOG(WARNING) << "ShowLoginDialog called on Chrome OS.";
- return;
- }
-
if (WizardIsVisible()) {
wizard_.Focus();
return;
@@ -600,10 +544,10 @@ void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
auth_error_time_ = base::TimeTicks(); // Reset auth_error_time_ to null.
}
- wizard_.SetParent(parent_window);
- wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
-
- FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+ if (last_auth_error_.state() != AuthError::NONE) {
+ wizard_.SetParent(parent_window);
+ wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
+ }
}
void ProfileSyncService::ShowChooseDataTypes(gfx::NativeWindow parent_window) {
@@ -679,26 +623,16 @@ string16 ProfileSyncService::GetAuthenticatedUsername() const {
void ProfileSyncService::OnUserSubmittedAuth(
const std::string& username, const std::string& password,
const std::string& captcha) {
+ if (!backend_.get()) {
+ NOTREACHED();
+ return;
+ }
last_attempted_user_email_ = username;
is_auth_in_progress_ = true;
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
auth_start_time_ = base::TimeTicks::Now();
-
- // TODO(chron): Mechanism for ChromeOS auth renewal?
- // (maybe just run the dialog anyway?)
- // or send it to the CrOS login somehow?
- if (!cros_user_.empty()) {
- LOG(WARNING) << "No mechanism on ChromeOS yet. See http://crbug.com/50292";
- }
-
- if (!signin_.GetUsername().empty()) {
- signin_.SignOut();
- }
- signin_.StartSignIn(username,
- password,
- last_auth_error_.captcha().token,
- captcha);
+ backend_->Authenticate(username, password, captcha);
}
void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
@@ -715,7 +649,7 @@ void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
}
void ProfileSyncService::OnUserCancelledDialog() {
- if (!HasSyncSetupCompleted()) {
+ if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) {
// A sync dialog was aborted before authentication.
// Rollback.
expect_sync_configuration_aborted_ = true;
@@ -881,43 +815,10 @@ void ProfileSyncService::Observe(NotificationType type,
std::string* pref_name = Details<std::string>(details).ptr();
if (*pref_name == prefs::kSyncManaged) {
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
- if (*pref_sync_managed_) {
+ if (*pref_sync_managed_)
DisableForUser();
- } else if (HasSyncSetupCompleted() && AreCredentialsAvailable()) {
+ else if (HasSyncSetupCompleted())
StartUp();
- }
- }
- break;
- }
- case NotificationType::GOOGLE_SIGNIN_SUCCESSFUL: {
- LOG(INFO) << "Signin OK. Waiting on tokens.";
- // TODO(chron): UI update?
- // TODO(chron): Timeout?
- break;
- }
- case NotificationType::GOOGLE_SIGNIN_FAILED: {
- GoogleServiceAuthError error =
- *(Details<GoogleServiceAuthError>(details).ptr());
- UpdateAuthErrorState(error);
- break;
- }
- case NotificationType::TOKEN_AVAILABLE: {
- if (AreCredentialsAvailable()) {
- if (backend_initialized_) {
- backend_->UpdateCredentials(GetCredentials());
- }
-
- StartUp();
- }
- break;
- }
- case NotificationType::TOKEN_LOADING_FINISHED: {
- // If not in Chrome OS, and we have a username without tokens,
- // the user will need to signin again, so sign out.
- if (cros_user_.empty() &&
- !signin_.GetUsername().empty() &&
- !AreCredentialsAvailable()) {
- DisableForUser();
}
break;
}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index efa2cb2..c0f023f 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -15,14 +15,12 @@
#include "base/string16.h"
#include "base/time.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/data_type_manager.h"
#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/notification_method.h"
#include "chrome/browser/sync/profile_sync_service_observer.h"
-#include "chrome/browser/sync/signin_manager.h"
#include "chrome/browser/sync/sync_setup_wizard.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
@@ -36,7 +34,6 @@ class NotificationSource;
class NotificationType;
class Profile;
class ProfileSyncFactory;
-class TokenMigrator;
// ProfileSyncService is the layer between browser subsystems like bookmarks,
// and the sync backend. Each subsystem is logically thought of as being
@@ -117,23 +114,13 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
ProfileSyncService(ProfileSyncFactory* factory_,
Profile* profile,
- const std::string& cros_user);
+ bool bootstrap_sync_authentication);
virtual ~ProfileSyncService();
// Initializes the object. This should be called every time an object of this
// class is constructed.
void Initialize();
- void RegisterAuthNotifications();
-
- // Return whether all sync tokens are loaded and
- // available for the backend to start up.
- bool AreCredentialsAvailable();
-
- // Loads credentials migrated from the old user settings db.
- void LoadMigratedCredentials(const std::string& username,
- const std::string& token);
-
// Registers a data type controller with the sync service. This
// makes the data type controller available for use, it does not
// enable or activate the synchronization of the data type (see
@@ -151,7 +138,8 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
void GetDataTypeControllerStates(
browser_sync::DataTypeController::StateMap* state_map) const;
- // Disables sync for user. Use ShowLoginDialog to enable.
+ // Enables/disables sync for user.
+ virtual void EnableForUser(gfx::NativeWindow parent_window);
virtual void DisableForUser();
// Whether sync is enabled by user or not.
@@ -169,9 +157,6 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
const std::string& password,
const std::string& captcha);
- // Update the last auth error and notify observers of error state.
- void UpdateAuthErrorState(const GoogleServiceAuthError& error);
-
// Called when a user chooses which data types to sync as part of the sync
// setup wizard. |sync_everything| represents whether they chose the
// "keep everything synced" option; if true, |chosen_types| will be ignored
@@ -341,9 +326,6 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
void RegisterPreferences();
void ClearPreferences();
- // Return SyncCredentials from the TokenService.
- sync_api::SyncCredentials GetCredentials();
-
// Test need to override this to create backends that allow setting up
// initial conditions, such as populating sync nodes.
virtual void CreateBackend();
@@ -352,8 +334,10 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
return data_type_controllers_;
}
- // The wizard will try to read the auth state out of the profile sync
- // service using this member. Captcha and error state are reflected.
+ // We keep track of the last auth error observed so we can cover up the first
+ // "expected" auth failure from observers.
+ // TODO(timsteele): Same as expecting_first_run_auth_needed_event_. Remove
+ // this!
GoogleServiceAuthError last_auth_error_;
// Our asynchronous backend to communicate with sync components living on
@@ -396,8 +380,11 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// The profile whose data we are synchronizing.
Profile* profile_;
- // Email for the ChromiumOS user, if we're running under ChromiumOS.
- std::string cros_user_;
+ // True if the profile sync service should attempt to use an LSID
+ // cookie for authentication. This is typically set to true in
+ // ChromiumOS since we want to use the system level authentication
+ // for sync.
+ bool bootstrap_sync_authentication_;
// TODO(ncarter): Put this in a profile, once there is UI for it.
// This specifies where to find the sync server.
@@ -413,6 +400,17 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// Whether the SyncBackendHost has been initialized.
bool backend_initialized_;
+ // Set to true when the user first enables sync, and we are waiting for
+ // syncapi to give us the green light on providing credentials for the first
+ // time. It is set back to false as soon as we get this message, and is
+ // false all other times so we don't have to persist this value as it will
+ // get initialized to false.
+ // TODO(timsteele): Remove this by way of starting the wizard when enabling
+ // sync *before* initializing the backend. syncapi will need to change, but
+ // it means we don't have to wait for the first AuthError; if we ever get
+ // one, it is actually an error and this bool isn't needed.
+ bool expecting_first_run_auth_needed_event_;
+
// Various pieces of UI query this value to determine if they should show
// an "Authenticating.." type of message. We are the only central place
// all auth attempts funnel through, so it makes sense to provide this.
@@ -421,9 +419,6 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
SyncSetupWizard wizard_;
- // Encapsulates user signin with TokenService.
- SigninManager signin_;
-
// True if an unrecoverable error (e.g. violation of an assumed invariant)
// occurred during syncer operation. This value should be checked before
// doing any work that might corrupt things further.
@@ -459,8 +454,6 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// desist syncing immediately.
bool expect_sync_configuration_aborted_;
- scoped_ptr<TokenMigrator> token_migrator_;
-
DISALLOW_COPY_AND_ASSIGN(ProfileSyncService);
};
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index d0884cc..e970457 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -31,7 +31,6 @@
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/profile_mock.h"
@@ -138,7 +137,7 @@ class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
void StartSyncService(Task* task, bool will_fail_association) {
if (!service_.get()) {
service_.reset(
- new TestProfileSyncService(&factory_, &profile_, "test_user", false,
+ new TestProfileSyncService(&factory_, &profile_, false, false,
task));
AutofillDataTypeController* data_type_controller =
new AutofillDataTypeController(&factory_,
@@ -165,13 +164,6 @@ class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
EXPECT_CALL(*personal_data_manager_, IsDataLoaded()).
WillRepeatedly(Return(true));
- // We need tokens to get the tests going
- token_service_.IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
-
- EXPECT_CALL(profile_, GetTokenService()).
- WillRepeatedly(Return(&token_service_));
-
service_->set_num_expected_resumes(will_fail_association ? 0 : 1);
service_->RegisterDataTypeController(data_type_controller);
service_->Initialize();
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index 3142baf..1b36c63 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -20,6 +20,7 @@ class ProfileSyncServiceMock : public ProfileSyncService {
ProfileSyncServiceMock() {}
virtual ~ProfileSyncServiceMock() {}
+ MOCK_METHOD0(EnableForUser, void());
MOCK_METHOD0(DisableForUser, void());
MOCK_METHOD0(OnBackendInitialized, void());
MOCK_METHOD0(OnSyncCycleCompleted, void());
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index ea53bf7..c989822 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -24,7 +24,6 @@
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
@@ -141,7 +140,7 @@ class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
int num_pause_expectations) {
if (!service_.get()) {
service_.reset(new TestProfileSyncService(&factory_, &profile_,
- "test_user", false, root_task));
+ false, false, root_task));
service_->set_num_expected_resumes(num_resume_expectations);
service_->set_num_expected_pauses(num_pause_expectations);
PasswordDataTypeController* data_type_controller =
@@ -156,13 +155,6 @@ class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
WillOnce(ReturnNewDataTypeManager());
- // We need tokens to get the tests going
- token_service_.IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
-
- EXPECT_CALL(profile_, GetTokenService()).
- WillRepeatedly(Return(&token_service_));
-
// Creating model safe workers will request the history service and
// password store. I couldn't manage to convince gmock that splitting up
// the expectations to match the class responsibilities was a good thing,
diff --git a/chrome/browser/sync/profile_sync_service_preference_unittest.cc b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
index e1f3299..b706f7d 100644
--- a/chrome/browser/sync/profile_sync_service_preference_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
@@ -69,7 +68,7 @@ class ProfileSyncServicePreferenceTest
return false;
service_.reset(new TestProfileSyncService(
- &factory_, profile_.get(), "test", false, task));
+ &factory_, profile_.get(), false, false, task));
// Register the preference data type.
model_associator_ =
@@ -88,8 +87,6 @@ class ProfileSyncServicePreferenceTest
service_->RegisterDataTypeController(
new PreferenceDataTypeController(&factory_,
service_.get()));
- profile_->GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
service_->Initialize();
MessageLoop::current()->Run();
return true;
diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc
index 23e4885..e12192b 100644
--- a/chrome/browser/sync/profile_sync_service_session_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc
@@ -26,7 +26,6 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
@@ -111,7 +110,7 @@ class ProfileSyncServiceSessionTest
return false;
sync_service_.reset(new TestProfileSyncService(
- &factory_, profile(), "test user", false, task));
+ &factory_, profile(), false, false, task));
profile()->set_session_service(helper_.service());
// Register the session data type.
@@ -127,8 +126,6 @@ class ProfileSyncServiceSessionTest
sync_service_->set_num_expected_resumes(will_fail_association ? 0 : 1);
sync_service_->RegisterDataTypeController(
new SessionDataTypeController(&factory_, sync_service_.get()));
- profile()->GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
sync_service_->Initialize();
MessageLoop::current()->Run();
return true;
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index e831e36..d38e6c9 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -15,7 +15,6 @@
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
@@ -41,7 +40,6 @@ ACTION_P(InvokeCallback, callback_result) {
#define SKIP_MACOSX(test) test
#endif
-// TODO(chron): Test not using cros_user flag and use signin_
class ProfileSyncServiceStartupTest : public testing::Test {
public:
ProfileSyncServiceStartupTest()
@@ -56,7 +54,7 @@ class ProfileSyncServiceStartupTest : public testing::Test {
virtual void SetUp() {
service_.reset(new TestProfileSyncService(&factory_, &profile_,
- "test", true, NULL));
+ false, true, NULL));
service_->AddObserver(&observer_);
service_->set_num_expected_resumes(0);
service_->set_num_expected_pauses(0);
@@ -101,17 +99,12 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFirstTime)) {
Mock::VerifyAndClearExpectations(data_type_manager);
// Then start things up.
- EXPECT_CALL(*data_type_manager, Configure(_)).Times(2);
+ EXPECT_CALL(*data_type_manager, Configure(_)).Times(1);
EXPECT_CALL(*data_type_manager, state()).
WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(5);
-
- // Create some tokens in the token service; the service will startup when
- // it is notified that tokens are available.
- profile_.GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "sync_token");
-
+ EXPECT_CALL(observer_, OnStateChanged()).Times(4);
+ service_->EnableForUser(NULL);
syncable::ModelTypeSet set;
set.insert(syncable::BOOKMARKS);
service_->OnUserChoseDatatypes(false, set);
@@ -126,9 +119,6 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartNormal)) {
EXPECT_CALL(observer_, OnStateChanged()).Times(3);
- // Pre load the tokens
- profile_.GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
}
@@ -140,8 +130,6 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(ManagedStartup)) {
EXPECT_CALL(observer_, OnStateChanged()).Times(1);
// Service should not be started by Initialize() since it's managed.
- profile_.GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
}
@@ -150,8 +138,6 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(SwitchManaged)) {
EXPECT_CALL(*data_type_manager, Configure(_)).Times(1);
EXPECT_CALL(observer_, OnStateChanged()).Times(3);
- profile_.GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
// The service should stop when switching to managed mode.
@@ -178,13 +164,51 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFailure)) {
WillOnce(DoAll(Notify(NotificationType::SYNC_CONFIGURE_START),
NotifyWithResult(NotificationType::SYNC_CONFIGURE_DONE,
&result)));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
EXPECT_CALL(*data_type_manager, state()).
WillOnce(Return(DataTypeManager::STOPPED));
EXPECT_CALL(observer_, OnStateChanged()).Times(3);
- profile_.GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
EXPECT_TRUE(service_->unrecoverable_error_detected());
}
+
+class ProfileSyncServiceStartupBootstrapTest
+ : public ProfileSyncServiceStartupTest {
+ public:
+ ProfileSyncServiceStartupBootstrapTest() {}
+ virtual ~ProfileSyncServiceStartupBootstrapTest() {}
+
+ virtual void SetUp() {
+ service_.reset(new TestProfileSyncService(&factory_, &profile_,
+ true, true, NULL));
+ service_->AddObserver(&observer_);
+ service_->set_num_expected_resumes(0);
+ service_->set_num_expected_pauses(0);
+ service_->set_synchronous_sync_configuration();
+ }
+};
+
+TEST_F(ProfileSyncServiceStartupBootstrapTest, SKIP_MACOSX(StartFirstTime)) {
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_)).Times(1);
+ EXPECT_CALL(*data_type_manager, state()).
+ WillOnce(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(4);
+
+ profile_.GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
+
+ // Pretend the login screen worked.
+ GaiaAuthConsumer::ClientLoginResult result;
+ result.sid = "sid";
+ result.lsid = "lsid";
+ profile_.GetTokenService()->Initialize("test",
+ &profile_);
+ profile_.GetTokenService()->UpdateCredentials(result);
+
+ // Will start sync even though setup hasn't been completed (since
+ // setup is bypassed when bootstrapping is enabled).
+ service_->Initialize();
+}
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index f913433..17137ea4 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -27,7 +27,6 @@
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/profile_mock.h"
#include "chrome/test/sync/engine/test_id_factory.h"
@@ -154,7 +153,7 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
void StartSyncService(Task* task) {
if (!service_.get()) {
service_.reset(
- new TestProfileSyncService(&factory_, &profile_, "test", false,
+ new TestProfileSyncService(&factory_, &profile_, false, false,
task));
TypedUrlDataTypeController* data_type_controller =
new TypedUrlDataTypeController(&factory_,
@@ -177,14 +176,7 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
EXPECT_CALL(profile_, GetHistoryService(_)).
WillRepeatedly(Return(history_service_.get()));
- token_service_.IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
-
- EXPECT_CALL(profile_, GetTokenService()).
- WillRepeatedly(Return(&token_service_));
-
service_->RegisterDataTypeController(data_type_controller);
-
service_->Initialize();
MessageLoop::current()->Run();
}
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 8ea701a..bb366c7 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -15,7 +15,6 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
@@ -33,7 +32,6 @@
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -248,10 +246,9 @@ class ProfileSyncServiceTest : public testing::Test {
}
void StartSyncServiceAndSetInitialSyncEnded(bool set_initial_sync_ended) {
if (!service_.get()) {
- // Set bootstrap to true and it will provide a logged in user for test
service_.reset(new TestProfileSyncService(&factory_,
profile_.get(),
- "test", false, NULL));
+ false, false, NULL));
if (!set_initial_sync_ended)
service_->dont_set_initial_sync_ended_on_init();
@@ -270,9 +267,6 @@ class ProfileSyncServiceTest : public testing::Test {
new browser_sync::BookmarkDataTypeController(&factory_,
profile_.get(),
service_.get()));
-
- profile_->GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "token");
service_->Initialize();
MessageLoop::current()->Run();
}
@@ -473,15 +467,15 @@ TEST_F(ProfileSyncServiceTest, InitialState) {
TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
service_.reset(new TestProfileSyncService(&factory_, profile_.get(),
- "test", true, NULL));
+ false, true, NULL));
service_->set_num_expected_resumes(0);
- EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).Times(0);
+ EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
+ WillOnce(ReturnNewDataTypeManager());
EXPECT_CALL(factory_, CreateBookmarkSyncComponents(_, _)).Times(0);
service_->RegisterDataTypeController(
new browser_sync::BookmarkDataTypeController(&factory_,
profile_.get(),
service_.get()));
-
service_->Initialize();
service_.reset();
}
@@ -1355,9 +1349,9 @@ TEST_F(ProfileSyncServiceTestWithData, TestStartupWithOldSyncData) {
if (!service_.get()) {
service_.reset(
new TestProfileSyncService(&factory_, profile_.get(),
- "test", true, NULL));
+ false, true, NULL));
+
service_->dont_set_initial_sync_ended_on_init();
- service_->set_synchronous_sync_configuration();
profile_->GetPrefs()->SetBoolean(prefs::kSyncHasSetupCompleted, false);
model_associator_ = new TestBookmarkModelAssociator(service_.get(),
@@ -1382,25 +1376,26 @@ TEST_F(ProfileSyncServiceTestWithData, TestStartupWithOldSyncData) {
ASSERT_FALSE(service_->backend());
ASSERT_FALSE(service_->HasSyncSetupCompleted());
- // Create some tokens in the token service; the service will startup when
- // it is notified that tokens are available.
- profile_->GetTokenService()->IssueAuthTokenForTest(
- GaiaConstants::kSyncService, "sync_token");
-
+ // This will actually start up the sync service.
+ service_->EnableForUser(NULL);
syncable::ModelTypeSet set;
set.insert(syncable::BOOKMARKS);
service_->OnUserChoseDatatypes(false, set);
- MessageLoop::current()->RunAllPending();
+ MessageLoop::current()->Run();
// Stop the service so we can read the new Sync Data files that were created.
service_.reset();
// This file should have been deleted when the whole directory was nuked.
ASSERT_FALSE(file_util::PathExists(sync_file3));
- ASSERT_FALSE(file_util::PathExists(sync_file1));
- // This will still exist, but the text should have changed.
+ // These two will still exist, but their texts should have changed.
+ ASSERT_TRUE(file_util::PathExists(sync_file1));
+ std::string file1text;
+ file_util::ReadFileToString(sync_file1, &file1text);
+ ASSERT_FALSE(file1text.compare(nonsense1) == 0);
+
ASSERT_TRUE(file_util::PathExists(sync_file2));
std::string file2text;
file_util::ReadFileToString(sync_file2, &file2text);
diff --git a/chrome/browser/sync/sessions/sync_session_context.h b/chrome/browser/sync/sessions/sync_session_context.h
index 4c6b63f..1e37a7c 100644
--- a/chrome/browser/sync/sessions/sync_session_context.h
+++ b/chrome/browser/sync/sessions/sync_session_context.h
@@ -31,6 +31,7 @@ class DirectoryManager;
namespace browser_sync {
+class AuthWatcher;
class ConflictResolver;
class ModelSafeWorkerRegistrar;
class ServerConnectionManager;
@@ -42,11 +43,13 @@ class ScopedSessionContextSyncerEventChannel;
class SyncSessionContext {
public:
SyncSessionContext(ServerConnectionManager* connection_manager,
+ AuthWatcher* auth_watcher,
syncable::DirectoryManager* directory_manager,
ModelSafeWorkerRegistrar* model_safe_worker_registrar)
: resolver_(NULL),
syncer_event_channel_(NULL),
connection_manager_(connection_manager),
+ auth_watcher_(auth_watcher),
directory_manager_(directory_manager),
registrar_(model_safe_worker_registrar),
extensions_activity_monitor_(new ExtensionsActivityMonitor()),
@@ -65,6 +68,9 @@ class SyncSessionContext {
ServerConnectionManager* connection_manager() {
return connection_manager_;
}
+ AuthWatcher* auth_watcher() {
+ return auth_watcher_;
+ }
syncable::DirectoryManager* directory_manager() {
return directory_manager_;
}
@@ -119,6 +125,7 @@ class SyncSessionContext {
SyncerEventChannel* syncer_event_channel_;
ServerConnectionManager* const connection_manager_;
+ AuthWatcher* const auth_watcher_;
syncable::DirectoryManager* const directory_manager_;
// A registrar of workers capable of processing work closures on a thread
diff --git a/chrome/browser/sync/sessions/sync_session_unittest.cc b/chrome/browser/sync/sessions/sync_session_unittest.cc
index 011f667..2bc4594 100644
--- a/chrome/browser/sync/sessions/sync_session_unittest.cc
+++ b/chrome/browser/sync/sessions/sync_session_unittest.cc
@@ -27,7 +27,7 @@ class SyncSessionTest : public testing::Test,
GetModelSafeRoutingInfo(&routes_);
}
virtual void SetUp() {
- context_.reset(new SyncSessionContext(NULL, NULL, this));
+ context_.reset(new SyncSessionContext(NULL, NULL, NULL, this));
session_.reset(new SyncSession(context_.get(), this));
}
virtual void TearDown() {
@@ -40,7 +40,7 @@ class SyncSessionTest : public testing::Test,
}
virtual bool IsSyncingCurrentlySilenced() {
FailControllerInvocationIfDisabled("IsSyncingCurrentlySilenced");
- return false;
+ return false;
}
virtual void OnReceivedLongPollIntervalUpdate(
const base::TimeDelta& new_interval) {
@@ -51,7 +51,7 @@ class SyncSessionTest : public testing::Test,
FailControllerInvocationIfDisabled("OnReceivedShortPollIntervalUpdate");
}
virtual void OnShouldStopSyncingPermanently() {
- FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently");
+ FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently");
}
// ModelSafeWorkerRegistrar implementation.
@@ -110,7 +110,7 @@ TEST_F(SyncSessionTest, SetWriteTransaction) {
TestDirectorySetterUpper db;
db.SetUp();
session_.reset(NULL);
- context_.reset(new SyncSessionContext(NULL, db.manager(), this));
+ context_.reset(new SyncSessionContext(NULL, NULL, db.manager(), this));
session_.reset(new SyncSession(context_.get(), this));
context_->set_account_name(db.name());
syncable::ScopedDirLookup dir(context_->directory_manager(),
diff --git a/chrome/browser/sync/signin_manager.cc b/chrome/browser/sync/signin_manager.cc
deleted file mode 100644
index 6f2a30c..0000000
--- a/chrome/browser/sync/signin_manager.cc
+++ /dev/null
@@ -1,95 +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 "chrome/browser/sync/signin_manager.h"
-
-#include "base/string_util.h"
-#include "chrome/browser/net/gaia/token_service.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-
-// static
-void SigninManager::RegisterUserPrefs(PrefService* user_prefs) {
- user_prefs->RegisterStringPref(prefs::kGoogleServicesUsername, "");
-}
-
-void SigninManager::Initialize(Profile* profile) {
- profile_ = profile;
- username_ = profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername);
- profile_->GetTokenService()->Initialize(
- GaiaConstants::kChromeSource, profile_);
- if (!username_.empty()) {
- profile_->GetTokenService()->LoadTokensFromDB();
- }
-}
-
-// If a username already exists, the user is logged in.
-const std::string& SigninManager::GetUsername() {
- return username_;
-}
-
-void SigninManager::SetUsername(const std::string& username) {
- username_ = username;
-}
-
-// Users must always sign out before they sign in again.
-void SigninManager::StartSignIn(const std::string& username,
- const std::string& password,
- const std::string& login_token,
- const std::string& login_captcha) {
- DCHECK(username_.empty());
- // The Sign out should clear the token service credentials.
- DCHECK(!profile_->GetTokenService()->AreCredentialsValid());
-
- username_.assign(username);
- password_.assign(password);
-
- client_login_.reset(new GaiaAuthenticator2(this,
- GaiaConstants::kChromeSource,
- profile_->GetRequestContext()));
- client_login_->StartClientLogin(username,
- password,
- "",
- login_token,
- login_captcha);
-}
-
-void SigninManager::SignOut() {
- client_login_.reset();
- username_.clear();
- password_.clear();
- profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_);
- profile_->GetPrefs()->ScheduleSavePersistentPrefs();
- profile_->GetTokenService()->ResetCredentialsInMemory();
- profile_->GetTokenService()->EraseTokensFromDB();
-}
-
-void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) {
- profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_);
- profile_->GetPrefs()->ScheduleSavePersistentPrefs();
-
- GoogleServiceSigninSuccessDetails details(username_, password_);
- NotificationService::current()->Notify(
- NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
- Source<SigninManager>(this),
- Details<const GoogleServiceSigninSuccessDetails>(&details));
-
- password_.clear(); // Don't need it anymore.
-
- profile_->GetTokenService()->UpdateCredentials(result);
- DCHECK(profile_->GetTokenService()->AreCredentialsValid());
- profile_->GetTokenService()->StartFetchingTokens();
-}
-
-void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) {
- GoogleServiceAuthError details(error);
- NotificationService::current()->Notify(
- NotificationType::GOOGLE_SIGNIN_FAILED,
- Source<SigninManager>(this),
- Details<const GoogleServiceAuthError>(&details));
- SignOut();
-}
diff --git a/chrome/browser/sync/signin_manager.h b/chrome/browser/sync/signin_manager.h
deleted file mode 100644
index a62514f..0000000
--- a/chrome/browser/sync/signin_manager.h
+++ /dev/null
@@ -1,81 +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.
-//
-// The signin manager encapsulates some functionality tracking
-// which user is signed in. When a user is signed in, a ClientLogin
-// request is run on their behalf. Auth tokens are fetched from Google
-// and the results are stored in the TokenService.
-
-#ifndef CHROME_BROWSER_SYNC_SIGNIN_MANAGER_H_
-#define CHROME_BROWSER_SYNC_SIGNIN_MANAGER_H_
-#pragma once
-
-#include <string>
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "chrome/common/net/gaia/gaia_auth_consumer.h"
-#include "chrome/common/net/gaia/google_service_auth_error.h"
-
-class GaiaAuthenticator2;
-class Profile;
-class PrefService;
-
-// Details for the Notification type GOOGLE_SIGNIN_SUCCESSFUL.
-// A listener might use this to make note of a username / password
-// pair for encryption keys.
-struct GoogleServiceSigninSuccessDetails {
- GoogleServiceSigninSuccessDetails(const std::string& in_username,
- const std::string& in_password)
- : username(in_username),
- password(in_password) {}
- std::string username;
- std::string password;
-};
-
-class SigninManager : public GaiaAuthConsumer {
- public:
- // Call to register our prefs.
- static void RegisterUserPrefs(PrefService* user_prefs);
-
- // If user was signed in, load tokens from DB if available.
- void Initialize(Profile* profile);
-
- // If a user is signed in, this will return their name.
- // Otherwise, it will return an empty string.
- const std::string& GetUsername();
-
- // Sets the user name. Used for migrating credentials from previous system.
- void SetUsername(const std::string& username);
-
- // Attempt to sign in this user. If successful, set a preference indicating
- // the signed in user and send out a notification, then start fetching tokens
- // for the user.
- void StartSignIn(const std::string& username,
- const std::string& password,
- const std::string& login_token,
- const std::string& login_captcha);
- // Sign a user out, removing the preference, erasing all keys
- // associated with the user, and cancelling all auth in progress.
- void SignOut();
-
- // GaiaAuthConsumer
- virtual void OnClientLoginSuccess(const ClientLoginResult& result);
- virtual void OnClientLoginFailure(const GoogleServiceAuthError& error);
- virtual void OnIssueAuthTokenSuccess(const std::string& service,
- const std::string& auth_token) {
- NOTREACHED();
- }
- virtual void OnIssueAuthTokenFailure(const std::string& service,
- const GoogleServiceAuthError& error) {
- NOTREACHED();
- }
-
- private:
- Profile* profile_;
- std::string username_;
- std::string password_; // This is kept empty whenever possible.
- scoped_ptr<GaiaAuthenticator2> client_login_;
-};
-
-#endif // CHROME_BROWSER_SYNC_SIGNIN_MANAGER_H_
diff --git a/chrome/browser/sync/signin_manager_unittest.cc b/chrome/browser/sync/signin_manager_unittest.cc
deleted file mode 100644
index 208667c..0000000
--- a/chrome/browser/sync/signin_manager_unittest.cc
+++ /dev/null
@@ -1,93 +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 "chrome/browser/sync/signin_manager.h"
-
-#include "chrome/browser/net/gaia/token_service.h"
-#include "chrome/browser/net/gaia/token_service_unittest.h"
-#include "chrome/browser/password_manager/encryptor.h"
-#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/common/net/test_url_fetcher_factory.h"
-#include "chrome/test/testing_profile.h"
-#include "chrome/test/signaling_task.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-class SigninManagerTest : public TokenServiceTestHarness {
- public:
- virtual void SetUp() {
- TokenServiceTestHarness::SetUp();
- manager_.reset(new SigninManager());
- google_login_success_.ListenFor(NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
- Source<SigninManager>(manager_.get()));
- google_login_failure_.ListenFor(NotificationType::GOOGLE_SIGNIN_FAILED,
- Source<SigninManager>(manager_.get()));
-
- URLFetcher::set_factory(&factory_);
- }
-
- TestURLFetcherFactory factory_;
- scoped_ptr<SigninManager> manager_;
- TestNotificationTracker google_login_success_;
- TestNotificationTracker google_login_failure_;
-};
-
-TEST_F(SigninManagerTest, SignIn) {
- manager_->Initialize(profile_.get());
- EXPECT_TRUE(manager_->GetUsername().empty());
-
- manager_->StartSignIn("username", "password", "", "");
- EXPECT_FALSE(manager_->GetUsername().empty());
-
- // Should go into token service and stop.
- manager_->OnClientLoginSuccess(credentials_);
- EXPECT_EQ(1U, google_login_success_.size());
- EXPECT_EQ(0U, google_login_failure_.size());
-
- // Should persist across resets.
- manager_.reset(new SigninManager());
- manager_->Initialize(profile_.get());
- EXPECT_FALSE(manager_->GetUsername().empty());
-}
-
-TEST_F(SigninManagerTest, SignOut) {
- manager_->Initialize(profile_.get());
- manager_->StartSignIn("username", "password", "", "");
- manager_->OnClientLoginSuccess(credentials_);
-
- EXPECT_FALSE(manager_->GetUsername().empty());
- manager_->SignOut();
- EXPECT_TRUE(manager_->GetUsername().empty());
- // Should not be persisted anymore
- manager_.reset(new SigninManager());
- manager_->Initialize(profile_.get());
- EXPECT_TRUE(manager_->GetUsername().empty());
-}
-
-TEST_F(SigninManagerTest, SignInFailure) {
- manager_->Initialize(profile_.get());
- manager_->StartSignIn("username", "password", "", "");
- GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
- manager_->OnClientLoginFailure(error);
-
- EXPECT_EQ(0U, google_login_success_.size());
- EXPECT_EQ(1U, google_login_failure_.size());
-
- EXPECT_TRUE(manager_->GetUsername().empty());
-
- // Should not be persisted
- manager_.reset(new SigninManager());
- manager_->Initialize(profile_.get());
- EXPECT_TRUE(manager_->GetUsername().empty());
-}
-
-TEST_F(SigninManagerTest, SignOutMidConnect) {
- manager_->Initialize(profile_.get());
- manager_->StartSignIn("username", "password", "", "");
- manager_->SignOut();
- EXPECT_EQ(0U, google_login_success_.size());
- EXPECT_EQ(0U, google_login_failure_.size());
-
- EXPECT_TRUE(manager_->GetUsername().empty());
-}
diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc
index 484d376..5ecd9b6 100644
--- a/chrome/browser/sync/sync_setup_wizard_unittest.cc
+++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc
@@ -32,7 +32,7 @@ typedef GoogleServiceAuthError AuthError;
class ProfileSyncServiceForWizardTest : public ProfileSyncService {
public:
ProfileSyncServiceForWizardTest(ProfileSyncFactory* factory, Profile* profile)
- : ProfileSyncService(factory, profile, ""),
+ : ProfileSyncService(factory, profile, false),
user_cancelled_dialog_(false) {
RegisterPreferences();
ResetTestStats();
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 32391ae..c7c1575 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -188,8 +188,8 @@ void OpenSyncMyBookmarksDialog(
if (service->HasSyncSetupCompleted()) {
ShowOptionsWindow(OPTIONS_PAGE_CONTENT, OPTIONS_GROUP_NONE, profile);
} else {
- service->ShowLoginDialog(NULL);
- ProfileSyncService::SyncEvent(code); // UMA stats
+ service->EnableForUser(NULL);
+ ProfileSyncService::SyncEvent(code);
}
}
diff --git a/chrome/browser/sync/syncable/directory_manager.cc b/chrome/browser/sync/syncable/directory_manager.cc
index fbdeb46..0719c67 100644
--- a/chrome/browser/sync/syncable/directory_manager.cc
+++ b/chrome/browser/sync/syncable/directory_manager.cc
@@ -54,6 +54,17 @@ bool DirectoryManager::Open(const std::string& name) {
bool was_open = false;
const DirOpenResult result = OpenImpl(name,
GetSyncDataDatabasePath(), &was_open);
+ if (!was_open) {
+ DirectoryManagerEvent event;
+ event.dirname = name;
+ if (syncable::OPENED == result) {
+ event.what_happened = DirectoryManagerEvent::OPENED;
+ } else {
+ event.what_happened = DirectoryManagerEvent::OPEN_FAILED;
+ event.error = result;
+ }
+ channel_->NotifyListeners(event);
+ }
return syncable::OPENED == result;
}
diff --git a/chrome/browser/sync/syncable/directory_manager.h b/chrome/browser/sync/syncable/directory_manager.h
index 0c0b55d..a6f0847 100644
--- a/chrome/browser/sync/syncable/directory_manager.h
+++ b/chrome/browser/sync/syncable/directory_manager.h
@@ -31,11 +31,14 @@ namespace syncable {
struct DirectoryManagerEvent {
enum {
+ OPEN_FAILED,
+ OPENED,
CLOSED,
CLOSED_ALL,
SHUTDOWN,
} what_happened;
std::string dirname;
+ DirOpenResult error; // Only for OPEN_FAILED.
typedef DirectoryManagerEvent EventType;
static inline bool IsChannelShutdownEvent(const EventType& event) {
return SHUTDOWN == event.what_happened;
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index 0854a6b..aba7c42 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -100,7 +100,7 @@ class SyncBackendHostForProfileSyncTest : public SyncBackendHost {
UserShare* user_share = core_->syncapi()->GetUserShare();
DirectoryManager* dir_manager = user_share->dir_manager.get();
- ScopedDirLookup dir(dir_manager, user_share->name);
+ ScopedDirLookup dir(dir_manager, user_share->authenticated_name);
if (!dir.good())
FAIL();
@@ -154,6 +154,7 @@ class SyncBackendHostForProfileSyncTest : public SyncBackendHost {
&SyncBackendHost::Core::DoInitializeForTest,
user,
options.http_bridge_factory,
+ options.auth_http_bridge_factory,
options.delete_sync_data_folder,
browser_sync::kDefaultNotificationMethod));
@@ -185,12 +186,10 @@ class TestProfileSyncService : public ProfileSyncService {
public:
TestProfileSyncService(ProfileSyncFactory* factory,
Profile* profile,
- const std::string& test_user,
+ bool bootstrap_sync_authentication,
bool synchronous_backend_initialization,
Task* initial_condition_setup_task)
- : ProfileSyncService(factory, profile,
- !test_user.empty() ?
- test_user : ""),
+ : ProfileSyncService(factory, profile, bootstrap_sync_authentication),
synchronous_backend_initialization_(
synchronous_backend_initialization),
synchronous_sync_configuration_(false),
diff --git a/chrome/browser/sync/token_migrator.cc b/chrome/browser/sync/token_migrator.cc
deleted file mode 100644
index 084bc40..0000000
--- a/chrome/browser/sync/token_migrator.cc
+++ /dev/null
@@ -1,53 +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 "chrome/browser/sync/token_migrator.h"
-
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/util/user_settings.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
-
-const FilePath::CharType kSyncDataFolderName[] =
- FILE_PATH_LITERAL("Sync Data");
-
-const FilePath::CharType kBookmarkSyncUserSettingsDatabase[] =
- FILE_PATH_LITERAL("BookmarkSyncSettings.sqlite3");
-
-using browser_sync::UserSettings;
-
-TokenMigrator::TokenMigrator(ProfileSyncService* service,
- const FilePath& profile_path)
- : service_(service),
- database_location_(profile_path.Append(kSyncDataFolderName)) {
-}
-
-TokenMigrator::~TokenMigrator() {
-}
-
-void TokenMigrator::TryMigration() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
- NewRunnableMethod(this, &TokenMigrator::LoadTokens));
-}
-
-void TokenMigrator::LoadTokens() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
- scoped_ptr<UserSettings> user_settings(new UserSettings());
- FilePath settings_db_file =
- database_location_.Append(FilePath(kBookmarkSyncUserSettingsDatabase));
- if (!user_settings->Init(settings_db_file))
- return;
-
- if (!user_settings->GetLastUserAndServiceToken(GaiaConstants::kSyncService,
- &username_, &token_))
- return;
-
- ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &TokenMigrator::PostTokensBack));
-}
-
-void TokenMigrator::PostTokensBack() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- service_->LoadMigratedCredentials(username_, token_);
-}
diff --git a/chrome/browser/sync/token_migrator.h b/chrome/browser/sync/token_migrator.h
deleted file mode 100644
index 6ee3394..0000000
--- a/chrome/browser/sync/token_migrator.h
+++ /dev/null
@@ -1,53 +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 <string>
-
-#include "base/file_path.h"
-#include "base/task.h"
-
-class ProfileSyncService;
-
-// The TokenMigrator provides a bridge between the IO thread and
-// the UI thread to load the old-style credentials from the user
-// settings DB, and post them back to the UI thread to store the
-// token in the token service.
-class TokenMigrator {
- public:
- TokenMigrator(ProfileSyncService* service,
- const FilePath& profile_path);
- ~TokenMigrator();
-
- // This is called on the UI thread, it only posts a task.
- // If migration succeeds, the tokens will become available in
- // the token service.
- void TryMigration();
-
- private:
- // This runs as a deferred task on the DB thread.
- void LoadTokens();
-
- // This runs as a deferred task on the UI thread (only after the DB thread is
- // finished with the data.
- void PostTokensBack();
-
- // The username and token retrieved from the user settings DB.
- std::string username_;
- std::string token_;
-
- // The ProfileSyncService owns this object, so this pointer is valid when
- // PostTokensBack is called.
- ProfileSyncService* service_;
-
- // Pending tasks, stored so they can be canceled if this object is destroyed.
- CancelableTask* loading_task_;
-
- // The directory to search for the user settings database.
- FilePath database_location_;
-
- DISALLOW_COPY_AND_ASSIGN(TokenMigrator);
-};
-
-// We ensure this object will outlive its tasks, so don't need refcounting.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(TokenMigrator);
diff --git a/chrome/browser/views/options/content_page_view.cc b/chrome/browser/views/options/content_page_view.cc
index 9af444f..41b9ffa 100644
--- a/chrome/browser/views/options/content_page_view.cc
+++ b/chrome/browser/views/options/content_page_view.cc
@@ -139,7 +139,7 @@ void ContentPageView::ButtonPressed(
IDS_CONFIRM_STOP_SYNCING_DIALOG_HEIGHT_LINES)));
return;
} else {
- sync_service_->ShowLoginDialog(GetWindow()->GetNativeWindow());
+ sync_service_->EnableForUser(GetWindow()->GetNativeWindow());
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
}
} else if (sender == sync_customize_button_) {
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 47e84f4..8851192 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -903,6 +903,10 @@
'browser/sync/engine/all_status.h',
'browser/sync/engine/apply_updates_command.cc',
'browser/sync/engine/apply_updates_command.h',
+ 'browser/sync/engine/auth_watcher.cc',
+ 'browser/sync/engine/auth_watcher.h',
+ 'browser/sync/engine/authenticator.cc',
+ 'browser/sync/engine/authenticator.h',
'browser/sync/engine/build_and_process_conflict_sets_command.cc',
'browser/sync/engine/build_and_process_conflict_sets_command.h',
'browser/sync/engine/build_commit_command.cc',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index e6343f3..257b1e0 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2538,18 +2538,18 @@
'browser/sync/engine/syncapi.h',
'browser/sync/glue/app_data_type_controller.cc',
'browser/sync/glue/app_data_type_controller.h',
- 'browser/sync/glue/autofill_change_processor.cc',
'browser/sync/glue/autofill_change_processor.h',
+ 'browser/sync/glue/autofill_change_processor.cc',
'browser/sync/glue/autofill_data_type_controller.cc',
'browser/sync/glue/autofill_data_type_controller.h',
- 'browser/sync/glue/autofill_model_associator.cc',
'browser/sync/glue/autofill_model_associator.h',
+ 'browser/sync/glue/autofill_model_associator.cc',
'browser/sync/glue/bookmark_change_processor.cc',
'browser/sync/glue/bookmark_change_processor.h',
'browser/sync/glue/bookmark_data_type_controller.cc',
'browser/sync/glue/bookmark_data_type_controller.h',
- 'browser/sync/glue/bookmark_model_associator.cc',
'browser/sync/glue/bookmark_model_associator.h',
+ 'browser/sync/glue/bookmark_model_associator.cc',
'browser/sync/glue/change_processor.cc',
'browser/sync/glue/change_processor.h',
'browser/sync/glue/data_type_controller.h',
@@ -2566,14 +2566,16 @@
'browser/sync/glue/extension_data_type_controller.h',
'browser/sync/glue/extension_model_associator.cc',
'browser/sync/glue/extension_model_associator.h',
- 'browser/sync/glue/extension_sync.cc',
- 'browser/sync/glue/extension_sync.h',
'browser/sync/glue/extension_sync_traits.cc',
'browser/sync/glue/extension_sync_traits.h',
+ 'browser/sync/glue/extension_sync.cc',
+ 'browser/sync/glue/extension_sync.h',
'browser/sync/glue/extension_util.cc',
'browser/sync/glue/extension_util.h',
'browser/sync/glue/history_model_worker.cc',
'browser/sync/glue/history_model_worker.h',
+ 'browser/sync/glue/password_model_worker.cc',
+ 'browser/sync/glue/password_model_worker.h',
'browser/sync/glue/http_bridge.cc',
'browser/sync/glue/http_bridge.h',
'browser/sync/glue/model_associator.h',
@@ -2583,8 +2585,6 @@
'browser/sync/glue/password_data_type_controller.h',
'browser/sync/glue/password_model_associator.cc',
'browser/sync/glue/password_model_associator.h',
- 'browser/sync/glue/password_model_worker.cc',
- 'browser/sync/glue/password_model_worker.h',
'browser/sync/glue/preference_change_processor.cc',
'browser/sync/glue/preference_change_processor.h',
'browser/sync/glue/preference_data_type_controller.cc',
@@ -2616,15 +2616,13 @@
'browser/sync/glue/typed_url_model_associator.h',
'browser/sync/glue/ui_model_worker.cc',
'browser/sync/glue/ui_model_worker.h',
- 'browser/sync/notification_method.cc',
'browser/sync/notification_method.h',
+ 'browser/sync/notification_method.cc',
+ 'browser/sync/profile_sync_service.cc',
+ 'browser/sync/profile_sync_service.h',
'browser/sync/profile_sync_factory.h',
'browser/sync/profile_sync_factory_impl.cc',
'browser/sync/profile_sync_factory_impl.h',
- 'browser/sync/profile_sync_service.cc',
- 'browser/sync/profile_sync_service.h',
- 'browser/sync/signin_manager.cc',
- 'browser/sync/signin_manager.h',
'browser/sync/sync_constants.cc',
'browser/sync/sync_constants.h',
'browser/sync/sync_setup_flow.cc',
@@ -2633,10 +2631,8 @@
'browser/sync/sync_setup_wizard.h',
'browser/sync/sync_ui_util.cc',
'browser/sync/sync_ui_util.h',
- 'browser/sync/sync_ui_util_mac.h',
'browser/sync/sync_ui_util_mac.mm',
- 'browser/sync/token_migrator.cc',
- 'browser/sync/token_migrator.h',
+ 'browser/sync/sync_ui_util_mac.h',
'browser/tab_closeable_state_watcher.cc',
'browser/tab_closeable_state_watcher.h',
'browser/tab_contents/background_contents.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index f0470e9..d9c244c 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1147,7 +1147,6 @@
'browser/net/chrome_url_request_context_unittest.cc',
'browser/net/connection_tester_unittest.cc',
'browser/net/gaia/token_service_unittest.cc',
- 'browser/net/gaia/token_service_unittest.h',
'browser/net/load_timing_observer_unittest.cc',
'browser/net/passive_log_collector_unittest.cc',
'browser/net/predictor_unittest.cc',
@@ -1264,7 +1263,6 @@
'browser/sync/profile_sync_service_typed_url_unittest.cc',
'browser/sync/profile_sync_service_unittest.cc',
'browser/sync/profile_sync_test_util.h',
- 'browser/sync/signin_manager_unittest.cc',
'browser/sync/sync_setup_wizard_unittest.cc',
'browser/sync/sync_ui_util_mac_unittest.mm',
'browser/sync/test_profile_sync_service.h',
@@ -2180,6 +2178,7 @@
'sources': [
'app/breakpad_mac_stubs.mm',
'browser/sync/engine/apply_updates_command_unittest.cc',
+ 'browser/sync/engine/auth_watcher_unittest.cc',
'browser/sync/engine/cleanup_disabled_types_command_unittest.cc',
'browser/sync/engine/download_updates_command_unittest.cc',
'browser/sync/engine/mock_model_safe_workers.h',
@@ -2354,6 +2353,7 @@
'test/live_sync/many_client_live_preferences_sync_test.cc',
'test/live_sync/multiple_client_live_bookmarks_sync_test.cc',
'test/live_sync/multiple_client_live_preferences_sync_test.cc',
+ 'test/live_sync/offline_sync_test.cc',
'test/live_sync/profile_sync_service_test_harness.cc',
'test/live_sync/profile_sync_service_test_harness.h',
'test/live_sync/single_client_live_bookmarks_sync_test.cc',
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index 834b9e5..df520c6 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -1045,13 +1045,6 @@ class NotificationType {
// are a ChromeCookieDetails object.
COOKIE_CHANGED,
- // Sidebar -----------------------------------------------------------------
-
- // Sent when the sidebar state is changed.
- // The source is a SidebarManager instance, the details are the changed
- // SidebarContainer object.
- SIDEBAR_CHANGED,
-
// Token Service -----------------------------------------------------------
// When the token service has a new token available for a service, one of
@@ -1060,32 +1053,16 @@ class NotificationType {
// TokenAvailableDetails object.
TOKEN_AVAILABLE,
- // When there aren't any additional tokens left to load, this notification
- // is sent.
- // The source is a TokenService on the profile. There are no details.
- TOKEN_LOADING_FINISHED,
+ // Sent when the sidebar state is changed.
+ // The source is a SidebarManager instance, the details are the changed
+ // SidebarContainer object.
+ SIDEBAR_CHANGED,
// If a token request failed, one of these is issued per failed request.
// The source is a TokenService on the Profile. The details are a
// TokenRequestFailedDetails object.
TOKEN_REQUEST_FAILED,
- // When a service has a new token they got from a frontend that the
- // TokenService should know about, fire this notification. The details
- // are a TokenAvailableDetails object.
- TOKEN_UPDATED,
-
- // Sent when a user signs into Google services such as sync.
- // The source is the SigninManager instance. The details are a
- // GoogleServiceSignin object.
- GOOGLE_SIGNIN_SUCCESSFUL,
-
- // Sent when a user fails to sign into Google services such as sync.
- // The source is the SigninManager instance. The details are a
- // GoogleServiceAuthError object.
- GOOGLE_SIGNIN_FAILED,
-
-
// Misc --------------------------------------------------------------------
#if defined(OS_CHROMEOS)
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 168f4e8..2cd8b84 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -923,17 +923,10 @@ const char kSyncManaged[] = "sync.managed";
// used when sync is disabled by the user via the privacy dashboard.
const char kSyncSuppressStart[] = "sync.suppress_start";
-// Boolean to reperesent if sync credentials have been migrated from the
-// user settings DB to the token service.
-const char kSyncCredentialsMigrated[] = "sync.credentials_migrated";
-
// A string that can be used to restore sync encryption infrastructure on
// startup so that the user doesn't need to provide credentials on each start.
const char kEncryptionBootstrapToken[] = "sync.encryption_bootstrap_token";
-// String that identifies the user logged into sync and other google services.
-const char kGoogleServicesUsername[] = "google.services.username";
-
// Create web application shortcut dialog preferences.
const char kWebAppCreateOnDesktop[] = "browser.web_app.create_on_desktop";
const char kWebAppCreateInAppsMenu[] = "browser.web_app.create_in_apps_menu";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 1caaa31b..6321c6a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -342,8 +342,6 @@ extern const char kSyncTypedUrls[];
extern const char kSyncExtensions[];
extern const char kSyncManaged[];
extern const char kSyncSuppressStart[];
-extern const char kGoogleServicesUsername[];
-extern const char kSyncCredentialsMigrated[];
extern const char kEncryptionBootstrapToken[];
extern const char kWebAppCreateOnDesktop[];
diff --git a/chrome/test/live_sync/live_sync_test.cc b/chrome/test/live_sync/live_sync_test.cc
index 9fc8598..5ff3e74 100644
--- a/chrome/test/live_sync/live_sync_test.cc
+++ b/chrome/test/live_sync/live_sync_test.cc
@@ -22,7 +22,6 @@
#include "chrome/test/testing_browser_process.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"
-#include "net/base/network_change_notifier.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
@@ -232,10 +231,6 @@ void LiveSyncTest::SetUpInProcessBrowserTestFixture() {
// Without this, running the test case on Linux causes an error as we make an
// external DNS lookup of "ocsp.thawte.com".
resolver->AllowDirectLookup("*.thawte.com");
- // The new XMPP cert seems to use crl.geotrust.com on Linux.
- resolver->AllowDirectLookup("*.geotrust.com");
- // SSL chain.
- resolver->AllowDirectLookup("*.gstatic.com");
mock_host_resolver_override_.reset(
new net::ScopedDefaultHostResolverProc(resolver));
}
@@ -260,12 +255,10 @@ void LiveSyncTest::TearDownLocalTestServer() {
ASSERT_TRUE(test_server_.Stop());
}
+
void LiveSyncTest::EnableNetwork(Profile* profile) {
SetProxyConfig(profile->GetRequestContext(),
net::ProxyConfig::CreateDirect());
- // Bugs: http://crbug.com/53857
- // http://crbug.com/53858
- net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
}
void LiveSyncTest::DisableNetwork(Profile* profile) {
@@ -274,7 +267,6 @@ void LiveSyncTest::DisableNetwork(Profile* profile) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString("http=127.0.0.1:0");
SetProxyConfig(profile->GetRequestContext(), config);
- net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
}
bool LiveSyncTest::EnsureSyncServerConfiguration() {
diff --git a/chrome/test/live_sync/offline_sync_test.cc b/chrome/test/live_sync/offline_sync_test.cc
new file mode 100644
index 0000000..c64df34
--- /dev/null
+++ b/chrome/test/live_sync/offline_sync_test.cc
@@ -0,0 +1,29 @@
+// 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 "chrome/browser/profile.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "chrome/test/live_sync/live_sync_test.h"
+#include "chrome/test/live_sync/profile_sync_service_test_harness.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+class OfflineSyncTest : public LiveSyncTest {
+ public:
+ OfflineSyncTest() : LiveSyncTest(LiveSyncTest::SINGLE_CLIENT) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OfflineSyncTest);
+};
+
+IN_PROC_BROWSER_TEST_F(OfflineSyncTest, OfflineStart) {
+ ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+ DisableNetwork(GetProfile(0));
+
+ EXPECT_FALSE(GetClient(0)->SetupSync());
+ EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED,
+ GetClient(0)->service()->GetAuthError().state());
+
+ EnableNetwork(GetProfile(0));
+ EXPECT_TRUE(GetClient(0)->RetryAuthentication());
+}
diff --git a/chrome/test/live_sync/profile_sync_service_test_harness.cc b/chrome/test/live_sync/profile_sync_service_test_harness.cc
index b49bf56..12448da 100644
--- a/chrome/test/live_sync/profile_sync_service_test_harness.cc
+++ b/chrome/test/live_sync/profile_sync_service_test_harness.cc
@@ -7,11 +7,9 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/live_sync/profile_sync_service_test_harness.h"
@@ -86,8 +84,7 @@ bool StateChangeTimeoutEvent::Abort() {
ProfileSyncServiceTestHarness::ProfileSyncServiceTestHarness(Profile* p,
const std::string& username, const std::string& password, int id)
- : wait_state_(WAITING_FOR_ON_BACKEND_INITIALIZED),
- profile_(p), service_(NULL),
+ : wait_state_(WAITING_FOR_ON_AUTH_ERROR), profile_(p), service_(NULL),
last_status_(kInvalidStatus),
last_timestamp_(0),
min_timestamp_needed_(kMinTimestampNeededNone),
@@ -98,11 +95,15 @@ ProfileSyncServiceTestHarness::ProfileSyncServiceTestHarness(Profile* p,
}
bool ProfileSyncServiceTestHarness::SetupSync() {
- service_ = profile_->GetProfileSyncService("");
+ service_ = profile_->GetProfileSyncService();
+ service_->StartUp();
service_->AddObserver(this);
- service_->signin_.StartSignIn(username_, password_, "", "");
+ return WaitForServiceInit(false);
+}
- return WaitForServiceInit();
+bool ProfileSyncServiceTestHarness::RetryAuthentication() {
+ wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
+ return WaitForServiceInit(true);
}
void ProfileSyncServiceTestHarness::SignalStateCompleteWithNextState(
@@ -120,6 +121,11 @@ bool ProfileSyncServiceTestHarness::RunStateChangeMachine() {
WaitState state = wait_state_;
ProfileSyncService::Status status(service_->QueryDetailedSyncStatus());
switch (wait_state_) {
+ case WAITING_FOR_ON_AUTH_ERROR: {
+ LogClientInfo("WAITING_FOR_ON_AUTH_ERROR");
+ SignalStateCompleteWithNextState(WAITING_FOR_ON_BACKEND_INITIALIZED);
+ break;
+ }
case WAITING_FOR_ON_BACKEND_INITIALIZED: {
LogClientInfo("WAITING_FOR_ON_BACKEND_INITIALIZED");
if (service_->GetAuthError().state() != GoogleServiceAuthError::NONE) {
@@ -137,21 +143,6 @@ bool ProfileSyncServiceTestHarness::RunStateChangeMachine() {
}
break;
}
- case WAITING_FOR_SERVER_REACHABLE: {
- LogClientInfo("WAITING_FOR_SERVER_REACHABLE");
- const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
- if (!status.server_reachable) {
- break;
- }
- if (service()->backend()->HasUnsyncedItems() ||
- snap->has_more_to_sync || snap->unsynced_count != 0) {
- SignalStateCompleteWithNextState(WAITING_FOR_SYNC_TO_FINISH);
- break;
- }
- last_timestamp_ = snap->max_local_timestamp;
- SignalStateCompleteWithNextState(FULLY_SYNCED);
- break;
- }
case WAITING_FOR_SYNC_TO_FINISH: {
LogClientInfo("WAITING_FOR_SYNC_TO_FINISH");
const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
@@ -160,10 +151,7 @@ bool ProfileSyncServiceTestHarness::RunStateChangeMachine() {
// be a sufficient condition for sync to have completed. However, the
// additional check of snap->unsynced_count is required due to
// http://crbug.com/48989.
- if (service()->backend()->HasUnsyncedItems() ||
- snap->has_more_to_sync || snap->unsynced_count != 0) {
- if (!status.server_reachable)
- SignalStateCompleteWithNextState(WAITING_FOR_SERVER_REACHABLE);
+ if (snap->has_more_to_sync || snap->unsynced_count != 0) {
break;
}
EXPECT_LE(last_timestamp_, snap->max_local_timestamp);
@@ -298,10 +286,18 @@ bool ProfileSyncServiceTestHarness::AwaitStatusChangeWithTimeout(
return timeout_signal->Abort();
}
-bool ProfileSyncServiceTestHarness::WaitForServiceInit() {
+bool ProfileSyncServiceTestHarness::WaitForServiceInit(bool is_auth_retry) {
LogClientInfo("WaitForServiceInit");
+ if (!is_auth_retry) {
+ // Wait for the OnAuthError() callback.
+ EXPECT_EQ(wait_state_, WAITING_FOR_ON_AUTH_ERROR);
+ EXPECT_TRUE(AwaitStatusChangeWithTimeout(30,
+ "Waiting for the OnAuthError() callback.")) <<
+ "OnAuthError() not seen after 30 seconds.";
+ }
- // Wait for the OnBackendInitialized() callback.
+ // Enter GAIA credentials and wait for the OnBackendInitialized() callback.
+ service_->backend()->Authenticate(username_, password_, std::string());
EXPECT_EQ(wait_state_, WAITING_FOR_ON_BACKEND_INITIALIZED);
EXPECT_TRUE(AwaitStatusChangeWithTimeout(30,
"Waiting for OnBackendInitialized().")) <<
@@ -311,13 +307,15 @@ bool ProfileSyncServiceTestHarness::WaitForServiceInit() {
return false;
}
- // Choose datatypes to be synced.
- syncable::ModelTypeSet set;
- for (int i = syncable::FIRST_REAL_MODEL_TYPE;
- i < syncable::MODEL_TYPE_COUNT; ++i) {
- set.insert(syncable::ModelTypeFromInt(i));
+ // Choose datatypes to be synced. Note: This is unnecessary on Chrome OS.
+ if (!browser_defaults::kBootstrapSyncAuthentication) {
+ syncable::ModelTypeSet set;
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
+ set.insert(syncable::ModelTypeFromInt(i));
+ }
+ service_->OnUserChoseDatatypes(true, set);
}
- service_->OnUserChoseDatatypes(true, set);
// Wait for notifications_enabled to be set to true.
EXPECT_EQ(wait_state_, WAITING_FOR_NOTIFICATIONS_ENABLED);
@@ -331,10 +329,7 @@ bool ProfileSyncServiceTestHarness::WaitForServiceInit() {
const SyncSessionSnapshot*
ProfileSyncServiceTestHarness::GetLastSessionSnapshot() const {
EXPECT_FALSE(service_ == NULL) << "Sync service has not yet been set up.";
- if (service_->backend()) {
- return service_->backend()->GetLastSessionSnapshot();
- }
- return NULL;
+ return service_->backend()->GetLastSessionSnapshot();
}
void ProfileSyncServiceTestHarness::LogClientInfo(std::string message) {
diff --git a/chrome/test/live_sync/profile_sync_service_test_harness.h b/chrome/test/live_sync/profile_sync_service_test_harness.h
index 34cfde3..3b32930 100644
--- a/chrome/test/live_sync/profile_sync_service_test_harness.h
+++ b/chrome/test/live_sync/profile_sync_service_test_harness.h
@@ -31,6 +31,10 @@ class ProfileSyncServiceTestHarness : public ProfileSyncServiceObserver {
// authenticated, and we are ready to process changes.
bool SetupSync();
+ // Retries a sync setup when the previous attempt was aborted by an
+ // authentication failure.
+ bool RetryAuthentication();
+
// ProfileSyncServiceObserver implementation.
virtual void OnStateChanged();
@@ -75,16 +79,16 @@ class ProfileSyncServiceTestHarness : public ProfileSyncServiceObserver {
friend class StateChangeTimeoutEvent;
enum WaitState {
+ // The sync client awaits the OnAuthError() callback.
+ WAITING_FOR_ON_AUTH_ERROR = 0,
// The sync client awaits the OnBackendInitialized() callback.
- WAITING_FOR_ON_BACKEND_INITIALIZED = 0,
+ WAITING_FOR_ON_BACKEND_INITIALIZED,
// The sync client is waiting for notifications_enabled to become true.
WAITING_FOR_NOTIFICATIONS_ENABLED,
// The sync client is waiting for an ongoing sync cycle to complete.
WAITING_FOR_SYNC_TO_FINISH,
// The sync client anticipates incoming updates leading to a new sync cycle.
WAITING_FOR_UPDATES,
- // The sync client is waiting for server_reachable to become true.
- WAITING_FOR_SERVER_REACHABLE,
// The sync client is fully synced and there are no pending updates.
FULLY_SYNCED,
// An authentication error has occurred.
@@ -106,7 +110,7 @@ class ProfileSyncServiceTestHarness : public ProfileSyncServiceObserver {
// Returns true if the service initialized correctly. Set is_auth_retry to
// true when calling this method second time after an authentication failure.
- bool WaitForServiceInit();
+ bool WaitForServiceInit(bool is_auth_retry);
// Logs message with relevant info about client's sync state (if available).
void LogClientInfo(std::string message);
diff --git a/chrome/test/live_sync/single_client_live_bookmarks_sync_test.cc b/chrome/test/live_sync/single_client_live_bookmarks_sync_test.cc
index bc66917..c4cc585 100644
--- a/chrome/test/live_sync/single_client_live_bookmarks_sync_test.cc
+++ b/chrome/test/live_sync/single_client_live_bookmarks_sync_test.cc
@@ -4,37 +4,6 @@
#include "chrome/test/live_sync/live_bookmarks_sync_test.h"
-// TODO(rsimha): Debug the flakiness of this with fred. http://crbug.com/53858
-IN_PROC_BROWSER_TEST_F(SingleClientLiveBookmarksSyncTest,
- FAILS_OfflineToOnline) {
- ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-
- DisableNetwork(GetProfile(0));
-
- BookmarkModel* bm = GetBookmarkModel(0);
- BookmarkModelVerifier* v = verifier_helper();
-
- const BookmarkNode* top = v->AddGroup(bm, bm->other_node(), 0, L"top");
- v->SetTitle(bm, top, L"title");
-
-
- EXPECT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Offline state change."));
- {
- ProfileSyncService::Status status(
- GetClient(0)->service()->QueryDetailedSyncStatus());
- EXPECT_EQ(status.summary, ProfileSyncService::Status::OFFLINE_UNSYNCED);
- }
-
- EnableNetwork(GetProfile(0));
- {
- EXPECT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Commit changes."));
- ProfileSyncService::Status status(
- GetClient(0)->service()->QueryDetailedSyncStatus());
- EXPECT_EQ(status.summary, ProfileSyncService::Status::READY);
- v->ExpectMatch(bm);
- }
-}
-
IN_PROC_BROWSER_TEST_F(SingleClientLiveBookmarksSyncTest, Sanity) {
ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
BookmarkModel* bm = GetBookmarkModel(0);
diff --git a/chrome/test/profile_mock.h b/chrome/test/profile_mock.h
index b3b0dcf..67f7ee2 100644
--- a/chrome/test/profile_mock.h
+++ b/chrome/test/profile_mock.h
@@ -18,7 +18,6 @@ class ProfileMock : public TestingProfile {
MOCK_METHOD1(GetWebDataService, WebDataService*(ServiceAccessType access));
MOCK_METHOD0(GetPersonalDataManager, PersonalDataManager*());
MOCK_METHOD1(GetPasswordStore, PasswordStore* (ServiceAccessType access));
- MOCK_METHOD0(GetTokenService, TokenService*());
};
#endif // CHROME_TEST_PROFILE_MOCK_H__
diff --git a/chrome/test/sync/engine/mock_connection_manager.cc b/chrome/test/sync/engine/mock_connection_manager.cc
index 24ad1f2..bfba668 100644
--- a/chrome/test/sync/engine/mock_connection_manager.cc
+++ b/chrome/test/sync/engine/mock_connection_manager.cc
@@ -33,7 +33,7 @@ using syncable::WriteTransaction;
MockConnectionManager::MockConnectionManager(DirectoryManager* dirmgr,
const string& name)
- : ServerConnectionManager("unused", 0, false, "version"),
+ : ServerConnectionManager("unused", 0, false, "version", "id"),
conflict_all_commits_(false),
conflict_n_commits_(0),
next_new_id_(10000),
diff --git a/chrome/test/sync/engine/syncer_command_test.h b/chrome/test/sync/engine/syncer_command_test.h
index 02ea57d..eed8def 100644
--- a/chrome/test/sync/engine/syncer_command_test.h
+++ b/chrome/test/sync/engine/syncer_command_test.h
@@ -48,9 +48,6 @@ class SyncerCommandTestWithParam : public testing::TestWithParam<T>,
virtual void OnShouldStopSyncingPermanently() {
FAIL() << "Shouldn't be forced to stop syncing.";
}
- virtual void SignalUpdatedToken(const std::string& token) {
- FAIL() << "Should never update token.";
- }
// ModelSafeWorkerRegistrar implementation.
virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {
@@ -94,7 +91,7 @@ class SyncerCommandTestWithParam : public testing::TestWithParam<T>,
void ResetContext() {
context_.reset(new sessions::SyncSessionContext(
- mock_server_.get(), syncdb_->manager(), registrar()));
+ mock_server_.get(), NULL, syncdb_->manager(), registrar()));
context_->set_account_name(syncdb_->name());
ClearSession();
}
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index 6fd04fc..c6ad9b3 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -453,11 +453,6 @@ TokenService* TestingProfile::GetTokenService() {
}
ProfileSyncService* TestingProfile::GetProfileSyncService() {
- return GetProfileSyncService("");
-}
-
-ProfileSyncService* TestingProfile::GetProfileSyncService(
- const std::string& cros_user) {
if (!profile_sync_service_.get()) {
// Use a NiceMock here since we are really using the mock as a
// fake. Test cases that want to set expectations on a
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index d75b7c1..6399692 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -224,7 +224,6 @@ class TestingProfile : public Profile {
virtual void InitExtensions() {}
virtual void InitWebResources() {}
virtual NTPResourceCache* GetNTPResourceCache();
-
virtual DesktopNotificationService* GetDesktopNotificationService();
virtual BackgroundContentsService* GetBackgroundContentsService() {
return NULL;
@@ -253,8 +252,6 @@ class TestingProfile : public Profile {
// Creates and initializes a profile sync service if the tests require one.
virtual TokenService* GetTokenService();
virtual ProfileSyncService* GetProfileSyncService();
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_notes);
virtual CloudPrintProxyService* GetCloudPrintProxyService() { return NULL; }
virtual ChromeBlobStorageContext* GetBlobStorageContext() {