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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/login/profile_auth_data.h" 6 7 #include "chrome/browser/profiles/profile.h" 8 #include "content/public/browser/browser_thread.h" 9 #include "net/cookies/cookie_monster.h" 10 #include "net/cookies/cookie_store.h" 11 #include "net/http/http_auth_cache.h" 12 #include "net/http/http_network_session.h" 13 #include "net/http/http_transaction_factory.h" 14 #include "net/ssl/server_bound_cert_service.h" 15 #include "net/ssl/server_bound_cert_store.h" 16 #include "net/url_request/url_request_context.h" 17 #include "net/url_request/url_request_context_getter.h" 18 19 using content::BrowserThread; 20 21 namespace chromeos { 22 23 namespace { 24 25 class ProfileAuthDataTransferer { 26 public: 27 ProfileAuthDataTransferer( 28 Profile* from_profile, 29 Profile* to_profile, 30 bool transfer_cookies, 31 const base::Closure& completion_callback); 32 33 void BeginTransfer(); 34 35 private: 36 void BeginTransferOnIOThread(); 37 void MaybeDoCookieAndCertTransfer(); 38 void Finish(); 39 40 void OnTransferCookiesIfEmptyJar(const net::CookieList& cookies_in_jar); 41 void OnGetCookiesToTransfer(const net::CookieList& cookies_to_transfer); 42 void RetrieveDefaultCookies(); 43 void OnGetServerBoundCertsToTransfer( 44 const net::ServerBoundCertStore::ServerBoundCertList& certs); 45 void RetrieveDefaultServerBoundCerts(); 46 void TransferDefaultAuthCache(); 47 48 scoped_refptr<net::URLRequestContextGetter> from_context_; 49 scoped_refptr<net::URLRequestContextGetter> to_context_; 50 bool transfer_cookies_; 51 base::Closure completion_callback_; 52 53 net::CookieList cookies_to_transfer_; 54 net::ServerBoundCertStore::ServerBoundCertList certs_to_transfer_; 55 56 bool got_cookies_; 57 bool got_server_bound_certs_; 58 }; 59 60 ProfileAuthDataTransferer::ProfileAuthDataTransferer( 61 Profile* from_profile, 62 Profile* to_profile, 63 bool transfer_cookies, 64 const base::Closure& completion_callback) 65 : from_context_(from_profile->GetRequestContext()), 66 to_context_(to_profile->GetRequestContext()), 67 transfer_cookies_(transfer_cookies), 68 completion_callback_(completion_callback), 69 got_cookies_(false), 70 got_server_bound_certs_(false) { 71 } 72 73 void ProfileAuthDataTransferer::BeginTransfer() { 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 75 // If we aren't transferring cookies, post the completion callback 76 // immediately. Otherwise, it will be called when both cookies and channel 77 // ids are finished transferring. 78 if (!transfer_cookies_) { 79 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, completion_callback_); 80 // Null the callback so that when Finish is called the callback won't be 81 // called again. 82 completion_callback_.Reset(); 83 } 84 BrowserThread::PostTask( 85 BrowserThread::IO, FROM_HERE, 86 base::Bind(&ProfileAuthDataTransferer::BeginTransferOnIOThread, 87 base::Unretained(this))); 88 } 89 90 void ProfileAuthDataTransferer::BeginTransferOnIOThread() { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 92 TransferDefaultAuthCache(); 93 94 if (transfer_cookies_) { 95 RetrieveDefaultCookies(); 96 RetrieveDefaultServerBoundCerts(); 97 } else { 98 Finish(); 99 } 100 } 101 102 // If both cookies and server bound certs have been retrieved, see if we need to 103 // do the actual transfer. 104 void ProfileAuthDataTransferer::MaybeDoCookieAndCertTransfer() { 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 106 if (!(got_cookies_ && got_server_bound_certs_)) 107 return; 108 109 // Nothing to transfer over? 110 if (!cookies_to_transfer_.size()) { 111 Finish(); 112 return; 113 } 114 115 // Now let's see if the target cookie monster's jar is even empty. 116 net::CookieStore* to_store = 117 to_context_->GetURLRequestContext()->cookie_store(); 118 net::CookieMonster* to_monster = to_store->GetCookieMonster(); 119 to_monster->GetAllCookiesAsync( 120 base::Bind(&ProfileAuthDataTransferer::OnTransferCookiesIfEmptyJar, 121 base::Unretained(this))); 122 } 123 124 // Post the |completion_callback_| and delete ourself. 125 void ProfileAuthDataTransferer::Finish() { 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 127 if (!completion_callback_.is_null()) 128 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, completion_callback_); 129 delete this; 130 } 131 132 // Callback for transferring |cookies_to_transfer_| into |to_context_|'s 133 // CookieMonster if its jar is completely empty. If authentication was 134 // performed by an extension, then the set of cookies that was acquired through 135 // such that process will be automatically transfered into the profile. 136 void ProfileAuthDataTransferer::OnTransferCookiesIfEmptyJar( 137 const net::CookieList& cookies_in_jar) { 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 139 // Transfer only if the existing cookie jar is empty. 140 if (!cookies_in_jar.size()) { 141 net::CookieStore* to_store = 142 to_context_->GetURLRequestContext()->cookie_store(); 143 net::CookieMonster* to_monster = to_store->GetCookieMonster(); 144 to_monster->InitializeFrom(cookies_to_transfer_); 145 146 net::ServerBoundCertService* to_cert_service = 147 to_context_->GetURLRequestContext()->server_bound_cert_service(); 148 to_cert_service->GetCertStore()->InitializeFrom(certs_to_transfer_); 149 } 150 151 Finish(); 152 } 153 154 // Callback for receiving |cookies_to_transfer| from the authentication profile 155 // cookie jar. 156 void ProfileAuthDataTransferer::OnGetCookiesToTransfer( 157 const net::CookieList& cookies_to_transfer) { 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 159 160 got_cookies_ = true; 161 cookies_to_transfer_ = cookies_to_transfer; 162 MaybeDoCookieAndCertTransfer(); 163 } 164 165 // Retrieves initial set of Profile cookies from the |from_context_|. 166 void ProfileAuthDataTransferer::RetrieveDefaultCookies() { 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 168 169 net::CookieStore* from_store = 170 from_context_->GetURLRequestContext()->cookie_store(); 171 net::CookieMonster* from_monster = from_store->GetCookieMonster(); 172 from_monster->SetKeepExpiredCookies(); 173 from_monster->GetAllCookiesAsync( 174 base::Bind(&ProfileAuthDataTransferer::OnGetCookiesToTransfer, 175 base::Unretained(this))); 176 } 177 178 // Callback for receiving |cookies_to_transfer| from the authentication profile 179 // cookie jar. 180 void ProfileAuthDataTransferer::OnGetServerBoundCertsToTransfer( 181 const net::ServerBoundCertStore::ServerBoundCertList& certs) { 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 183 certs_to_transfer_ = certs; 184 got_server_bound_certs_ = true; 185 MaybeDoCookieAndCertTransfer(); 186 } 187 188 // Retrieves server bound certs of |from_context_|. 189 void ProfileAuthDataTransferer::RetrieveDefaultServerBoundCerts() { 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 191 net::ServerBoundCertService* from_service = 192 from_context_->GetURLRequestContext()->server_bound_cert_service(); 193 194 from_service->GetCertStore()->GetAllServerBoundCerts( 195 base::Bind(&ProfileAuthDataTransferer::OnGetServerBoundCertsToTransfer, 196 base::Unretained(this))); 197 } 198 199 // Transfers HTTP authentication cache from the |from_context_| 200 // into the |to_context_|. If user was required to authenticate with a proxy 201 // during the login, this authentication information will be transferred 202 // into the new session. 203 void ProfileAuthDataTransferer::TransferDefaultAuthCache() { 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 205 net::HttpAuthCache* new_cache = to_context_->GetURLRequestContext()-> 206 http_transaction_factory()->GetSession()->http_auth_cache(); 207 new_cache->UpdateAllFrom(*from_context_->GetURLRequestContext()-> 208 http_transaction_factory()->GetSession()->http_auth_cache()); 209 } 210 211 } // namespace 212 213 void ProfileAuthData::Transfer( 214 Profile* from_profile, 215 Profile* to_profile, 216 bool transfer_cookies, 217 const base::Closure& completion_callback) { 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 219 (new ProfileAuthDataTransferer(from_profile, to_profile, transfer_cookies, 220 completion_callback))->BeginTransfer(); 221 } 222 223 } // namespace chromeos 224