1 // Copyright 2014 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 <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/compiler_specific.h"
14 #include "base/run_loop.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/test/bind.h"
18 #include "base/time/time.h"
19 #include "chrome/test/base/testing_profile.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/network_service_instance.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/test/browser_task_environment.h"
24 #include "content/public/test/test_utils.h"
25 #include "mojo/public/cpp/bindings/pending_remote.h"
26 #include "mojo/public/cpp/bindings/remote.h"
27 #include "net/base/network_isolation_key.h"
28 #include "net/cookies/canonical_cookie.h"
29 #include "net/cookies/cookie_constants.h"
30 #include "net/http/http_auth.h"
31 #include "net/http/http_auth_cache.h"
32 #include "net/http/http_network_session.h"
33 #include "net/http/http_transaction_factory.h"
34 #include "net/url_request/url_request_context.h"
35 #include "net/url_request/url_request_context_getter.h"
36 #include "services/network/network_context.h"
37 #include "services/network/network_service.h"
38 #include "services/network/public/mojom/cookie_manager.mojom.h"
39 #include "services/network/public/mojom/network_context.mojom-forward.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 #include "url/gurl.h"
42 
43 namespace chromeos {
44 
45 namespace {
46 
47 const char kProxyAuthURL[] = "https://example.com/";
48 const char kProxyAuthRealm[] = "realm";
49 const char kProxyAuthChallenge[] = "challenge";
50 const char kProxyAuthPassword1[] = "password 1";
51 const char kProxyAuthPassword2[] = "password 2";
52 
53 const char kGAIACookieURL[] = "https://google.com/";
54 const char kSAMLIdPCookieURL[] = "https://example.com/";
55 const char kCookieName[] = "cookie";
56 const char kCookieValue1[] = "value 1";
57 const char kCookieValue2[] = "value 2";
58 const char kGAIACookieDomain[] = "google.com";
59 const char kSAMLIdPCookieDomain[] = "example.com";
60 const char kSAMLIdPCookieDomainWithWildcard[] = ".example.com";
61 
62 std::unique_ptr<network::NetworkContext>
CreateNetworkContextForDefaultStoragePartition(network::NetworkService * network_service,content::BrowserContext * browser_context)63 CreateNetworkContextForDefaultStoragePartition(
64     network::NetworkService* network_service,
65     content::BrowserContext* browser_context) {
66   mojo::PendingRemote<network::mojom::NetworkContext> network_context_remote;
67   auto params = network::mojom::NetworkContextParams::New();
68   params->cert_verifier_params = content::GetCertVerifierParams(
69       network::mojom::CertVerifierCreationParams::New());
70   auto network_context = std::make_unique<network::NetworkContext>(
71       network_service, network_context_remote.InitWithNewPipeAndPassReceiver(),
72       std::move(params));
73   content::BrowserContext::GetDefaultStoragePartition(browser_context)
74       ->SetNetworkContextForTesting(std::move(network_context_remote));
75   return network_context;
76 }
77 
GetNetworkService()78 network::NetworkService* GetNetworkService() {
79   content::GetNetworkService();
80   // Wait for the Network Service to initialize on the IO thread.
81   content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
82   return network::NetworkService::GetNetworkServiceForTesting();
83 }
84 
85 }  // namespace
86 
87 class ProfileAuthDataTest : public testing::Test {
88  public:
89   ProfileAuthDataTest();
90 
91   // testing::Test:
92   void SetUp() override;
93 
94   void PopulateUserBrowserContext();
95 
96   void Transfer(bool transfer_auth_cookies_on_first_login,
97                 bool transfer_saml_auth_cookies_on_subsequent_login);
98 
99   net::CookieList GetUserCookies();
100 
101   void VerifyTransferredUserProxyAuthEntry();
102   void VerifyUserCookies(const std::string& expected_gaia_cookie_value,
103                          const std::string& expected_saml_idp_cookie_value);
104 
105  private:
106   void PopulateBrowserContext(TestingProfile* browser_context,
107                               network::NetworkContext* network_context,
108                               const std::string& proxy_auth_password,
109                               const std::string& cookie_value);
110 
111   net::HttpAuthCache* GetAuthCache(network::NetworkContext* network_context);
112   network::mojom::CookieManager* GetCookies(
113       content::BrowserContext* browser_context);
114 
115   content::BrowserTaskEnvironment task_environment_;
116 
117   network::NetworkService* network_service_;
118   TestingProfile login_browser_context_;
119   TestingProfile user_browser_context_;
120   std::unique_ptr<network::NetworkContext> login_network_context_;
121   std::unique_ptr<network::NetworkContext> user_network_context_;
122 };
123 
ProfileAuthDataTest()124 ProfileAuthDataTest::ProfileAuthDataTest()
125     : network_service_(GetNetworkService()) {
126   login_network_context_ = CreateNetworkContextForDefaultStoragePartition(
127       network_service_, &login_browser_context_);
128   user_network_context_ = CreateNetworkContextForDefaultStoragePartition(
129       network_service_, &user_browser_context_);
130 }
131 
SetUp()132 void ProfileAuthDataTest::SetUp() {
133   PopulateBrowserContext(&login_browser_context_, login_network_context_.get(),
134                          kProxyAuthPassword1, kCookieValue1);
135 }
136 
PopulateUserBrowserContext()137 void ProfileAuthDataTest::PopulateUserBrowserContext() {
138   PopulateBrowserContext(&user_browser_context_, user_network_context_.get(),
139                          kProxyAuthPassword2, kCookieValue2);
140 }
141 
Transfer(bool transfer_auth_cookies_on_first_login,bool transfer_saml_auth_cookies_on_subsequent_login)142 void ProfileAuthDataTest::Transfer(
143     bool transfer_auth_cookies_on_first_login,
144     bool transfer_saml_auth_cookies_on_subsequent_login) {
145   base::RunLoop run_loop;
146   ProfileAuthData::Transfer(content::BrowserContext::GetDefaultStoragePartition(
147                                 &login_browser_context_),
148                             content::BrowserContext::GetDefaultStoragePartition(
149                                 &user_browser_context_),
150                             transfer_auth_cookies_on_first_login,
151                             transfer_saml_auth_cookies_on_subsequent_login,
152                             run_loop.QuitClosure());
153   run_loop.Run();
154   if (!transfer_auth_cookies_on_first_login &&
155       !transfer_saml_auth_cookies_on_subsequent_login) {
156     // When only proxy auth state is being transferred, the completion callback
157     // is invoked before the transfer has actually completed. Spin the loop once
158     // more to allow the transfer to complete.
159     base::RunLoop().RunUntilIdle();
160   }
161 }
162 
GetUserCookies()163 net::CookieList ProfileAuthDataTest::GetUserCookies() {
164   base::RunLoop run_loop;
165   net::CookieList result;
166   GetCookies(&user_browser_context_)
167       ->GetAllCookies(
168           base::BindLambdaForTesting([&](const net::CookieList& cookie_list) {
169             result = cookie_list;
170             run_loop.Quit();
171           }));
172   run_loop.Run();
173   return result;
174 }
175 
VerifyTransferredUserProxyAuthEntry()176 void ProfileAuthDataTest::VerifyTransferredUserProxyAuthEntry() {
177   net::HttpAuthCache::Entry* entry =
178       GetAuthCache(user_network_context_.get())
179           ->Lookup(GURL(kProxyAuthURL), net::HttpAuth::AUTH_PROXY,
180                    kProxyAuthRealm, net::HttpAuth::AUTH_SCHEME_BASIC,
181                    net::NetworkIsolationKey());
182   ASSERT_TRUE(entry);
183   EXPECT_EQ(base::ASCIIToUTF16(kProxyAuthPassword1),
184             entry->credentials().password());
185 }
186 
VerifyUserCookies(const std::string & expected_gaia_cookie_value,const std::string & expected_saml_idp_cookie_value)187 void ProfileAuthDataTest::VerifyUserCookies(
188     const std::string& expected_gaia_cookie_value,
189     const std::string& expected_saml_idp_cookie_value) {
190   net::CookieList user_cookies = GetUserCookies();
191   ASSERT_EQ(3u, user_cookies.size());
192 
193   // Cookies are returned chronoligically, in the order they were set.
194   net::CanonicalCookie* cookie = &user_cookies[0];
195   EXPECT_EQ(kCookieName, cookie->Name());
196   EXPECT_EQ(expected_saml_idp_cookie_value, cookie->Value());
197   EXPECT_EQ(kSAMLIdPCookieDomainWithWildcard, cookie->Domain());
198 
199   cookie = &user_cookies[1];
200   EXPECT_EQ(kCookieName, cookie->Name());
201   EXPECT_EQ(expected_saml_idp_cookie_value, cookie->Value());
202   EXPECT_EQ(kSAMLIdPCookieDomain, cookie->Domain());
203 
204   cookie = &user_cookies[2];
205   EXPECT_EQ(kCookieName, cookie->Name());
206   EXPECT_EQ(expected_gaia_cookie_value, cookie->Value());
207   EXPECT_EQ(kGAIACookieDomain, cookie->Domain());
208 }
209 
PopulateBrowserContext(TestingProfile * browser_context,network::NetworkContext * network_context,const std::string & proxy_auth_password,const std::string & cookie_value)210 void ProfileAuthDataTest::PopulateBrowserContext(
211     TestingProfile* browser_context,
212     network::NetworkContext* network_context,
213     const std::string& proxy_auth_password,
214     const std::string& cookie_value) {
215   GetAuthCache(network_context)
216       ->Add(GURL(kProxyAuthURL), net::HttpAuth::AUTH_PROXY, kProxyAuthRealm,
217             net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(),
218             kProxyAuthChallenge,
219             net::AuthCredentials(base::string16(),
220                                  base::ASCIIToUTF16(proxy_auth_password)),
221             std::string());
222 
223   network::mojom::CookieManager* cookies = GetCookies(browser_context);
224   // Ensure `cookies` is fully initialized.
225   base::RunLoop run_loop;
226   cookies->GetAllCookies(base::BindLambdaForTesting(
227       [&](const net::CookieList& cookies) { run_loop.Quit(); }));
228   run_loop.Run();
229 
230   net::CookieOptions options;
231   options.set_include_httponly();
232   cookies->SetCanonicalCookie(
233       *net::CanonicalCookie::CreateSanitizedCookie(
234           GURL(kSAMLIdPCookieURL), kCookieName, cookie_value,
235           kSAMLIdPCookieDomainWithWildcard, std::string(), base::Time(),
236           base::Time(), base::Time(), true, false,
237           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
238           false),
239       GURL(kSAMLIdPCookieURL), options, base::DoNothing());
240 
241   cookies->SetCanonicalCookie(
242       *net::CanonicalCookie::CreateSanitizedCookie(
243           GURL(kSAMLIdPCookieURL), kCookieName, cookie_value, std::string(),
244           std::string(), base::Time(), base::Time(), base::Time(), true, false,
245           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
246           false),
247       GURL(kSAMLIdPCookieURL), options, base::DoNothing());
248 
249   cookies->SetCanonicalCookie(
250       *net::CanonicalCookie::CreateSanitizedCookie(
251           GURL(kGAIACookieURL), kCookieName, cookie_value, std::string(),
252           std::string(), base::Time(), base::Time(), base::Time(), true, false,
253           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
254           false),
255       GURL(kGAIACookieURL), options, base::DoNothing());
256 }
257 
GetAuthCache(network::NetworkContext * network_context)258 net::HttpAuthCache* ProfileAuthDataTest::GetAuthCache(
259     network::NetworkContext* network_context) {
260   return network_context->url_request_context()
261       ->http_transaction_factory()
262       ->GetSession()
263       ->http_auth_cache();
264 }
265 
GetCookies(content::BrowserContext * browser_context)266 network::mojom::CookieManager* ProfileAuthDataTest::GetCookies(
267     content::BrowserContext* browser_context) {
268   return content::BrowserContext::GetDefaultStoragePartition(browser_context)
269       ->GetCookieManagerForBrowserProcess();
270 }
271 
272 // Verifies that when no transfer of auth cookies is requested, only the proxy
273 // auth state is transferred.
TEST_F(ProfileAuthDataTest,DoNotTransfer)274 TEST_F(ProfileAuthDataTest, DoNotTransfer) {
275   Transfer(false, false);
276 
277   VerifyTransferredUserProxyAuthEntry();
278   EXPECT_TRUE(GetUserCookies().empty());
279 }
280 
281 // Verifies that when the transfer of auth cookies on first login is requested,
282 // they do get transferred along with the proxy auth state on first login.
TEST_F(ProfileAuthDataTest,TransferOnFirstLoginWithNewProfile)283 TEST_F(ProfileAuthDataTest, TransferOnFirstLoginWithNewProfile) {
284   Transfer(true, false);
285 
286   VerifyTransferredUserProxyAuthEntry();
287   VerifyUserCookies(kCookieValue1, kCookieValue1);
288 }
289 
290 // Verifies that even if the transfer of auth cookies on first login is
291 // requested, only the proxy auth state is transferred on subsequent login.
TEST_F(ProfileAuthDataTest,TransferOnFirstLoginWithExistingProfile)292 TEST_F(ProfileAuthDataTest, TransferOnFirstLoginWithExistingProfile) {
293   PopulateUserBrowserContext();
294 
295   Transfer(true, false);
296 
297   VerifyTransferredUserProxyAuthEntry();
298   VerifyUserCookies(kCookieValue2, kCookieValue2);
299 }
300 
301 // Verifies that when the transfer of auth cookies set by a SAML IdP on
302 // subsequent login is requested, they do get transferred along with the proxy
303 // auth state on subsequent login.
TEST_F(ProfileAuthDataTest,TransferOnSubsequentLogin)304 TEST_F(ProfileAuthDataTest, TransferOnSubsequentLogin) {
305   PopulateUserBrowserContext();
306 
307   Transfer(false, true);
308 
309   VerifyTransferredUserProxyAuthEntry();
310   VerifyUserCookies(kCookieValue2, kCookieValue1);
311 }
312 
313 }  // namespace chromeos
314