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