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