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

Unified Diff: chrome/browser/sync/profile_sync_service.cc

Issue 3305003: New authorization framework for sync. ... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/sync/profile_sync_service.cc
===================================================================
--- chrome/browser/sync/profile_sync_service.cc (revision 58702)
+++ chrome/browser/sync/profile_sync_service.cc (working copy)
@@ -30,7 +30,10 @@
#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"
@@ -44,6 +47,7 @@
using browser_sync::DataTypeController;
using browser_sync::DataTypeManager;
using browser_sync::SyncBackendHost;
+using sync_api::SyncCredentials;
typedef GoogleServiceAuthError AuthError;
@@ -55,20 +59,20 @@
ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
Profile* profile,
- bool bootstrap_sync_authentication)
+ const std::string& cros_user)
: last_auth_error_(AuthError::None()),
factory_(factory),
profile_(profile),
- bootstrap_sync_authentication_(bootstrap_sync_authentication),
+ cros_user_(cros_user),
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)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)),
+ token_migrator_(NULL) {
DCHECK(factory);
DCHECK(profile);
registrar_.Add(this,
@@ -109,10 +113,8 @@
: 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),
@@ -126,6 +128,37 @@
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();
@@ -141,26 +174,51 @@
return;
}
- if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) {
+ 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()) {
DisableForUser(); // Clean up in case of previous crash / setup abort.
-
- // 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();
+ if (!cros_user_.empty() && AreCredentialsAvailable()) {
+ StartUp(); // Under ChromeOS, just autostart it anyway if creds are here.
}
+ } 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 {
- StartUp();
+ // 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();
+ }
}
+
}
+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(
DataTypeController* data_type_controller) {
DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
@@ -232,6 +290,7 @@
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.
@@ -269,23 +328,29 @@
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(akalin): Gather all the command-line-controlled switches
- // into an Options struct to make passing them down less annoying.
+ // 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.
- 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
@@ -294,15 +359,17 @@
// 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(),
- profile_->GetTokenService()->GetLsid(),
+ credentials,
delete_sync_data_folder,
- invalidate_sync_login,
- invalidate_sync_xmpp_login,
use_chrome_async_socket_,
try_ssltcp_first,
notification_method_);
@@ -321,8 +388,10 @@
return;
}
- LOG(INFO) << "ProfileSyncSerivce bringing up backend host.";
+ DCHECK(AreCredentialsAvailable());
+ LOG(INFO) << "ProfileSyncService bringing up backend host.";
+
last_synced_time_ = base::Time::FromInternalValue(
profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
@@ -355,31 +424,21 @@
// 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) << "Clearing Sync DB.";
+ LOG(INFO) << "Disabling sync for user.";
- // 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());
}
@@ -441,29 +500,20 @@
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.";
+ LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable."
+ << message;
std::string location;
from_here.Write(true, true, &location);
LOG(ERROR) << location;
- 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,
+ // Shut all data types down.
+ 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() {
@@ -472,11 +522,12 @@
// 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 (bootstrap_sync_authentication_) {
+ if (!cros_user_.empty()) {
if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
ShowChooseDataTypes(NULL);
} else {
@@ -484,8 +535,9 @@
}
}
- if (HasSyncSetupCompleted())
+ if (HasSyncSetupCompleted()) {
ConfigureDataTypeManager();
+ }
}
void ProfileSyncService::OnSyncCycleCompleted() {
@@ -493,22 +545,16 @@
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
-void ProfileSyncService::OnAuthError() {
- last_auth_error_ = backend_->GetAuthError();
+void ProfileSyncService::UpdateAuthErrorState(
+ const GoogleServiceAuthError& error) {
+ last_auth_error_ = error;
// 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() || expecting_first_run_auth_needed_event_) {
+ if (WizardIsVisible()) {
wizard_.Step(AuthError::NONE == last_auth_error_.state() ?
SyncSetupWizard::GAIA_SUCCESS : SyncSetupWizard::GAIA_LOGIN);
- }
-
- if (expecting_first_run_auth_needed_event_) {
- last_auth_error_ = AuthError::None();
- expecting_first_run_auth_needed_event_ = false;
- }
-
- if (!WizardIsVisible()) {
+ } else {
auth_error_time_ == base::TimeTicks::Now();
}
@@ -523,6 +569,10 @@
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);
@@ -533,6 +583,12 @@
}
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;
@@ -544,10 +600,10 @@
auth_error_time_ = base::TimeTicks(); // Reset auth_error_time_ to null.
}
- if (last_auth_error_.state() != AuthError::NONE) {
- wizard_.SetParent(parent_window);
- wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
- }
+ wizard_.SetParent(parent_window);
+ wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
void ProfileSyncService::ShowChooseDataTypes(gfx::NativeWindow parent_window) {
@@ -623,16 +679,26 @@
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();
- backend_->Authenticate(username, password, captcha);
+
+ // 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);
}
void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
@@ -649,7 +715,7 @@
}
void ProfileSyncService::OnUserCancelledDialog() {
- if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) {
+ if (!HasSyncSetupCompleted()) {
// A sync dialog was aborted before authentication.
// Rollback.
expect_sync_configuration_aborted_ = true;
@@ -815,13 +881,46 @@
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())
+ } else if (HasSyncSetupCompleted() && AreCredentialsAvailable()) {
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;
+ }
default: {
NOTREACHED();
}

Powered by Google App Engine
This is Rietveld 408576698