Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / webui / signin / inline_login_handler_impl.cc
blob7294764b9e6edd82e9e15acb677d568bd7abe3ab
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"
7 #include <string>
9 #include "base/bind.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"
60 namespace {
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())
73 return;
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,
80 content::Referrer(),
81 CURRENT_TAB,
82 ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
83 false);
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 {
94 public:
95 enum Action {
96 CREATE_NEW_USER,
97 START_SYNC,
98 CLOSE
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,
108 Callback callback);
110 private:
111 ConfirmEmailDialogDelegate(content::WebContents* contents,
112 const std::string& last_email,
113 const std::string& email,
114 Callback callback);
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_;
129 std::string email_;
130 Callback callback_;
132 // Web contents from which the "Learn more" link should be opened.
133 content::WebContents* web_contents_;
135 DISALLOW_COPY_AND_ASSIGN(ConfirmEmailDialogDelegate);
138 // static
139 void ConfirmEmailDialogDelegate::AskForConfirmation(
140 content::WebContents* contents,
141 const std::string& last_email,
142 const std::string& email,
143 Callback callback) {
144 TabModalConfirmDialog::Create(
145 new ConfirmEmailDialogDelegate(contents, last_email, email, callback),
146 contents);
149 ConfirmEmailDialogDelegate::ConfirmEmailDialogDelegate(
150 content::WebContents* contents,
151 const std::string& last_email,
152 const std::string& email,
153 Callback callback)
154 : TabModalConfirmDialogDelegate(contents),
155 last_email_(last_email),
156 email_(email),
157 callback_(callback),
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),
205 content::Referrer(),
206 NEW_POPUP,
207 ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
208 false);
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
211 // performed.
212 web_contents_->OpenURL(params);
215 class InlineSigninHelper : public GaiaAuthConsumer {
216 public:
217 InlineSigninHelper(
218 base::WeakPtr<InlineLoginHandlerImpl> handler,
219 net::URLRequestContextGetter* getter,
220 Profile* profile,
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);
230 private:
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)
253 override;
255 GaiaAuthFetcher gaia_auth_fetcher_;
256 base::WeakPtr<InlineLoginHandlerImpl> handler_;
257 Profile* profile_;
258 GURL current_url_;
259 std::string email_;
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,
272 Profile* profile,
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),
282 handler_(handler),
283 profile_(profile),
284 current_url_(current_url),
285 email_(email),
286 gaia_id_(gaia_id),
287 password_(password),
288 session_index_(session_index),
289 choose_what_to_sync_(choose_what_to_sync),
290 confirm_untrusted_signin_(confirm_untrusted_signin) {
291 DCHECK(profile_);
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;
300 if (handler_) {
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 // Prime the account tracker with this combination of gaia id/display email.
310 std::string account_id =
311 AccountTrackerServiceFactory::GetForProfile(profile_)
312 ->SeedAccountInfo(gaia_id_, email_);
314 signin_metrics::Source source = signin::GetSourceForPromoURL(current_url_);
316 SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile_);
317 std::string primary_email = signin_manager->GetAuthenticatedUsername();
318 if (gaia::AreEmailsSame(email_, primary_email) &&
319 source == signin_metrics::SOURCE_REAUTH &&
320 switches::IsNewProfileManagement() &&
321 !password_.empty() &&
322 profiles::IsLockAvailable(profile_)) {
323 LocalAuth::SetLocalAuthCredentials(profile_, password_);
326 if (source == signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ||
327 source == signin_metrics::SOURCE_REAUTH) {
328 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
329 UpdateCredentials(account_id, result.refresh_token);
331 if (signin::IsAutoCloseEnabledInURL(current_url_)) {
332 // Close the gaia sign in tab via a task to make sure we aren't in the
333 // middle of any webui handler code.
334 base::MessageLoop::current()->PostTask(
335 FROM_HERE,
336 base::Bind(&InlineLoginHandlerImpl::CloseTab,
337 handler_,
338 signin::ShouldShowAccountManagement(current_url_)));
341 if (source == signin_metrics::SOURCE_REAUTH)
342 signin_manager->MergeSigninCredentialIntoCookieJar();
343 } else {
344 ProfileSyncService* sync_service =
345 ProfileSyncServiceFactory::GetForProfile(profile_);
346 SigninErrorController* error_controller =
347 SigninErrorControllerFactory::GetForProfile(profile_);
349 bool is_new_avatar_menu = switches::IsNewAvatarMenu();
351 OneClickSigninSyncStarter::StartSyncMode start_mode;
352 if (source == signin_metrics::SOURCE_SETTINGS || choose_what_to_sync_) {
353 bool show_settings_without_configure =
354 error_controller->HasError() &&
355 sync_service &&
356 sync_service->HasSyncSetupCompleted();
357 start_mode = show_settings_without_configure ?
358 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
359 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST;
360 } else {
361 start_mode = is_new_avatar_menu ?
362 OneClickSigninSyncStarter::CONFIRM_SYNC_SETTINGS_FIRST :
363 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
366 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required;
367 if (confirm_untrusted_signin_) {
368 confirmation_required =
369 OneClickSigninSyncStarter::CONFIRM_UNTRUSTED_SIGNIN;
370 } else if (is_new_avatar_menu) {
371 confirmation_required = OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
372 } else {
373 confirmation_required =
374 source == signin_metrics::SOURCE_SETTINGS ||
375 choose_what_to_sync_ ?
376 OneClickSigninSyncStarter::NO_CONFIRMATION :
377 OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
380 bool start_signin = !HandleCrossAccountError(result.refresh_token, source,
381 confirmation_required, start_mode);
382 if (start_signin) {
383 // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
384 // OneClickSigninSyncStarter will delete itself once the job is done.
385 new OneClickSigninSyncStarter(
386 profile_, browser,
387 gaia_id_, email_, password_, result.refresh_token,
388 start_mode,
389 contents,
390 confirmation_required,
391 signin::GetNextPageURLForPromoURL(current_url_),
392 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback, handler_));
393 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
398 bool InlineSigninHelper::HandleCrossAccountError(
399 const std::string& refresh_token,
400 signin_metrics::Source source,
401 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required,
402 OneClickSigninSyncStarter::StartSyncMode start_mode) {
403 std::string last_email =
404 profile_->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
406 if (last_email.empty() || gaia::AreEmailsSame(last_email, email_))
407 return false;
409 Browser* browser = chrome::FindLastActiveWithProfile(
410 profile_, chrome::GetActiveDesktop());
411 content::WebContents* web_contents =
412 browser->tab_strip_model()->GetActiveWebContents();
414 ConfirmEmailDialogDelegate::AskForConfirmation(
415 web_contents,
416 last_email,
417 email_,
418 base::Bind(&InlineSigninHelper::ConfirmEmailAction,
419 base::Unretained(this),
420 web_contents,
421 refresh_token,
422 source,
423 confirmation_required,
424 start_mode));
425 return true;
428 void InlineSigninHelper::ConfirmEmailAction(
429 content::WebContents* web_contents,
430 const std::string& refresh_token,
431 signin_metrics::Source source,
432 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required,
433 OneClickSigninSyncStarter::StartSyncMode start_mode,
434 ConfirmEmailDialogDelegate::Action action) {
435 Browser* browser = chrome::FindLastActiveWithProfile(
436 profile_, chrome::GetActiveDesktop());
437 switch (action) {
438 case ConfirmEmailDialogDelegate::CREATE_NEW_USER:
439 if (handler_) {
440 handler_->SyncStarterCallback(
441 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
443 chrome::ShowSettingsSubPage(browser,
444 std::string(chrome::kCreateProfileSubPage));
445 break;
446 case ConfirmEmailDialogDelegate::START_SYNC:
447 new OneClickSigninSyncStarter(
448 profile_, browser, gaia_id_, email_, password_, refresh_token,
449 start_mode, web_contents, confirmation_required, GURL(),
450 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback, handler_));
451 break;
452 case ConfirmEmailDialogDelegate::CLOSE:
453 if (handler_) {
454 handler_->SyncStarterCallback(
455 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
457 break;
458 default:
459 DCHECK(false) << "Invalid action";
461 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
464 void InlineSigninHelper::OnClientOAuthFailure(
465 const GoogleServiceAuthError& error) {
466 if (handler_)
467 handler_->HandleLoginError(error.ToString());
469 AboutSigninInternals* about_signin_internals =
470 AboutSigninInternalsFactory::GetForProfile(profile_);
471 about_signin_internals->OnRefreshTokenReceived("Failure");
473 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
476 } // namespace
478 InlineLoginHandlerImpl::InlineLoginHandlerImpl()
479 : confirm_untrusted_signin_(false),
480 weak_factory_(this) {
483 InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
485 // This method is not called with webview sign in enabled.
486 void InlineLoginHandlerImpl::DidCommitProvisionalLoadForFrame(
487 content::RenderFrameHost* render_frame_host,
488 const GURL& url,
489 ui::PageTransition transition_type) {
490 if (!web_contents())
491 return;
493 // Returns early if this is not a gaia iframe navigation.
494 const GURL kGaiaExtOrigin(
495 "chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/");
496 content::RenderFrameHost* gaia_frame = InlineLoginUI::GetAuthFrame(
497 web_contents(), kGaiaExtOrigin, "signin-frame");
498 if (render_frame_host != gaia_frame)
499 return;
501 // Loading any untrusted (e.g., HTTP) URLs in the privileged sign-in process
502 // will require confirmation before the sign in takes effect.
503 if (!url.is_empty()) {
504 GURL origin(url.GetOrigin());
505 if (url.spec() != url::kAboutBlankURL &&
506 origin != kGaiaExtOrigin &&
507 !gaia::IsGaiaSignonRealm(origin)) {
508 confirm_untrusted_signin_ = true;
513 // static
514 bool InlineLoginHandlerImpl::CanOffer(Profile* profile,
515 CanOfferFor can_offer_for,
516 const std::string& gaia_id,
517 const std::string& email,
518 std::string* error_message) {
519 if (error_message)
520 error_message->clear();
522 if (!profile)
523 return false;
525 SigninManager* manager = SigninManagerFactory::GetForProfile(profile);
526 if (manager && !manager->IsSigninAllowed())
527 return false;
529 if (!ChromeSigninClient::ProfileAllowsSigninCookies(profile))
530 return false;
532 if (!email.empty()) {
533 if (!manager)
534 return false;
536 // Make sure this username is not prohibited by policy.
537 if (!manager->IsAllowedUsername(email)) {
538 if (error_message) {
539 error_message->assign(
540 l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED));
542 return false;
545 if (can_offer_for == CAN_OFFER_FOR_SECONDARY_ACCOUNT)
546 return true;
548 // If the signin manager already has an authenticated name, then this is a
549 // re-auth scenario. Make sure the email just signed in corresponds to
550 // the one sign in manager expects.
551 std::string current_email = manager->GetAuthenticatedUsername();
552 const bool same_email = gaia::AreEmailsSame(current_email, email);
553 if (!current_email.empty() && !same_email) {
554 UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
555 signin_metrics::HISTOGRAM_ACCOUNT_MISSMATCH,
556 signin_metrics::HISTOGRAM_MAX);
557 if (error_message) {
558 error_message->assign(
559 l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL,
560 base::UTF8ToUTF16(current_email)));
562 return false;
565 // If some profile, not just the current one, is already connected to this
566 // account, don't show the infobar.
567 if (g_browser_process && !same_email) {
568 ProfileManager* profile_manager = g_browser_process->profile_manager();
569 if (profile_manager) {
570 ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
571 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
572 // For backward compatibility, need to also check the username of the
573 // profile, since the GAIA ID may not have been set yet for the
574 // profile cache info. It will get set once the profile is opened.
575 std::string profile_gaia_id = cache.GetGAIAIdOfProfileAtIndex(i);
576 std::string profile_email =
577 base::UTF16ToUTF8(cache.GetUserNameOfProfileAtIndex(i));
578 if (gaia_id == profile_gaia_id ||
579 gaia::AreEmailsSame(email, profile_email)) {
580 if (error_message) {
581 error_message->assign(
582 l10n_util::GetStringUTF8(IDS_SYNC_USER_NAME_IN_USE_ERROR));
584 return false;
591 return true;
594 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
595 params.SetString("service", "chromiumsync");
597 content::WebContents* contents = web_ui()->GetWebContents();
598 const GURL& current_url = contents->GetURL();
599 std::string is_constrained;
600 net::GetValueForKeyInQuery(current_url, "constrained", &is_constrained);
602 content::WebContentsObserver::Observe(contents);
603 LogHistogramValue(signin_metrics::HISTOGRAM_SHOWN);
606 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
607 content::WebContents* contents = web_ui()->GetWebContents();
608 const GURL& current_url = contents->GetURL();
610 const base::DictionaryValue* dict = NULL;
611 args->GetDictionary(0, &dict);
613 bool skip_for_now = false;
614 dict->GetBoolean("skipForNow", &skip_for_now);
615 if (skip_for_now) {
616 signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui()));
617 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
618 return;
621 // This value exists only for webview sign in.
622 bool trusted = false;
623 if (dict->GetBoolean("trusted", &trusted))
624 confirm_untrusted_signin_ = !trusted;
626 base::string16 email_string16;
627 dict->GetString("email", &email_string16);
628 DCHECK(!email_string16.empty());
629 std::string email(base::UTF16ToASCII(email_string16));
631 base::string16 password_string16;
632 dict->GetString("password", &password_string16);
633 std::string password(base::UTF16ToASCII(password_string16));
635 base::string16 gaia_id_string16;
636 dict->GetString("gaiaId", &gaia_id_string16);
637 DCHECK(!gaia_id_string16.empty());
638 std::string gaia_id = base::UTF16ToASCII(gaia_id_string16);
640 // When doing a SAML sign in, this email check may result in a false
641 // positive. This happens when the user types one email address in the
642 // gaia sign in page, but signs in to a different account in the SAML sign in
643 // page.
644 std::string default_email;
645 std::string validate_email;
646 if (net::GetValueForKeyInQuery(current_url, "email", &default_email) &&
647 net::GetValueForKeyInQuery(current_url, "validateEmail",
648 &validate_email) &&
649 validate_email == "1") {
650 if (!gaia::AreEmailsSame(email, default_email)) {
651 HandleLoginError(
652 l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL,
653 base::UTF8ToUTF16(default_email)));
654 return;
658 base::string16 session_index_string16;
659 dict->GetString("sessionIndex", &session_index_string16);
660 std::string session_index = base::UTF16ToASCII(session_index_string16);
661 DCHECK(!session_index.empty());
663 bool choose_what_to_sync = false;
664 dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync);
666 signin_metrics::Source source = signin::GetSourceForPromoURL(current_url);
667 LogHistogramValue(signin_metrics::HISTOGRAM_ACCEPTED);
668 bool switch_to_advanced =
669 choose_what_to_sync && (source != signin_metrics::SOURCE_SETTINGS);
670 LogHistogramValue(
671 switch_to_advanced ? signin_metrics::HISTOGRAM_WITH_ADVANCED :
672 signin_metrics::HISTOGRAM_WITH_DEFAULTS);
674 CanOfferFor can_offer_for = CAN_OFFER_FOR_ALL;
675 switch (source) {
676 case signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT:
677 can_offer_for = CAN_OFFER_FOR_SECONDARY_ACCOUNT;
678 break;
679 case signin_metrics::SOURCE_REAUTH: {
680 std::string primary_username =
681 SigninManagerFactory::GetForProfile(
682 Profile::FromWebUI(web_ui()))->GetAuthenticatedUsername();
683 if (!gaia::AreEmailsSame(default_email, primary_username))
684 can_offer_for = CAN_OFFER_FOR_SECONDARY_ACCOUNT;
685 break;
687 default:
688 // No need to change |can_offer_for|.
689 break;
692 std::string error_msg;
693 bool can_offer = CanOffer(Profile::FromWebUI(web_ui()), can_offer_for,
694 gaia_id, email, &error_msg);
695 if (!can_offer) {
696 HandleLoginError(error_msg);
697 return;
700 AboutSigninInternals* about_signin_internals =
701 AboutSigninInternalsFactory::GetForProfile(Profile::FromWebUI(web_ui()));
702 about_signin_internals->OnAuthenticationResultReceived("Successful");
704 content::StoragePartition* partition =
705 content::BrowserContext::GetStoragePartitionForSite(
706 contents->GetBrowserContext(), signin::GetSigninPartitionURL());
708 SigninClient* signin_client =
709 ChromeSigninClientFactory::GetForProfile(Profile::FromWebUI(web_ui()));
710 std::string signin_scoped_device_id =
711 signin_client->GetSigninScopedDeviceId();
712 // InlineSigninHelper will delete itself.
713 new InlineSigninHelper(GetWeakPtr(), partition->GetURLRequestContext(),
714 Profile::FromWebUI(web_ui()), current_url,
715 email, gaia_id, password, session_index,
716 signin_scoped_device_id, choose_what_to_sync,
717 confirm_untrusted_signin_);
719 web_ui()->CallJavascriptFunction("inline.login.closeDialog");
722 void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) {
723 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
725 Browser* browser = GetDesktopBrowser();
726 if (browser && !error_msg.empty()) {
727 LoginUIServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
728 DisplayLoginResult(browser, base::UTF8ToUTF16(error_msg));
732 Browser* InlineLoginHandlerImpl::GetDesktopBrowser() {
733 Browser* browser = chrome::FindBrowserWithWebContents(
734 web_ui()->GetWebContents());
735 if (!browser) {
736 browser = chrome::FindLastActiveWithProfile(
737 Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop());
739 return browser;
742 void InlineLoginHandlerImpl::SyncStarterCallback(
743 OneClickSigninSyncStarter::SyncSetupResult result) {
744 content::WebContents* contents = web_ui()->GetWebContents();
746 if (contents->GetController().GetPendingEntry()) {
747 // Do nothing if a navigation is pending, since this call can be triggered
748 // from DidStartLoading. This avoids deleting the pending entry while we are
749 // still navigating to it. See crbug/346632.
750 return;
753 const GURL& current_url = contents->GetLastCommittedURL();
754 signin_metrics::Source source = signin::GetSourceForPromoURL(current_url);
755 bool auto_close = signin::IsAutoCloseEnabledInURL(current_url);
757 if (result == OneClickSigninSyncStarter::SYNC_SETUP_FAILURE) {
758 RedirectToNtpOrAppsPage(contents, source);
759 } else if (auto_close) {
760 base::MessageLoop::current()->PostTask(
761 FROM_HERE,
762 base::Bind(&InlineLoginHandlerImpl::CloseTab,
763 weak_factory_.GetWeakPtr(),
764 signin::ShouldShowAccountManagement(current_url)));
765 } else {
766 RedirectToNtpOrAppsPageIfNecessary(contents, source);
770 void InlineLoginHandlerImpl::CloseTab(bool show_account_management) {
771 content::WebContents* tab = web_ui()->GetWebContents();
772 Browser* browser = chrome::FindBrowserWithWebContents(tab);
773 if (browser) {
774 TabStripModel* tab_strip_model = browser->tab_strip_model();
775 if (tab_strip_model) {
776 int index = tab_strip_model->GetIndexOfWebContents(tab);
777 if (index != TabStripModel::kNoTab) {
778 tab_strip_model->ExecuteContextMenuCommand(
779 index, TabStripModel::CommandCloseTab);
783 if (show_account_management) {
784 browser->window()->ShowAvatarBubbleFromAvatarButton(
785 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT,
786 signin::ManageAccountsParams());