blob: ebb1a1acaab1814309afc29abe2bbcc4414e1456 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/login/signin_partition_manager.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/uuid.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/storage_partition_config.h"
#include "content/public/browser/web_contents.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "url/gurl.h"
namespace ash {
namespace login {
namespace {
// Generates a new unique StoragePartition name.
std::string GeneratePartitionName() {
return base::Uuid::GenerateRandomV4().AsLowercaseString();
}
// Clears data from the passed storage partition. `partition_data_cleared`
// will be called when all cached data has been cleared.
void ClearStoragePartition(content::StoragePartition* storage_partition,
base::OnceClosure partition_data_cleared) {
storage_partition->ClearData(
content::StoragePartition::REMOVE_DATA_MASK_ALL,
content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey(), base::Time(), base::Time::Max(),
std::move(partition_data_cleared));
}
network::mojom::NetworkContext* GetSystemNetworkContext() {
return g_browser_process->system_network_context_manager()->GetContext();
}
// Copies the http auth cache proxy entries with key `cache_key` into
// `signin_storage_partition`'s NetworkContext.
void LoadHttpAuthCacheProxyEntries(
content::StoragePartition* signin_storage_partition,
base::OnceClosure completion_callback,
const base::UnguessableToken& cache_key) {
signin_storage_partition->GetNetworkContext()->LoadHttpAuthCacheProxyEntries(
cache_key, std::move(completion_callback));
}
// Transfers http auth cache proxy entries from `main_network_context` into
// `signin_storage_partition`'s NetworkContext.
void TransferHttpAuthCacheProxyEntries(
network::mojom::NetworkContext* main_network_context,
content::StoragePartition* signin_storage_partition,
base::OnceClosure completion_callback) {
main_network_context->SaveHttpAuthCacheProxyEntries(
base::BindOnce(&LoadHttpAuthCacheProxyEntries,
base::Unretained(signin_storage_partition),
std::move(completion_callback)));
}
} // namespace
SigninPartitionManager::SigninPartitionManager(
content::BrowserContext* browser_context)
: browser_context_(browser_context),
clear_storage_partition_task_(
base::BindRepeating(&ClearStoragePartition)),
get_system_network_context_task_(
base::BindRepeating(&GetSystemNetworkContext)) {}
SigninPartitionManager::~SigninPartitionManager() = default;
void SigninPartitionManager::StartSigninSession(
content::WebContents* embedder_web_contents,
StartSigninSessionDoneCallback signin_session_started) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// If we already were in a sign-in session, close it first.
// This clears stale data from the last-used StoragePartition.
CloseCurrentSigninSession(base::DoNothing());
// The storage partition domain identifies the site embedding the webview. It
// won't change when the webview navigates.
storage_partition_domain_ =
embedder_web_contents->GetLastCommittedURL().host();
current_storage_partition_name_ = GeneratePartitionName();
auto storage_partition_config = content::StoragePartitionConfig::Create(
browser_context_, storage_partition_domain_,
current_storage_partition_name_, true /*in_memory */);
current_storage_partition_ =
browser_context_->GetStoragePartition(storage_partition_config, true);
if (on_create_new_storage_partition_) {
on_create_new_storage_partition_.Run(current_storage_partition_.get());
}
TransferHttpAuthCacheProxyEntries(
get_system_network_context_task_.Run(), current_storage_partition_,
base::BindOnce(std::move(signin_session_started),
current_storage_partition_name_));
}
void SigninPartitionManager::CloseCurrentSigninSession(
base::OnceClosure partition_data_cleared) {
if (!current_storage_partition_) {
std::move(partition_data_cleared).Run();
return;
}
clear_storage_partition_task_.Run(current_storage_partition_.get(),
std::move(partition_data_cleared));
current_storage_partition_ = nullptr;
current_storage_partition_name_.clear();
}
bool SigninPartitionManager::IsInSigninSession() const {
return !current_storage_partition_name_.empty();
}
void SigninPartitionManager::SetClearStoragePartitionTaskForTesting(
ClearStoragePartitionTask clear_storage_partition_task) {
clear_storage_partition_task_ = clear_storage_partition_task;
}
void SigninPartitionManager::SetGetSystemNetworkContextForTesting(
network::NetworkContextGetter get_system_network_context_task) {
get_system_network_context_task_ = std::move(get_system_network_context_task);
}
void SigninPartitionManager::SetOnCreateNewStoragePartitionForTesting(
OnCreateNewStoragePartition on_create_new_storage_partition) {
on_create_new_storage_partition_ = on_create_new_storage_partition;
}
const std::string& SigninPartitionManager::GetCurrentStoragePartitionName()
const {
DCHECK(IsInSigninSession());
return current_storage_partition_name_;
}
content::StoragePartition*
SigninPartitionManager::GetCurrentStoragePartition() {
DCHECK(IsInSigninSession());
return current_storage_partition_;
}
bool SigninPartitionManager::IsCurrentSigninStoragePartition(
const content::StoragePartition* storage_partition) const {
return IsInSigninSession() && storage_partition == current_storage_partition_;
}
SigninPartitionManager::Factory::Factory()
: ProfileKeyedServiceFactory(
"SigninPartitionManager",
ProfileSelections::Builder()
.WithRegular(ProfileSelection::kOwnInstance)
// TODO(crbug.com/40257657): Check if this service is needed in
// Guest mode.
.WithGuest(ProfileSelection::kOwnInstance)
// TODO(crbug.com/41488885): Check if this service is needed for
// Ash Internals.
.WithAshInternals(ProfileSelection::kOwnInstance)
.Build()) {}
SigninPartitionManager::Factory::~Factory() = default;
// static
SigninPartitionManager* SigninPartitionManager::Factory::GetForBrowserContext(
content::BrowserContext* browser_context) {
return static_cast<SigninPartitionManager*>(
GetInstance()->GetServiceForBrowserContext(browser_context,
true /* create */));
}
// static
SigninPartitionManager::Factory*
SigninPartitionManager::Factory::GetInstance() {
return base::Singleton<SigninPartitionManager::Factory>::get();
}
std::unique_ptr<KeyedService>
SigninPartitionManager::Factory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
return std::make_unique<SigninPartitionManager>(context);
}
} // namespace login
} // namespace ash