Commit bd1e40af authored by Pavol Marko's avatar Pavol Marko Committed by Commit Bot

Add unit tests for CertificateProvisioningUiHandler

Add unit tests for CertificateProvisioningUiHandler.
Introduce mock variant of CertProvisioningScheduler
to make unit testing possible.

Bug: 1081396
Test: unit_tests

Change-Id: I66cd3c70bb331de60e192f022d10f751153eefef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2288792
Commit-Queue: Pavol Marko <pmarko@chromium.org>
Reviewed-by: default avatarMichael Ershov <miersh@google.com>
Reviewed-by: default avatarDenis Kuznetsov [CET] <antrim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790234}
parent 440d8bdc
......@@ -2778,6 +2778,8 @@ static_library("test_support") {
"attestation/mock_enrollment_certificate_uploader.h",
"attestation/mock_machine_certificate_uploader.cc",
"attestation/mock_machine_certificate_uploader.h",
"cert_provisioning/mock_cert_provisioning_scheduler.cc",
"cert_provisioning/mock_cert_provisioning_scheduler.h",
"certificate_provider/test_certificate_provider_extension.cc",
"certificate_provider/test_certificate_provider_extension.h",
"crostini/ansible/ansible_management_test_helper.cc",
......
......@@ -99,7 +99,7 @@ NetworkStateHandler* GetNetworkStateHandler() {
// static
std::unique_ptr<CertProvisioningScheduler>
CertProvisioningScheduler::CreateUserCertProvisioningScheduler(
CertProvisioningSchedulerImpl::CreateUserCertProvisioningScheduler(
Profile* profile) {
PrefService* pref_service = profile->GetPrefs();
policy::CloudPolicyClient* cloud_policy_client =
......@@ -114,7 +114,7 @@ CertProvisioningScheduler::CreateUserCertProvisioningScheduler(
return nullptr;
}
return std::make_unique<CertProvisioningScheduler>(
return std::make_unique<CertProvisioningSchedulerImpl>(
CertScope::kUser, profile, pref_service, cloud_policy_client,
platform_keys_service, network_state_handler,
std::make_unique<CertProvisioningUserInvalidatorFactory>(profile));
......@@ -122,7 +122,7 @@ CertProvisioningScheduler::CreateUserCertProvisioningScheduler(
// static
std::unique_ptr<CertProvisioningScheduler>
CertProvisioningScheduler::CreateDeviceCertProvisioningScheduler(
CertProvisioningSchedulerImpl::CreateDeviceCertProvisioningScheduler(
policy::AffiliatedInvalidationServiceProvider*
invalidation_service_provider) {
Profile* profile = ProfileHelper::GetSigninProfile();
......@@ -139,14 +139,14 @@ CertProvisioningScheduler::CreateDeviceCertProvisioningScheduler(
return nullptr;
}
return std::make_unique<CertProvisioningScheduler>(
return std::make_unique<CertProvisioningSchedulerImpl>(
CertScope::kDevice, profile, pref_service, cloud_policy_client,
platform_keys_service, network_state_handler,
std::make_unique<CertProvisioningDeviceInvalidatorFactory>(
invalidation_service_provider));
}
CertProvisioningScheduler::CertProvisioningScheduler(
CertProvisioningSchedulerImpl::CertProvisioningSchedulerImpl(
CertScope cert_scope,
Profile* profile,
PrefService* pref_service,
......@@ -179,42 +179,44 @@ CertProvisioningScheduler::CertProvisioningScheduler(
ScheduleDailyUpdate();
}
CertProvisioningScheduler::~CertProvisioningScheduler() {
CertProvisioningSchedulerImpl::~CertProvisioningSchedulerImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
network_state_handler_->RemoveObserver(this, FROM_HERE);
}
void CertProvisioningScheduler::ScheduleInitialUpdate() {
void CertProvisioningSchedulerImpl::ScheduleInitialUpdate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&CertProvisioningScheduler::InitialUpdateCerts,
FROM_HERE, base::Bind(&CertProvisioningSchedulerImpl::InitialUpdateCerts,
weak_factory_.GetWeakPtr()));
}
void CertProvisioningScheduler::ScheduleDailyUpdate() {
void CertProvisioningSchedulerImpl::ScheduleDailyUpdate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&CertProvisioningScheduler::DailyUpdateCerts,
base::Bind(&CertProvisioningSchedulerImpl::DailyUpdateCerts,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromDays(1));
}
void CertProvisioningScheduler::ScheduleRetry(const CertProfileId& profile_id) {
void CertProvisioningSchedulerImpl::ScheduleRetry(
const CertProfileId& profile_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&CertProvisioningScheduler::UpdateOneCertImpl,
base::Bind(&CertProvisioningSchedulerImpl::UpdateOneCertImpl,
weak_factory_.GetWeakPtr(), profile_id),
kInconsistentDataErrorRetryDelay);
}
void CertProvisioningScheduler::ScheduleRenewal(const CertProfileId& profile_id,
base::TimeDelta delay) {
void CertProvisioningSchedulerImpl::ScheduleRenewal(
const CertProfileId& profile_id,
base::TimeDelta delay) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (base::Contains(scheduled_renewals_, profile_id)) {
......@@ -223,18 +225,18 @@ void CertProvisioningScheduler::ScheduleRenewal(const CertProfileId& profile_id,
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&CertProvisioningScheduler::InitiateRenewal,
base::Bind(&CertProvisioningSchedulerImpl::InitiateRenewal,
weak_factory_.GetWeakPtr(), profile_id),
delay);
}
void CertProvisioningScheduler::InitialUpdateCerts() {
void CertProvisioningSchedulerImpl::InitialUpdateCerts() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DeleteCertsWithoutPolicy();
}
void CertProvisioningScheduler::DeleteCertsWithoutPolicy() {
void CertProvisioningSchedulerImpl::DeleteCertsWithoutPolicy() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::flat_set<CertProfileId> cert_profile_ids_to_keep;
......@@ -249,11 +251,12 @@ void CertProvisioningScheduler::DeleteCertsWithoutPolicy() {
cert_deleter_.DeleteCerts(
cert_profile_ids_to_keep,
base::BindOnce(&CertProvisioningScheduler::OnDeleteCertsWithoutPolicyDone,
weak_factory_.GetWeakPtr()));
base::BindOnce(
&CertProvisioningSchedulerImpl::OnDeleteCertsWithoutPolicyDone,
weak_factory_.GetWeakPtr()));
}
void CertProvisioningScheduler::OnDeleteCertsWithoutPolicyDone(
void CertProvisioningSchedulerImpl::OnDeleteCertsWithoutPolicyDone(
const std::string& error_message) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -266,7 +269,7 @@ void CertProvisioningScheduler::OnDeleteCertsWithoutPolicyDone(
CleanVaKeysIfIdle();
}
void CertProvisioningScheduler::CleanVaKeysIfIdle() {
void CertProvisioningSchedulerImpl::CleanVaKeysIfIdle() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!workers_.empty()) {
......@@ -276,11 +279,11 @@ void CertProvisioningScheduler::CleanVaKeysIfIdle() {
DeleteVaKeysByPrefix(
cert_scope_, profile_, kKeyNamePrefix,
base::BindOnce(&CertProvisioningScheduler::OnCleanVaKeysIfIdleDone,
base::BindOnce(&CertProvisioningSchedulerImpl::OnCleanVaKeysIfIdleDone,
weak_factory_.GetWeakPtr()));
}
void CertProvisioningScheduler::OnCleanVaKeysIfIdleDone(
void CertProvisioningSchedulerImpl::OnCleanVaKeysIfIdleDone(
base::Optional<bool> delete_result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -292,16 +295,17 @@ void CertProvisioningScheduler::OnCleanVaKeysIfIdleDone(
UpdateAllCerts();
}
void CertProvisioningScheduler::RegisterForPrefsChanges() {
void CertProvisioningSchedulerImpl::RegisterForPrefsChanges() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(
pref_name_, base::BindRepeating(&CertProvisioningScheduler::OnPrefsChange,
weak_factory_.GetWeakPtr()));
pref_name_,
base::BindRepeating(&CertProvisioningSchedulerImpl::OnPrefsChange,
weak_factory_.GetWeakPtr()));
}
void CertProvisioningScheduler::DailyUpdateCerts() {
void CertProvisioningSchedulerImpl::DailyUpdateCerts() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
failed_cert_profiles_.clear();
......@@ -309,7 +313,7 @@ void CertProvisioningScheduler::DailyUpdateCerts() {
ScheduleDailyUpdate();
}
void CertProvisioningScheduler::DeserializeWorkers() {
void CertProvisioningSchedulerImpl::DeserializeWorkers() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const base::Value* saved_workers =
......@@ -325,7 +329,7 @@ void CertProvisioningScheduler::DeserializeWorkers() {
CertProvisioningWorkerFactory::Get()->Deserialize(
cert_scope_, profile_, pref_service_, saved_worker,
cloud_policy_client_, invalidator_factory_->Create(),
base::BindOnce(&CertProvisioningScheduler::OnProfileFinished,
base::BindOnce(&CertProvisioningSchedulerImpl::OnProfileFinished,
weak_factory_.GetWeakPtr()));
if (!worker) {
// Deserialization error message was already logged.
......@@ -336,19 +340,19 @@ void CertProvisioningScheduler::DeserializeWorkers() {
}
}
void CertProvisioningScheduler::OnPrefsChange() {
void CertProvisioningSchedulerImpl::OnPrefsChange() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
UpdateAllCerts();
}
void CertProvisioningScheduler::InitiateRenewal(
void CertProvisioningSchedulerImpl::InitiateRenewal(
const CertProfileId& cert_profile_id) {
scheduled_renewals_.erase(cert_profile_id);
UpdateOneCertImpl(cert_profile_id);
}
void CertProvisioningScheduler::UpdateOneCert(
void CertProvisioningSchedulerImpl::UpdateOneCert(
const CertProfileId& cert_profile_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -356,7 +360,7 @@ void CertProvisioningScheduler::UpdateOneCert(
UpdateOneCertImpl(cert_profile_id);
}
void CertProvisioningScheduler::UpdateOneCertImpl(
void CertProvisioningSchedulerImpl::UpdateOneCertImpl(
const CertProfileId& cert_profile_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -370,7 +374,7 @@ void CertProvisioningScheduler::UpdateOneCertImpl(
UpdateCertList({std::move(cert_profile).value()});
}
void CertProvisioningScheduler::UpdateAllCerts() {
void CertProvisioningSchedulerImpl::UpdateAllCerts() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::vector<CertProfile> profiles = GetCertProfiles();
......@@ -383,7 +387,7 @@ void CertProvisioningScheduler::UpdateAllCerts() {
UpdateCertList(std::move(profiles));
}
void CertProvisioningScheduler::UpdateCertList(
void CertProvisioningSchedulerImpl::UpdateCertList(
std::vector<CertProfile> profiles) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -398,11 +402,11 @@ void CertProvisioningScheduler::UpdateCertList(
}
certs_with_ids_getter_.GetCertsWithIds(base::BindOnce(
&CertProvisioningScheduler::UpdateCertListWithExistingCerts,
&CertProvisioningSchedulerImpl::UpdateCertListWithExistingCerts,
weak_factory_.GetWeakPtr(), std::move(profiles)));
}
void CertProvisioningScheduler::UpdateCertListWithExistingCerts(
void CertProvisioningSchedulerImpl::UpdateCertListWithExistingCerts(
std::vector<CertProfile> profiles,
base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
existing_certs_with_ids,
......@@ -450,7 +454,7 @@ void CertProvisioningScheduler::UpdateCertListWithExistingCerts(
}
}
void CertProvisioningScheduler::ProcessProfile(
void CertProvisioningSchedulerImpl::ProcessProfile(
const CertProfile& cert_profile) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -478,7 +482,7 @@ void CertProvisioningScheduler::ProcessProfile(
return;
}
void CertProvisioningScheduler::CreateCertProvisioningWorker(
void CertProvisioningSchedulerImpl::CreateCertProvisioningWorker(
CertProfile cert_profile) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -486,14 +490,14 @@ void CertProvisioningScheduler::CreateCertProvisioningWorker(
CertProvisioningWorkerFactory::Get()->Create(
cert_scope_, profile_, pref_service_, cert_profile,
cloud_policy_client_, invalidator_factory_->Create(),
base::BindOnce(&CertProvisioningScheduler::OnProfileFinished,
base::BindOnce(&CertProvisioningSchedulerImpl::OnProfileFinished,
weak_factory_.GetWeakPtr()));
CertProvisioningWorker* worker_unowned = worker.get();
workers_[cert_profile.profile_id] = std::move(worker);
worker_unowned->DoStep();
}
void CertProvisioningScheduler::OnProfileFinished(
void CertProvisioningSchedulerImpl::OnProfileFinished(
const CertProfile& profile,
CertProvisioningWorkerState state) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -527,7 +531,7 @@ void CertProvisioningScheduler::OnProfileFinished(
workers_.erase(worker_iter);
}
CertProvisioningWorker* CertProvisioningScheduler::FindWorker(
CertProvisioningWorker* CertProvisioningSchedulerImpl::FindWorker(
CertProfileId profile_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -539,7 +543,7 @@ CertProvisioningWorker* CertProvisioningScheduler::FindWorker(
return iter->second.get();
}
base::Optional<CertProfile> CertProvisioningScheduler::GetOneCertProfile(
base::Optional<CertProfile> CertProvisioningSchedulerImpl::GetOneCertProfile(
const CertProfileId& cert_profile_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -561,7 +565,7 @@ base::Optional<CertProfile> CertProvisioningScheduler::GetOneCertProfile(
return base::nullopt;
}
std::vector<CertProfile> CertProvisioningScheduler::GetCertProfiles() {
std::vector<CertProfile> CertProvisioningSchedulerImpl::GetCertProfiles() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const base::Value* profile_list = pref_service_->Get(pref_name_);
......@@ -584,20 +588,20 @@ std::vector<CertProfile> CertProvisioningScheduler::GetCertProfiles() {
return result_profiles;
}
const WorkerMap& CertProvisioningScheduler::GetWorkers() const {
const WorkerMap& CertProvisioningSchedulerImpl::GetWorkers() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return workers_;
}
const base::flat_map<CertProfileId, FailedWorkerInfo>&
CertProvisioningScheduler::GetFailedCertProfileIds() const {
CertProvisioningSchedulerImpl::GetFailedCertProfileIds() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return failed_cert_profiles_;
}
bool CertProvisioningScheduler::MaybeWaitForInternetConnection() {
bool CertProvisioningSchedulerImpl::MaybeWaitForInternetConnection() {
const NetworkState* network = network_state_handler_->DefaultNetwork();
bool is_online = network && network->IsOnline();
......@@ -610,7 +614,7 @@ bool CertProvisioningScheduler::MaybeWaitForInternetConnection() {
return false;
}
void CertProvisioningScheduler::WaitForInternetConnection() {
void CertProvisioningSchedulerImpl::WaitForInternetConnection() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (is_waiting_for_online_) {
......@@ -628,7 +632,7 @@ void CertProvisioningScheduler::WaitForInternetConnection() {
}
}
void CertProvisioningScheduler::OnNetworkChange(
void CertProvisioningSchedulerImpl::OnNetworkChange(
const chromeos::NetworkState* network) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -647,21 +651,21 @@ void CertProvisioningScheduler::OnNetworkChange(
}
}
void CertProvisioningScheduler::DefaultNetworkChanged(
void CertProvisioningSchedulerImpl::DefaultNetworkChanged(
const chromeos::NetworkState* network) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
OnNetworkChange(network);
}
void CertProvisioningScheduler::NetworkConnectionStateChanged(
void CertProvisioningSchedulerImpl::NetworkConnectionStateChanged(
const chromeos::NetworkState* network) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
OnNetworkChange(network);
}
void CertProvisioningScheduler::UpdateFailedCertProfiles(
void CertProvisioningSchedulerImpl::UpdateFailedCertProfiles(
const CertProvisioningWorker& worker) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......@@ -673,7 +677,7 @@ void CertProvisioningScheduler::UpdateFailedCertProfiles(
failed_cert_profiles_[worker.GetCertProfile().profile_id] = std::move(info);
}
void CertProvisioningScheduler::CancelWorkersWithoutPolicy(
void CertProvisioningSchedulerImpl::CancelWorkersWithoutPolicy(
const std::vector<CertProfile>& profiles) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
......
......@@ -56,13 +56,34 @@ struct FailedWorkerInfo {
base::Time last_update_time;
};
// Interface for the scheduler for client certificate provisioning using device
// management.
class CertProvisioningScheduler {
public:
virtual ~CertProvisioningScheduler() = default;
// Intended to be called when a user presses a button in certificate manager
// UI. Retries provisioning of a specific certificate.
virtual void UpdateOneCert(const CertProfileId& cert_profile_id) = 0;
virtual void UpdateAllCerts() = 0;
// Returns all certificate provisioning workers that are currently active.
virtual const WorkerMap& GetWorkers() const = 0;
// Returns a |FailedWorkerInfo| for certificate provisioning processes that
// failed and have not been restarted (yet).
virtual const base::flat_map<CertProfileId, FailedWorkerInfo>&
GetFailedCertProfileIds() const = 0;
};
// This class is a part of certificate provisioning feature. It tracks updates
// of |RequiredClientCertificateForUser|, |RequiredClientCertificateForDevice|
// policies and creates one CertProvisioningWorker for every policy entry.
// Should work on the UI thread because it interacts with PlatformKeysService
// and some methods are called from the UI to populate certificate manager
// settings page.
class CertProvisioningScheduler : public NetworkStateHandlerObserver {
class CertProvisioningSchedulerImpl : public CertProvisioningScheduler,
public NetworkStateHandlerObserver {
public:
static std::unique_ptr<CertProvisioningScheduler>
CreateUserCertProvisioningScheduler(Profile* profile);
......@@ -71,7 +92,7 @@ class CertProvisioningScheduler : public NetworkStateHandlerObserver {
policy::AffiliatedInvalidationServiceProvider*
invalidation_service_provider);
CertProvisioningScheduler(
CertProvisioningSchedulerImpl(
CertScope cert_scope,
Profile* profile,
PrefService* pref_service,
......@@ -79,22 +100,21 @@ class CertProvisioningScheduler : public NetworkStateHandlerObserver {
platform_keys::PlatformKeysService* platform_keys_service,
NetworkStateHandler* network_state_handler,
std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory);
~CertProvisioningScheduler() override;
~CertProvisioningSchedulerImpl() override;
CertProvisioningScheduler(const CertProvisioningScheduler&) = delete;
CertProvisioningScheduler& operator=(const CertProvisioningScheduler&) =
delete;
// Intended to be called when a user presses a button in certificate manager
// UI. Retries provisioning of a specific certificate.
void UpdateOneCert(const CertProfileId& cert_profile_id);
void UpdateAllCerts();
void OnProfileFinished(const CertProfile& profile,
CertProvisioningWorkerState state);
const WorkerMap& GetWorkers() const;
CertProvisioningSchedulerImpl(const CertProvisioningSchedulerImpl&) = delete;
CertProvisioningSchedulerImpl& operator=(
const CertProvisioningSchedulerImpl&) = delete;
// CertProvisioningScheduler:
void UpdateOneCert(const CertProfileId& cert_profile_id) override;
void UpdateAllCerts() override;
const WorkerMap& GetWorkers() const override;
const base::flat_map<CertProfileId, FailedWorkerInfo>&
GetFailedCertProfileIds() const;
GetFailedCertProfileIds() const override;
void OnProfileFinished(const CertProfile& profile,
CertProvisioningWorkerState state);
private:
void ScheduleInitialUpdate();
......@@ -177,7 +197,7 @@ class CertProvisioningScheduler : public NetworkStateHandlerObserver {
CertDeleter cert_deleter_;
std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory_;
base::WeakPtrFactory<CertProvisioningScheduler> weak_factory_{this};
base::WeakPtrFactory<CertProvisioningSchedulerImpl> weak_factory_{this};
};
} // namespace cert_provisioning
......
......@@ -135,13 +135,13 @@ TEST_F(CertProvisioningSchedulerTest, Success) {
MockCertProvisioningInvalidatorFactory* mock_invalidation_factory =
mock_invalidation_factory_obj.get();
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
std::move(mock_invalidation_factory_obj));
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_USER, kKeyNamePrefix))
......@@ -196,13 +196,13 @@ TEST_F(CertProvisioningSchedulerTest, Success) {
TEST_F(CertProvisioningSchedulerTest, WorkerFailed) {
const CertScope kCertScope = CertScope::kDevice;
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
......@@ -264,13 +264,13 @@ TEST_F(CertProvisioningSchedulerTest, InitialAndDailyUpdates) {
"key_algorithm":"rsa"}])");
pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_USER, kKeyNamePrefix))
......@@ -316,13 +316,13 @@ TEST_F(CertProvisioningSchedulerTest, InitialAndDailyUpdates) {
TEST_F(CertProvisioningSchedulerTest, MultipleWorkers) {
const CertScope kCertScope = CertScope::kDevice;
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
......@@ -420,7 +420,7 @@ TEST_F(CertProvisioningSchedulerTest, RemoveCertWithoutPolicy) {
certificate_helper_->AddCert(kCertScope, kCertProfileId);
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
......@@ -474,7 +474,7 @@ TEST_F(CertProvisioningSchedulerTest, DeserializeWorkers) {
worker->SetExpectations(/*do_step_times=*/AtLeast(1),
/*is_waiting=*/true, cert_profile);
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
......@@ -491,13 +491,13 @@ TEST_F(CertProvisioningSchedulerTest, InconsistentDataErrorHandling) {
const char kCertProfileVersion1[] = "cert_profile_version_1";
const char kCertProfileVersion2[] = "cert_profile_version_2";
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
......@@ -614,13 +614,13 @@ TEST_F(CertProvisioningSchedulerTest, RetryAfterNoInternetConnection) {
"key_algorithm":"rsa"}])");
pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
......@@ -653,13 +653,13 @@ TEST_F(CertProvisioningSchedulerTest, DeleteWorkerWithoutPolicy) {
"policy_version":"cert_profile_version_1",
"key_algorithm":"rsa"}])");
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
......@@ -696,13 +696,13 @@ TEST_F(CertProvisioningSchedulerTest, DeleteVaKeysOnIdle) {
const CertScope kCertScope = CertScope::kDevice;
{
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
MakeFakeInvalidationFactory());
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(
fake_cryptohome_client_,
OnTpmAttestationDeleteKeysByPrefix(
......@@ -742,7 +742,7 @@ TEST_F(CertProvisioningSchedulerTest, DeleteVaKeysOnIdle) {
worker->SetExpectations(/*do_step_times=*/Exactly(0),
/*is_waiting=*/true, cert_profile);
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
......@@ -758,7 +758,7 @@ TEST_F(CertProvisioningSchedulerTest, DeleteVaKeysOnIdle) {
TEST_F(CertProvisioningSchedulerTest, UpdateOneCert) {
const CertScope kCertScope = CertScope::kUser;
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
......@@ -767,7 +767,7 @@ TEST_F(CertProvisioningSchedulerTest, UpdateOneCert) {
CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
/*is_va_enabled=*/true, kCertProfileRenewalPeriod);
// From CertProvisioningScheduler::CleanVaKeysIfIdle.
// From CertProvisioningSchedulerImpl::CleanVaKeysIfIdle.
EXPECT_CALL(fake_cryptohome_client_, OnTpmAttestationDeleteKeysByPrefix);
FastForwardBy(TimeDelta::FromSeconds(1));
......@@ -868,7 +868,7 @@ TEST_F(CertProvisioningSchedulerTest, CertRenewal) {
"renewal_period_seconds": 86400}])");
pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
CertProvisioningScheduler scheduler(
CertProvisioningSchedulerImpl scheduler(
kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
&platform_keys_service_,
network_state_test_helper_.network_state_handler(),
......
......@@ -18,8 +18,9 @@ namespace cert_provisioning {
CertProvisioningSchedulerUserService::CertProvisioningSchedulerUserService(
Profile* profile)
: scheduler_(CertProvisioningScheduler::CreateUserCertProvisioningScheduler(
profile)) {}
: scheduler_(
CertProvisioningSchedulerImpl::CreateUserCertProvisioningScheduler(
profile)) {}
CertProvisioningSchedulerUserService::~CertProvisioningSchedulerUserService() =
default;
......
......@@ -125,13 +125,16 @@ const char kTestUserGaiaId[] = "test_gaia_id";
} // namespace
ProfileHelperForTesting::ProfileHelperForTesting()
: ProfileHelperForTesting(/*user_is_affiilated=*/false) {}
ProfileHelperForTesting::ProfileHelperForTesting(bool user_is_affiliated)
: testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
Init();
Init(user_is_affiliated);
}
ProfileHelperForTesting::~ProfileHelperForTesting() = default;
void ProfileHelperForTesting::Init() {
void ProfileHelperForTesting::Init(bool user_is_affiliated) {
ASSERT_TRUE(testing_profile_manager_.SetUp());
testing_profile_ =
......@@ -140,7 +143,8 @@ void ProfileHelperForTesting::Init() {
auto test_account =
AccountId::FromUserEmailGaiaId(kTestUserEmail, kTestUserGaiaId);
fake_user_manager_.AddUser(test_account);
user_ = fake_user_manager_.AddUserWithAffiliation(test_account,
user_is_affiliated);
ProfileHelper::Get()->SetUserToProfileMappingForTesting(
fake_user_manager_.GetPrimaryUser(), testing_profile_);
......@@ -150,6 +154,10 @@ Profile* ProfileHelperForTesting::GetProfile() const {
return testing_profile_;
}
user_manager::User* ProfileHelperForTesting::GetUser() const {
return user_;
}
//================ SpyingFakeCryptohomeClient ==================================
SpyingFakeCryptohomeClient::SpyingFakeCryptohomeClient() = default;
......
......@@ -14,6 +14,10 @@
#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace user_manager {
class User;
}
namespace chromeos {
namespace cert_provisioning {
......@@ -70,19 +74,23 @@ struct CertificateHelperForTesting {
class ProfileHelperForTesting {
public:
// Equivalent to ProfileHelperForTesting(/*user_is_affiliated=*/false)
ProfileHelperForTesting();
explicit ProfileHelperForTesting(bool user_is_affiliated);
ProfileHelperForTesting(const ProfileHelperForTesting&) = delete;
ProfileHelperForTesting& operator=(const ProfileHelperForTesting&) = delete;
~ProfileHelperForTesting();
Profile* GetProfile() const;
user_manager::User* GetUser() const;
private:
void Init();
void Init(bool user_is_affiliated);
TestingProfileManager testing_profile_manager_;
FakeChromeUserManager fake_user_manager_;
TestingProfile* testing_profile_ = nullptr;
user_manager::User* user_ = nullptr;
};
//================ SpyingFakeCryptohomeClient ==================================
......
// Copyright 2020 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/cert_provisioning/mock_cert_provisioning_scheduler.h"
namespace chromeos {
namespace cert_provisioning {
MockCertProvisioningScheduler::MockCertProvisioningScheduler() = default;
MockCertProvisioningScheduler::~MockCertProvisioningScheduler() = default;
} // namespace cert_provisioning
} // namespace chromeos
// Copyright 2020 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.
#ifndef CHROME_BROWSER_CHROMEOS_CERT_PROVISIONING_MOCK_CERT_PROVISIONING_SCHEDULER_H_
#define CHROME_BROWSER_CHROMEOS_CERT_PROVISIONING_MOCK_CERT_PROVISIONING_SCHEDULER_H_
#include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace chromeos {
namespace cert_provisioning {
class MockCertProvisioningScheduler : public CertProvisioningScheduler {
public:
MockCertProvisioningScheduler();
MockCertProvisioningScheduler(const MockCertProvisioningScheduler&) = delete;
MockCertProvisioningScheduler& operator=(
const MockCertProvisioningScheduler&) = delete;
~MockCertProvisioningScheduler() override;
MOCK_METHOD(void,
UpdateOneCert,
(const CertProfileId& cert_profile_id),
(override));
MOCK_METHOD(void, UpdateAllCerts, (), (override));
MOCK_METHOD(const WorkerMap&, GetWorkers, (), (const override));
MOCK_METHOD((const base::flat_map<CertProfileId, FailedWorkerInfo>&),
GetFailedCertProfileIds,
(),
(const override));
};
} // namespace cert_provisioning
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CERT_PROVISIONING_MOCK_CERT_PROVISIONING_SCHEDULER_H_
......@@ -466,7 +466,7 @@ void BrowserPolicyConnectorChromeOS::OnDeviceCloudPolicyManagerConnected() {
// CertProvisioningScheduler does not depend on SignIn Profile.
if (!device_cert_provisioning_scheduler_) {
device_cert_provisioning_scheduler_ = chromeos::cert_provisioning::
CertProvisioningScheduler::CreateDeviceCertProvisioningScheduler(
CertProvisioningSchedulerImpl::CreateDeviceCertProvisioningScheduler(
affiliated_invalidation_service_provider_.get());
}
}
......
......@@ -32,12 +32,29 @@ namespace cert_provisioning {
namespace {
// Returns the per-user CertProvisioningScheduler for |user_profile|, if it has
// any.
CertProvisioningScheduler* GetCertProvisioningSchedulerForUser(
Profile* user_profile) {
CertProvisioningSchedulerUserService* user_service =
CertProvisioningSchedulerUserServiceFactory::GetForProfile(user_profile);
if (!user_service)
return nullptr;
return user_service->scheduler();
}
// Returns the per-device CertProvisioningScheduler, if it exists. No
// affiliation check is done here.
CertProvisioningScheduler* GetCertProvisioningSchedulerForDevice() {
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
return connector->GetDeviceCertProvisioningScheduler();
}
// Returns localized representation for the state of a certificate provisioning
// process.
base::string16 GetProvisioningProcessStatus(
chromeos::cert_provisioning::CertProvisioningWorkerState state) {
using CertProvisioningWorkerState =
chromeos::cert_provisioning::CertProvisioningWorkerState;
base::string16 GetProvisioningProcessStatus(CertProvisioningWorkerState state) {
using CertProvisioningWorkerState = CertProvisioningWorkerState;
switch (state) {
case CertProvisioningWorkerState ::kInitState:
return l10n_util::GetStringUTF16(
......@@ -90,7 +107,7 @@ base::string16 GetTimeSinceLastUpdate(base::Time last_update_time) {
base::Value CreateProvisioningProcessEntry(
const std::string& cert_profile_id,
bool is_device_wide,
chromeos::cert_provisioning::CertProvisioningWorkerState state,
CertProvisioningWorkerState state,
base::Time time_since_last_update,
const std::string& public_key_spki_der) {
base::Value entry(base::Value::Type::DICTIONARY);
......@@ -123,8 +140,7 @@ void CollectProvisioningProcesses(
}
for (const auto& failed_worker_entry :
cert_provisioning_scheduler->GetFailedCertProfileIds()) {
const chromeos::cert_provisioning::FailedWorkerInfo& worker =
failed_worker_entry.second;
const FailedWorkerInfo& worker = failed_worker_entry.second;
list_to_append_to->Append(CreateProvisioningProcessEntry(
failed_worker_entry.first, is_device_wide,
CertProvisioningWorkerState::kFailed, worker.last_update_time,
......@@ -134,7 +150,23 @@ void CollectProvisioningProcesses(
} // namespace
CertificateProvisioningUiHandler::CertificateProvisioningUiHandler() = default;
// static
std::unique_ptr<CertificateProvisioningUiHandler>
CertificateProvisioningUiHandler::CreateForProfile(Profile* user_profile) {
return std::make_unique<CertificateProvisioningUiHandler>(
user_profile, GetCertProvisioningSchedulerForUser(user_profile),
GetCertProvisioningSchedulerForDevice());
}
CertificateProvisioningUiHandler::CertificateProvisioningUiHandler(
Profile* user_profile,
CertProvisioningScheduler* scheduler_for_user,
CertProvisioningScheduler* scheduler_for_device)
: scheduler_for_user_(scheduler_for_user),
scheduler_for_device_(ShouldUseDeviceWideProcesses(user_profile)
? scheduler_for_device
: nullptr) {}
CertificateProvisioningUiHandler::~CertificateProvisioningUiHandler() = default;
void CertificateProvisioningUiHandler::RegisterMessages() {
......@@ -153,31 +185,6 @@ void CertificateProvisioningUiHandler::RegisterMessages() {
base::Unretained(this)));
}
CertProvisioningScheduler*
CertificateProvisioningUiHandler::GetCertProvisioningSchedulerForUser(
Profile* user_profile) {
chromeos::cert_provisioning::CertProvisioningSchedulerUserService*
user_service = chromeos::cert_provisioning::
CertProvisioningSchedulerUserServiceFactory::GetForProfile(
user_profile);
if (!user_service)
return nullptr;
return user_service->scheduler();
}
CertProvisioningScheduler*
CertificateProvisioningUiHandler::GetCertProvisioningSchedulerForDevice(
Profile* user_profile) {
const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile(user_profile);
if (!user || !user->IsAffiliated())
return nullptr;
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
return connector->GetDeviceCertProvisioningScheduler();
}
void CertificateProvisioningUiHandler::
HandleRefreshCertificateProvisioningProcesses(const base::ListValue* args) {
CHECK_EQ(0U, args->GetSize());
......@@ -198,10 +205,11 @@ void CertificateProvisioningUiHandler::
if (!device_wide.is_bool())
return;
Profile* profile = Profile::FromWebUI(web_ui());
if (device_wide.GetBool() && !scheduler_for_device_)
return;
CertProvisioningScheduler* scheduler =
device_wide.GetBool() ? GetCertProvisioningSchedulerForDevice(profile)
: GetCertProvisioningSchedulerForUser(profile);
device_wide.GetBool() ? scheduler_for_device_ : scheduler_for_user_;
if (!scheduler)
return;
......@@ -225,24 +233,28 @@ void CertificateProvisioningUiHandler::
void CertificateProvisioningUiHandler::
RefreshCertificateProvisioningProcesses() {
Profile* profile = Profile::FromWebUI(web_ui());
base::ListValue all_processes;
CertProvisioningScheduler* scheduler_for_user =
GetCertProvisioningSchedulerForUser(profile);
if (scheduler_for_user)
CollectProvisioningProcesses(&all_processes, scheduler_for_user,
if (scheduler_for_user_) {
CollectProvisioningProcesses(&all_processes, scheduler_for_user_,
/*is_device_wide=*/false);
}
CertProvisioningScheduler* scheduler_for_device =
GetCertProvisioningSchedulerForDevice(profile);
if (scheduler_for_device)
CollectProvisioningProcesses(&all_processes, scheduler_for_device,
if (scheduler_for_device_) {
CollectProvisioningProcesses(&all_processes, scheduler_for_device_,
/*is_device_wide=*/true);
}
FireWebUIListener("certificate-provisioning-processes-changed",
std::move(all_processes));
}
// static
bool CertificateProvisioningUiHandler::ShouldUseDeviceWideProcesses(
Profile* user_profile) {
const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile(user_profile);
return user && user->IsAffiliated();
}
} // namespace cert_provisioning
} // namespace chromeos
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_UI_WEBUI_CERTIFICATE_PROVISIONING_UI_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_CERTIFICATE_PROVISIONING_UI_HANDLER_H_
#include <utility>
#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "content/public/browser/web_ui_message_handler.h"
......@@ -18,7 +20,26 @@ class CertProvisioningScheduler;
class CertificateProvisioningUiHandler : public content::WebUIMessageHandler {
public:
CertificateProvisioningUiHandler();
// Creates a CertificateProvisioningUiHandler for |user_profile|, which uses:
// (*) The CertProvisioningScheduler associated with |user_profile|, if any.
// (*) The device-wide CertProvisioningScheduler, if it exists and the
// |user_profile| is affiliated.
static std::unique_ptr<CertificateProvisioningUiHandler> CreateForProfile(
Profile* user_profile);
// The constructed CertificateProvisioningUiHandler will use
// |scheduler_for_user| to list certificate provisioning processes that belong
// to the user, and |scheduler_for_device|, to list certificatge provisioning
// processes that are device-wide. Both can be nullptr. Note: Intended to be
// called directly for testing. Use CreateForProfile in production code
// instead.
// |user_profile| is used to determine if the current user is affiliated and
// decide if |scheduler_for_device| should be used based on that. This pattern
// is useful for unit-testing the affiliation detection logic.
CertificateProvisioningUiHandler(
Profile* user_profile,
CertProvisioningScheduler* scheduler_for_user,
CertProvisioningScheduler* scheduler_for_device);
CertificateProvisioningUiHandler(
const CertificateProvisioningUiHandler& other) = delete;
......@@ -31,16 +52,6 @@ class CertificateProvisioningUiHandler : public content::WebUIMessageHandler {
void RegisterMessages() override;
private:
// Returns the per-user CertProvisioningScheduler for |user_profile|, if it
// has any.
chromeos::cert_provisioning::CertProvisioningScheduler*
GetCertProvisioningSchedulerForUser(Profile* user_profile);
// Returns the per-device CertProvisioningScheduler, if |user_profile| is
// associated with a user that has access to device-wide client certificates.
chromeos::cert_provisioning::CertProvisioningScheduler*
GetCertProvisioningSchedulerForDevice(Profile* user_profile);
// Send the list of certificate provisioning processes to the UI, triggered by
// the UI when it loads.
// |args| is expected to be empty.
......@@ -59,6 +70,18 @@ class CertificateProvisioningUiHandler : public content::WebUIMessageHandler {
// Send the list of certificate provisioning processes to the UI.
void RefreshCertificateProvisioningProcesses();
// Returns true if device-wide certificate provisioning processes should be
// displayed, i.e. if the |user_profile| is affiliated.
static bool ShouldUseDeviceWideProcesses(Profile* user_profile);
// The user-specific CertProvisioningScheduler. Can be nullptr.
// Unowned.
CertProvisioningScheduler* const scheduler_for_user_;
// The device-wide CertProvisioningScheduler. Can be nullptr.
// Unowned.
CertProvisioningScheduler* const scheduler_for_device_;
base::WeakPtrFactory<CertificateProvisioningUiHandler> weak_ptr_factory_{
this};
};
......
// Copyright 2020 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/ui/webui/certificate_provisioning_ui_handler.h"
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include "base/base64.h"
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/values_test_util.h"
#include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h"
#include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.h"
#include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.h"
#include "chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_scheduler.h"
#include "chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_worker.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_web_ui.h"
#include "content/public/test/test_web_ui_listener_observer.h"
#include "crypto/nss_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
namespace chromeos {
namespace cert_provisioning {
namespace {
using ::testing::Return;
using ::testing::ReturnPointee;
using ::testing::ReturnRef;
using ::testing::UnorderedElementsAre;
// Extracted from a X.509 certificate using the command:
// openssl x509 -pubkey -noout -in cert.pem
// and reformatted as a single line.
// This represents a RSA public key.
constexpr char kDerEncodedSpkiBase64[] =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1na7r6WiaL5slsyHI7bEpP5ad9ffsz"
"T0mBi8yc03hJpxaA3/2/"
"PX7esUdTSGoZr1XVBxjjJc4AypzZKlsPqYKZ+lPHZPpXlp8JVHn8w8+"
"zmPKl319vVYdJv5AE0HOuJZ6a19fXxItgzoB+"
"oXgkA0mhyPygJwF3HMJfJHRrkxJ73c23R6kKvKTxqRKswvzTo5O5AzZFLdCe+"
"GVTJuPo4VToGd+ZhS7QvsY38nAYG57fMnzzs5jjMF042AzzWiMt9gGbeuqCE6LXqFuSJYPo+"
"TLaN7pwQx68PK5pd/lv58B7jjxCIAai0BX1rV6bl/Am3EukhTSuIcQiTr5c1G4E6bKwIDAQAB";
// Display-formatted version of |kDerEncodedSpkiBase64|.
constexpr char kFormattedPublicKey[] = R"(Modulus (2048 bits):
D6 76 BB AF A5 A2 68 BE 6C 96 CC 87 23 B6 C4 A4
FE 5A 77 D7 DF B3 34 F4 98 18 BC C9 CD 37 84 9A
71 68 0D FF DB F3 D7 ED EB 14 75 34 86 A1 9A F5
5D 50 71 8E 32 5C E0 0C A9 CD 92 A5 B0 FA 98 29
9F A5 3C 76 4F A5 79 69 F0 95 47 9F CC 3C FB 39
8F 2A 5D F5 F6 F5 58 74 9B F9 00 4D 07 3A E2 59
E9 AD 7D 7D 7C 48 B6 0C E8 07 EA 17 82 40 34 9A
1C 8F CA 02 70 17 71 CC 25 F2 47 46 B9 31 27 BD
DC DB 74 7A 90 AB CA 4F 1A 91 2A CC 2F CD 3A 39
3B 90 33 64 52 DD 09 EF 86 55 32 6E 3E 8E 15 4E
81 9D F9 98 52 ED 0B EC 63 7F 27 01 81 B9 ED F3
27 CF 3B 39 8E 33 05 D3 8D 80 CF 35 A2 32 DF 60
19 B7 AE A8 21 3A 2D 7A 85 B9 22 58 3E 8F 93 2D
A3 7B A7 04 31 EB C3 CA E6 97 7F 96 FE 7C 07 B8
E3 C4 22 00 6A 2D 01 5F 5A D5 E9 B9 7F 02 6D C4
BA 48 53 4A E2 1C 42 24 EB E5 CD 46 E0 4E 9B 2B
Public Exponent (24 bits):
01 00 01)";
void SetupMockCertProvisioningWorker(MockCertProvisioningWorker* worker,
CertProvisioningWorkerState state,
const std::string* public_key) {
EXPECT_CALL(*worker, GetState).WillRepeatedly(Return(state));
EXPECT_CALL(*worker, GetLastUpdateTime).WillRepeatedly(Return(base::Time()));
EXPECT_CALL(*worker, GetPublicKey).WillRepeatedly(ReturnPointee(public_key));
}
// Recursively visits all strings in |value| and replaces placeholders such as
// "$0" with the corresponding message from |messages|.
void FormatDictRecurse(base::Value* value,
const std::vector<std::string>& messages) {
if (value->is_dict()) {
for (const auto& child : value->DictItems())
FormatDictRecurse(&child.second, messages);
return;
}
if (value->is_list()) {
for (base::Value& child : value->GetList())
FormatDictRecurse(&child, messages);
return;
}
if (!value->is_string())
return;
for (size_t i = 0; i < messages.size(); ++i) {
std::string placeholder = std::string("$") + base::NumberToString(i);
if (value->GetString() != placeholder)
continue;
*value = base::Value(messages[i]);
}
}
// Parses |input| as JSON, replaces string fields that match the placeholder
// format "$0" with the corresponding translated message from |message_ids|.
base::Value FormatJsonDict(const base::StringPiece input,
std::vector<std::string> messages) {
base::Value parsed = base::test::ParseJson(input);
FormatDictRecurse(&parsed, messages);
return parsed;
}
// When |all_processes| is a list Value that contains the UI representation of
// certifiate provisioning processes, returns the one that has certProfileId
// |profile_id|.
base::Value GetByProfileId(const base::Value& all_processes,
const std::string& profile_id) {
for (const base::Value& process : all_processes.GetList()) {
if (profile_id == *process.FindStringKey("certProfileId"))
return process.Clone();
}
return base::Value();
}
class CertificateProvisioningUiHandlerTestBase : public ::testing::Test {
public:
explicit CertificateProvisioningUiHandlerTestBase(bool user_is_affiliated)
: profile_helper_for_testing_(user_is_affiliated) {
base::Base64Decode(kDerEncodedSpkiBase64, &der_encoded_spki_);
web_contents_ =
content::WebContents::Create(content::WebContents::CreateParams(
profile_helper_for_testing_.GetProfile()));
web_ui_.set_web_contents(web_contents_.get());
auto handler = std::make_unique<CertificateProvisioningUiHandler>(
GetProfile(), &scheduler_for_user_, &scheduler_for_device_);
handler_ = handler.get();
web_ui_.AddMessageHandler(std::move(handler));
EXPECT_CALL(scheduler_for_user_, GetWorkers)
.WillRepeatedly(ReturnRef(user_workers_));
EXPECT_CALL(scheduler_for_user_, GetFailedCertProfileIds)
.WillRepeatedly(ReturnRef(user_failed_workers_));
EXPECT_CALL(scheduler_for_device_, GetWorkers)
.WillRepeatedly(ReturnRef(device_workers_));
EXPECT_CALL(scheduler_for_device_, GetFailedCertProfileIds)
.WillRepeatedly(ReturnRef(device_failed_workers_));
}
~CertificateProvisioningUiHandlerTestBase() override {}
CertificateProvisioningUiHandlerTestBase(
const CertificateProvisioningUiHandlerTestBase& other) = delete;
CertificateProvisioningUiHandlerTestBase& operator=(
const CertificateProvisioningUiHandlerTestBase& other) = delete;
void SetUp() override {
// Required for public key (SubjectPublicKeyInfo) formatting that is being
// done in the UI handler.
crypto::EnsureNSSInit();
}
void RefreshCertProvisioningProcesses(
base::Value* out_all_processes,
std::vector<std::string>* out_profile_ids) {
content::TestWebUIListenerObserver result_waiter(
&web_ui_, "certificate-provisioning-processes-changed");
base::ListValue args;
web_ui_.HandleReceivedMessage("refreshCertificateProvisioningProcessses",
&args);
result_waiter.Wait();
ASSERT_EQ(1U, result_waiter.args().size());
ASSERT_TRUE(result_waiter.args()[0].is_list());
*out_all_processes = std::move(result_waiter.args()[0]);
// Extract all profile ids for easier verification.
if (!out_profile_ids)
return;
out_profile_ids->clear();
for (const base::Value& process : out_all_processes->GetList()) {
const std::string* profile_id = process.FindStringKey("certProfileId");
ASSERT_TRUE(profile_id);
out_profile_ids->push_back(*profile_id);
}
}
protected:
Profile* GetProfile() { return profile_helper_for_testing_.GetProfile(); }
std::string der_encoded_spki_;
content::BrowserTaskEnvironment task_environment_;
ProfileHelperForTesting profile_helper_for_testing_;
WorkerMap user_workers_;
base::flat_map<CertProfileId, FailedWorkerInfo> user_failed_workers_;
MockCertProvisioningScheduler scheduler_for_user_;
WorkerMap device_workers_;
base::flat_map<CertProfileId, FailedWorkerInfo> device_failed_workers_;
MockCertProvisioningScheduler scheduler_for_device_;
content::TestWebUI web_ui_;
std::unique_ptr<content::WebContents> web_contents_;
// Owned by |web_ui_|.
CertificateProvisioningUiHandler* handler_;
};
class CertificateProvisioningUiHandlerTest
: public CertificateProvisioningUiHandlerTestBase {
public:
CertificateProvisioningUiHandlerTest()
: CertificateProvisioningUiHandlerTestBase(/*user_is_affiilated=*/false) {
}
~CertificateProvisioningUiHandlerTest() override = default;
};
class CertificateProvisioningUiHandlerAffiliatedTest
: public CertificateProvisioningUiHandlerTestBase {
public:
CertificateProvisioningUiHandlerAffiliatedTest()
: CertificateProvisioningUiHandlerTestBase(/*user_is_affiilated=*/true) {}
~CertificateProvisioningUiHandlerAffiliatedTest() override = default;
};
TEST_F(CertificateProvisioningUiHandlerTest, NoProcesses) {
base::Value all_processes;
ASSERT_NO_FATAL_FAILURE(RefreshCertProvisioningProcesses(
&all_processes, /*out_profile_ids=*/nullptr));
EXPECT_TRUE(all_processes.GetList().empty());
}
TEST_F(CertificateProvisioningUiHandlerTest, HasProcesses) {
auto user_cert_worker = std::make_unique<MockCertProvisioningWorker>();
SetupMockCertProvisioningWorker(
user_cert_worker.get(), CertProvisioningWorkerState::kKeypairGenerated,
&der_encoded_spki_);
user_workers_["user_cert_profile_1"] = std::move(user_cert_worker);
auto device_cert_worker = std::make_unique<MockCertProvisioningWorker>();
SetupMockCertProvisioningWorker(
device_cert_worker.get(), CertProvisioningWorkerState::kKeypairGenerated,
&der_encoded_spki_);
device_workers_["device_cert_profile_1"] = std::move(device_cert_worker);
// Only the user worker is expected to be displayed in the UI, because the
// user is not affiliated.
base::Value all_processes;
std::vector<std::string> profile_ids;
ASSERT_NO_FATAL_FAILURE(
RefreshCertProvisioningProcesses(&all_processes, &profile_ids));
ASSERT_THAT(profile_ids, UnorderedElementsAre("user_cert_profile_1"));
EXPECT_EQ(
GetByProfileId(all_processes, "user_cert_profile_1"),
FormatJsonDict(
R"({
"certProfileId": "user_cert_profile_1",
"isDeviceWide": false,
"publicKey": "$1",
"stateId": 1,
"status": "$0",
"timeSinceLastUpdate": ""
})",
{l10n_util::GetStringUTF8(
IDS_SETTINGS_CERTIFICATE_MANAGER_PROVISIONING_STATUS_PREPARING_CSR_WAITING),
kFormattedPublicKey}));
}
TEST_F(CertificateProvisioningUiHandlerAffiliatedTest, HasProcessesAffiliated) {
auto user_cert_worker = std::make_unique<MockCertProvisioningWorker>();
SetupMockCertProvisioningWorker(
user_cert_worker.get(), CertProvisioningWorkerState::kKeypairGenerated,
&der_encoded_spki_);
user_workers_["user_cert_profile_1"] = std::move(user_cert_worker);
auto device_cert_worker = std::make_unique<MockCertProvisioningWorker>();
SetupMockCertProvisioningWorker(device_cert_worker.get(),
CertProvisioningWorkerState::kFailed,
&der_encoded_spki_);
device_workers_["device_cert_profile_1"] = std::move(device_cert_worker);
// Both user and device-wide workers are expected to be displayed in the UI,
// because the user is affiliated.
base::Value all_processes;
std::vector<std::string> profile_ids;
ASSERT_NO_FATAL_FAILURE(
RefreshCertProvisioningProcesses(&all_processes, &profile_ids));
ASSERT_THAT(profile_ids, UnorderedElementsAre("user_cert_profile_1",
"device_cert_profile_1"));
EXPECT_EQ(
GetByProfileId(all_processes, "user_cert_profile_1"),
FormatJsonDict(
R"({
"certProfileId": "user_cert_profile_1",
"isDeviceWide": false,
"publicKey": "$1",
"stateId": 1,
"status": "$0",
"timeSinceLastUpdate": ""
})",
{l10n_util::GetStringUTF8(
IDS_SETTINGS_CERTIFICATE_MANAGER_PROVISIONING_STATUS_PREPARING_CSR_WAITING),
kFormattedPublicKey}));
EXPECT_EQ(
GetByProfileId(all_processes, "device_cert_profile_1"),
FormatJsonDict(
R"({
"certProfileId": "device_cert_profile_1",
"isDeviceWide": true,
"publicKey": "$1",
"stateId": 10,
"status": "$0",
"timeSinceLastUpdate": ""
})",
{l10n_util::GetStringUTF8(
IDS_SETTINGS_CERTIFICATE_MANAGER_PROVISIONING_STATUS_FAILURE),
kFormattedPublicKey}));
}
} // namespace
} // namespace cert_provisioning
} // namespace chromeos
......@@ -45,6 +45,7 @@ CertificateManagerDialogUI::CertificateManagerDialogUI(content::WebUI* web_ui)
: WebDialogUI(web_ui) {
content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUICertificateManagerHost);
Profile* profile = Profile::FromWebUI(web_ui);
AddCertificateManagerStrings(source);
source->AddBoolean(
......@@ -61,10 +62,10 @@ CertificateManagerDialogUI::CertificateManagerDialogUI(content::WebUI* web_ui)
web_ui->AddMessageHandler(
std::make_unique<certificate_manager::CertificatesHandler>());
web_ui->AddMessageHandler(
std::make_unique<
chromeos::cert_provisioning::CertificateProvisioningUiHandler>());
chromeos::cert_provisioning::CertificateProvisioningUiHandler::
CreateForProfile(profile));
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source);
content::WebUIDataSource::Add(profile, source);
}
CertificateManagerDialogUI::~CertificateManagerDialogUI() {}
......
......@@ -174,8 +174,8 @@ SettingsUI::SettingsUI(content::WebUI* web_ui)
#endif // defined(USE_NSS_CERTS)
#if defined(OS_CHROMEOS)
AddSettingsPageUIHandler(
std::make_unique<
chromeos::cert_provisioning::CertificateProvisioningUiHandler>());
chromeos::cert_provisioning::CertificateProvisioningUiHandler::
CreateForProfile(profile));
#endif
AddSettingsPageUIHandler(std::make_unique<AccessibilityMainHandler>());
......
......@@ -3681,6 +3681,7 @@ test("unit_tests") {
if (is_chromeos) {
sources += [
"../browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc",
"../browser/ui/webui/certificate_provisioning_ui_handler_unittest.cc",
"../browser/ui/webui/chromeos/add_supervision/add_supervision_handler_utils_unittest.cc",
"../browser/ui/webui/chromeos/edu_account_login_handler_unittest.cc",
"../renderer/chromeos_delayed_callback_group_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment