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
ProfileAuthDataTransferer(Profile * from_profile,Profile * to_profile,bool transfer_cookies,const base::Closure & completion_callback)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
BeginTransfer()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
BeginTransferOnIOThread()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.
MaybeDoCookieAndCertTransfer()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.
Finish()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.
OnTransferCookiesIfEmptyJar(const net::CookieList & cookies_in_jar)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.
OnGetCookiesToTransfer(const net::CookieList & cookies_to_transfer)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_|.
RetrieveDefaultCookies()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.
OnGetServerBoundCertsToTransfer(const net::ServerBoundCertStore::ServerBoundCertList & certs)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_|.
RetrieveDefaultServerBoundCerts()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.
TransferDefaultAuthCache()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
Transfer(Profile * from_profile,Profile * to_profile,bool transfer_cookies,const base::Closure & completion_callback)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