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/location.h"
12 #include "base/metrics/histogram.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/profiles/profile_window.h"
23 #include "chrome/browser/signin/about_signin_internals_factory.h"
24 #include "chrome/browser/signin/account_tracker_service_factory.h"
25 #include "chrome/browser/signin/chrome_signin_client_factory.h"
26 #include "chrome/browser/signin/local_auth.h"
27 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
28 #include "chrome/browser/signin/signin_error_controller_factory.h"
29 #include "chrome/browser/signin/signin_manager_factory.h"
30 #include "chrome/browser/signin/signin_promo.h"
31 #include "chrome/browser/sync/profile_sync_service.h"
32 #include "chrome/browser/sync/profile_sync_service_factory.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_window.h"
35 #include "chrome/browser/ui/chrome_pages.h"
36 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
37 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
38 #include "chrome/browser/ui/tabs/tab_strip_model.h"
39 #include "chrome/browser/ui/user_manager.h"
40 #include "chrome/browser/ui/webui/signin/inline_login_ui.h"
41 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
42 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
43 #include "chrome/common/url_constants.h"
44 #include "chrome/grit/chromium_strings.h"
45 #include "chrome/grit/generated_resources.h"
46 #include "components/signin/core/browser/about_signin_internals.h"
47 #include "components/signin/core/browser/account_tracker_service.h"
48 #include "components/signin/core/browser/profile_oauth2_token_service.h"
49 #include "components/signin/core/browser/signin_error_controller.h"
50 #include "components/signin/core/browser/signin_header_helper.h"
51 #include "components/signin/core/browser/signin_metrics.h"
52 #include "components/signin/core/common/profile_management_switches.h"
53 #include "components/signin/core/common/signin_pref_names.h"
54 #include "content/public/browser/storage_partition.h"
55 #include "content/public/browser/web_ui.h"
56 #include "google_apis/gaia/gaia_auth_consumer.h"
57 #include "google_apis/gaia/gaia_auth_fetcher.h"
58 #include "google_apis/gaia/gaia_auth_util.h"
59 #include "google_apis/gaia/gaia_constants.h"
60 #include "google_apis/gaia/gaia_urls.h"
61 #include "grit/components_strings.h"
62 #include "net/base/url_util.h"
63 #include "ui/base/l10n/l10n_util.h"
67 void LogHistogramValue(int action
) {
68 UMA_HISTOGRAM_ENUMERATION("Signin.AllAccessPointActions", action
,
69 signin_metrics::HISTOGRAM_MAX
);
72 void RedirectToNtpOrAppsPage(content::WebContents
* contents
,
73 signin_metrics::Source source
) {
74 // Do nothing if a navigation is pending, since this call can be triggered
75 // from DidStartLoading. This avoids deleting the pending entry while we are
76 // still navigating to it. See crbug/346632.
77 if (contents
->GetController().GetPendingEntry())
80 VLOG(1) << "RedirectToNtpOrAppsPage";
81 // Redirect to NTP/Apps page and display a confirmation bubble
82 GURL
url(source
== signin_metrics::SOURCE_APPS_PAGE_LINK
?
83 chrome::kChromeUIAppsURL
: chrome::kChromeUINewTabURL
);
84 content::OpenURLParams
params(url
,
87 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
89 contents
->OpenURL(params
);
92 void RedirectToNtpOrAppsPageIfNecessary(content::WebContents
* contents
,
93 signin_metrics::Source source
) {
94 if (source
!= signin_metrics::SOURCE_SETTINGS
)
95 RedirectToNtpOrAppsPage(contents
, source
);
98 class ConfirmEmailDialogDelegate
: public TabModalConfirmDialogDelegate
{
106 // Callback indicating action performed by the user.
107 typedef base::Callback
<void(Action
)> Callback
;
109 // Ask the user for confirmation before starting to sync.
110 static void AskForConfirmation(content::WebContents
* contents
,
111 const std::string
& last_email
,
112 const std::string
& email
,
116 ConfirmEmailDialogDelegate(content::WebContents
* contents
,
117 const std::string
& last_email
,
118 const std::string
& email
,
120 ~ConfirmEmailDialogDelegate() override
;
122 // TabModalConfirmDialogDelegate:
123 base::string16
GetTitle() override
;
124 base::string16
GetDialogMessage() override
;
125 base::string16
GetAcceptButtonTitle() override
;
126 base::string16
GetCancelButtonTitle() override
;
127 base::string16
GetLinkText() const override
;
128 void OnAccepted() override
;
129 void OnCanceled() override
;
130 void OnClosed() override
;
131 void OnLinkClicked(WindowOpenDisposition disposition
) override
;
133 std::string last_email_
;
137 // Web contents from which the "Learn more" link should be opened.
138 content::WebContents
* web_contents_
;
140 DISALLOW_COPY_AND_ASSIGN(ConfirmEmailDialogDelegate
);
144 void ConfirmEmailDialogDelegate::AskForConfirmation(
145 content::WebContents
* contents
,
146 const std::string
& last_email
,
147 const std::string
& email
,
149 TabModalConfirmDialog::Create(
150 new ConfirmEmailDialogDelegate(contents
, last_email
, email
, callback
),
154 ConfirmEmailDialogDelegate::ConfirmEmailDialogDelegate(
155 content::WebContents
* contents
,
156 const std::string
& last_email
,
157 const std::string
& email
,
159 : TabModalConfirmDialogDelegate(contents
),
160 last_email_(last_email
),
163 web_contents_(contents
) {
166 ConfirmEmailDialogDelegate::~ConfirmEmailDialogDelegate() {
169 base::string16
ConfirmEmailDialogDelegate::GetTitle() {
170 return l10n_util::GetStringUTF16(
171 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_TITLE
);
174 base::string16
ConfirmEmailDialogDelegate::GetDialogMessage() {
175 return l10n_util::GetStringFUTF16(
176 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_MESSAGE
,
177 base::UTF8ToUTF16(last_email_
), base::UTF8ToUTF16(email_
));
180 base::string16
ConfirmEmailDialogDelegate::GetAcceptButtonTitle() {
181 return l10n_util::GetStringUTF16(
182 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_OK_BUTTON
);
185 base::string16
ConfirmEmailDialogDelegate::GetCancelButtonTitle() {
186 return l10n_util::GetStringUTF16(
187 IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_CANCEL_BUTTON
);
190 base::string16
ConfirmEmailDialogDelegate::GetLinkText() const {
191 return l10n_util::GetStringUTF16(IDS_LEARN_MORE
);
194 void ConfirmEmailDialogDelegate::OnAccepted() {
195 base::ResetAndReturn(&callback_
).Run(CREATE_NEW_USER
);
198 void ConfirmEmailDialogDelegate::OnCanceled() {
199 base::ResetAndReturn(&callback_
).Run(START_SYNC
);
202 void ConfirmEmailDialogDelegate::OnClosed() {
203 base::ResetAndReturn(&callback_
).Run(CLOSE
);
206 void ConfirmEmailDialogDelegate::OnLinkClicked(
207 WindowOpenDisposition disposition
) {
208 content::OpenURLParams
params(
209 GURL(chrome::kChromeSyncMergeTroubleshootingURL
),
212 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
214 // It is guaranteed that |web_contents_| is valid here because when it's
215 // deleted, the dialog is immediately closed and no further action can be
217 web_contents_
->OpenURL(params
);
220 class InlineSigninHelper
: public GaiaAuthConsumer
{
223 base::WeakPtr
<InlineLoginHandlerImpl
> handler
,
224 net::URLRequestContextGetter
* getter
,
226 const GURL
& current_url
,
227 const std::string
& email
,
228 const std::string
& gaia_id
,
229 const std::string
& password
,
230 const std::string
& session_index
,
231 const std::string
& signin_scoped_device_id
,
232 bool choose_what_to_sync
,
233 bool confirm_untrusted_signin
);
236 // Handles cross account sign in error. If the supplied |email| does not match
237 // the last signed in email of the current profile, then Chrome will show a
238 // confirmation dialog before starting sync. It returns true if there is a
239 // cross account error, and false otherwise.
240 bool HandleCrossAccountError(
241 const std::string
& refresh_token
,
242 signin_metrics::Source source
,
243 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
244 OneClickSigninSyncStarter::StartSyncMode start_mode
);
246 // Callback used with ConfirmEmailDialogDelegate.
247 void ConfirmEmailAction(
248 content::WebContents
* web_contents
,
249 const std::string
& refresh_token
,
250 signin_metrics::Source source
,
251 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
252 OneClickSigninSyncStarter::StartSyncMode start_mode
,
253 ConfirmEmailDialogDelegate::Action action
);
255 // Overridden from GaiaAuthConsumer.
256 void OnClientOAuthSuccess(const ClientOAuthResult
& result
) override
;
257 void OnClientOAuthFailure(const GoogleServiceAuthError
& error
)
260 GaiaAuthFetcher gaia_auth_fetcher_
;
261 base::WeakPtr
<InlineLoginHandlerImpl
> handler_
;
265 std::string gaia_id_
;
266 std::string password_
;
267 std::string session_index_
;
268 bool choose_what_to_sync_
;
269 bool confirm_untrusted_signin_
;
271 DISALLOW_COPY_AND_ASSIGN(InlineSigninHelper
);
274 InlineSigninHelper::InlineSigninHelper(
275 base::WeakPtr
<InlineLoginHandlerImpl
> handler
,
276 net::URLRequestContextGetter
* getter
,
278 const GURL
& current_url
,
279 const std::string
& email
,
280 const std::string
& gaia_id
,
281 const std::string
& password
,
282 const std::string
& session_index
,
283 const std::string
& signin_scoped_device_id
,
284 bool choose_what_to_sync
,
285 bool confirm_untrusted_signin
)
286 : gaia_auth_fetcher_(this, GaiaConstants::kChromeSource
, getter
),
289 current_url_(current_url
),
293 session_index_(session_index
),
294 choose_what_to_sync_(choose_what_to_sync
),
295 confirm_untrusted_signin_(confirm_untrusted_signin
) {
297 DCHECK(!email_
.empty());
298 gaia_auth_fetcher_
.StartCookieForOAuthLoginTokenExchangeWithDeviceId(
299 session_index
, signin_scoped_device_id
);
302 void InlineSigninHelper::OnClientOAuthSuccess(const ClientOAuthResult
& result
) {
303 content::WebContents
* contents
= NULL
;
304 Browser
* browser
= NULL
;
306 contents
= handler_
->web_ui()->GetWebContents();
307 browser
= handler_
->GetDesktopBrowser();
310 AboutSigninInternals
* about_signin_internals
=
311 AboutSigninInternalsFactory::GetForProfile(profile_
);
312 about_signin_internals
->OnRefreshTokenReceived("Successful");
314 // Prime the account tracker with this combination of gaia id/display email.
315 std::string account_id
=
316 AccountTrackerServiceFactory::GetForProfile(profile_
)
317 ->SeedAccountInfo(gaia_id_
, email_
);
319 signin_metrics::Source source
= signin::GetSourceForPromoURL(current_url_
);
321 SigninManager
* signin_manager
= SigninManagerFactory::GetForProfile(profile_
);
322 std::string primary_email
=
323 signin_manager
->GetAuthenticatedAccountInfo().email
;
324 if (gaia::AreEmailsSame(email_
, primary_email
) &&
325 source
== signin_metrics::SOURCE_REAUTH
&&
326 switches::IsNewProfileManagement() &&
327 !password_
.empty() &&
328 profiles::IsLockAvailable(profile_
)) {
329 LocalAuth::SetLocalAuthCredentials(profile_
, password_
);
332 if (source
== signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
||
333 source
== signin_metrics::SOURCE_REAUTH
) {
334 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
)->
335 UpdateCredentials(account_id
, result
.refresh_token
);
337 if (signin::IsAutoCloseEnabledInURL(current_url_
)) {
338 // Close the gaia sign in tab via a task to make sure we aren't in the
339 // middle of any webui handler code.
340 base::ThreadTaskRunnerHandle::Get()->PostTask(
342 base::Bind(&InlineLoginHandlerImpl::CloseTab
, handler_
,
343 signin::ShouldShowAccountManagement(current_url_
)));
346 if (source
== signin_metrics::SOURCE_REAUTH
)
347 signin_manager
->MergeSigninCredentialIntoCookieJar();
349 ProfileSyncService
* sync_service
=
350 ProfileSyncServiceFactory::GetForProfile(profile_
);
351 SigninErrorController
* error_controller
=
352 SigninErrorControllerFactory::GetForProfile(profile_
);
354 bool is_new_avatar_menu
= switches::IsNewAvatarMenu();
356 OneClickSigninSyncStarter::StartSyncMode start_mode
;
357 if (source
== signin_metrics::SOURCE_SETTINGS
|| choose_what_to_sync_
) {
358 bool show_settings_without_configure
=
359 error_controller
->HasError() &&
361 sync_service
->HasSyncSetupCompleted();
362 start_mode
= show_settings_without_configure
?
363 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE
:
364 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST
;
366 start_mode
= is_new_avatar_menu
?
367 OneClickSigninSyncStarter::CONFIRM_SYNC_SETTINGS_FIRST
:
368 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS
;
371 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
;
372 if (confirm_untrusted_signin_
) {
373 confirmation_required
=
374 OneClickSigninSyncStarter::CONFIRM_UNTRUSTED_SIGNIN
;
375 } else if (is_new_avatar_menu
) {
376 confirmation_required
= OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN
;
378 confirmation_required
=
379 source
== signin_metrics::SOURCE_SETTINGS
||
380 choose_what_to_sync_
?
381 OneClickSigninSyncStarter::NO_CONFIRMATION
:
382 OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN
;
385 bool start_signin
= !HandleCrossAccountError(result
.refresh_token
, source
,
386 confirmation_required
, start_mode
);
388 // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
389 // OneClickSigninSyncStarter will delete itself once the job is done.
390 new OneClickSigninSyncStarter(
392 gaia_id_
, email_
, password_
, result
.refresh_token
,
395 confirmation_required
,
396 signin::GetNextPageURLForPromoURL(current_url_
),
397 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback
, handler_
));
398 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE
, this);
403 bool InlineSigninHelper::HandleCrossAccountError(
404 const std::string
& refresh_token
,
405 signin_metrics::Source source
,
406 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
407 OneClickSigninSyncStarter::StartSyncMode start_mode
) {
408 std::string last_email
=
409 profile_
->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername
);
411 if (last_email
.empty() || gaia::AreEmailsSame(last_email
, email_
))
414 Browser
* browser
= chrome::FindLastActiveWithProfile(
415 profile_
, chrome::GetActiveDesktop());
416 content::WebContents
* web_contents
=
417 browser
->tab_strip_model()->GetActiveWebContents();
419 ConfirmEmailDialogDelegate::AskForConfirmation(
423 base::Bind(&InlineSigninHelper::ConfirmEmailAction
,
424 base::Unretained(this),
428 confirmation_required
,
433 void InlineSigninHelper::ConfirmEmailAction(
434 content::WebContents
* web_contents
,
435 const std::string
& refresh_token
,
436 signin_metrics::Source source
,
437 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required
,
438 OneClickSigninSyncStarter::StartSyncMode start_mode
,
439 ConfirmEmailDialogDelegate::Action action
) {
440 Browser
* browser
= chrome::FindLastActiveWithProfile(
441 profile_
, chrome::GetActiveDesktop());
443 case ConfirmEmailDialogDelegate::CREATE_NEW_USER
:
445 handler_
->SyncStarterCallback(
446 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
448 chrome::ShowSettingsSubPage(browser
,
449 std::string(chrome::kCreateProfileSubPage
));
451 case ConfirmEmailDialogDelegate::START_SYNC
:
452 new OneClickSigninSyncStarter(
453 profile_
, browser
, gaia_id_
, email_
, password_
, refresh_token
,
454 start_mode
, web_contents
, confirmation_required
, GURL(),
455 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback
, handler_
));
457 case ConfirmEmailDialogDelegate::CLOSE
:
459 handler_
->SyncStarterCallback(
460 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
464 DCHECK(false) << "Invalid action";
466 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE
, this);
469 void InlineSigninHelper::OnClientOAuthFailure(
470 const GoogleServiceAuthError
& error
) {
472 handler_
->HandleLoginError(error
.ToString());
474 AboutSigninInternals
* about_signin_internals
=
475 AboutSigninInternalsFactory::GetForProfile(profile_
);
476 about_signin_internals
->OnRefreshTokenReceived("Failure");
478 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE
, this);
483 InlineLoginHandlerImpl::InlineLoginHandlerImpl()
484 : confirm_untrusted_signin_(false),
485 weak_factory_(this) {
488 InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
490 // This method is not called with webview sign in enabled.
491 void InlineLoginHandlerImpl::DidCommitProvisionalLoadForFrame(
492 content::RenderFrameHost
* render_frame_host
,
494 ui::PageTransition transition_type
) {
498 // Returns early if this is not a gaia iframe navigation.
499 const GURL
kGaiaExtOrigin(
500 GaiaUrls::GetInstance()->signin_completed_continue_url().GetOrigin());
501 content::RenderFrameHost
* gaia_frame
= InlineLoginUI::GetAuthFrame(
502 web_contents(), kGaiaExtOrigin
, "signin-frame");
503 if (render_frame_host
!= gaia_frame
)
506 // Loading any untrusted (e.g., HTTP) URLs in the privileged sign-in process
507 // will require confirmation before the sign in takes effect.
508 if (!url
.is_empty()) {
509 GURL
origin(url
.GetOrigin());
510 if (url
.spec() != url::kAboutBlankURL
&&
511 origin
!= kGaiaExtOrigin
&&
512 !gaia::IsGaiaSignonRealm(origin
)) {
513 confirm_untrusted_signin_
= true;
519 bool InlineLoginHandlerImpl::CanOffer(Profile
* profile
,
520 CanOfferFor can_offer_for
,
521 const std::string
& gaia_id
,
522 const std::string
& email
,
523 std::string
* error_message
) {
525 error_message
->clear();
530 SigninManager
* manager
= SigninManagerFactory::GetForProfile(profile
);
531 if (manager
&& !manager
->IsSigninAllowed())
534 if (!ChromeSigninClient::ProfileAllowsSigninCookies(profile
))
537 if (!email
.empty()) {
541 // Make sure this username is not prohibited by policy.
542 if (!manager
->IsAllowedUsername(email
)) {
544 error_message
->assign(
545 l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED
));
550 if (can_offer_for
== CAN_OFFER_FOR_SECONDARY_ACCOUNT
)
553 // If the signin manager already has an authenticated name, then this is a
554 // re-auth scenario. Make sure the email just signed in corresponds to
555 // the one sign in manager expects.
556 std::string current_email
= manager
->GetAuthenticatedAccountInfo().email
;
557 const bool same_email
= gaia::AreEmailsSame(current_email
, email
);
558 if (!current_email
.empty() && !same_email
) {
559 UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
560 signin_metrics::HISTOGRAM_ACCOUNT_MISSMATCH
,
561 signin_metrics::HISTOGRAM_MAX
);
563 error_message
->assign(
564 l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL
,
565 base::UTF8ToUTF16(current_email
)));
570 // If some profile, not just the current one, is already connected to this
571 // account, don't show the infobar.
572 if (g_browser_process
&& !same_email
) {
573 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
574 if (profile_manager
) {
575 ProfileInfoCache
& cache
= profile_manager
->GetProfileInfoCache();
576 for (size_t i
= 0; i
< cache
.GetNumberOfProfiles(); ++i
) {
577 // For backward compatibility, need to also check the username of the
578 // profile, since the GAIA ID may not have been set yet for the
579 // profile cache info. It will get set once the profile is opened.
580 std::string profile_gaia_id
= cache
.GetGAIAIdOfProfileAtIndex(i
);
581 std::string profile_email
=
582 base::UTF16ToUTF8(cache
.GetUserNameOfProfileAtIndex(i
));
583 if (gaia_id
== profile_gaia_id
||
584 gaia::AreEmailsSame(email
, profile_email
)) {
586 error_message
->assign(
587 l10n_util::GetStringUTF8(IDS_SYNC_USER_NAME_IN_USE_ERROR
));
599 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue
& params
) {
600 params
.SetString("service", "chromiumsync");
602 content::WebContents
* contents
= web_ui()->GetWebContents();
603 const GURL
& current_url
= contents
->GetURL();
604 std::string is_constrained
;
605 net::GetValueForKeyInQuery(current_url
, "constrained", &is_constrained
);
607 content::WebContentsObserver::Observe(contents
);
608 LogHistogramValue(signin_metrics::HISTOGRAM_SHOWN
);
611 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue
* args
) {
612 content::WebContents
* contents
= web_ui()->GetWebContents();
613 const GURL
& current_url
= contents
->GetURL();
615 const base::DictionaryValue
* dict
= NULL
;
616 args
->GetDictionary(0, &dict
);
618 bool skip_for_now
= false;
619 dict
->GetBoolean("skipForNow", &skip_for_now
);
621 signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui()));
622 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
626 // This value exists only for webview sign in.
627 bool trusted
= false;
628 if (dict
->GetBoolean("trusted", &trusted
))
629 confirm_untrusted_signin_
= !trusted
;
631 base::string16 email_string16
;
632 dict
->GetString("email", &email_string16
);
633 DCHECK(!email_string16
.empty());
634 std::string
email(base::UTF16ToASCII(email_string16
));
636 base::string16 password_string16
;
637 dict
->GetString("password", &password_string16
);
638 std::string
password(base::UTF16ToASCII(password_string16
));
640 base::string16 gaia_id_string16
;
641 dict
->GetString("gaiaId", &gaia_id_string16
);
642 DCHECK(!gaia_id_string16
.empty());
643 std::string gaia_id
= base::UTF16ToASCII(gaia_id_string16
);
645 base::string16 session_index_string16
;
646 dict
->GetString("sessionIndex", &session_index_string16
);
647 std::string session_index
= base::UTF16ToASCII(session_index_string16
);
648 DCHECK(!session_index
.empty());
650 bool choose_what_to_sync
= false;
651 dict
->GetBoolean("chooseWhatToSync", &choose_what_to_sync
);
653 content::StoragePartition
* partition
=
654 content::BrowserContext::GetStoragePartitionForSite(
655 contents
->GetBrowserContext(), signin::GetSigninPartitionURL());
657 // If this was called from the user manager to reauthenticate the profile,
658 // the current profile is the system profile. In this case, use the email to
659 // find the right profile to reauthenticate. Otherwise the profile can be
660 // taken from web_ui().
661 Profile
* profile
= Profile::FromWebUI(web_ui());
662 if (profile
->GetOriginalProfile()->IsSystemProfile()) {
663 // Switch to the profile and finish the login. Don't pass a handler pointer
664 // since it will be destroyed before the callback runs.
665 ProfileManager
* manager
= g_browser_process
->profile_manager();
666 base::FilePath path
= profiles::GetPathOfProfileWithEmail(manager
, email
);
668 FinishCompleteLoginParams
params(nullptr, partition
, current_url
, path
,
669 confirm_untrusted_signin_
, email
,
670 gaia_id
, password
, session_index
,
671 choose_what_to_sync
);
672 ProfileManager::CreateCallback callback
= base::Bind(
673 &InlineLoginHandlerImpl::FinishCompleteLogin
, params
);
674 profiles::SwitchToProfile(path
, chrome::GetActiveDesktop(), true,
675 callback
, ProfileMetrics::SWITCH_PROFILE_UNLOCK
);
679 FinishCompleteLoginParams(this, partition
, current_url
,
680 base::FilePath(), confirm_untrusted_signin_
,
681 email
, gaia_id
, password
, session_index
,
682 choose_what_to_sync
),
684 Profile::CREATE_STATUS_CREATED
);
688 InlineLoginHandlerImpl::FinishCompleteLoginParams::FinishCompleteLoginParams(
689 InlineLoginHandlerImpl
* handler
,
690 content::StoragePartition
* partition
,
692 const base::FilePath
& profile_path
,
693 bool confirm_untrusted_signin
,
694 const std::string
& email
,
695 const std::string
& gaia_id
,
696 const std::string
& password
,
697 const std::string
& session_index
,
698 bool choose_what_to_sync
)
700 partition(partition
),
702 profile_path(profile_path
),
703 confirm_untrusted_signin(confirm_untrusted_signin
),
707 session_index(session_index
),
708 choose_what_to_sync(choose_what_to_sync
) {}
710 InlineLoginHandlerImpl::
711 FinishCompleteLoginParams::~FinishCompleteLoginParams() {}
714 void InlineLoginHandlerImpl::FinishCompleteLogin(
715 const FinishCompleteLoginParams
& params
,
717 Profile::CreateStatus status
) {
718 // When doing a SAML sign in, this email check may result in a false
719 // positive. This happens when the user types one email address in the
720 // gaia sign in page, but signs in to a different account in the SAML sign in
722 std::string default_email
;
723 std::string validate_email
;
724 if (net::GetValueForKeyInQuery(params
.url
, "email", &default_email
) &&
725 net::GetValueForKeyInQuery(params
.url
, "validateEmail",
727 validate_email
== "1") {
728 if (!gaia::AreEmailsSame(params
.email
, default_email
)) {
729 if (params
.handler
) {
730 params
.handler
->HandleLoginError(
731 l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL
,
732 base::UTF8ToUTF16(default_email
)));
738 signin_metrics::Source source
= signin::GetSourceForPromoURL(params
.url
);
739 LogHistogramValue(signin_metrics::HISTOGRAM_ACCEPTED
);
740 bool switch_to_advanced
=
741 params
.choose_what_to_sync
&& (source
!= signin_metrics::SOURCE_SETTINGS
);
743 switch_to_advanced
? signin_metrics::HISTOGRAM_WITH_ADVANCED
:
744 signin_metrics::HISTOGRAM_WITH_DEFAULTS
);
746 CanOfferFor can_offer_for
= CAN_OFFER_FOR_ALL
;
748 case signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
:
749 can_offer_for
= CAN_OFFER_FOR_SECONDARY_ACCOUNT
;
751 case signin_metrics::SOURCE_REAUTH
: {
752 std::string primary_username
=
753 SigninManagerFactory::GetForProfile(profile
)
754 ->GetAuthenticatedAccountInfo()
756 if (!gaia::AreEmailsSame(default_email
, primary_username
))
757 can_offer_for
= CAN_OFFER_FOR_SECONDARY_ACCOUNT
;
761 // No need to change |can_offer_for|.
765 std::string error_msg
;
766 bool can_offer
= CanOffer(profile
, can_offer_for
, params
.gaia_id
,
767 params
.email
, &error_msg
);
770 params
.handler
->HandleLoginError(error_msg
);
774 AboutSigninInternals
* about_signin_internals
=
775 AboutSigninInternalsFactory::GetForProfile(profile
);
776 about_signin_internals
->OnAuthenticationResultReceived("Successful");
778 SigninClient
* signin_client
=
779 ChromeSigninClientFactory::GetForProfile(profile
);
780 std::string signin_scoped_device_id
=
781 signin_client
->GetSigninScopedDeviceId();
782 base::WeakPtr
<InlineLoginHandlerImpl
> handler_weak_ptr
;
784 handler_weak_ptr
= params
.handler
->GetWeakPtr();
786 // InlineSigninHelper will delete itself.
787 new InlineSigninHelper(handler_weak_ptr
,
788 params
.partition
->GetURLRequestContext(), profile
,
790 params
.email
, params
.gaia_id
, params
.password
,
791 params
.session_index
, signin_scoped_device_id
,
792 params
.choose_what_to_sync
,
793 params
.confirm_untrusted_signin
);
795 // If opened from user manager to reauthenticate, make sure the user manager
796 // is closed and that the profile is marked as unlocked.
797 if (!params
.profile_path
.empty()) {
799 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
800 if (profile_manager
) {
801 ProfileAttributesEntry
* entry
;
802 if (profile_manager
->GetProfileInfoCache()
803 .GetProfileAttributesWithPath(params
.profile_path
, &entry
)) {
804 entry
->SetIsSigninRequired(false);
811 web_ui()->CallJavascriptFunction("inline.login.closeDialog");
814 void InlineLoginHandlerImpl::HandleLoginError(const std::string
& error_msg
) {
815 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
);
817 Browser
* browser
= GetDesktopBrowser();
818 if (browser
&& !error_msg
.empty()) {
819 LoginUIServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
820 DisplayLoginResult(browser
, base::UTF8ToUTF16(error_msg
));
824 Browser
* InlineLoginHandlerImpl::GetDesktopBrowser() {
825 Browser
* browser
= chrome::FindBrowserWithWebContents(
826 web_ui()->GetWebContents());
828 browser
= chrome::FindLastActiveWithProfile(
829 Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop());
834 void InlineLoginHandlerImpl::SyncStarterCallback(
835 OneClickSigninSyncStarter::SyncSetupResult result
) {
836 content::WebContents
* contents
= web_ui()->GetWebContents();
838 if (contents
->GetController().GetPendingEntry()) {
839 // Do nothing if a navigation is pending, since this call can be triggered
840 // from DidStartLoading. This avoids deleting the pending entry while we are
841 // still navigating to it. See crbug/346632.
845 const GURL
& current_url
= contents
->GetLastCommittedURL();
846 signin_metrics::Source source
= signin::GetSourceForPromoURL(current_url
);
847 bool auto_close
= signin::IsAutoCloseEnabledInURL(current_url
);
849 if (result
== OneClickSigninSyncStarter::SYNC_SETUP_FAILURE
) {
850 RedirectToNtpOrAppsPage(contents
, source
);
851 } else if (auto_close
) {
852 base::ThreadTaskRunnerHandle::Get()->PostTask(
854 base::Bind(&InlineLoginHandlerImpl::CloseTab
,
855 weak_factory_
.GetWeakPtr(),
856 signin::ShouldShowAccountManagement(current_url
)));
858 RedirectToNtpOrAppsPageIfNecessary(contents
, source
);
862 void InlineLoginHandlerImpl::CloseTab(bool show_account_management
) {
863 content::WebContents
* tab
= web_ui()->GetWebContents();
864 Browser
* browser
= chrome::FindBrowserWithWebContents(tab
);
866 TabStripModel
* tab_strip_model
= browser
->tab_strip_model();
867 if (tab_strip_model
) {
868 int index
= tab_strip_model
->GetIndexOfWebContents(tab
);
869 if (index
!= TabStripModel::kNoTab
) {
870 tab_strip_model
->ExecuteContextMenuCommand(
871 index
, TabStripModel::CommandCloseTab
);
875 if (show_account_management
) {
876 browser
->window()->ShowAvatarBubbleFromAvatarButton(
877 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT
,
878 signin::ManageAccountsParams());