blob: a1c2a450704b2ebb3201cf1eb30935a840e3a829 [file] [log] [blame]
// Copyright (c) 2017 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/signin_partition_manager.h"
#include <memory>
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/web_contents_tester.h"
#include "net/cookies/cookie_store.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace chromeos {
namespace login {
namespace {
constexpr char kEmbedderUrl[] = "http://www.whatever.com/";
void StorePartitionNameAndQuitLoop(base::RunLoop* loop,
std::string* out_partition_name,
const std::string& partition_name) {
*out_partition_name = partition_name;
loop->Quit();
}
void AddEntryToHttpAuthCache(net::URLRequestContext* url_request_context) {
net::HttpAuthCache* http_auth_cache =
url_request_context->http_transaction_factory()
->GetSession()
->http_auth_cache();
http_auth_cache->Add(GURL("http://whatever.com/"), "",
net::HttpAuth::AUTH_SCHEME_BASIC, "",
net::AuthCredentials(), "");
}
void IsEntryInHttpAuthCache(
net::URLRequestContextGetter* url_request_context_getter,
bool* out_entry_found) {
net::HttpAuthCache* http_auth_cache =
url_request_context_getter->GetURLRequestContext()
->http_transaction_factory()
->GetSession()
->http_auth_cache();
*out_entry_found =
http_auth_cache->Lookup(GURL("http://whatever.com/"), "",
net::HttpAuth::AUTH_SCHEME_BASIC) != nullptr;
}
} // namespace
class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness {
protected:
SigninPartitionManagerTest() {}
~SigninPartitionManagerTest() override {}
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
signin_browser_context_ = std::make_unique<TestingProfile>();
signin_ui_web_contents_ = content::WebContentsTester::CreateTestWebContents(
GetSigninProfile(), content::SiteInstance::Create(GetSigninProfile()));
// Let Profile creation finish, which creates the NetworkService instance.
base::RunLoop().RunUntilIdle();
network::mojom::NetworkContextParamsPtr params =
network::mojom::NetworkContextParams::New();
system_network_context_ = std::make_unique<network::NetworkContext>(
network::NetworkService::GetNetworkServiceForTesting(),
mojo::MakeRequest(&system_network_context_ptr_), std::move(params));
GURL url(kEmbedderUrl);
content::WebContentsTester::For(signin_ui_web_contents())
->NavigateAndCommit(url);
GetSigninPartitionManager()->SetClearStoragePartitionTaskForTesting(
base::Bind(&SigninPartitionManagerTest::ClearStoragePartitionTask,
base::Unretained(this)));
GetSigninPartitionManager()->SetGetSystemNetworkContextForTesting(
base::BindRepeating(
&SigninPartitionManagerTest::GetSystemNetworkContext,
base::Unretained(this)));
}
void TearDown() override {
signin_ui_web_contents_.reset();
signin_browser_context_.reset();
ChromeRenderViewHostTestHarness::TearDown();
}
Profile* GetSigninProfile() {
return signin_browser_context_->GetOffTheRecordProfile();
}
SigninPartitionManager* GetSigninPartitionManager() {
return SigninPartitionManager::Factory::GetForBrowserContext(
GetSigninProfile());
}
content::WebContents* signin_ui_web_contents() {
return signin_ui_web_contents_.get();
}
void ExpectOneClearPartitionTask(
content::StoragePartition* storage_partition) {
EXPECT_EQ(1u, pending_clear_tasks_.size());
if (pending_clear_tasks_.size() > 0) {
EXPECT_EQ(storage_partition, pending_clear_tasks_[0].first);
}
}
void FinishAllClearPartitionTasks() {
for (auto& task : pending_clear_tasks_) {
std::move(task.second).Run();
}
pending_clear_tasks_.clear();
}
std::string RunStartSigninSesssion(content::WebContents* webcontents) {
std::string partition_name;
base::RunLoop loop;
GetSigninPartitionManager()->StartSigninSession(
webcontents,
base::BindOnce(&StorePartitionNameAndQuitLoop, &loop, &partition_name));
loop.Run();
return partition_name;
}
net::URLRequestContext* GetSystemURLRequestContext() {
return system_network_context_->url_request_context();
}
network::mojom::NetworkContext* GetSystemNetworkContext() {
return system_network_context_.get();
}
private:
void ClearStoragePartitionTask(content::StoragePartition* partition,
base::OnceClosure clear_done_closure) {
pending_clear_tasks_.push_back({partition, std::move(clear_done_closure)});
}
std::unique_ptr<network::NetworkContext> system_network_context_;
network::mojom::NetworkContextPtr system_network_context_ptr_;
std::unique_ptr<TestingProfile> signin_browser_context_;
// Web contents of the sign-in UI, embedder of the signin-frame webview.
std::unique_ptr<content::WebContents> signin_ui_web_contents_;
std::vector<std::pair<content::StoragePartition*, base::OnceClosure>>
pending_clear_tasks_;
DISALLOW_COPY_AND_ASSIGN(SigninPartitionManagerTest);
};
TEST_F(SigninPartitionManagerTest, TestSubsequentAttempts) {
// First sign-in attempt
std::string signin_partition_name_1 =
RunStartSigninSesssion(signin_ui_web_contents());
auto* signin_partition_1 =
GetSigninPartitionManager()->GetCurrentStoragePartition();
EXPECT_FALSE(signin_partition_name_1.empty());
EXPECT_EQ(signin_partition_name_1,
GetSigninPartitionManager()->GetCurrentStoragePartitionName());
// Second sign-in attempt
std::string signin_partition_name_2 =
RunStartSigninSesssion(signin_ui_web_contents());
auto* signin_partition_2 =
GetSigninPartitionManager()->GetCurrentStoragePartition();
EXPECT_FALSE(signin_partition_name_2.empty());
EXPECT_EQ(signin_partition_name_2,
GetSigninPartitionManager()->GetCurrentStoragePartitionName());
// Make sure that the StoragePartition has not been re-used.
EXPECT_NE(signin_partition_name_1, signin_partition_name_2);
EXPECT_NE(signin_partition_1, signin_partition_2);
// Make sure that the first StoragePartition has been cleared automatically.
ExpectOneClearPartitionTask(signin_partition_1);
FinishAllClearPartitionTasks();
// Make sure that the second StoragePartition will be cleared when we
// explicitly close the current sign-in session.
bool closure_called = false;
base::RepeatingClosure partition_cleared_closure = base::BindRepeating(
[](bool* closure_called_ptr) { *closure_called_ptr = true; },
&closure_called);
GetSigninPartitionManager()->CloseCurrentSigninSession(
partition_cleared_closure);
EXPECT_FALSE(closure_called);
ExpectOneClearPartitionTask(signin_partition_2);
FinishAllClearPartitionTasks();
EXPECT_TRUE(closure_called);
}
TEST_F(SigninPartitionManagerTest, HttpAuthCacheTransferred) {
base::RunLoop loop_prepare;
base::PostTaskWithTraitsAndReply(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(AddEntryToHttpAuthCache,
base::Unretained(GetSystemURLRequestContext())),
loop_prepare.QuitClosure());
loop_prepare.Run();
RunStartSigninSesssion(signin_ui_web_contents());
net::URLRequestContextGetter* signin_url_request_context_getter =
GetSigninPartitionManager()
->GetCurrentStoragePartition()
->GetURLRequestContext();
bool entry_found = false;
base::RunLoop loop_check;
base::PostTaskWithTraitsAndReply(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(IsEntryInHttpAuthCache,
base::RetainedRef(signin_url_request_context_getter),
&entry_found),
loop_check.QuitClosure());
loop_check.Run();
EXPECT_TRUE(entry_found);
}
} // namespace login
} // namespace chromeos