OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/sync/one_click_signin_helper.h" | 5 #include "chrome/browser/ui/sync/one_click_signin_helper.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 break; | 116 break; |
117 default: | 117 default: |
118 NOTREACHED() << "Invalid auto_accept: " << auto_accept; | 118 NOTREACHED() << "Invalid auto_accept: " << auto_accept; |
119 break; | 119 break; |
120 } | 120 } |
121 | 121 |
122 UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action, | 122 UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action, |
123 one_click_signin::HISTOGRAM_MAX); | 123 one_click_signin::HISTOGRAM_MAX); |
124 } | 124 } |
125 | 125 |
| 126 void ClearPendingEmailOnIOThread(content::ResourceContext* context) { |
| 127 ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| 128 DCHECK(io_data); |
| 129 io_data->set_reverse_autologin_pending_email(std::string()); |
| 130 } |
| 131 |
126 // Determines the source of the sign in and the continue URL. Its either one | 132 // Determines the source of the sign in and the continue URL. Its either one |
127 // of the known sign in access point (first run, NTP, menu, settings) or its | 133 // of the known sign in access point (first run, NTP, menu, settings) or its |
128 // an implicit sign in via another Google property. In the former case, | 134 // an implicit sign in via another Google property. In the former case, |
129 // "service" is also checked to make sure its "chromiumsync". | 135 // "service" is also checked to make sure its "chromiumsync". |
130 SyncPromoUI::Source GetSigninSource(const GURL& url, GURL* continue_url) { | 136 SyncPromoUI::Source GetSigninSource(const GURL& url, GURL* continue_url) { |
131 std::string value; | 137 std::string value; |
132 chrome_common_net::GetValueForKeyInQuery(url, "service", &value); | 138 chrome_common_net::GetValueForKeyInQuery(url, "service", &value); |
133 bool possibly_an_explicit_signin = value == "chromiumsync"; | 139 bool possibly_an_explicit_signin = value == "chromiumsync"; |
134 | 140 |
135 // Find the final continue URL for this sign in. In some cases, Gaia can | 141 // Find the final continue URL for this sign in. In some cases, Gaia can |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 } | 180 } |
175 | 181 |
176 GURL origin = url.GetOrigin(); | 182 GURL origin = url.GetOrigin(); |
177 if (origin == GURL("https://accounts.youtube.com") || | 183 if (origin == GURL("https://accounts.youtube.com") || |
178 origin == GURL("https://accounts.blogger.com")) | 184 origin == GURL("https://accounts.blogger.com")) |
179 return true; | 185 return true; |
180 | 186 |
181 return false; | 187 return false; |
182 } | 188 } |
183 | 189 |
184 // This class is associated as user data with a given URLRequest object, in | |
185 // order to pass information from one response to another during the process | |
186 // of signing the user into their Gaia account. This class is only meant | |
187 // to be used from the IO thread. | |
188 class OneClickSigninRequestUserData : public base::SupportsUserData::Data { | |
189 public: | |
190 const std::string& email() const { return email_; } | |
191 | |
192 // Associates signin information with the request. Overwrites existing | |
193 // information if any. | |
194 static void AssociateWithRequest(base::SupportsUserData* request, | |
195 const std::string& email); | |
196 | |
197 // Gets the one-click sign in information associated with the request. | |
198 static OneClickSigninRequestUserData* FromRequest( | |
199 base::SupportsUserData* request); | |
200 | |
201 private: | |
202 // Key used when setting this object on the request. | |
203 static const void* const kUserDataKey; | |
204 | |
205 explicit OneClickSigninRequestUserData(const std::string& email) | |
206 : email_(email) { | |
207 } | |
208 | |
209 std::string email_; | |
210 | |
211 DISALLOW_COPY_AND_ASSIGN(OneClickSigninRequestUserData); | |
212 }; | |
213 | |
214 // static | |
215 void OneClickSigninRequestUserData::AssociateWithRequest( | |
216 base::SupportsUserData* request, | |
217 const std::string& email) { | |
218 request->SetUserData(kUserDataKey, new OneClickSigninRequestUserData(email)); | |
219 } | |
220 | |
221 // static | |
222 OneClickSigninRequestUserData* OneClickSigninRequestUserData::FromRequest( | |
223 base::SupportsUserData* request) { | |
224 return static_cast<OneClickSigninRequestUserData*>( | |
225 request->GetUserData(kUserDataKey)); | |
226 } | |
227 | |
228 const void* const OneClickSigninRequestUserData::kUserDataKey = | |
229 static_cast<const void* const>( | |
230 &OneClickSigninRequestUserData::kUserDataKey); | |
231 | |
232 } // namespace | 190 } // namespace |
233 | 191 |
234 // The infobar asking the user if they want to use one-click sign in. | 192 // The infobar asking the user if they want to use one-click sign in. |
235 // TODO(rogerta): once we move to a web-based sign in flow, we can get rid | 193 // TODO(rogerta): once we move to a web-based sign in flow, we can get rid |
236 // of this infobar. | 194 // of this infobar. |
237 class OneClickInfoBarDelegateImpl : public OneClickSigninInfoBarDelegate { | 195 class OneClickInfoBarDelegateImpl : public OneClickSigninInfoBarDelegate { |
238 public: | 196 public: |
239 // Creates a one click signin delegate and adds it to |infobar_service|. | 197 // Creates a one click signin delegate and adds it to |infobar_service|. |
240 static void Create(InfoBarService* infobar_service, | 198 static void Create(InfoBarService* infobar_service, |
241 const std::string& session_index, | 199 const std::string& session_index, |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents) | 361 OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents) |
404 : content::WebContentsObserver(web_contents), | 362 : content::WebContentsObserver(web_contents), |
405 auto_accept_(AUTO_ACCEPT_NONE), | 363 auto_accept_(AUTO_ACCEPT_NONE), |
406 source_(SyncPromoUI::SOURCE_UNKNOWN) { | 364 source_(SyncPromoUI::SOURCE_UNKNOWN) { |
407 } | 365 } |
408 | 366 |
409 OneClickSigninHelper::~OneClickSigninHelper() { | 367 OneClickSigninHelper::~OneClickSigninHelper() { |
410 } | 368 } |
411 | 369 |
412 // static | 370 // static |
413 void OneClickSigninHelper::AssociateWithRequestForTesting( | |
414 base::SupportsUserData* request, | |
415 const std::string& email) { | |
416 OneClickSigninRequestUserData::AssociateWithRequest(request, email); | |
417 } | |
418 | |
419 // static | |
420 bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, | 371 bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, |
421 CanOfferFor can_offer_for, | 372 CanOfferFor can_offer_for, |
422 const std::string& email, | 373 const std::string& email, |
423 int* error_message_id) { | 374 int* error_message_id) { |
424 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 375 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
425 VLOG(1) << "OneClickSigninHelper::CanOffer"; | 376 VLOG(1) << "OneClickSigninHelper::CanOffer"; |
426 | 377 |
427 if (error_message_id) | 378 if (error_message_id) |
428 *error_message_id = 0; | 379 *error_message_id = 0; |
429 | 380 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 | 509 |
559 if (!SigninManager::AreSigninCookiesAllowed(io_data->GetCookieSettings())) | 510 if (!SigninManager::AreSigninCookiesAllowed(io_data->GetCookieSettings())) |
560 return DONT_OFFER; | 511 return DONT_OFFER; |
561 | 512 |
562 // The checks below depend on chrome already knowing what account the user | 513 // The checks below depend on chrome already knowing what account the user |
563 // signed in with. This happens only after receiving the response containing | 514 // signed in with. This happens only after receiving the response containing |
564 // the Google-Accounts-SignIn header. Until then, if there is even a chance | 515 // the Google-Accounts-SignIn header. Until then, if there is even a chance |
565 // that we want to connect the profile, chrome needs to tell Gaia that | 516 // that we want to connect the profile, chrome needs to tell Gaia that |
566 // it should offer the interstitial. Therefore missing one click data on | 517 // it should offer the interstitial. Therefore missing one click data on |
567 // the request means can offer is true. | 518 // the request means can offer is true. |
568 OneClickSigninRequestUserData* one_click_data = | 519 const std::string& pending_email = io_data->reverse_autologin_pending_email(); |
569 OneClickSigninRequestUserData::FromRequest(request); | 520 if (!pending_email.empty()) { |
570 if (one_click_data) { | 521 if (!SigninManager::IsAllowedUsername(pending_email, |
571 if (!SigninManager::IsAllowedUsername(one_click_data->email(), | |
572 io_data->google_services_username_pattern()->GetValue())) { | 522 io_data->google_services_username_pattern()->GetValue())) { |
573 return DONT_OFFER; | 523 return DONT_OFFER; |
574 } | 524 } |
575 | 525 |
576 std::vector<std::string> rejected_emails = | 526 std::vector<std::string> rejected_emails = |
577 io_data->one_click_signin_rejected_email_list()->GetValue(); | 527 io_data->one_click_signin_rejected_email_list()->GetValue(); |
578 if (std::count_if(rejected_emails.begin(), rejected_emails.end(), | 528 if (std::count_if(rejected_emails.begin(), rejected_emails.end(), |
579 std::bind2nd(std::equal_to<std::string>(), | 529 std::bind2nd(std::equal_to<std::string>(), |
580 one_click_data->email())) > 0) { | 530 pending_email)) > 0) { |
581 return DONT_OFFER; | 531 return DONT_OFFER; |
582 } | 532 } |
583 | 533 |
584 if (io_data->signin_names()->GetEmails().count( | 534 if (io_data->signin_names()->GetEmails().count( |
585 UTF8ToUTF16(one_click_data->email())) > 0) { | 535 UTF8ToUTF16(pending_email)) > 0) { |
586 return DONT_OFFER; | 536 return DONT_OFFER; |
587 } | 537 } |
588 } | 538 } |
589 | 539 |
590 return CAN_OFFER; | 540 return CAN_OFFER; |
591 } | 541 } |
592 | 542 |
593 // static | 543 // static |
594 void OneClickSigninHelper::InitializeFieldTrial() { | 544 void OneClickSigninHelper::InitializeFieldTrial() { |
595 scoped_refptr<base::FieldTrial> trial( | 545 scoped_refptr<base::FieldTrial> trial( |
596 base::FieldTrialList::FactoryGetFieldTrial("OneClickSignIn", 100, | 546 base::FieldTrialList::FactoryGetFieldTrial("OneClickSignIn", 100, |
597 "Standard", 2013, 9, 1, NULL)); | 547 "Standard", 2013, 9, 1, NULL)); |
598 | 548 |
599 // For dev and beta, we'll give half the people the new experience. For | 549 // For dev and beta, we'll give half the people the new experience. For |
600 // stable, only 1%. These numbers are overridable on the server. | 550 // stable, only 1%. These numbers are overridable on the server. |
601 const bool kIsStableChannel = | 551 const bool kIsStableChannel = |
602 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE; | 552 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE; |
603 const int kBlueOnWhiteGroup = trial->AppendGroup("BlueOnWhite", | 553 const int kBlueOnWhiteGroup = trial->AppendGroup("BlueOnWhite", |
604 kIsStableChannel ? 1 : 50); | 554 kIsStableChannel ? 1 : 50); |
605 use_blue_on_white = trial->group() == kBlueOnWhiteGroup; | 555 use_blue_on_white = trial->group() == kBlueOnWhiteGroup; |
606 } | 556 } |
607 | 557 |
608 // static | 558 // static |
609 void OneClickSigninHelper::ShowInfoBarIfPossible(net::URLRequest* request, | 559 void OneClickSigninHelper::ShowInfoBarIfPossible(net::URLRequest* request, |
| 560 ProfileIOData* io_data, |
610 int child_id, | 561 int child_id, |
611 int route_id) { | 562 int route_id) { |
612 std::string google_chrome_signin_value; | 563 std::string google_chrome_signin_value; |
613 std::string google_accounts_signin_value; | 564 std::string google_accounts_signin_value; |
614 request->GetResponseHeaderByName("Google-Chrome-SignIn", | 565 request->GetResponseHeaderByName("Google-Chrome-SignIn", |
615 &google_chrome_signin_value); | 566 &google_chrome_signin_value); |
616 request->GetResponseHeaderByName("Google-Accounts-SignIn", | 567 request->GetResponseHeaderByName("Google-Accounts-SignIn", |
617 &google_accounts_signin_value); | 568 &google_accounts_signin_value); |
618 | 569 |
619 if (!google_accounts_signin_value.empty() || | 570 if (!google_accounts_signin_value.empty() || |
(...skipping 25 matching lines...) Expand all Loading... |
645 TrimString(value, "\"", &email); | 596 TrimString(value, "\"", &email); |
646 } else if (key == "sessionindex") { | 597 } else if (key == "sessionindex") { |
647 session_index = value; | 598 session_index = value; |
648 } | 599 } |
649 } | 600 } |
650 | 601 |
651 // Later in the chain of this request, we'll need to check the email address | 602 // Later in the chain of this request, we'll need to check the email address |
652 // in the IO thread (see CanOfferOnIOThread). So save the email address as | 603 // in the IO thread (see CanOfferOnIOThread). So save the email address as |
653 // user data on the request (only for web-based flow). | 604 // user data on the request (only for web-based flow). |
654 if (SyncPromoUI::UseWebBasedSigninFlow() && !email.empty()) | 605 if (SyncPromoUI::UseWebBasedSigninFlow() && !email.empty()) |
655 OneClickSigninRequestUserData::AssociateWithRequest(request, email); | 606 io_data->set_reverse_autologin_pending_email(email); |
656 | 607 |
657 if (!email.empty() || !session_index.empty()) { | 608 if (!email.empty() || !session_index.empty()) { |
658 VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:" | 609 VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:" |
659 << " email=" << email | 610 << " email=" << email |
660 << " sessionindex=" << session_index; | 611 << " sessionindex=" << session_index; |
661 } | 612 } |
662 | 613 |
663 // Parse Google-Chrome-SignIn. | 614 // Parse Google-Chrome-SignIn. |
664 AutoAccept auto_accept = AUTO_ACCEPT_NONE; | 615 AutoAccept auto_accept = AUTO_ACCEPT_NONE; |
665 SyncPromoUI::Source source = SyncPromoUI::SOURCE_UNKNOWN; | 616 SyncPromoUI::Source source = SyncPromoUI::SOURCE_UNKNOWN; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 | 675 |
725 // TODO(mathp): The appearance of this infobar should be tested using a | 676 // TODO(mathp): The appearance of this infobar should be tested using a |
726 // browser_test. | 677 // browser_test. |
727 OneClickSigninHelper* helper = | 678 OneClickSigninHelper* helper = |
728 OneClickSigninHelper::FromWebContents(web_contents); | 679 OneClickSigninHelper::FromWebContents(web_contents); |
729 if (!helper) | 680 if (!helper) |
730 return; | 681 return; |
731 | 682 |
732 int error_message_id = 0; | 683 int error_message_id = 0; |
733 | 684 |
734 CanOfferFor can_offer_for = | |
735 (auto_accept != AUTO_ACCEPT_EXPLICIT && | |
736 helper->auto_accept_ != AUTO_ACCEPT_EXPLICIT) ? | |
737 CAN_OFFER_FOR_INTERSTITAL_ONLY : CAN_OFFER_FOR_ALL; | |
738 | |
739 if (!web_contents || !CanOffer(web_contents, can_offer_for, email, | |
740 &error_message_id)) { | |
741 VLOG(1) << "OneClickSigninHelper::ShowInfoBarUIThread: not offering"; | |
742 if (helper && helper->error_message_.empty() && error_message_id != 0) | |
743 helper->error_message_ = l10n_util::GetStringUTF8(error_message_id); | |
744 | |
745 return; | |
746 } | |
747 | |
748 // Save the email in the one-click signin manager. The manager may | 685 // Save the email in the one-click signin manager. The manager may |
749 // not exist if the contents is incognito or if the profile is already | 686 // not exist if the contents is incognito or if the profile is already |
750 // connected to a Google account. | 687 // connected to a Google account. |
751 if (!session_index.empty()) | 688 if (!session_index.empty()) |
752 helper->session_index_ = session_index; | 689 helper->session_index_ = session_index; |
753 | 690 |
754 if (!email.empty()) | 691 if (!email.empty()) |
755 helper->email_ = email; | 692 helper->email_ = email; |
756 | 693 |
757 if (auto_accept != AUTO_ACCEPT_NONE) { | 694 if (auto_accept != AUTO_ACCEPT_NONE) { |
758 helper->auto_accept_ = auto_accept; | 695 helper->auto_accept_ = auto_accept; |
759 helper->source_ = source; | 696 helper->source_ = source; |
760 } | 697 } |
761 | 698 |
| 699 CanOfferFor can_offer_for = |
| 700 (auto_accept != AUTO_ACCEPT_EXPLICIT && |
| 701 helper->auto_accept_ != AUTO_ACCEPT_EXPLICIT) ? |
| 702 CAN_OFFER_FOR_INTERSTITAL_ONLY : CAN_OFFER_FOR_ALL; |
| 703 |
| 704 if (!web_contents || !CanOffer(web_contents, can_offer_for, email, |
| 705 &error_message_id)) { |
| 706 VLOG(1) << "OneClickSigninHelper::ShowInfoBarUIThread: not offering"; |
| 707 if (helper && helper->error_message_.empty() && error_message_id != 0) |
| 708 helper->error_message_ = l10n_util::GetStringUTF8(error_message_id); |
| 709 |
| 710 return; |
| 711 } |
| 712 |
762 if (continue_url.is_valid()) { | 713 if (continue_url.is_valid()) { |
763 // When Gaia finally redirects to the continue URL, Gaia will add some | 714 // When Gaia finally redirects to the continue URL, Gaia will add some |
764 // extra query parameters. So ignore the parameters when checking to see | 715 // extra query parameters. So ignore the parameters when checking to see |
765 // if the user has continued. | 716 // if the user has continued. |
766 GURL::Replacements replacements; | 717 GURL::Replacements replacements; |
767 replacements.ClearQuery(); | 718 replacements.ClearQuery(); |
768 helper->continue_url_ = continue_url.ReplaceComponents(replacements); | 719 helper->continue_url_ = continue_url.ReplaceComponents(replacements); |
769 } | 720 } |
770 } | 721 } |
771 | 722 |
(...skipping 17 matching lines...) Expand all Loading... |
789 signin_tracker_.reset(); | 740 signin_tracker_.reset(); |
790 } | 741 } |
791 | 742 |
792 void OneClickSigninHelper::CleanTransientState() { | 743 void OneClickSigninHelper::CleanTransientState() { |
793 VLOG(1) << "OneClickSigninHelper::CleanTransientState"; | 744 VLOG(1) << "OneClickSigninHelper::CleanTransientState"; |
794 email_.clear(); | 745 email_.clear(); |
795 password_.clear(); | 746 password_.clear(); |
796 auto_accept_ = AUTO_ACCEPT_NONE; | 747 auto_accept_ = AUTO_ACCEPT_NONE; |
797 source_ = SyncPromoUI::SOURCE_UNKNOWN; | 748 source_ = SyncPromoUI::SOURCE_UNKNOWN; |
798 continue_url_ = GURL(); | 749 continue_url_ = GURL(); |
| 750 |
| 751 // Post to IO thread to clear pending email. |
| 752 Profile* profile = |
| 753 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); |
| 754 content::BrowserThread::PostTask( |
| 755 content::BrowserThread::IO, FROM_HERE, |
| 756 base::Bind(&ClearPendingEmailOnIOThread, |
| 757 base::Unretained(profile->GetResourceContext()))); |
799 } | 758 } |
800 | 759 |
801 void OneClickSigninHelper::DidNavigateAnyFrame( | 760 void OneClickSigninHelper::DidNavigateAnyFrame( |
802 const content::LoadCommittedDetails& details, | 761 const content::LoadCommittedDetails& details, |
803 const content::FrameNavigateParams& params) { | 762 const content::FrameNavigateParams& params) { |
804 // We only need to scrape the password for Gaia logins. | 763 // We only need to scrape the password for Gaia logins. |
805 const content::PasswordForm& form = params.password_form; | 764 const content::PasswordForm& form = params.password_form; |
806 if (form.origin.is_valid() && | 765 if (form.origin.is_valid() && |
807 gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) { | 766 gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) { |
808 VLOG(1) << "OneClickSigninHelper::DidNavigateAnyFrame: got password"; | 767 VLOG(1) << "OneClickSigninHelper::DidNavigateAnyFrame: got password"; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
973 break; | 932 break; |
974 } | 933 } |
975 } | 934 } |
976 | 935 |
977 RedirectToNTP(); | 936 RedirectToNTP(); |
978 } | 937 } |
979 | 938 |
980 void OneClickSigninHelper::SigninSuccess() { | 939 void OneClickSigninHelper::SigninSuccess() { |
981 RedirectToNTP(); | 940 RedirectToNTP(); |
982 } | 941 } |
OLD | NEW |