Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
      6 
      7 #include "base/metrics/histogram.h"
      8 #include "base/prefs/pref_service.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/browser/browser_process.h"
     11 
     12 #if defined(ENABLE_CONFIGURATION_POLICY)
     13 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
     14 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
     15 #endif
     16 
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
     19 #include "chrome/browser/profiles/profile_info_cache.h"
     20 #include "chrome/browser/profiles/profile_io_data.h"
     21 #include "chrome/browser/profiles/profile_manager.h"
     22 #include "chrome/browser/profiles/profile_window.h"
     23 #include "chrome/browser/signin/signin_manager_factory.h"
     24 #include "chrome/browser/signin/signin_tracker_factory.h"
     25 #include "chrome/browser/sync/profile_sync_service.h"
     26 #include "chrome/browser/sync/profile_sync_service_factory.h"
     27 #include "chrome/browser/ui/browser.h"
     28 #include "chrome/browser/ui/browser_dialogs.h"
     29 #include "chrome/browser/ui/browser_finder.h"
     30 #include "chrome/browser/ui/browser_list.h"
     31 #include "chrome/browser/ui/browser_navigator.h"
     32 #include "chrome/browser/ui/browser_tabstrip.h"
     33 #include "chrome/browser/ui/browser_window.h"
     34 #include "chrome/browser/ui/chrome_pages.h"
     35 #include "chrome/browser/ui/sync/one_click_signin_sync_observer.h"
     36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     37 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
     38 #include "chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.h"
     39 #include "chrome/common/url_constants.h"
     40 #include "chrome/grit/chromium_strings.h"
     41 #include "chrome/grit/generated_resources.h"
     42 #include "components/signin/core/browser/signin_manager.h"
     43 #include "components/signin/core/browser/signin_metrics.h"
     44 #include "components/signin/core/common/profile_management_switches.h"
     45 #include "components/sync_driver/sync_prefs.h"
     46 #include "net/url_request/url_request_context_getter.h"
     47 #include "ui/base/l10n/l10n_util.h"
     48 
     49 namespace {
     50 
     51 // UMA histogram for tracking what users do when presented with the signin
     52 // screen.
     53 // Hence,
     54 //   (a) existing enumerated constants should never be deleted or reordered, and
     55 //   (b) new constants should only be appended at the end of the enumeration.
     56 //
     57 // Keep this in sync with SigninChoice in histograms.xml.
     58 enum SigninChoice {
     59   SIGNIN_CHOICE_CANCEL = 0,
     60   SIGNIN_CHOICE_CONTINUE = 1,
     61   SIGNIN_CHOICE_NEW_PROFILE = 2,
     62   // SIGNIN_CHOICE_SIZE should always be last - this is a count of the number
     63   // of items in this enum.
     64   SIGNIN_CHOICE_SIZE,
     65 };
     66 
     67 void SetUserChoiceHistogram(SigninChoice choice) {
     68   UMA_HISTOGRAM_ENUMERATION("Enterprise.UserSigninChoice",
     69                             choice,
     70                             SIGNIN_CHOICE_SIZE);
     71 }
     72 
     73 }  // namespace
     74 
     75 OneClickSigninSyncStarter::OneClickSigninSyncStarter(
     76     Profile* profile,
     77     Browser* browser,
     78     const std::string& email,
     79     const std::string& password,
     80     const std::string& refresh_token,
     81     StartSyncMode start_mode,
     82     content::WebContents* web_contents,
     83     ConfirmationRequired confirmation_required,
     84     const GURL& continue_url,
     85     Callback sync_setup_completed_callback)
     86     : content::WebContentsObserver(web_contents),
     87       profile_(NULL),
     88       start_mode_(start_mode),
     89       desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE),
     90       confirmation_required_(confirmation_required),
     91       continue_url_(continue_url),
     92       sync_setup_completed_callback_(sync_setup_completed_callback),
     93       weak_pointer_factory_(this) {
     94   DCHECK(profile);
     95   DCHECK(web_contents || continue_url.is_empty());
     96   BrowserList::AddObserver(this);
     97   Initialize(profile, browser);
     98 
     99   // Policy is enabled, so pass in a callback to do extra policy-related UI
    100   // before signin completes.
    101   SigninManagerFactory::GetForProfile(profile_)->
    102       StartSignInWithRefreshToken(
    103           refresh_token, email, password,
    104           base::Bind(&OneClickSigninSyncStarter::ConfirmSignin,
    105                      weak_pointer_factory_.GetWeakPtr()));
    106 }
    107 
    108 void OneClickSigninSyncStarter::OnBrowserRemoved(Browser* browser) {
    109   if (browser == browser_)
    110     browser_ = NULL;
    111 }
    112 
    113 OneClickSigninSyncStarter::~OneClickSigninSyncStarter() {
    114   BrowserList::RemoveObserver(this);
    115   LoginUIServiceFactory::GetForProfile(profile_)->RemoveObserver(this);
    116 }
    117 
    118 void OneClickSigninSyncStarter::Initialize(Profile* profile, Browser* browser) {
    119   DCHECK(profile);
    120 
    121   if (profile_)
    122     LoginUIServiceFactory::GetForProfile(profile_)->RemoveObserver(this);
    123 
    124   profile_ = profile;
    125   browser_ = browser;
    126 
    127   LoginUIServiceFactory::GetForProfile(profile_)->AddObserver(this);
    128 
    129   // Cache the parent desktop for the browser, so we can reuse that same
    130   // desktop for any UI we want to display.
    131   if (browser) {
    132     desktop_type_ = browser->host_desktop_type();
    133   } else {
    134     desktop_type_ = chrome::GetActiveDesktop();
    135   }
    136 
    137   signin_tracker_ = SigninTrackerFactory::CreateForProfile(profile_, this);
    138 
    139   // Let the sync service know that setup is in progress so it doesn't start
    140   // syncing until the user has finished any configuration.
    141   ProfileSyncService* profile_sync_service = GetProfileSyncService();
    142   if (profile_sync_service)
    143     profile_sync_service->SetSetupInProgress(true);
    144 
    145   // Make sure the syncing is not suppressed, otherwise the SigninManager
    146   // will not be able to complete sucessfully.
    147   sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
    148   sync_prefs.SetStartSuppressed(false);
    149 }
    150 
    151 void OneClickSigninSyncStarter::ConfirmSignin(const std::string& oauth_token) {
    152   DCHECK(!oauth_token.empty());
    153   SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
    154   // If this is a new signin (no authenticated username yet) try loading
    155   // policy for this user now, before any signed in services are initialized.
    156   if (!signin->IsAuthenticated()) {
    157 #if defined(ENABLE_CONFIGURATION_POLICY)
    158     policy::UserPolicySigninService* policy_service =
    159         policy::UserPolicySigninServiceFactory::GetForProfile(profile_);
    160     policy_service->RegisterForPolicy(
    161         signin->GetUsernameForAuthInProgress(),
    162         oauth_token,
    163         base::Bind(&OneClickSigninSyncStarter::OnRegisteredForPolicy,
    164                    weak_pointer_factory_.GetWeakPtr()));
    165     return;
    166 #else
    167     ConfirmAndSignin();
    168 #endif
    169   } else {
    170     // The user is already signed in - just tell SigninManager to continue
    171     // with its re-auth flow.
    172     signin->CompletePendingSignin();
    173   }
    174 }
    175 
    176 #if defined(ENABLE_CONFIGURATION_POLICY)
    177 OneClickSigninSyncStarter::SigninDialogDelegate::SigninDialogDelegate(
    178     base::WeakPtr<OneClickSigninSyncStarter> sync_starter)
    179   : sync_starter_(sync_starter) {
    180 }
    181 
    182 OneClickSigninSyncStarter::SigninDialogDelegate::~SigninDialogDelegate() {
    183 }
    184 
    185 void OneClickSigninSyncStarter::SigninDialogDelegate::OnCancelSignin() {
    186   SetUserChoiceHistogram(SIGNIN_CHOICE_CANCEL);
    187   if (sync_starter_ != NULL)
    188     sync_starter_->CancelSigninAndDelete();
    189 }
    190 
    191 void OneClickSigninSyncStarter::SigninDialogDelegate::OnContinueSignin() {
    192   SetUserChoiceHistogram(SIGNIN_CHOICE_CONTINUE);
    193 
    194   if (sync_starter_ != NULL)
    195     sync_starter_->LoadPolicyWithCachedCredentials();
    196 }
    197 
    198 void OneClickSigninSyncStarter::SigninDialogDelegate::OnSigninWithNewProfile() {
    199   SetUserChoiceHistogram(SIGNIN_CHOICE_NEW_PROFILE);
    200 
    201   if (sync_starter_ != NULL)
    202     sync_starter_->CreateNewSignedInProfile();
    203 }
    204 
    205 void OneClickSigninSyncStarter::OnRegisteredForPolicy(
    206     const std::string& dm_token, const std::string& client_id) {
    207   SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
    208   // If there's no token for the user (policy registration did not succeed) just
    209   // finish signing in.
    210   if (dm_token.empty()) {
    211     DVLOG(1) << "Policy registration failed";
    212     ConfirmAndSignin();
    213     return;
    214   }
    215 
    216   DVLOG(1) << "Policy registration succeeded: dm_token=" << dm_token;
    217 
    218   // Stash away a copy of our CloudPolicyClient (should not already have one).
    219   DCHECK(dm_token_.empty());
    220   DCHECK(client_id_.empty());
    221   dm_token_ = dm_token;
    222   client_id_ = client_id;
    223 
    224   // Allow user to create a new profile before continuing with sign-in.
    225   browser_ = EnsureBrowser(browser_, profile_, desktop_type_);
    226   content::WebContents* web_contents =
    227       browser_->tab_strip_model()->GetActiveWebContents();
    228   if (!web_contents) {
    229     CancelSigninAndDelete();
    230     return;
    231   }
    232   chrome::ShowProfileSigninConfirmationDialog(
    233       browser_,
    234       web_contents,
    235       profile_,
    236       signin->GetUsernameForAuthInProgress(),
    237       new SigninDialogDelegate(weak_pointer_factory_.GetWeakPtr()));
    238 }
    239 
    240 void OneClickSigninSyncStarter::LoadPolicyWithCachedCredentials() {
    241   DCHECK(!dm_token_.empty());
    242   DCHECK(!client_id_.empty());
    243   SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
    244   policy::UserPolicySigninService* policy_service =
    245       policy::UserPolicySigninServiceFactory::GetForProfile(profile_);
    246   policy_service->FetchPolicyForSignedInUser(
    247       signin->GetUsernameForAuthInProgress(),
    248       dm_token_,
    249       client_id_,
    250       profile_->GetRequestContext(),
    251       base::Bind(&OneClickSigninSyncStarter::OnPolicyFetchComplete,
    252                  weak_pointer_factory_.GetWeakPtr()));
    253 }
    254 
    255 void OneClickSigninSyncStarter::OnPolicyFetchComplete(bool success) {
    256   // For now, we allow signin to complete even if the policy fetch fails. If
    257   // we ever want to change this behavior, we could call
    258   // SigninManager::SignOut() here instead.
    259   DLOG_IF(ERROR, !success) << "Error fetching policy for user";
    260   DVLOG_IF(1, success) << "Policy fetch successful - completing signin";
    261   SigninManagerFactory::GetForProfile(profile_)->CompletePendingSignin();
    262 }
    263 
    264 void OneClickSigninSyncStarter::CreateNewSignedInProfile() {
    265   SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
    266   DCHECK(!signin->GetUsernameForAuthInProgress().empty());
    267   DCHECK(!dm_token_.empty());
    268   DCHECK(!client_id_.empty());
    269   // Create a new profile and have it call back when done so we can inject our
    270   // signin credentials.
    271   size_t icon_index = g_browser_process->profile_manager()->
    272       GetProfileInfoCache().ChooseAvatarIconIndexForNewProfile();
    273   ProfileManager::CreateMultiProfileAsync(
    274       base::UTF8ToUTF16(signin->GetUsernameForAuthInProgress()),
    275       base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(icon_index)),
    276       base::Bind(&OneClickSigninSyncStarter::CompleteInitForNewProfile,
    277                  weak_pointer_factory_.GetWeakPtr(), desktop_type_),
    278       std::string());
    279 }
    280 
    281 void OneClickSigninSyncStarter::CompleteInitForNewProfile(
    282     chrome::HostDesktopType desktop_type,
    283     Profile* new_profile,
    284     Profile::CreateStatus status) {
    285   DCHECK_NE(profile_, new_profile);
    286 
    287   // TODO(atwilson): On error, unregister the client to release the DMToken
    288   // and surface a better error for the user.
    289   switch (status) {
    290     case Profile::CREATE_STATUS_LOCAL_FAIL: {
    291       NOTREACHED() << "Error creating new profile";
    292       CancelSigninAndDelete();
    293       return;
    294     }
    295     case Profile::CREATE_STATUS_CREATED: {
    296       break;
    297     }
    298     case Profile::CREATE_STATUS_INITIALIZED: {
    299       // Wait until the profile is initialized before we transfer credentials.
    300       SigninManager* old_signin_manager =
    301           SigninManagerFactory::GetForProfile(profile_);
    302       SigninManager* new_signin_manager =
    303           SigninManagerFactory::GetForProfile(new_profile);
    304       DCHECK(!old_signin_manager->GetUsernameForAuthInProgress().empty());
    305       DCHECK(!old_signin_manager->IsAuthenticated());
    306       DCHECK(!new_signin_manager->IsAuthenticated());
    307       DCHECK(!dm_token_.empty());
    308       DCHECK(!client_id_.empty());
    309 
    310       // Copy credentials from the old profile to the just-created profile,
    311       // and switch over to tracking that profile.
    312       new_signin_manager->CopyCredentialsFrom(*old_signin_manager);
    313       FinishProfileSyncServiceSetup();
    314       Initialize(new_profile, NULL);
    315       DCHECK_EQ(profile_, new_profile);
    316 
    317       // We've transferred our credentials to the new profile - notify that
    318       // the signin for the original profile was cancelled (must do this after
    319       // we have called Initialize() with the new profile, as otherwise this
    320       // object will get freed when the signin on the old profile is cancelled.
    321       old_signin_manager->SignOut(signin_metrics::TRANSFER_CREDENTIALS);
    322 
    323       // Load policy for the just-created profile - once policy has finished
    324       // loading the signin process will complete.
    325       LoadPolicyWithCachedCredentials();
    326 
    327       // Open the profile's first window, after all initialization.
    328       profiles::FindOrCreateNewWindowForProfile(
    329         new_profile,
    330         chrome::startup::IS_PROCESS_STARTUP,
    331         chrome::startup::IS_FIRST_RUN,
    332         desktop_type,
    333         false);
    334       break;
    335     }
    336     case Profile::CREATE_STATUS_REMOTE_FAIL:
    337     case Profile::CREATE_STATUS_CANCELED:
    338     case Profile::MAX_CREATE_STATUS: {
    339       NOTREACHED() << "Invalid profile creation status";
    340       CancelSigninAndDelete();
    341       return;
    342     }
    343   }
    344 }
    345 #endif
    346 
    347 void OneClickSigninSyncStarter::CancelSigninAndDelete() {
    348   SigninManagerFactory::GetForProfile(profile_)->SignOut(
    349       signin_metrics::ABORT_SIGNIN);
    350   // The statement above results in a call to SigninFailed() which will free
    351   // this object, so do not refer to the OneClickSigninSyncStarter object
    352   // after this point.
    353 }
    354 
    355 void OneClickSigninSyncStarter::ConfirmAndSignin() {
    356   SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
    357   if (confirmation_required_ == CONFIRM_UNTRUSTED_SIGNIN) {
    358     browser_ = EnsureBrowser(browser_, profile_, desktop_type_);
    359     // Display a confirmation dialog to the user.
    360     browser_->window()->ShowOneClickSigninBubble(
    361         BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_SAML_MODAL_DIALOG,
    362         base::UTF8ToUTF16(signin->GetUsernameForAuthInProgress()),
    363         base::string16(),  // No error message to display.
    364         base::Bind(&OneClickSigninSyncStarter::UntrustedSigninConfirmed,
    365                    weak_pointer_factory_.GetWeakPtr()));
    366     LoginUIServiceFactory::GetForProfile(profile_)->UntrustedLoginUIShown();
    367   } else {
    368     // No confirmation required - just sign in the user.
    369     signin->CompletePendingSignin();
    370   }
    371 }
    372 
    373 void OneClickSigninSyncStarter::UntrustedSigninConfirmed(
    374     StartSyncMode response) {
    375   if (response == UNDO_SYNC) {
    376     CancelSigninAndDelete();  // This statement frees this object.
    377   } else {
    378     // If the user clicked the "Advanced" link in the confirmation dialog, then
    379     // override the current start_mode_ to bring up the advanced sync settings.
    380 
    381     // If the user signs in from the new avatar bubble, the untrusted dialog
    382     // would dismiss the avatar bubble, thus it won't show any confirmation upon
    383     // sign in completes. This dialog already has a settings link, thus we just
    384     // start sync immediately .
    385 
    386     if (response == CONFIGURE_SYNC_FIRST)
    387       start_mode_ = response;
    388     else if (start_mode_ == CONFIRM_SYNC_SETTINGS_FIRST)
    389       start_mode_ = SYNC_WITH_DEFAULT_SETTINGS;
    390 
    391     SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
    392     signin->CompletePendingSignin();
    393   }
    394 }
    395 
    396 void OneClickSigninSyncStarter::OnSyncConfirmationUIClosed(
    397     bool configure_sync_first) {
    398   if (configure_sync_first) {
    399     chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
    400   } else {
    401     ProfileSyncService* profile_sync_service = GetProfileSyncService();
    402     if (profile_sync_service)
    403       profile_sync_service->SetSyncSetupCompleted();
    404     FinishProfileSyncServiceSetup();
    405   }
    406 
    407   delete this;
    408 }
    409 
    410 void OneClickSigninSyncStarter::SigninFailed(
    411     const GoogleServiceAuthError& error) {
    412   if (!sync_setup_completed_callback_.is_null())
    413     sync_setup_completed_callback_.Run(SYNC_SETUP_FAILURE);
    414 
    415   FinishProfileSyncServiceSetup();
    416   if (confirmation_required_ == CONFIRM_AFTER_SIGNIN) {
    417     switch (error.state()) {
    418       case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
    419         DisplayFinalConfirmationBubble(l10n_util::GetStringUTF16(
    420             IDS_SYNC_UNRECOVERABLE_ERROR));
    421         break;
    422       case GoogleServiceAuthError::REQUEST_CANCELED:
    423         // No error notification needed if the user manually cancelled signin.
    424         break;
    425       default:
    426         DisplayFinalConfirmationBubble(l10n_util::GetStringUTF16(
    427             IDS_SYNC_ERROR_SIGNING_IN));
    428         break;
    429     }
    430   }
    431   delete this;
    432 }
    433 
    434 void OneClickSigninSyncStarter::SigninSuccess() {
    435   if (switches::IsEnableWebBasedSignin())
    436     MergeSessionComplete(GoogleServiceAuthError(GoogleServiceAuthError::NONE));
    437 }
    438 
    439 void OneClickSigninSyncStarter::MergeSessionComplete(
    440     const GoogleServiceAuthError& error) {
    441   // Regardless of whether the merge session completed sucessfully or not,
    442   // continue with sync starting.
    443 
    444   if (!sync_setup_completed_callback_.is_null())
    445     sync_setup_completed_callback_.Run(SYNC_SETUP_SUCCESS);
    446 
    447   switch (start_mode_) {
    448     case SYNC_WITH_DEFAULT_SETTINGS: {
    449       // Just kick off the sync machine, no need to configure it first.
    450       ProfileSyncService* profile_sync_service = GetProfileSyncService();
    451       if (profile_sync_service)
    452         profile_sync_service->SetSyncSetupCompleted();
    453       FinishProfileSyncServiceSetup();
    454       if (confirmation_required_ == CONFIRM_AFTER_SIGNIN) {
    455         base::string16 message;
    456         if (!profile_sync_service) {
    457           // Sync is disabled by policy.
    458           message = l10n_util::GetStringUTF16(
    459               IDS_ONE_CLICK_SIGNIN_BUBBLE_SYNC_DISABLED_MESSAGE);
    460         }
    461         DisplayFinalConfirmationBubble(message);
    462       }
    463       break;
    464     }
    465     case CONFIRM_SYNC_SETTINGS_FIRST:
    466       // Blocks sync until the sync settings confirmation UI is closed.
    467       DisplayFinalConfirmationBubble(base::string16());
    468       return;
    469     case CONFIGURE_SYNC_FIRST:
    470       ShowSettingsPage(true);  // Show sync config UI.
    471       break;
    472     case SHOW_SETTINGS_WITHOUT_CONFIGURE:
    473       ShowSettingsPage(false);  // Don't show sync config UI.
    474       break;
    475     case UNDO_SYNC:
    476       NOTREACHED();
    477   }
    478 
    479   // Navigate to the |continue_url_| if one is set, unless the user first needs
    480   // to configure Sync.
    481   if (web_contents() && !continue_url_.is_empty() &&
    482       start_mode_ != CONFIGURE_SYNC_FIRST) {
    483     LoadContinueUrl();
    484   }
    485 
    486   delete this;
    487 }
    488 
    489 void OneClickSigninSyncStarter::DisplayFinalConfirmationBubble(
    490     const base::string16& custom_message) {
    491   browser_ = EnsureBrowser(browser_, profile_, desktop_type_);
    492   LoginUIServiceFactory::GetForProfile(browser_->profile())->
    493       DisplayLoginResult(browser_, custom_message);
    494 }
    495 
    496 // static
    497 Browser* OneClickSigninSyncStarter::EnsureBrowser(
    498     Browser* browser,
    499     Profile* profile,
    500     chrome::HostDesktopType desktop_type) {
    501   if (!browser) {
    502     // The user just created a new profile or has closed the browser that
    503     // we used previously. Grab the most recently active browser or else
    504     // create a new one.
    505     browser = chrome::FindLastActiveWithProfile(profile, desktop_type);
    506     if (!browser) {
    507       browser = new Browser(Browser::CreateParams(profile,
    508                                                    desktop_type));
    509       chrome::AddTabAt(browser, GURL(), -1, true);
    510     }
    511     browser->window()->Show();
    512   }
    513   return browser;
    514 }
    515 
    516 void OneClickSigninSyncStarter::ShowSettingsPage(bool configure_sync) {
    517   // Give the user a chance to configure things. We don't clear the
    518   // ProfileSyncService::setup_in_progress flag because we don't want sync
    519   // to start up until after the configure UI is displayed (the configure UI
    520   // will clear the flag when the user is done setting up sync).
    521   ProfileSyncService* profile_sync_service = GetProfileSyncService();
    522   LoginUIService* login_ui = LoginUIServiceFactory::GetForProfile(profile_);
    523   if (login_ui->current_login_ui()) {
    524     login_ui->current_login_ui()->FocusUI();
    525   } else {
    526     browser_ = EnsureBrowser(browser_, profile_, desktop_type_);
    527 
    528     // If the sign in tab is showing the native signin page or the blank page
    529     // for web-based flow, and is not about to be closed, use it to show the
    530     // settings UI.
    531     bool use_same_tab = false;
    532     if (web_contents()) {
    533       GURL current_url = web_contents()->GetLastCommittedURL();
    534       bool is_chrome_signin_url =
    535           current_url.GetOrigin().spec() == chrome::kChromeUIChromeSigninURL;
    536       bool is_same_profile =
    537           Profile::FromBrowserContext(web_contents()->GetBrowserContext()) ==
    538           profile_;
    539       use_same_tab =
    540           (is_chrome_signin_url ||
    541            signin::IsContinueUrlForWebBasedSigninFlow(current_url)) &&
    542           !signin::IsAutoCloseEnabledInURL(current_url) &&
    543           is_same_profile;
    544     }
    545     if (profile_sync_service) {
    546       // Need to navigate to the settings page and display the sync UI.
    547       if (use_same_tab) {
    548         ShowSettingsPageInWebContents(web_contents(),
    549                                       chrome::kSyncSetupSubPage);
    550       } else {
    551         // If the user is setting up sync for the first time, let them configure
    552         // advanced sync settings. However, in the case of re-authentication,
    553         // return the user to the settings page without showing any config UI.
    554         if (configure_sync) {
    555           chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
    556         } else {
    557           FinishProfileSyncServiceSetup();
    558           chrome::ShowSettings(browser_);
    559         }
    560       }
    561     } else {
    562       // Sync is disabled - just display the settings page or redirect to the
    563       // |continue_url_|.
    564       FinishProfileSyncServiceSetup();
    565       if (!use_same_tab)
    566         chrome::ShowSettings(browser_);
    567       else if (!continue_url_.is_empty())
    568         LoadContinueUrl();
    569       else
    570         ShowSettingsPageInWebContents(web_contents(), std::string());
    571     }
    572   }
    573 }
    574 
    575 ProfileSyncService* OneClickSigninSyncStarter::GetProfileSyncService() {
    576   ProfileSyncService* service = NULL;
    577   if (profile_->IsSyncAccessible())
    578     service = ProfileSyncServiceFactory::GetForProfile(profile_);
    579   return service;
    580 }
    581 
    582 void OneClickSigninSyncStarter::FinishProfileSyncServiceSetup() {
    583   ProfileSyncService* service =
    584       ProfileSyncServiceFactory::GetForProfile(profile_);
    585   if (service)
    586     service->SetSetupInProgress(false);
    587 }
    588 
    589 void OneClickSigninSyncStarter::ShowSettingsPageInWebContents(
    590     content::WebContents* contents,
    591     const std::string& sub_page) {
    592   if (!continue_url_.is_empty()) {
    593     // The observer deletes itself once it's done.
    594     DCHECK(!sub_page.empty());
    595     new OneClickSigninSyncObserver(contents, continue_url_);
    596   }
    597 
    598   GURL url = chrome::GetSettingsUrl(sub_page);
    599   content::OpenURLParams params(url,
    600                                 content::Referrer(),
    601                                 CURRENT_TAB,
    602                                 ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
    603                                 false);
    604   contents->OpenURL(params);
    605 
    606   // Activate the tab.
    607   Browser* browser = chrome::FindBrowserWithWebContents(contents);
    608   int content_index =
    609       browser->tab_strip_model()->GetIndexOfWebContents(contents);
    610   browser->tab_strip_model()->ActivateTabAt(content_index,
    611                                             false /* user_gesture */);
    612 }
    613 
    614 void OneClickSigninSyncStarter::LoadContinueUrl() {
    615   web_contents()->GetController().LoadURL(
    616       continue_url_,
    617       content::Referrer(),
    618       ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
    619       std::string());
    620 }
    621