| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/login/profile_auth_data.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/compiler_specific.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "net/cookies/canonical_cookie.h" |
| #include "net/cookies/cookie_constants.h" |
| #include "net/cookies/cookie_store.h" |
| #include "net/http/http_auth.h" |
| #include "net/http/http_auth_cache.h" |
| #include "net/http/http_network_session.h" |
| #include "net/http/http_transaction_factory.h" |
| #include "net/ssl/channel_id_service.h" |
| #include "net/ssl/channel_id_store.h" |
| #include "net/test/channel_id_test_util.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_context_getter.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| const char kProxyAuthURL[] = "http://example.com/"; |
| const char kProxyAuthRealm[] = "realm"; |
| const char kProxyAuthChallenge[] = "challenge"; |
| const char kProxyAuthPassword1[] = "password 1"; |
| const char kProxyAuthPassword2[] = "password 2"; |
| |
| const char kGAIACookieURL[] = "http://google.com/"; |
| const char kSAMLIdPCookieURL[] = "http://example.com/"; |
| const char kCookieName[] = "cookie"; |
| const char kCookieValue1[] = "value 1"; |
| const char kCookieValue2[] = "value 2"; |
| const char kGAIACookieDomain[] = "google.com"; |
| const char kSAMLIdPCookieDomain[] = "example.com"; |
| |
| const char kChannelIDServerIdentifier[] = "server"; |
| |
| } // namespace |
| |
| class ProfileAuthDataTest : public testing::Test { |
| public: |
| // testing::Test: |
| void SetUp() override; |
| |
| void PopulateUserBrowserContext(); |
| |
| void Transfer( |
| bool transfer_auth_cookies_and_channel_ids_on_first_login, |
| bool transfer_saml_auth_cookies_on_subsequent_login); |
| |
| net::CookieList GetUserCookies(); |
| net::ChannelIDStore::ChannelIDList GetUserChannelIDs(); |
| |
| void VerifyTransferredUserProxyAuthEntry(); |
| void VerifyUserCookies(const std::string& expected_gaia_cookie_value, |
| const std::string& expected_saml_idp_cookie_value); |
| void VerifyUserChannelID(crypto::ECPrivateKey* expected_key); |
| |
| protected: |
| scoped_ptr<crypto::ECPrivateKey> channel_id_key1_; |
| scoped_ptr<crypto::ECPrivateKey> channel_id_key2_; |
| |
| private: |
| void PopulateBrowserContext(content::BrowserContext* browser_context, |
| const std::string& proxy_auth_password, |
| const std::string& cookie_value, |
| scoped_ptr<crypto::ECPrivateKey> channel_id_key); |
| |
| net::URLRequestContext* GetRequestContext( |
| content::BrowserContext* browser_context); |
| net::HttpAuthCache* GetProxyAuth(content::BrowserContext* browser_context); |
| net::CookieStore* GetCookies(content::BrowserContext* browser_context); |
| net::ChannelIDStore* GetChannelIDs(content::BrowserContext* browser_context); |
| |
| void QuitLoop(const net::CookieList& ignored); |
| void StoreCookieListAndQuitLoop(const net::CookieList& cookie_list); |
| void StoreChannelIDListAndQuitLoop( |
| const net::ChannelIDStore::ChannelIDList& channel_id_list); |
| |
| content::TestBrowserThreadBundle thread_bundle_; |
| |
| TestingProfile login_browser_context_; |
| TestingProfile user_browser_context_; |
| |
| net::CookieList user_cookie_list_; |
| net::ChannelIDStore::ChannelIDList user_channel_id_list_; |
| |
| scoped_ptr<base::RunLoop> run_loop_; |
| }; |
| |
| void ProfileAuthDataTest::SetUp() { |
| channel_id_key1_.reset(crypto::ECPrivateKey::Create()); |
| channel_id_key2_.reset(crypto::ECPrivateKey::Create()); |
| PopulateBrowserContext(&login_browser_context_, kProxyAuthPassword1, |
| kCookieValue1, |
| make_scoped_ptr(channel_id_key1_->Copy())); |
| } |
| |
| void ProfileAuthDataTest::PopulateUserBrowserContext() { |
| PopulateBrowserContext(&user_browser_context_, kProxyAuthPassword2, |
| kCookieValue2, |
| make_scoped_ptr(channel_id_key2_->Copy())); |
| } |
| |
| void ProfileAuthDataTest::Transfer( |
| bool transfer_auth_cookies_and_channel_ids_on_first_login, |
| bool transfer_saml_auth_cookies_on_subsequent_login) { |
| base::RunLoop run_loop; |
| ProfileAuthData::Transfer( |
| login_browser_context_.GetRequestContext(), |
| user_browser_context_.GetRequestContext(), |
| transfer_auth_cookies_and_channel_ids_on_first_login, |
| transfer_saml_auth_cookies_on_subsequent_login, |
| run_loop.QuitClosure()); |
| run_loop.Run(); |
| if (!transfer_auth_cookies_and_channel_ids_on_first_login && |
| !transfer_saml_auth_cookies_on_subsequent_login) { |
| // When only proxy auth state is being transferred, the completion callback |
| // is invoked before the transfer has actually completed. Spin the loop once |
| // more to allow the transfer to complete. |
| base::RunLoop().RunUntilIdle(); |
| } |
| } |
| |
| net::CookieList ProfileAuthDataTest::GetUserCookies() { |
| run_loop_.reset(new base::RunLoop); |
| GetCookies(&user_browser_context_)->GetAllCookiesAsync(base::Bind( |
| &ProfileAuthDataTest::StoreCookieListAndQuitLoop, |
| base::Unretained(this))); |
| run_loop_->Run(); |
| return user_cookie_list_; |
| } |
| |
| net::ChannelIDStore::ChannelIDList ProfileAuthDataTest::GetUserChannelIDs() { |
| run_loop_.reset(new base::RunLoop); |
| GetChannelIDs(&user_browser_context_)->GetAllChannelIDs(base::Bind( |
| &ProfileAuthDataTest::StoreChannelIDListAndQuitLoop, |
| base::Unretained(this))); |
| run_loop_->Run(); |
| return user_channel_id_list_; |
| } |
| |
| void ProfileAuthDataTest::VerifyTransferredUserProxyAuthEntry() { |
| net::HttpAuthCache::Entry* entry = |
| GetProxyAuth(&user_browser_context_)->Lookup( |
| GURL(kProxyAuthURL), |
| kProxyAuthRealm, |
| net::HttpAuth::AUTH_SCHEME_BASIC); |
| ASSERT_TRUE(entry); |
| EXPECT_EQ(base::ASCIIToUTF16(kProxyAuthPassword1), |
| entry->credentials().password()); |
| } |
| |
| void ProfileAuthDataTest::VerifyUserCookies( |
| const std::string& expected_gaia_cookie_value, |
| const std::string& expected_saml_idp_cookie_value) { |
| net::CookieList user_cookies = GetUserCookies(); |
| ASSERT_EQ(2u, user_cookies.size()); |
| net::CanonicalCookie* cookie = &user_cookies[0]; |
| // kSAMLIdPCookieURL is returned first because it was created first, so has |
| // the earliest creation date. |
| EXPECT_EQ(GURL(kSAMLIdPCookieURL), cookie->Source()); |
| EXPECT_EQ(kCookieName, cookie->Name()); |
| EXPECT_EQ(expected_saml_idp_cookie_value, cookie->Value()); |
| EXPECT_EQ(kSAMLIdPCookieDomain, cookie->Domain()); |
| cookie = &user_cookies[1]; |
| EXPECT_EQ(GURL(kGAIACookieURL), cookie->Source()); |
| EXPECT_EQ(kCookieName, cookie->Name()); |
| EXPECT_EQ(expected_gaia_cookie_value, cookie->Value()); |
| EXPECT_EQ(kGAIACookieDomain, cookie->Domain()); |
| } |
| |
| void ProfileAuthDataTest::VerifyUserChannelID( |
| crypto::ECPrivateKey* expected_key) { |
| net::ChannelIDStore::ChannelIDList user_channel_ids = GetUserChannelIDs(); |
| ASSERT_EQ(1u, user_channel_ids.size()); |
| net::ChannelIDStore::ChannelID* channel_id = &user_channel_ids.front(); |
| EXPECT_EQ(kChannelIDServerIdentifier, channel_id->server_identifier()); |
| EXPECT_TRUE(net::KeysEqual(expected_key, channel_id->key())); |
| } |
| |
| void ProfileAuthDataTest::PopulateBrowserContext( |
| content::BrowserContext* browser_context, |
| const std::string& proxy_auth_password, |
| const std::string& cookie_value, |
| scoped_ptr<crypto::ECPrivateKey> channel_id_key) { |
| GetProxyAuth(browser_context)->Add( |
| GURL(kProxyAuthURL), |
| kProxyAuthRealm, |
| net::HttpAuth::AUTH_SCHEME_BASIC, |
| kProxyAuthChallenge, |
| net::AuthCredentials(base::string16(), |
| base::ASCIIToUTF16(proxy_auth_password)), |
| std::string()); |
| |
| net::CookieStore* cookies = GetCookies(browser_context); |
| // Ensure |cookies| is fully initialized. |
| run_loop_.reset(new base::RunLoop); |
| cookies->GetAllCookiesAsync(base::Bind(&ProfileAuthDataTest::QuitLoop, |
| base::Unretained(this))); |
| run_loop_->Run(); |
| |
| cookies->SetCookieWithDetailsAsync( |
| GURL(kSAMLIdPCookieURL), kCookieName, cookie_value, std::string(), |
| std::string(), base::Time(), base::Time(), base::Time(), true, false, |
| net::CookieSameSite::DEFAULT_MODE, false, net::COOKIE_PRIORITY_DEFAULT, |
| net::CookieStore::SetCookiesCallback()); |
| cookies->SetCookieWithDetailsAsync( |
| GURL(kGAIACookieURL), kCookieName, cookie_value, std::string(), |
| std::string(), base::Time(), base::Time(), base::Time(), true, false, |
| net::CookieSameSite::DEFAULT_MODE, false, net::COOKIE_PRIORITY_DEFAULT, |
| net::CookieStore::SetCookiesCallback()); |
| |
| GetChannelIDs(browser_context) |
| ->SetChannelID(make_scoped_ptr(new net::ChannelIDStore::ChannelID( |
| kChannelIDServerIdentifier, base::Time(), |
| std::move(channel_id_key)))); |
| } |
| |
| net::URLRequestContext* ProfileAuthDataTest::GetRequestContext( |
| content::BrowserContext* browser_context) { |
| return browser_context->GetRequestContext()->GetURLRequestContext(); |
| } |
| |
| net::HttpAuthCache* ProfileAuthDataTest::GetProxyAuth( |
| content::BrowserContext* browser_context) { |
| return GetRequestContext(browser_context)->http_transaction_factory()-> |
| GetSession()->http_auth_cache(); |
| } |
| |
| net::CookieStore* ProfileAuthDataTest::GetCookies( |
| content::BrowserContext* browser_context) { |
| return GetRequestContext(browser_context)->cookie_store(); |
| } |
| |
| net::ChannelIDStore* ProfileAuthDataTest::GetChannelIDs( |
| content::BrowserContext* browser_context) { |
| return GetRequestContext(browser_context)->channel_id_service()-> |
| GetChannelIDStore(); |
| } |
| |
| void ProfileAuthDataTest::QuitLoop(const net::CookieList& ignored) { |
| run_loop_->Quit(); |
| } |
| |
| void ProfileAuthDataTest::StoreCookieListAndQuitLoop( |
| const net::CookieList& cookie_list) { |
| user_cookie_list_ = cookie_list; |
| run_loop_->Quit(); |
| } |
| |
| void ProfileAuthDataTest::StoreChannelIDListAndQuitLoop( |
| const net::ChannelIDStore::ChannelIDList& channel_id_list) { |
| user_channel_id_list_ = channel_id_list; |
| run_loop_->Quit(); |
| } |
| |
| // Verifies that when no transfer of auth cookies or channel IDs is requested, |
| // only the proxy auth state is transferred. |
| TEST_F(ProfileAuthDataTest, DoNotTransfer) { |
| Transfer(false, false); |
| |
| VerifyTransferredUserProxyAuthEntry(); |
| EXPECT_TRUE(GetUserCookies().empty()); |
| EXPECT_TRUE(GetUserChannelIDs().empty()); |
| } |
| |
| // Verifies that when the transfer of auth cookies and channel IDs on first |
| // login is requested, they do get transferred along with the proxy auth state |
| // on first login. |
| TEST_F(ProfileAuthDataTest, TransferOnFirstLoginWithNewProfile) { |
| Transfer(true, false); |
| |
| VerifyTransferredUserProxyAuthEntry(); |
| VerifyUserCookies(kCookieValue1, kCookieValue1); |
| VerifyUserChannelID(channel_id_key1_.get()); |
| } |
| |
| // Verifies that even if the transfer of auth cookies and channel IDs on first |
| // login is requested, only the proxy auth state is transferred on subsequent |
| // login. |
| TEST_F(ProfileAuthDataTest, TransferOnFirstLoginWithExistingProfile) { |
| PopulateUserBrowserContext(); |
| |
| Transfer(true, false); |
| |
| VerifyTransferredUserProxyAuthEntry(); |
| VerifyUserCookies(kCookieValue2, kCookieValue2); |
| VerifyUserChannelID(channel_id_key2_.get()); |
| } |
| |
| // Verifies that when the transfer of auth cookies set by a SAML IdP on |
| // subsequent login is requested, they do get transferred along with the proxy |
| // auth state on subsequent login. |
| TEST_F(ProfileAuthDataTest, TransferOnSubsequentLogin) { |
| PopulateUserBrowserContext(); |
| |
| Transfer(false, true); |
| |
| VerifyTransferredUserProxyAuthEntry(); |
| VerifyUserCookies(kCookieValue2, kCookieValue1); |
| VerifyUserChannelID(channel_id_key2_.get()); |
| } |
| |
| } // namespace chromeos |