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. 4 5 #include "components/autofill/content/browser/wallet/wallet_signin_helper.h" 6 7 #include "base/callback_helpers.h" 8 #include "base/json/json_reader.h" 9 #include "base/logging.h" 10 #include "base/rand_util.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/time/time.h" 14 #include "base/values.h" 15 #include "components/autofill/content/browser/wallet/wallet_service_url.h" 16 #include "components/autofill/content/browser/wallet/wallet_signin_helper_delegate.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "google_apis/gaia/google_service_auth_error.h" 19 #include "net/base/escape.h" 20 #include "net/cookies/canonical_cookie.h" 21 #include "net/cookies/cookie_monster.h" 22 #include "net/cookies/cookie_options.h" 23 #include "net/cookies/cookie_store.h" 24 #include "net/url_request/url_fetcher.h" 25 #include "net/url_request/url_request_context.h" 26 #include "net/url_request/url_request_context_getter.h" 27 28 namespace autofill { 29 namespace wallet { 30 31 namespace { 32 33 const char kWalletCookieName[] = "gdtoken"; 34 35 // Callback for retrieving Google Wallet cookies. |callback| is passed the 36 // retrieved cookies and posted back to the UI thread. |cookies| is any Google 37 // Wallet cookies. 38 void GetGoogleCookiesCallback( 39 const base::Callback<void(const std::string&)>& callback, 40 const net::CookieList& cookies) { 41 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 42 43 // Cookies for parent domains will also be returned; we only want cookies with 44 // exact host matches. TODO(estade): really? 45 std::string host = wallet::GetPassiveAuthUrl(0).host(); 46 std::string wallet_cookie; 47 for (size_t i = 0; i < cookies.size(); ++i) { 48 if (LowerCaseEqualsASCII(cookies[i].Name(), kWalletCookieName) && 49 LowerCaseEqualsASCII(cookies[i].Domain(), host.c_str())) { 50 wallet_cookie = cookies[i].Value(); 51 break; 52 } 53 } 54 content::BrowserThread::PostTask(content::BrowserThread::UI, 55 FROM_HERE, 56 base::Bind(callback, wallet_cookie)); 57 } 58 59 // Gets Google Wallet cookies. Must be called on the IO thread. 60 // |request_context_getter| is a getter for the current request context. 61 // |callback| is called when retrieving cookies is completed. 62 void GetGoogleCookies( 63 scoped_refptr<net::URLRequestContextGetter> request_context_getter, 64 const base::Callback<void(const std::string&)>& callback) { 65 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 66 67 net::URLRequestContext* url_request_context = 68 request_context_getter->GetURLRequestContext(); 69 net::CookieStore* cookie_store = url_request_context ? 70 url_request_context->cookie_store() : NULL; 71 net::CookieMonster* cookie_monster = cookie_store ? 72 cookie_store->GetCookieMonster() : NULL; 73 if (!cookie_monster) { 74 content::BrowserThread::PostTask(content::BrowserThread::UI, 75 FROM_HERE, 76 base::Bind(callback, std::string())); 77 return; 78 } 79 80 net::CookieOptions cookie_options; 81 cookie_options.set_include_httponly(); 82 cookie_monster->GetAllCookiesForURLWithOptionsAsync( 83 wallet::GetPassiveAuthUrl(0).GetWithEmptyPath(), 84 cookie_options, 85 base::Bind(&GetGoogleCookiesCallback, callback)); 86 } 87 88 } // namespace 89 90 WalletSigninHelper::WalletSigninHelper( 91 WalletSigninHelperDelegate* delegate, 92 net::URLRequestContextGetter* getter) 93 : delegate_(delegate), 94 getter_(getter), 95 weak_ptr_factory_(this) { 96 DCHECK(delegate_); 97 } 98 99 WalletSigninHelper::~WalletSigninHelper() { 100 } 101 102 void WalletSigninHelper::StartPassiveSignin(size_t user_index) { 103 DCHECK(!url_fetcher_); 104 105 const GURL& url = wallet::GetPassiveAuthUrl(user_index); 106 url_fetcher_.reset(net::URLFetcher::Create( 107 0, url, net::URLFetcher::GET, this)); 108 url_fetcher_->SetRequestContext(getter_); 109 url_fetcher_->Start(); 110 } 111 112 void WalletSigninHelper::StartWalletCookieValueFetch() { 113 scoped_refptr<net::URLRequestContextGetter> request_context(getter_); 114 if (!request_context.get()) { 115 ReturnWalletCookieValue(std::string()); 116 return; 117 } 118 119 base::Callback<void(const std::string&)> callback = base::Bind( 120 &WalletSigninHelper::ReturnWalletCookieValue, 121 weak_ptr_factory_.GetWeakPtr()); 122 123 base::Closure task = base::Bind(&GetGoogleCookies, request_context, callback); 124 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, task); 125 } 126 127 void WalletSigninHelper::OnServiceError(const GoogleServiceAuthError& error) { 128 delegate_->OnPassiveSigninFailure(error); 129 } 130 131 void WalletSigninHelper::OnOtherError() { 132 OnServiceError(GoogleServiceAuthError::AuthErrorNone()); 133 } 134 135 void WalletSigninHelper::OnURLFetchComplete( 136 const net::URLFetcher* fetcher) { 137 DCHECK_EQ(url_fetcher_.get(), fetcher); 138 scoped_ptr<net::URLFetcher> url_fetcher(url_fetcher_.release()); 139 140 if (!fetcher->GetStatus().is_success() || 141 fetcher->GetResponseCode() < 200 || 142 fetcher->GetResponseCode() >= 300) { 143 DVLOG(1) << "URLFetchFailure:" 144 << " r=" << fetcher->GetResponseCode() 145 << " s=" << fetcher->GetStatus().status() 146 << " e=" << fetcher->GetStatus().error(); 147 OnOtherError(); 148 return; 149 } 150 151 std::string data; 152 if (!fetcher->GetResponseAsString(&data)) { 153 DVLOG(1) << "failed to GetResponseAsString"; 154 OnOtherError(); 155 return; 156 } 157 158 if (!LowerCaseEqualsASCII(data, "yes")) { 159 OnServiceError( 160 GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP)); 161 return; 162 } 163 164 delegate_->OnPassiveSigninSuccess(); 165 } 166 167 void WalletSigninHelper::ReturnWalletCookieValue( 168 const std::string& cookie_value) { 169 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 170 171 delegate_->OnDidFetchWalletCookieValue(cookie_value); 172 } 173 174 } // namespace wallet 175 } // namespace autofill 176