| 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 if (io_data) |
| 130 io_data->set_reverse_autologin_pending_email(""); |
| 131 } |
| 132 |
| 126 // Determines the source of the sign in and the continue URL. Its either one | 133 // 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 | 134 // 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, | 135 // an implicit sign in via another Google property. In the former case, |
| 129 // "service" is also checked to make sure its "chromiumsync". | 136 // "service" is also checked to make sure its "chromiumsync". |
| 130 SyncPromoUI::Source GetSigninSource(const GURL& url, GURL* continue_url) { | 137 SyncPromoUI::Source GetSigninSource(const GURL& url, GURL* continue_url) { |
| 131 std::string value; | 138 std::string value; |
| 132 chrome_common_net::GetValueForKeyInQuery(url, "service", &value); | 139 chrome_common_net::GetValueForKeyInQuery(url, "service", &value); |
| 133 bool possibly_an_explicit_signin = value == "chromiumsync"; | 140 bool possibly_an_explicit_signin = value == "chromiumsync"; |
| 134 | 141 |
| 135 // Find the final continue URL for this sign in. In some cases, Gaia can | 142 // 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 } | 181 } |
| 175 | 182 |
| 176 GURL origin = url.GetOrigin(); | 183 GURL origin = url.GetOrigin(); |
| 177 if (origin == GURL("https://accounts.youtube.com") || | 184 if (origin == GURL("https://accounts.youtube.com") || |
| 178 origin == GURL("https://accounts.blogger.com")) | 185 origin == GURL("https://accounts.blogger.com")) |
| 179 return true; | 186 return true; |
| 180 | 187 |
| 181 return false; | 188 return false; |
| 182 } | 189 } |
| 183 | 190 |
| 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 | 191 } // namespace |
| 233 | 192 |
| 234 // The infobar asking the user if they want to use one-click sign in. | 193 // 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 | 194 // TODO(rogerta): once we move to a web-based sign in flow, we can get rid |
| 236 // of this infobar. | 195 // of this infobar. |
| 237 class OneClickInfoBarDelegateImpl : public OneClickSigninInfoBarDelegate { | 196 class OneClickInfoBarDelegateImpl : public OneClickSigninInfoBarDelegate { |
| 238 public: | 197 public: |
| 239 // Creates a one click signin delegate and adds it to |infobar_service|. | 198 // Creates a one click signin delegate and adds it to |infobar_service|. |
| 240 static void Create(InfoBarService* infobar_service, | 199 static void Create(InfoBarService* infobar_service, |
| 241 const std::string& session_index, | 200 const std::string& session_index, |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents) | 361 OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents) |
| 403 : content::WebContentsObserver(web_contents), | 362 : content::WebContentsObserver(web_contents), |
| 404 auto_accept_(AUTO_ACCEPT_NONE), | 363 auto_accept_(AUTO_ACCEPT_NONE), |
| 405 source_(SyncPromoUI::SOURCE_UNKNOWN) { | 364 source_(SyncPromoUI::SOURCE_UNKNOWN) { |
| 406 } | 365 } |
| 407 | 366 |
| 408 OneClickSigninHelper::~OneClickSigninHelper() { | 367 OneClickSigninHelper::~OneClickSigninHelper() { |
| 409 } | 368 } |
| 410 | 369 |
| 411 // static | 370 // static |
| 412 void OneClickSigninHelper::AssociateWithRequestForTesting( | |
| 413 base::SupportsUserData* request, | |
| 414 const std::string& email) { | |
| 415 OneClickSigninRequestUserData::AssociateWithRequest(request, email); | |
| 416 } | |
| 417 | |
| 418 // static | |
| 419 bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, | 371 bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, |
| 420 CanOfferFor can_offer_for, | 372 CanOfferFor can_offer_for, |
| 421 const std::string& email, | 373 const std::string& email, |
| 422 int* error_message_id) { | 374 int* error_message_id) { |
| 423 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 375 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 424 VLOG(1) << "OneClickSigninHelper::CanOffer"; | 376 VLOG(1) << "OneClickSigninHelper::CanOffer"; |
| 425 | 377 |
| 426 if (error_message_id) | 378 if (error_message_id) |
| 427 *error_message_id = 0; | 379 *error_message_id = 0; |
| 428 | 380 |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 | 509 |
| 558 if (!SigninManager::AreSigninCookiesAllowed(io_data->GetCookieSettings())) | 510 if (!SigninManager::AreSigninCookiesAllowed(io_data->GetCookieSettings())) |
| 559 return DONT_OFFER; | 511 return DONT_OFFER; |
| 560 | 512 |
| 561 // 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 |
| 562 // signed in with. This happens only after receiving the response containing | 514 // signed in with. This happens only after receiving the response containing |
| 563 // 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 |
| 564 // 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 |
| 565 // it should offer the interstitial. Therefore missing one click data on | 517 // it should offer the interstitial. Therefore missing one click data on |
| 566 // the request means can offer is true. | 518 // the request means can offer is true. |
| 567 OneClickSigninRequestUserData* one_click_data = | 519 const std::string& pending_email = io_data->reverse_autologin_pending_email(); |
| 568 OneClickSigninRequestUserData::FromRequest(request); | 520 if (!pending_email.empty()) { |
| 569 if (one_click_data) { | 521 if (!SigninManager::IsAllowedUsername(pending_email, |
| 570 if (!SigninManager::IsAllowedUsername(one_click_data->email(), | |
| 571 io_data->google_services_username_pattern()->GetValue())) { | 522 io_data->google_services_username_pattern()->GetValue())) { |
| 572 return DONT_OFFER; | 523 return DONT_OFFER; |
| 573 } | 524 } |
| 574 | 525 |
| 575 std::vector<std::string> rejected_emails = | 526 std::vector<std::string> rejected_emails = |
| 576 io_data->one_click_signin_rejected_email_list()->GetValue(); | 527 io_data->one_click_signin_rejected_email_list()->GetValue(); |
| 577 if (std::count_if(rejected_emails.begin(), rejected_emails.end(), | 528 if (std::count_if(rejected_emails.begin(), rejected_emails.end(), |
| 578 std::bind2nd(std::equal_to<std::string>(), | 529 std::bind2nd(std::equal_to<std::string>(), |
| 579 one_click_data->email())) > 0) { | 530 pending_email)) > 0) { |
| 580 return DONT_OFFER; | 531 return DONT_OFFER; |
| 581 } | 532 } |
| 582 | 533 |
| 583 if (io_data->signin_names()->GetEmails().count( | 534 if (io_data->signin_names()->GetEmails().count( |
| 584 UTF8ToUTF16(one_click_data->email())) > 0) { | 535 UTF8ToUTF16(pending_email)) > 0) { |
| 585 return DONT_OFFER; | 536 return DONT_OFFER; |
| 586 } | 537 } |
| 587 } | 538 } |
| 588 | 539 |
| 589 return CAN_OFFER; | 540 return CAN_OFFER; |
| 590 } | 541 } |
| 591 | 542 |
| 592 // static | 543 // static |
| 593 void OneClickSigninHelper::InitializeFieldTrial() { | 544 void OneClickSigninHelper::InitializeFieldTrial() { |
| 594 scoped_refptr<base::FieldTrial> trial( | 545 scoped_refptr<base::FieldTrial> trial( |
| 595 base::FieldTrialList::FactoryGetFieldTrial("OneClickSignIn", 100, | 546 base::FieldTrialList::FactoryGetFieldTrial("OneClickSignIn", 100, |
| 596 "Standard", 2013, 9, 1, NULL)); | 547 "Standard", 2013, 9, 1, NULL)); |
| 597 | 548 |
| 598 // 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 |
| 599 // stable, only 1%. These numbers are overridable on the server. | 550 // stable, only 1%. These numbers are overridable on the server. |
| 600 const bool kIsStableChannel = | 551 const bool kIsStableChannel = |
| 601 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE; | 552 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE; |
| 602 const int kBlueOnWhiteGroup = trial->AppendGroup("BlueOnWhite", | 553 const int kBlueOnWhiteGroup = trial->AppendGroup("BlueOnWhite", |
| 603 kIsStableChannel ? 1 : 50); | 554 kIsStableChannel ? 1 : 50); |
| 604 use_blue_on_white = trial->group() == kBlueOnWhiteGroup; | 555 use_blue_on_white = trial->group() == kBlueOnWhiteGroup; |
| 605 } | 556 } |
| 606 | 557 |
| 607 // static | 558 // static |
| 608 void OneClickSigninHelper::ShowInfoBarIfPossible(net::URLRequest* request, | 559 void OneClickSigninHelper::ShowInfoBarIfPossible(net::URLRequest* request, |
| 560 ProfileIOData* io_data, |
| 609 int child_id, | 561 int child_id, |
| 610 int route_id) { | 562 int route_id) { |
| 611 std::string google_chrome_signin_value; | 563 std::string google_chrome_signin_value; |
| 612 std::string google_accounts_signin_value; | 564 std::string google_accounts_signin_value; |
| 613 request->GetResponseHeaderByName("Google-Chrome-SignIn", | 565 request->GetResponseHeaderByName("Google-Chrome-SignIn", |
| 614 &google_chrome_signin_value); | 566 &google_chrome_signin_value); |
| 615 request->GetResponseHeaderByName("Google-Accounts-SignIn", | 567 request->GetResponseHeaderByName("Google-Accounts-SignIn", |
| 616 &google_accounts_signin_value); | 568 &google_accounts_signin_value); |
| 617 | 569 |
| 618 if (!google_accounts_signin_value.empty() || | 570 if (!google_accounts_signin_value.empty() || |
| (...skipping 25 matching lines...) Expand all Loading... |
| 644 TrimString(value, "\"", &email); | 596 TrimString(value, "\"", &email); |
| 645 } else if (key == "sessionindex") { | 597 } else if (key == "sessionindex") { |
| 646 session_index = value; | 598 session_index = value; |
| 647 } | 599 } |
| 648 } | 600 } |
| 649 | 601 |
| 650 // 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 |
| 651 // 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 |
| 652 // user data on the request (only for web-based flow). | 604 // user data on the request (only for web-based flow). |
| 653 if (SyncPromoUI::UseWebBasedSigninFlow() && !email.empty()) | 605 if (SyncPromoUI::UseWebBasedSigninFlow() && !email.empty()) |
| 654 OneClickSigninRequestUserData::AssociateWithRequest(request, email); | 606 io_data->set_reverse_autologin_pending_email(email); |
| 655 | 607 |
| 656 if (!email.empty() || !session_index.empty()) { | 608 if (!email.empty() || !session_index.empty()) { |
| 657 VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:" | 609 VLOG(1) << "OneClickSigninHelper::ShowInfoBarIfPossible:" |
| 658 << " email=" << email | 610 << " email=" << email |
| 659 << " sessionindex=" << session_index; | 611 << " sessionindex=" << session_index; |
| 660 } | 612 } |
| 661 | 613 |
| 662 // Parse Google-Chrome-SignIn. | 614 // Parse Google-Chrome-SignIn. |
| 663 AutoAccept auto_accept = AUTO_ACCEPT_NONE; | 615 AutoAccept auto_accept = AUTO_ACCEPT_NONE; |
| 664 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... |
| 723 | 675 |
| 724 // 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 |
| 725 // browser_test. | 677 // browser_test. |
| 726 OneClickSigninHelper* helper = | 678 OneClickSigninHelper* helper = |
| 727 OneClickSigninHelper::FromWebContents(web_contents); | 679 OneClickSigninHelper::FromWebContents(web_contents); |
| 728 if (!helper) | 680 if (!helper) |
| 729 return; | 681 return; |
| 730 | 682 |
| 731 int error_message_id = 0; | 683 int error_message_id = 0; |
| 732 | 684 |
| 733 CanOfferFor can_offer_for = | |
| 734 (auto_accept != AUTO_ACCEPT_EXPLICIT && | |
| 735 helper->auto_accept_ != AUTO_ACCEPT_EXPLICIT) ? | |
| 736 CAN_OFFER_FOR_INTERSTITAL_ONLY : CAN_OFFER_FOR_ALL; | |
| 737 | |
| 738 if (!web_contents || !CanOffer(web_contents, can_offer_for, email, | |
| 739 &error_message_id)) { | |
| 740 VLOG(1) << "OneClickSigninHelper::ShowInfoBarUIThread: not offering"; | |
| 741 if (helper && helper->error_message_.empty() && error_message_id != 0) | |
| 742 helper->error_message_ = l10n_util::GetStringUTF8(error_message_id); | |
| 743 | |
| 744 return; | |
| 745 } | |
| 746 | |
| 747 // 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 |
| 748 // 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 |
| 749 // connected to a Google account. | 687 // connected to a Google account. |
| 750 if (!session_index.empty()) | 688 if (!session_index.empty()) |
| 751 helper->session_index_ = session_index; | 689 helper->session_index_ = session_index; |
| 752 | 690 |
| 753 if (!email.empty()) | 691 if (!email.empty()) |
| 754 helper->email_ = email; | 692 helper->email_ = email; |
| 755 | 693 |
| 756 if (auto_accept != AUTO_ACCEPT_NONE) { | 694 if (auto_accept != AUTO_ACCEPT_NONE) { |
| 757 helper->auto_accept_ = auto_accept; | 695 helper->auto_accept_ = auto_accept; |
| 758 helper->source_ = source; | 696 helper->source_ = source; |
| 759 } | 697 } |
| 760 | 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 |
| 761 if (continue_url.is_valid()) { | 713 if (continue_url.is_valid()) { |
| 762 // 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 |
| 763 // extra query parameters. So ignore the parameters when checking to see | 715 // extra query parameters. So ignore the parameters when checking to see |
| 764 // if the user has continued. | 716 // if the user has continued. |
| 765 GURL::Replacements replacements; | 717 GURL::Replacements replacements; |
| 766 replacements.ClearQuery(); | 718 replacements.ClearQuery(); |
| 767 helper->continue_url_ = continue_url.ReplaceComponents(replacements); | 719 helper->continue_url_ = continue_url.ReplaceComponents(replacements); |
| 768 } | 720 } |
| 769 } | 721 } |
| 770 | 722 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 788 signin_tracker_.reset(); | 740 signin_tracker_.reset(); |
| 789 } | 741 } |
| 790 | 742 |
| 791 void OneClickSigninHelper::CleanTransientState() { | 743 void OneClickSigninHelper::CleanTransientState() { |
| 792 VLOG(1) << "OneClickSigninHelper::CleanTransientState"; | 744 VLOG(1) << "OneClickSigninHelper::CleanTransientState"; |
| 793 email_.clear(); | 745 email_.clear(); |
| 794 password_.clear(); | 746 password_.clear(); |
| 795 auto_accept_ = AUTO_ACCEPT_NONE; | 747 auto_accept_ = AUTO_ACCEPT_NONE; |
| 796 source_ = SyncPromoUI::SOURCE_UNKNOWN; | 748 source_ = SyncPromoUI::SOURCE_UNKNOWN; |
| 797 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()))); |
| 798 } | 758 } |
| 799 | 759 |
| 800 void OneClickSigninHelper::DidNavigateAnyFrame( | 760 void OneClickSigninHelper::DidNavigateAnyFrame( |
| 801 const content::LoadCommittedDetails& details, | 761 const content::LoadCommittedDetails& details, |
| 802 const content::FrameNavigateParams& params) { | 762 const content::FrameNavigateParams& params) { |
| 803 // We only need to scrape the password for Gaia logins. | 763 // We only need to scrape the password for Gaia logins. |
| 804 const content::PasswordForm& form = params.password_form; | 764 const content::PasswordForm& form = params.password_form; |
| 805 if (form.origin.is_valid() && | 765 if (form.origin.is_valid() && |
| 806 gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) { | 766 gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) { |
| 807 VLOG(1) << "OneClickSigninHelper::DidNavigateAnyFrame: got password"; | 767 VLOG(1) << "OneClickSigninHelper::DidNavigateAnyFrame: got password"; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 break; | 931 break; |
| 972 } | 932 } |
| 973 } | 933 } |
| 974 | 934 |
| 975 RedirectToNTP(); | 935 RedirectToNTP(); |
| 976 } | 936 } |
| 977 | 937 |
| 978 void OneClickSigninHelper::SigninSuccess() { | 938 void OneClickSigninHelper::SigninSuccess() { |
| 979 RedirectToNTP(); | 939 RedirectToNTP(); |
| 980 } | 940 } |
| OLD | NEW |