Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / chromeos / login / profile_auth_data.cc
blobf8aef0892d39d21ed5d4e3d3703977d9dc816cef
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.
5 #include "chrome/browser/chromeos/login/profile_auth_data.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/time/time.h"
17 #include "content/public/browser/browser_context.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "net/cookies/canonical_cookie.h"
20 #include "net/cookies/cookie_monster.h"
21 #include "net/cookies/cookie_store.h"
22 #include "net/http/http_auth_cache.h"
23 #include "net/http/http_network_session.h"
24 #include "net/http/http_transaction_factory.h"
25 #include "net/ssl/channel_id_service.h"
26 #include "net/ssl/channel_id_store.h"
27 #include "net/url_request/url_request_context.h"
28 #include "net/url_request/url_request_context_getter.h"
29 #include "url/gurl.h"
31 using content::BrowserThread;
33 namespace chromeos {
35 namespace {
37 const char kSAMLStartCookie[] = "google-accounts-saml-start";
38 const char kSAMLEndCookie[] = "google-accounts-saml-end";
40 class ProfileAuthDataTransferer {
41 public:
42 ProfileAuthDataTransferer(
43 net::URLRequestContextGetter* from_context,
44 net::URLRequestContextGetter* to_context,
45 bool transfer_auth_cookies_and_channel_ids_on_first_login,
46 bool transfer_saml_auth_cookies_on_subsequent_login,
47 const base::Closure& completion_callback);
49 void BeginTransfer();
51 private:
52 void BeginTransferOnIOThread();
54 // Transfer the proxy auth cache from |from_context_| to |to_context_|. If
55 // the user was required to authenticate with a proxy during login, this
56 // authentication information will be transferred into the user's session.
57 void TransferProxyAuthCache();
59 // Callback that receives the content of |to_context_|'s cookie jar. Checks
60 // whether this is the user's first login, based on the state of the cookie
61 // jar, and starts retrieval of the data that should be transfered. Calls
62 // Finish() if there is no data to transfer.
63 void OnTargetCookieJarContentsRetrieved(
64 const net::CookieList& target_cookies);
66 // Retrieve the contents of |from_context_|'s cookie jar. When the retrieval
67 // finishes, OnCookiesToTransferRetrieved will be called with the result.
68 void RetrieveCookiesToTransfer();
70 // Callback that receives the contents of |from_context_|'s cookie jar. Calls
71 // MaybeTransferCookiesAndChannelIDs() to try and perform the transfer.
72 void OnCookiesToTransferRetrieved(const net::CookieList& cookies_to_transfer);
74 // Retrieve |from_context_|'s channel IDs. When the retrieval finishes,
75 // OnChannelIDsToTransferRetrieved will be called with the result.
76 void RetrieveChannelIDsToTransfer();
78 // Callback that receives |from_context_|'s channel IDs. Calls
79 // MaybeTransferCookiesAndChannelIDs() to try and perform the transfer.
80 void OnChannelIDsToTransferRetrieved(
81 const net::ChannelIDStore::ChannelIDList& channel_ids_to_transfer);
83 // Given a |cookie| set during login, returns true if the cookie may have been
84 // set by GAIA. The main criterion is the |cookie|'s creation date. The points
85 // in time at which redirects from GAIA to SAML IdP and back occur are stored
86 // in |saml_start_time_| and |saml_end_time_|. If the cookie was set between
87 // these two times, it was created by the SAML IdP. Otherwise, it was created
88 // by GAIA.
89 // As an additional precaution, the cookie's domain is checked. If the domain
90 // contains "google" or "youtube", the cookie is considered to have been set
91 // by GAIA as well.
92 bool IsGAIACookie(const net::CanonicalCookie& cookie);
94 // If all data to be transferred has been retrieved already, transfer it to
95 // |to_context_| and call Finish().
96 void MaybeTransferCookiesAndChannelIDs();
98 // Post the |completion_callback_| to the UI thread and schedule destruction
99 // of |this|.
100 void Finish();
102 scoped_refptr<net::URLRequestContextGetter> from_context_;
103 scoped_refptr<net::URLRequestContextGetter> to_context_;
104 bool transfer_auth_cookies_and_channel_ids_on_first_login_;
105 bool transfer_saml_auth_cookies_on_subsequent_login_;
106 base::Closure completion_callback_;
108 net::CookieList cookies_to_transfer_;
109 net::ChannelIDStore::ChannelIDList channel_ids_to_transfer_;
111 // The time at which a redirect from GAIA to a SAML IdP occurred.
112 base::Time saml_start_time_;
113 // The time at which a redirect from a SAML IdP back to GAIA occurred.
114 base::Time saml_end_time_;
116 bool first_login_;
117 bool waiting_for_auth_cookies_;
118 bool waiting_for_channel_ids_;
121 ProfileAuthDataTransferer::ProfileAuthDataTransferer(
122 net::URLRequestContextGetter* from_context,
123 net::URLRequestContextGetter* to_context,
124 bool transfer_auth_cookies_and_channel_ids_on_first_login,
125 bool transfer_saml_auth_cookies_on_subsequent_login,
126 const base::Closure& completion_callback)
127 : from_context_(from_context),
128 to_context_(to_context),
129 transfer_auth_cookies_and_channel_ids_on_first_login_(
130 transfer_auth_cookies_and_channel_ids_on_first_login),
131 transfer_saml_auth_cookies_on_subsequent_login_(
132 transfer_saml_auth_cookies_on_subsequent_login),
133 completion_callback_(completion_callback),
134 first_login_(false),
135 waiting_for_auth_cookies_(false),
136 waiting_for_channel_ids_(false) {
139 void ProfileAuthDataTransferer::BeginTransfer() {
140 DCHECK_CURRENTLY_ON(BrowserThread::UI);
141 // If we aren't transferring auth cookies or channel IDs, post the completion
142 // callback immediately. Otherwise, it will be called when the transfer
143 // finishes.
144 if (!transfer_auth_cookies_and_channel_ids_on_first_login_ &&
145 !transfer_saml_auth_cookies_on_subsequent_login_) {
146 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, completion_callback_);
147 // Null the callback so that when Finish is called, the callback won't be
148 // called again.
149 completion_callback_.Reset();
151 BrowserThread::PostTask(
152 BrowserThread::IO, FROM_HERE,
153 base::Bind(&ProfileAuthDataTransferer::BeginTransferOnIOThread,
154 base::Unretained(this)));
157 void ProfileAuthDataTransferer::BeginTransferOnIOThread() {
158 DCHECK_CURRENTLY_ON(BrowserThread::IO);
159 TransferProxyAuthCache();
160 if (transfer_auth_cookies_and_channel_ids_on_first_login_ ||
161 transfer_saml_auth_cookies_on_subsequent_login_) {
162 // Retrieve the contents of |to_context_|'s cookie jar.
163 net::CookieStore* to_store =
164 to_context_->GetURLRequestContext()->cookie_store();
165 net::CookieMonster* to_monster = to_store->GetCookieMonster();
166 to_monster->GetAllCookiesAsync(
167 base::Bind(
168 &ProfileAuthDataTransferer::OnTargetCookieJarContentsRetrieved,
169 base::Unretained(this)));
170 } else {
171 Finish();
175 void ProfileAuthDataTransferer::TransferProxyAuthCache() {
176 DCHECK_CURRENTLY_ON(BrowserThread::IO);
177 net::HttpAuthCache* new_cache = to_context_->GetURLRequestContext()->
178 http_transaction_factory()->GetSession()->http_auth_cache();
179 new_cache->UpdateAllFrom(*from_context_->GetURLRequestContext()->
180 http_transaction_factory()->GetSession()->http_auth_cache());
183 void ProfileAuthDataTransferer::OnTargetCookieJarContentsRetrieved(
184 const net::CookieList& target_cookies) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO);
186 first_login_ = target_cookies.empty();
187 if (first_login_) {
188 // On first login, transfer all auth cookies and channel IDs if
189 // |transfer_auth_cookies_and_channel_ids_on_first_login_| is true.
190 waiting_for_auth_cookies_ =
191 transfer_auth_cookies_and_channel_ids_on_first_login_;
192 waiting_for_channel_ids_ =
193 transfer_auth_cookies_and_channel_ids_on_first_login_;
194 } else {
195 // On subsequent login, transfer auth cookies set by the SAML IdP if
196 // |transfer_saml_auth_cookies_on_subsequent_login_| is true.
197 waiting_for_auth_cookies_ = transfer_saml_auth_cookies_on_subsequent_login_;
200 if (!waiting_for_auth_cookies_ && !waiting_for_channel_ids_) {
201 Finish();
202 return;
205 if (waiting_for_auth_cookies_)
206 RetrieveCookiesToTransfer();
207 if (waiting_for_channel_ids_)
208 RetrieveChannelIDsToTransfer();
211 void ProfileAuthDataTransferer::RetrieveCookiesToTransfer() {
212 DCHECK_CURRENTLY_ON(BrowserThread::IO);
213 net::CookieStore* from_store =
214 from_context_->GetURLRequestContext()->cookie_store();
215 net::CookieMonster* from_monster = from_store->GetCookieMonster();
216 from_monster->SetKeepExpiredCookies();
217 from_monster->GetAllCookiesAsync(
218 base::Bind(&ProfileAuthDataTransferer::OnCookiesToTransferRetrieved,
219 base::Unretained(this)));
222 void ProfileAuthDataTransferer::OnCookiesToTransferRetrieved(
223 const net::CookieList& cookies_to_transfer) {
224 DCHECK_CURRENTLY_ON(BrowserThread::IO);
225 waiting_for_auth_cookies_ = false;
226 cookies_to_transfer_ = cookies_to_transfer;
228 // Look for cookies indicating the points in time at which redirects from GAIA
229 // to SAML IdP and back occurred. These cookies are synthesized by
230 // chrome/browser/resources/gaia_auth/background.js. If the cookies are found,
231 // their creation times are stored in |saml_start_time_| and
232 // |cookies_to_transfer_| and the cookies are deleted.
233 for (net::CookieList::iterator it = cookies_to_transfer_.begin();
234 it != cookies_to_transfer_.end(); ) {
235 if (it->Name() == kSAMLStartCookie) {
236 saml_start_time_ = it->CreationDate();
237 it = cookies_to_transfer_.erase(it);
238 } else if (it->Name() == kSAMLEndCookie) {
239 saml_end_time_ = it->CreationDate();
240 it = cookies_to_transfer_.erase(it);
241 } else {
242 ++it;
246 MaybeTransferCookiesAndChannelIDs();
249 void ProfileAuthDataTransferer::RetrieveChannelIDsToTransfer() {
250 DCHECK_CURRENTLY_ON(BrowserThread::IO);
251 net::ChannelIDService* from_service =
252 from_context_->GetURLRequestContext()->channel_id_service();
253 from_service->GetChannelIDStore()->GetAllChannelIDs(
254 base::Bind(
255 &ProfileAuthDataTransferer::OnChannelIDsToTransferRetrieved,
256 base::Unretained(this)));
259 void ProfileAuthDataTransferer::OnChannelIDsToTransferRetrieved(
260 const net::ChannelIDStore::ChannelIDList& channel_ids_to_transfer) {
261 DCHECK_CURRENTLY_ON(BrowserThread::IO);
262 channel_ids_to_transfer_ = channel_ids_to_transfer;
263 waiting_for_channel_ids_ = false;
264 MaybeTransferCookiesAndChannelIDs();
267 bool ProfileAuthDataTransferer::IsGAIACookie(
268 const net::CanonicalCookie& cookie) {
269 const base::Time& creation_date = cookie.CreationDate();
270 if (creation_date < saml_start_time_)
271 return true;
272 if (!saml_end_time_.is_null() && creation_date > saml_end_time_)
273 return true;
275 const std::string& domain = cookie.Domain();
276 return domain.find("google") != std::string::npos ||
277 domain.find("youtube") != std::string::npos;
280 void ProfileAuthDataTransferer::MaybeTransferCookiesAndChannelIDs() {
281 DCHECK_CURRENTLY_ON(BrowserThread::IO);
282 if (waiting_for_auth_cookies_ || waiting_for_channel_ids_)
283 return;
285 net::CookieStore* to_store =
286 to_context_->GetURLRequestContext()->cookie_store();
287 net::CookieMonster* to_monster = to_store->GetCookieMonster();
288 if (first_login_) {
289 to_monster->ImportCookies(cookies_to_transfer_);
290 net::ChannelIDService* to_cert_service =
291 to_context_->GetURLRequestContext()->channel_id_service();
292 to_cert_service->GetChannelIDStore()->InitializeFrom(
293 channel_ids_to_transfer_);
294 } else {
295 net::CookieList non_gaia_cookies;
296 for (net::CookieList::const_iterator it = cookies_to_transfer_.begin();
297 it != cookies_to_transfer_.end(); ++it) {
298 if (!IsGAIACookie(*it))
299 non_gaia_cookies.push_back(*it);
301 to_monster->ImportCookies(non_gaia_cookies);
304 Finish();
307 void ProfileAuthDataTransferer::Finish() {
308 DCHECK_CURRENTLY_ON(BrowserThread::IO);
309 if (!completion_callback_.is_null())
310 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, completion_callback_);
311 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
314 } // namespace
316 void ProfileAuthData::Transfer(
317 net::URLRequestContextGetter* from_context,
318 net::URLRequestContextGetter* to_context,
319 bool transfer_auth_cookies_and_channel_ids_on_first_login,
320 bool transfer_saml_auth_cookies_on_subsequent_login,
321 const base::Closure& completion_callback) {
322 DCHECK_CURRENTLY_ON(BrowserThread::UI);
323 (new ProfileAuthDataTransferer(
324 from_context,
325 to_context,
326 transfer_auth_cookies_and_channel_ids_on_first_login,
327 transfer_saml_auth_cookies_on_subsequent_login,
328 completion_callback))->BeginTransfer();
331 } // namespace chromeos