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