1 // Copyright 2013 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/webui/signin/inline_login_handler_impl.h"
10 #include "base/callback_helpers.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_window.h"
20 #include "chrome/browser/signin/about_signin_internals_factory.h"
21 #include "chrome/browser/signin/account_tracker_service_factory.h"
22 #include "chrome/browser/signin/chrome_signin_client_factory.h"
23 #include "chrome/browser/signin/local_auth.h"
24 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
25 #include "chrome/browser/signin/signin_error_controller_factory.h"
26 #include "chrome/browser/signin/signin_manager_factory.h"
27 #include "chrome/browser/signin/signin_promo.h"
28 #include "chrome/browser/sync/profile_sync_service.h"
29 #include "chrome/browser/sync/profile_sync_service_factory.h"
30 #include "chrome/browser/ui/browser_finder.h"
31 #include "chrome/browser/ui/browser_window.h"
32 #include "chrome/browser/ui/chrome_pages.h"
33 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
34 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
35 #include "chrome/browser/ui/tabs/tab_strip_model.h"
36 #include "chrome/browser/ui/webui/signin/inline_login_ui.h"
37 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
38 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.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/about_signin_internals.h"
43 #include "components/signin/core/browser/account_tracker_service.h"
44 #include "components/signin/core/browser/profile_oauth2_token_service.h"
45 #include "components/signin/core/browser/signin_error_controller.h"
46 #include "components/signin/core/browser/signin_metrics.h"
47 #include "components/signin/core/common/profile_management_switches.h"
48 #include "components/signin/core/common/signin_pref_names.h"
49 #include "content/public/browser/storage_partition.h"
50 #include "content/public/browser/web_ui.h"
51 #include "google_apis/gaia/gaia_auth_consumer.h"
52 #include "google_apis/gaia/gaia_auth_fetcher.h"
53 #include "google_apis/gaia/gaia_auth_util.h"
54 #include "google_apis/gaia/gaia_constants.h"
55 #include "google_apis/gaia/gaia_urls.h"
56 #include "grit/components_strings.h"
57 #include "net/base/url_util.h"
58 #include "ui/base/l10n/l10n_util.h"
62 void LogHistogramValue(int action
) {
63 UMA_HISTOGRAM_ENUMERATION("Signin.AllAccessPointActions", action
,
64 signin_metrics::HISTOGRAM_MAX
);
67 void RedirectToNtpOrAppsPage(content::WebContents
* contents
,
68 signin_metrics::Source source
) {
69 // Do nothing if a navigation is pending, since this call can be triggered
70 // from DidStartLoading. This avoids deleting the pending entry while we are
71 // still navigating to it. See crbug/346632.
72 if (contents
->GetController().GetPendingEntry())
75 VLOG(1) << "RedirectToNtpOrAppsPage";
76 // Redirect to NTP/Apps page and display a confirmation bubble
77 GURL
url(source
== signin_metrics::SOURCE_APPS_PAGE_LINK
?
78 chrome::kChromeUIAppsURL
: chrome::kChromeUINewTabURL
);
79 content::OpenURLParams
params(url
,
82 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
84 contents
->OpenURL(params
);
87 void RedirectToNtpOrAppsPageIfNecessary(content::WebContents
* contents
,
88 signin_metrics::Source source
) {
89 if (source
!= signin_metrics::SOURCE_SETTINGS
)
90 RedirectToNtpOrAppsPage(contents
, source
);
93 class ConfirmEmailDialogDelegate
: public TabModalConfirmDialogDelegate
{
101 // Callback indicating action performed by the user.
102 typedef base::Callback
<void(Action
)> Callback
;
104 // Ask the user for confirmation before starting to sync.
105 static void AskForConfirmation(content::WebContents
* contents
,
106 const std::string
& last_email
,
107 const std::string
& email
,
111 ConfirmEmailDialogDelegate(content::WebContents
* contents
,
112 const std::string
& last_email
,
113 const std::string
& email
,
115 ~ConfirmEmailDialogDelegate() override
;
117 // TabModalConfirmDialogDelegate:
118 base::string16
GetTitle() override
;
119 base::string16
GetDialogMessage() override
;
120 base::string16
GetAcceptButtonTitle() override
;
121 base::string16
GetCancelButtonTitle() override
;
122 base::string16
GetLinkText() const override
;
123 void OnAccepted() override
;
124 void OnCanceled() override
;
125 void OnClosed() override
;
126 void OnLinkClicked(WindowOpenDisposition disposition
) override
;
128 std::string last_email_
;
132 // Web contents from which the "Learn more" link should be opened.
133 content::WebContents
* web_contents_
;
135 DISALLOW_COPY_AND_ASSIGN(ConfirmEmailDialogDelegate
);
139 void ConfirmEmailDialogDelegate::AskForConfirmation(
140 content::WebContents
* contents
,
141 const std::string
& last_email
,
142 const std::string
& email
,
144 TabModalConfirmDialog::Create(
145 new ConfirmEmailDialogDelegate(contents
, last_email
, email
, callback
),
149 ConfirmEmailDialogDelegate::ConfirmEmailDialogDelegate(
150 content::WebContents
* contents
,
151 const std::string
& last_email
,
152 const std::string
& email
,
154 : TabModalConfirmDialogDelegate(contents
),
155 last_email_(last_email
),
158 web_contents_(contents
) {
161 ConfirmEmailDialogDelegate::~ConfirmEmailDialogDelegate() {
164 base::string16
ConfirmEmailDialogDelegate::GetTitle() {
165 return l10n_util::GetStringUTF16(
166 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_TITLE
);
169 base::string16
ConfirmEmailDialogDelegate::GetDialogMessage() {
170 return l10n_util::GetStringFUTF16(
171 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_MESSAGE
,
172 base::UTF8ToUTF16(last_email_
), base::UTF8ToUTF16(email_
));
175 base::string16
ConfirmEmailDialogDelegate::GetAcceptButtonTitle() {
176 return l10n_util::GetStringUTF16(
177 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_OK_BUTTON
);
180 base::string16
ConfirmEmailDialogDelegate::GetCancelButtonTitle() {
181 return l10n_util::GetStringUTF16(
182 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_CANCEL_BUTTON
);
185 base::string16
ConfirmEmailDialogDelegate::GetLinkText() const {
186 return l10n_util::GetStringUTF16(IDS_LEARN_MORE
);
189 void ConfirmEmailDialogDelegate::OnAccepted() {
190 base::ResetAndReturn(&callback_
).Run(CREATE_NEW_USER
);
193 void ConfirmEmailDialogDelegate::OnCanceled() {
194 base::ResetAndReturn(&callback_
).Run(START_SYNC
);
197 void ConfirmEmailDialogDelegate::OnClosed() {
198 base::ResetAndReturn(&callback_
).Run(CLOSE
);
201 void ConfirmEmailDialogDelegate::OnLinkClicked(
202 WindowOpenDisposition disposition
) {
203 content::OpenURLParams
params(
204 GURL(chrome::kChromeSyncMergeTroubleshootingURL
),
207 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
209 // It is guaranteed that |web_contents_| is valid here because when it's
210 // deleted, the dialog is immediately closed and no further action can be
212 web_contents_
->OpenURL(params
);
215 class InlineSigninHelper
: public GaiaAuthConsumer
{
218 base::WeakPtr
<InlineLoginHandlerImpl
> handler
,
219 net::URLRequestContextGetter
* getter
,
221 const GURL
& current_url
,
222 const std::string
& email
,
223 const std::string
& gaia_id
,
224 const std::string
& password
,
225 const std::string
& session_index
,
226 const std::string
& signin_scoped_device_id
,
227 bool choose_what_to_sync
,
228 bool confirm_untrusted_signin
);
231 // Handles cross account sign in error. If the supplied |email| does not match
232 // the last signed in email of the current profile, then Chrome will show a
233 // confirmation dialog before starting sync. It returns true if there is a
234 // cross account error, and false otherwise.
235 bool HandleCrossAccountError(
236 const std::string
& refresh_token
,
237 signin_metrics::Source source
,
238 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
239 OneClickSigninSyncStarter::StartSyncMode start_mode
);
241 // Callback used with ConfirmEmailDialogDelegate.
242 void ConfirmEmailAction(
243 content::WebContents
* web_contents
,
244 const std::string
& refresh_token
,
245 signin_metrics::Source source
,
246 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
247 OneClickSigninSyncStarter::StartSyncMode start_mode
,
248 ConfirmEmailDialogDelegate::Action action
);
250 // Overridden from GaiaAuthConsumer.
251 void OnClientOAuthSuccess(const ClientOAuthResult
& result
) override
;
252 void OnClientOAuthFailure(const GoogleServiceAuthError
& error
)
255 GaiaAuthFetcher gaia_auth_fetcher_
;
256 base::WeakPtr
<InlineLoginHandlerImpl
> handler_
;
260 std::string gaia_id_
;
261 std::string password_
;
262 std::string session_index_
;
263 bool choose_what_to_sync_
;
264 bool confirm_untrusted_signin_
;
266 DISALLOW_COPY_AND_ASSIGN(InlineSigninHelper
);
269 InlineSigninHelper::InlineSigninHelper(
270 base::WeakPtr
<InlineLoginHandlerImpl
> handler
,
271 net::URLRequestContextGetter
* getter
,
273 const GURL
& current_url
,
274 const std::string
& email
,
275 const std::string
& gaia_id
,
276 const std::string
& password
,
277 const std::string
& session_index
,
278 const std::string
& signin_scoped_device_id
,
279 bool choose_what_to_sync
,
280 bool confirm_untrusted_signin
)
281 : gaia_auth_fetcher_(this, GaiaConstants::kChromeSource
, getter
),
284 current_url_(current_url
),
288 session_index_(session_index
),
289 choose_what_to_sync_(choose_what_to_sync
),
290 confirm_untrusted_signin_(confirm_untrusted_signin
) {
292 DCHECK(!email_
.empty());
293 gaia_auth_fetcher_
.StartCookieForOAuthLoginTokenExchangeWithDeviceId(
294 session_index
, signin_scoped_device_id
);
297 void InlineSigninHelper::OnClientOAuthSuccess(const ClientOAuthResult
& result
) {
298 content::WebContents
* contents
= NULL
;
299 Browser
* browser
= NULL
;
301 contents
= handler_
->web_ui()->GetWebContents();
302 browser
= handler_
->GetDesktopBrowser();
305 AboutSigninInternals
* about_signin_internals
=
306 AboutSigninInternalsFactory::GetForProfile(profile_
);
307 about_signin_internals
->OnRefreshTokenReceived("Successful");
309 AccountTrackerService
* account_tracker
=
310 AccountTrackerServiceFactory::GetForProfile(profile_
);
311 std::string account_id
=
312 account_tracker
->PickAccountIdForAccount(gaia_id_
, email_
);
314 // Prime the account tracker with this combination of gaia id/display email.
315 account_tracker
->SeedAccountInfo(gaia_id_
, email_
);
317 signin_metrics::Source source
= signin::GetSourceForPromoURL(current_url_
);
319 SigninManager
* signin_manager
= SigninManagerFactory::GetForProfile(profile_
);
320 std::string primary_email
= signin_manager
->GetAuthenticatedUsername();
321 if (gaia::AreEmailsSame(email_
, primary_email
) &&
322 source
== signin_metrics::SOURCE_REAUTH
&&
323 switches::IsNewProfileManagement() &&
324 !password_
.empty() &&
325 profiles::IsLockAvailable(profile_
)) {
326 LocalAuth::SetLocalAuthCredentials(profile_
, password_
);
329 if (source
== signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
||
330 source
== signin_metrics::SOURCE_REAUTH
) {
331 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
)->
332 UpdateCredentials(account_id
, result
.refresh_token
);
334 if (signin::IsAutoCloseEnabledInURL(current_url_
)) {
335 // Close the gaia sign in tab via a task to make sure we aren't in the
336 // middle of any webui handler code.
337 base::MessageLoop::current()->PostTask(
339 base::Bind(&InlineLoginHandlerImpl::CloseTab
,
341 signin::ShouldShowAccountManagement(current_url_
)));
344 if (source
== signin_metrics::SOURCE_REAUTH
)
345 signin_manager
->MergeSigninCredentialIntoCookieJar();
347 ProfileSyncService
* sync_service
=
348 ProfileSyncServiceFactory::GetForProfile(profile_
);
349 SigninErrorController
* error_controller
=
350 SigninErrorControllerFactory::GetForProfile(profile_
);
352 bool is_new_avatar_menu
= switches::IsNewAvatarMenu();
354 OneClickSigninSyncStarter::StartSyncMode start_mode
;
355 if (source
== signin_metrics::SOURCE_SETTINGS
|| choose_what_to_sync_
) {
356 bool show_settings_without_configure
=
357 error_controller
->HasError() &&
359 sync_service
->HasSyncSetupCompleted();
360 start_mode
= show_settings_without_configure
?
361 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE
:
362 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST
;
364 start_mode
= is_new_avatar_menu
?
365 OneClickSigninSyncStarter::CONFIRM_SYNC_SETTINGS_FIRST
:
366 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS
;
369 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
;
370 if (confirm_untrusted_signin_
) {
371 confirmation_required
=
372 OneClickSigninSyncStarter::CONFIRM_UNTRUSTED_SIGNIN
;
373 } else if (is_new_avatar_menu
) {
374 confirmation_required
= OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN
;
376 confirmation_required
=
377 source
== signin_metrics::SOURCE_SETTINGS
||
378 choose_what_to_sync_
?
379 OneClickSigninSyncStarter::NO_CONFIRMATION
:
380 OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN
;
383 bool start_signin
= !HandleCrossAccountError(result
.refresh_token
, source
,
384 confirmation_required
, start_mode
);
386 // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
387 // OneClickSigninSyncStarter will delete itself once the job is done.
388 new OneClickSigninSyncStarter(
390 email_
, password_
, result
.refresh_token
,
393 confirmation_required
,
394 signin::GetNextPageURLForPromoURL(current_url_
),
395 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback
, handler_
));
396 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
401 bool InlineSigninHelper::HandleCrossAccountError(
402 const std::string
& refresh_token
,
403 signin_metrics::Source source
,
404 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
405 OneClickSigninSyncStarter::StartSyncMode start_mode
) {
406 std::string last_email
=
407 profile_
->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername
);
409 if (last_email
.empty() || gaia::AreEmailsSame(last_email
, email_
))
412 Browser
* browser
= chrome::FindLastActiveWithProfile(
413 profile_
, chrome::GetActiveDesktop());
414 content::WebContents
* web_contents
=
415 browser
->tab_strip_model()->GetActiveWebContents();
417 ConfirmEmailDialogDelegate::AskForConfirmation(
421 base::Bind(&InlineSigninHelper::ConfirmEmailAction
,
422 base::Unretained(this),
426 confirmation_required
,
431 void InlineSigninHelper::ConfirmEmailAction(
432 content::WebContents
* web_contents
,
433 const std::string
& refresh_token
,
434 signin_metrics::Source source
,
435 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
436 OneClickSigninSyncStarter::StartSyncMode start_mode
,
437 ConfirmEmailDialogDelegate::Action action
) {
438 Browser
* browser
= chrome::FindLastActiveWithProfile(
439 profile_
, chrome::GetActiveDesktop());
441 case ConfirmEmailDialogDelegate::CREATE_NEW_USER
:
443 handler_
->SyncStarterCallback(
444 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
446 chrome::ShowSettingsSubPage(browser
,
447 std::string(chrome::kCreateProfileSubPage
));
449 case ConfirmEmailDialogDelegate::START_SYNC
:
450 new OneClickSigninSyncStarter(
451 profile_
, browser
, email_
, password_
, refresh_token
,
452 start_mode
, web_contents
, confirmation_required
, GURL(),
453 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback
, handler_
));
455 case ConfirmEmailDialogDelegate::CLOSE
:
457 handler_
->SyncStarterCallback(
458 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
462 DCHECK(false) << "Invalid action";
464 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
467 void InlineSigninHelper::OnClientOAuthFailure(
468 const GoogleServiceAuthError
& error
) {
470 handler_
->HandleLoginError(error
.ToString());
472 AboutSigninInternals
* about_signin_internals
=
473 AboutSigninInternalsFactory::GetForProfile(profile_
);
474 about_signin_internals
->OnRefreshTokenReceived("Failure");
476 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
481 InlineLoginHandlerImpl::InlineLoginHandlerImpl()
482 : confirm_untrusted_signin_(false),
483 weak_factory_(this) {
486 InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
488 // This method is not called with webview sign in enabled.
489 void InlineLoginHandlerImpl::DidCommitProvisionalLoadForFrame(
490 content::RenderFrameHost
* render_frame_host
,
492 ui::PageTransition transition_type
) {
496 // Returns early if this is not a gaia iframe navigation.
497 const GURL
kGaiaExtOrigin(
498 "chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/");
499 content::RenderFrameHost
* gaia_iframe
= InlineLoginUI::GetAuthIframe(
500 web_contents(), kGaiaExtOrigin
, "signin-frame");
501 if (render_frame_host
!= gaia_iframe
)
504 // Loading any untrusted (e.g., HTTP) URLs in the privileged sign-in process
505 // will require confirmation before the sign in takes effect.
506 if (!url
.is_empty()) {
507 GURL
origin(url
.GetOrigin());
508 if (url
.spec() != url::kAboutBlankURL
&&
509 origin
!= kGaiaExtOrigin
&&
510 !gaia::IsGaiaSignonRealm(origin
)) {
511 confirm_untrusted_signin_
= true;
517 bool InlineLoginHandlerImpl::CanOffer(Profile
* profile
,
518 CanOfferFor can_offer_for
,
519 const std::string
& email
,
520 std::string
* error_message
) {
522 error_message
->clear();
527 SigninManager
* manager
= SigninManagerFactory::GetForProfile(profile
);
528 if (manager
&& !manager
->IsSigninAllowed())
531 if (!ChromeSigninClient::ProfileAllowsSigninCookies(profile
))
534 if (!email
.empty()) {
538 // Make sure this username is not prohibited by policy.
539 if (!manager
->IsAllowedUsername(email
)) {
541 error_message
->assign(
542 l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED
));
547 if (can_offer_for
== CAN_OFFER_FOR_SECONDARY_ACCOUNT
)
550 // If the signin manager already has an authenticated name, then this is a
551 // re-auth scenario. Make sure the email just signed in corresponds to
552 // the one sign in manager expects.
553 std::string current_email
= manager
->GetAuthenticatedUsername();
554 const bool same_email
= gaia::AreEmailsSame(current_email
, email
);
555 if (!current_email
.empty() && !same_email
) {
556 UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
557 signin_metrics::HISTOGRAM_ACCOUNT_MISSMATCH
,
558 signin_metrics::HISTOGRAM_MAX
);
560 error_message
->assign(
561 l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL
,
562 base::UTF8ToUTF16(current_email
)));
567 // If some profile, not just the current one, is already connected to this
568 // account, don't show the infobar.
569 if (g_browser_process
&& !same_email
) {
570 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
571 if (profile_manager
) {
572 ProfileInfoCache
& cache
= profile_manager
->GetProfileInfoCache();
573 for (size_t i
= 0; i
< cache
.GetNumberOfProfiles(); ++i
) {
574 std::string profile_email
=
575 base::UTF16ToUTF8(cache
.GetUserNameOfProfileAtIndex(i
));
576 if (gaia::AreEmailsSame(email
, profile_email
)) {
578 error_message
->assign(
579 l10n_util::GetStringUTF8(IDS_SYNC_USER_NAME_IN_USE_ERROR
));
591 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue
& params
) {
592 params
.SetString("service", "chromiumsync");
594 content::WebContents
* contents
= web_ui()->GetWebContents();
595 const GURL
& current_url
= contents
->GetURL();
596 std::string is_constrained
;
597 net::GetValueForKeyInQuery(current_url
, "constrained", &is_constrained
);
599 content::WebContentsObserver::Observe(contents
);
600 LogHistogramValue(signin_metrics::HISTOGRAM_SHOWN
);
603 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue
* args
) {
604 content::WebContents
* contents
= web_ui()->GetWebContents();
605 const GURL
& current_url
= contents
->GetURL();
607 const base::DictionaryValue
* dict
= NULL
;
608 args
->GetDictionary(0, &dict
);
610 bool skip_for_now
= false;
611 dict
->GetBoolean("skipForNow", &skip_for_now
);
613 signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui()));
614 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
618 // This value exists only for webview sign in.
619 bool trusted
= false;
620 if (dict
->GetBoolean("trusted", &trusted
))
621 confirm_untrusted_signin_
= !trusted
;
623 base::string16 email_string16
;
624 dict
->GetString("email", &email_string16
);
625 DCHECK(!email_string16
.empty());
626 std::string
email(base::UTF16ToASCII(email_string16
));
628 base::string16 password_string16
;
629 dict
->GetString("password", &password_string16
);
630 std::string
password(base::UTF16ToASCII(password_string16
));
632 base::string16 gaia_id_string16
;
633 dict
->GetString("gaiaId", &gaia_id_string16
);
634 DCHECK(!gaia_id_string16
.empty());
635 std::string gaia_id
= base::UTF16ToASCII(gaia_id_string16
);
637 // When doing a SAML sign in, this email check may result in a false
638 // positive. This happens when the user types one email address in the
639 // gaia sign in page, but signs in to a different account in the SAML sign in
641 std::string default_email
;
642 std::string validate_email
;
643 if (net::GetValueForKeyInQuery(current_url
, "email", &default_email
) &&
644 net::GetValueForKeyInQuery(current_url
, "validateEmail",
646 validate_email
== "1") {
647 if (!gaia::AreEmailsSame(email
, default_email
)) {
648 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
653 base::string16 session_index_string16
;
654 dict
->GetString("sessionIndex", &session_index_string16
);
655 std::string session_index
= base::UTF16ToASCII(session_index_string16
);
656 DCHECK(!session_index
.empty());
658 bool choose_what_to_sync
= false;
659 dict
->GetBoolean("chooseWhatToSync", &choose_what_to_sync
);
661 signin_metrics::Source source
= signin::GetSourceForPromoURL(current_url
);
662 LogHistogramValue(signin_metrics::HISTOGRAM_ACCEPTED
);
663 bool switch_to_advanced
=
664 choose_what_to_sync
&& (source
!= signin_metrics::SOURCE_SETTINGS
);
666 switch_to_advanced
? signin_metrics::HISTOGRAM_WITH_ADVANCED
:
667 signin_metrics::HISTOGRAM_WITH_DEFAULTS
);
669 CanOfferFor can_offer_for
= CAN_OFFER_FOR_ALL
;
671 case signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
:
672 can_offer_for
= CAN_OFFER_FOR_SECONDARY_ACCOUNT
;
674 case signin_metrics::SOURCE_REAUTH
: {
675 std::string primary_username
=
676 SigninManagerFactory::GetForProfile(
677 Profile::FromWebUI(web_ui()))->GetAuthenticatedUsername();
678 if (!gaia::AreEmailsSame(default_email
, primary_username
))
679 can_offer_for
= CAN_OFFER_FOR_SECONDARY_ACCOUNT
;
683 // No need to change |can_offer_for|.
687 std::string error_msg
;
688 bool can_offer
= CanOffer(Profile::FromWebUI(web_ui()), can_offer_for
,
691 HandleLoginError(error_msg
);
695 AboutSigninInternals
* about_signin_internals
=
696 AboutSigninInternalsFactory::GetForProfile(Profile::FromWebUI(web_ui()));
697 about_signin_internals
->OnAuthenticationResultReceived("Successful");
699 content::StoragePartition
* partition
=
700 content::BrowserContext::GetStoragePartitionForSite(
701 contents
->GetBrowserContext(), signin::GetSigninPartitionURL());
703 SigninClient
* signin_client
=
704 ChromeSigninClientFactory::GetForProfile(Profile::FromWebUI(web_ui()));
705 std::string signin_scoped_device_id
=
706 signin_client
->GetSigninScopedDeviceId();
707 // InlineSigninHelper will delete itself.
708 new InlineSigninHelper(GetWeakPtr(), partition
->GetURLRequestContext(),
709 Profile::FromWebUI(web_ui()), current_url
,
710 email
, gaia_id
, password
, session_index
,
711 signin_scoped_device_id
, choose_what_to_sync
,
712 confirm_untrusted_signin_
);
714 web_ui()->CallJavascriptFunction("inline.login.closeDialog");
717 void InlineLoginHandlerImpl::HandleLoginError(const std::string
& error_msg
) {
718 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
720 Browser
* browser
= GetDesktopBrowser();
721 if (browser
&& !error_msg
.empty()) {
722 LoginUIServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
723 DisplayLoginResult(browser
, base::UTF8ToUTF16(error_msg
));
727 Browser
* InlineLoginHandlerImpl::GetDesktopBrowser() {
728 Browser
* browser
= chrome::FindBrowserWithWebContents(
729 web_ui()->GetWebContents());
731 browser
= chrome::FindLastActiveWithProfile(
732 Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop());
737 void InlineLoginHandlerImpl::SyncStarterCallback(
738 OneClickSigninSyncStarter::SyncSetupResult result
) {
739 content::WebContents
* contents
= web_ui()->GetWebContents();
741 if (contents
->GetController().GetPendingEntry()) {
742 // Do nothing if a navigation is pending, since this call can be triggered
743 // from DidStartLoading. This avoids deleting the pending entry while we are
744 // still navigating to it. See crbug/346632.
748 const GURL
& current_url
= contents
->GetLastCommittedURL();
749 signin_metrics::Source source
= signin::GetSourceForPromoURL(current_url
);
750 bool auto_close
= signin::IsAutoCloseEnabledInURL(current_url
);
752 if (result
== OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
) {
753 RedirectToNtpOrAppsPage(contents
, source
);
754 } else if (auto_close
) {
755 base::MessageLoop::current()->PostTask(
757 base::Bind(&InlineLoginHandlerImpl::CloseTab
,
758 weak_factory_
.GetWeakPtr(),
759 signin::ShouldShowAccountManagement(current_url
)));
761 RedirectToNtpOrAppsPageIfNecessary(contents
, source
);
765 void InlineLoginHandlerImpl::CloseTab(bool show_account_management
) {
766 content::WebContents
* tab
= web_ui()->GetWebContents();
767 Browser
* browser
= chrome::FindBrowserWithWebContents(tab
);
769 TabStripModel
* tab_strip_model
= browser
->tab_strip_model();
770 if (tab_strip_model
) {
771 int index
= tab_strip_model
->GetIndexOfWebContents(tab
);
772 if (index
!= TabStripModel::kNoTab
) {
773 tab_strip_model
->ExecuteContextMenuCommand(
774 index
, TabStripModel::CommandCloseTab
);
778 if (show_account_management
) {
779 browser
->window()->ShowAvatarBubbleFromAvatarButton(
780 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT
,
781 signin::ManageAccountsParams());