Home | History | Annotate | Download | only in login
      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 "content/public/browser/browser_context.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       content::BrowserContext* from_context,
     29       content::BrowserContext* to_context,
     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     content::BrowserContext* from_context,
     62     content::BrowserContext* to_context,
     63     bool transfer_cookies,
     64     const base::Closure& completion_callback)
     65     : from_context_(from_context->GetRequestContext()),
     66       to_context_(to_context->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 BrowserContext.
    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     content::BrowserContext* from_context,
    215     content::BrowserContext* to_context,
    216     bool transfer_cookies,
    217     const base::Closure& completion_callback) {
    218   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    219   (new ProfileAuthDataTransferer(from_context, to_context, transfer_cookies,
    220                                  completion_callback))->BeginTransfer();
    221 }
    222 
    223 }  // namespace chromeos
    224